PR-722301: Adding Library Components.
This commit is contained in:
parent
2410a0f8d0
commit
b100dc40c3
43
.github/workflows/npm-publish.yml
vendored
Normal file
43
.github/workflows/npm-publish.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
name: NPM testing and publish package
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci --legacy-peer-deps
|
||||
- run: npm test
|
||||
cypress-run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress install
|
||||
run: npm install --legacy-peer-deps
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v5 # use the explicit version number
|
||||
with:
|
||||
install: false
|
||||
component: true
|
||||
publish-npm:
|
||||
needs: [ build, cypress-run ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci --legacy-peer-deps
|
||||
- run: npm publish --access=public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
47
.github/workflows/npm-test.yml
vendored
Normal file
47
.github/workflows/npm-test.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Testing package
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ['*']
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js 16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci --legacy-peer-deps
|
||||
- run: npm test
|
||||
cypress-run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress install
|
||||
run: npm install --legacy-peer-deps
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v5 # use the explicit version number
|
||||
with:
|
||||
install: false
|
||||
component: true
|
||||
test-build-package:
|
||||
needs: [ test, cypress-run ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci --legacy-peer-deps
|
||||
- run: npm run build
|
@ -16,7 +16,9 @@ module.exports = {
|
||||
}),
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
'@components': path.resolve(__dirname, "../src/components/")
|
||||
'@components': path.resolve(__dirname, "../src/components/"),
|
||||
'@styles': path.resolve(__dirname, "../src/styles/"),
|
||||
'@utils': path.resolve(__dirname, "../src/utils/")
|
||||
};
|
||||
config.resolve.plugins = [new TsconfigPathsPlugin()];
|
||||
return config;
|
||||
|
142
package-lock.json
generated
142
package-lock.json
generated
@ -1,22 +1,24 @@
|
||||
{
|
||||
"name": "@aleleba/create-react-component-library",
|
||||
"version": "1.2.14",
|
||||
"name": "react-list-ui-library",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@aleleba/create-react-component-library",
|
||||
"version": "1.2.14",
|
||||
"name": "react-list-ui-library",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"create-react-component-library": "bin/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.0",
|
||||
"@babel/preset-env": "^7.22.20",
|
||||
"@babel/preset-react": "^7.22.15",
|
||||
"@babel/preset-typescript": "^7.23.0",
|
||||
"@babel/register": "^7.22.15",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@mdx-js/react": "^2.3.0",
|
||||
"@storybook/addon-actions": "^7.4.6",
|
||||
"@storybook/addon-docs": "^7.4.6",
|
||||
@ -2892,6 +2894,81 @@
|
||||
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz",
|
||||
"integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz",
|
||||
"integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
"integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||
"react": ">=16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
|
||||
@ -22689,6 +22766,57 @@
|
||||
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==",
|
||||
"dev": true
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz",
|
||||
"integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==",
|
||||
"dev": true
|
||||
},
|
||||
"@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz",
|
||||
"integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz",
|
||||
"integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.2"
|
||||
}
|
||||
},
|
||||
"@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
"integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prop-types": "^15.8.1"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "react-list-ui-library",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.0",
|
||||
"description": "A starter kit for create a React component Library with storybook",
|
||||
"main": "dist/index.js",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"start": "npm run storybook",
|
||||
"build": "webpack",
|
||||
@ -39,6 +39,11 @@
|
||||
"@babel/preset-react": "^7.22.15",
|
||||
"@babel/preset-typescript": "^7.23.0",
|
||||
"@babel/register": "^7.22.15",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@mdx-js/react": "^2.3.0",
|
||||
"@storybook/addon-actions": "^7.4.6",
|
||||
"@storybook/addon-docs": "^7.4.6",
|
||||
|
21
src/components/Button/AddButton/index.tsx
Normal file
21
src/components/Button/AddButton/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { FC, MouseEventHandler } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import "./style.scss";
|
||||
|
||||
type TAddButtonProps = {
|
||||
/**
|
||||
* Is this the onClick Event of the button.
|
||||
*/
|
||||
onClick?: MouseEventHandler<HTMLButtonElement> | undefined
|
||||
};
|
||||
|
||||
const AddButton: FC<TAddButtonProps> = ({ onClick }) => {
|
||||
return (
|
||||
<button type="button" className="addButton" onClick={onClick}>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export { AddButton, TAddButtonProps }
|
25
src/components/Button/AddButton/style.scss
Normal file
25
src/components/Button/AddButton/style.scss
Normal file
@ -0,0 +1,25 @@
|
||||
.addButton {
|
||||
border: none;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
// background-color: #FF6955;
|
||||
background-color: #71b9f5;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s ease-in-out;
|
||||
font-size: 18px;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
// background-color: #bc2d1a;
|
||||
background-color: #185c94;
|
||||
}
|
||||
|
||||
svg {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
}
|
40
src/components/Button/Buttons.stories.tsx
Normal file
40
src/components/Button/Buttons.stories.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { Button, ButtonTypes } from '@components';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: 'List Design System/Button',
|
||||
component: Button,
|
||||
argTypes: {
|
||||
type: {
|
||||
options: [
|
||||
ButtonTypes.ADD,
|
||||
ButtonTypes.REMOVE
|
||||
],
|
||||
control: {
|
||||
type: 'select',
|
||||
labels: {
|
||||
[ButtonTypes.ADD]: 'ADD',
|
||||
[ButtonTypes.REMOVE]: 'REMOVE'
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} as Meta<typeof Button>;
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
||||
const Template: StoryFn<typeof Button> = (args) => <Button {...args} />;
|
||||
|
||||
export const AddButton = Template.bind({});
|
||||
export const RemoveButton = Template.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
AddButton.args = {
|
||||
type: ButtonTypes.ADD,
|
||||
onClick: () => alert('AddButton Clicked')
|
||||
};
|
||||
|
||||
RemoveButton.args = {
|
||||
type: ButtonTypes.REMOVE,
|
||||
onClick: () => alert('RemoveButton Clicked')
|
||||
};
|
21
src/components/Button/RemoveButton/index.tsx
Normal file
21
src/components/Button/RemoveButton/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { FC, MouseEventHandler } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faTrashCan } from '@fortawesome/free-solid-svg-icons';
|
||||
import "./style.scss";
|
||||
|
||||
type TRemoveButtonProps = {
|
||||
/**
|
||||
* Is this the onClick Event of the button.
|
||||
*/
|
||||
onClick?: MouseEventHandler<HTMLButtonElement> | undefined
|
||||
};
|
||||
|
||||
const RemoveButton: FC<TRemoveButtonProps> = ({ onClick }) => {
|
||||
return (
|
||||
<button type="button" className="removeButton" onClick={onClick}>
|
||||
<FontAwesomeIcon icon={faTrashCan} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export { RemoveButton, TRemoveButtonProps }
|
19
src/components/Button/RemoveButton/style.scss
Normal file
19
src/components/Button/RemoveButton/style.scss
Normal file
@ -0,0 +1,19 @@
|
||||
.removeButton {
|
||||
border: none;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
transition: 0.3s ease-in-out;
|
||||
font-size: 18px;
|
||||
svg {
|
||||
color: #FF6955;
|
||||
transition: 0.3s ease-in-out;
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
color: #bc2d1a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
36
src/components/Button/index.tsx
Normal file
36
src/components/Button/index.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React, { FC, MouseEventHandler } from 'react';
|
||||
import { AddButton } from './AddButton';
|
||||
import { RemoveButton } from './RemoveButton';
|
||||
|
||||
type TButtonProps = {
|
||||
/**
|
||||
* Is this the title of the card.
|
||||
*/
|
||||
type?: ButtonTypes,
|
||||
/**
|
||||
* Is this the onClick Event of the button.
|
||||
*/
|
||||
onClick?: MouseEventHandler<HTMLButtonElement> | undefined
|
||||
};
|
||||
|
||||
enum ButtonTypes {
|
||||
ADD = 'ADD',
|
||||
REMOVE = 'REMOVE'
|
||||
}
|
||||
|
||||
const Button: FC<TButtonProps> = ({ type = ButtonTypes.ADD, onClick }) => {
|
||||
return(
|
||||
<>
|
||||
{
|
||||
type === ButtonTypes.ADD &&
|
||||
<AddButton onClick={onClick} />
|
||||
}
|
||||
{
|
||||
type === ButtonTypes.REMOVE &&
|
||||
<RemoveButton onClick={onClick} />
|
||||
}
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
export { Button, TButtonProps, ButtonTypes }
|
@ -1,25 +0,0 @@
|
||||
import React, { FC } from "react";
|
||||
import "./style.scss";
|
||||
|
||||
type TCardProps = {
|
||||
/**
|
||||
* Is this the title of the card.
|
||||
*/
|
||||
title?: string,
|
||||
/**
|
||||
* Is this the child component of the card. (The content)
|
||||
*/
|
||||
children?: JSX.Element,
|
||||
};
|
||||
|
||||
const Card: FC<TCardProps> = ({ title, children}) => {
|
||||
return (
|
||||
<div className="Card">
|
||||
<div className="Title">{title}</div>
|
||||
|
||||
<div className="Content">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { Card, TCardProps }
|
@ -1,25 +0,0 @@
|
||||
.Card{
|
||||
background-color: #20b0f3;
|
||||
border-radius: 10px;
|
||||
border: 3px solid #20b0f3;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
margin: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 500px;
|
||||
max-width: 500px;
|
||||
|
||||
.Title {
|
||||
padding: 15px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.Content {
|
||||
flex: 1;
|
||||
padding: 30px;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
42
src/components/ContainerList/ContainerList.stories.tsx
Normal file
42
src/components/ContainerList/ContainerList.stories.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { ContainerList, List, Status } from '@components';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: 'List Design System/ContainerList',
|
||||
component: ContainerList,
|
||||
} as Meta<typeof ContainerList>;
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
||||
const Template: StoryFn<typeof ContainerList> = (args) => <ContainerList {...args} />;
|
||||
|
||||
export const Basic = Template.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
Basic.args = {
|
||||
title: 'List Title',
|
||||
children:
|
||||
<>
|
||||
<List
|
||||
list={[
|
||||
{
|
||||
name: 'First Item',
|
||||
status: Status.TODO
|
||||
},
|
||||
{
|
||||
name: 'Second Item',
|
||||
status: Status.DONE
|
||||
},
|
||||
{
|
||||
name: 'Third Item',
|
||||
status: Status.TODO
|
||||
},
|
||||
{
|
||||
name: 'Fourth Item',
|
||||
status: Status.DONE
|
||||
}
|
||||
]}
|
||||
placeholderInput='Add a Item'
|
||||
/>
|
||||
</>
|
||||
};
|
24
src/components/ContainerList/index.tsx
Normal file
24
src/components/ContainerList/index.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React, { FC } from 'react';
|
||||
import './style.scss';
|
||||
|
||||
type TContainerListProps = {
|
||||
/**
|
||||
* Is this the title of the card.
|
||||
*/
|
||||
title?: string,
|
||||
/**
|
||||
* Is this the child component of the card. (The content)
|
||||
*/
|
||||
children?: JSX.Element,
|
||||
};
|
||||
|
||||
const ContainerList: FC<TContainerListProps> = ({ title, children }) => {
|
||||
return (
|
||||
<div className="ContainerList">
|
||||
<div className="title">{title}</div>
|
||||
<div className="content">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { ContainerList, TContainerListProps }
|
29
src/components/ContainerList/style.scss
Normal file
29
src/components/ContainerList/style.scss
Normal file
@ -0,0 +1,29 @@
|
||||
.ContainerList{
|
||||
position: relative;
|
||||
background-color: #FEF6F4;
|
||||
border-radius: 10px;
|
||||
color: #000000;
|
||||
font-weight: 200;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 100px;
|
||||
max-width: 600px;
|
||||
font-family: 'Roboto', 'sans-serif';
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.title {
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 10px 30px 30px 30px;
|
||||
background-color: #FEF6F4;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
import React from 'react';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { Card } from '@components';
|
||||
import { Input } from '@components';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: 'Example/Card',
|
||||
component: Card,
|
||||
} as Meta<typeof Card>;
|
||||
title: 'List Design System/Input',
|
||||
component: Input,
|
||||
} as Meta<typeof Input>;
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
||||
const Template: StoryFn<typeof Card> = (args) => <Card {...args} />;
|
||||
const Template: StoryFn<typeof Input> = (args) => <Input {...args} />;
|
||||
|
||||
export const Basic = Template.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
Basic.args = {
|
||||
title: 'Test Title',
|
||||
children: <p>Test Content</p>,
|
||||
placeholder: 'Basic Input',
|
||||
onChange: (e) => { console.log(e.target.value) }
|
||||
};
|
22
src/components/Input/index.tsx
Normal file
22
src/components/Input/index.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { FC, ChangeEventHandler } from 'react';
|
||||
import './style.scss';
|
||||
|
||||
export type TInputProps = {
|
||||
/**
|
||||
* Is this the text you want to add to the input placeholder
|
||||
*/
|
||||
placeholder?: string
|
||||
/**
|
||||
* Is this the onChange event of the input
|
||||
*/
|
||||
onChange?: ChangeEventHandler<HTMLInputElement>
|
||||
};
|
||||
|
||||
export const Input:FC<TInputProps> = ({
|
||||
placeholder = '',
|
||||
onChange = (e) => {}
|
||||
}) => {
|
||||
return(
|
||||
<input className='input' placeholder={placeholder} type='text' onChange={onChange} />
|
||||
)
|
||||
}
|
11
src/components/Input/style.scss
Normal file
11
src/components/Input/style.scss
Normal file
@ -0,0 +1,11 @@
|
||||
.input{
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 50px;
|
||||
font-size: 16px;
|
||||
outline: none;
|
||||
&:focus{
|
||||
border: 1px solid #000;
|
||||
}
|
||||
}
|
49
src/components/Item/Item.stories.tsx
Normal file
49
src/components/Item/Item.stories.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import React, { useState } from 'react';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { Item, Status } from '@components';
|
||||
|
||||
export default {
|
||||
title: 'List Design System/Item',
|
||||
component: Item,
|
||||
argTypes: {
|
||||
status: {
|
||||
options: [
|
||||
Status.TODO,
|
||||
Status.DONE
|
||||
],
|
||||
control: {
|
||||
type: 'select',
|
||||
labels: {
|
||||
[Status.TODO]: 'TODO',
|
||||
[Status.DONE]: 'DONE'
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} as Meta<typeof Item>;
|
||||
|
||||
const TemplateBasic: StoryFn<typeof Item> = (args) => {
|
||||
return <Item {...args} />;
|
||||
};
|
||||
|
||||
const TemplateWithHandleChange: StoryFn<typeof Item> = (args) => {
|
||||
const [status, setStatus] = useState(args.status);
|
||||
|
||||
const handleChange = (event) => {
|
||||
setStatus(event.target.checked ? Status.DONE : Status.TODO);
|
||||
};
|
||||
|
||||
return <Item {...args} status={status} handleChange={handleChange} />;
|
||||
};
|
||||
|
||||
|
||||
export const Basic = TemplateBasic.bind({});
|
||||
Basic.args = {
|
||||
name: 'Item Name',
|
||||
handleChange: () => {}
|
||||
};
|
||||
|
||||
export const WithHandleChange = TemplateWithHandleChange.bind({});
|
||||
WithHandleChange.args = {
|
||||
name: 'Item Name'
|
||||
};
|
14
src/components/Item/__tests__/Item.test.cy.tsx
Normal file
14
src/components/Item/__tests__/Item.test.cy.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Item, Status } from '@components';
|
||||
|
||||
describe('Testing Card Component', () => {
|
||||
beforeEach(() => {
|
||||
cy.mount(<Item name='Item Test' status={Status.DONE} />);
|
||||
})
|
||||
it('Show Item name', () => {
|
||||
cy.get('span').contains('Item Test');
|
||||
})
|
||||
it('Show Item as Checked', () => {
|
||||
cy.get('input').should('be.checked');
|
||||
})
|
||||
})
|
17
src/components/Item/__tests__/Item.test.tsx
Normal file
17
src/components/Item/__tests__/Item.test.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { Item, Status } from '@components';
|
||||
|
||||
describe('<App/> Component', () => {
|
||||
beforeEach(() => {
|
||||
// fetchMock.resetMocks();
|
||||
render(<Item name='Item Test' status={Status.DONE} handleChange={ () => {}} />)
|
||||
});
|
||||
it('Show Item Name', async () => {
|
||||
/* fetchMock.mockResponseOnce(JSON.stringify({
|
||||
//First Data Fetch
|
||||
data: 'data'
|
||||
})); */
|
||||
screen.getByText('Item Test')
|
||||
})
|
||||
})
|
63
src/components/Item/index.tsx
Normal file
63
src/components/Item/index.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import React, { FC, ChangeEventHandler } from 'react';
|
||||
import './style.scss';
|
||||
import { joinClassNames } from '@utils/index';
|
||||
|
||||
type TItemProps = {
|
||||
/**
|
||||
* Is this the name of the item.
|
||||
*/
|
||||
name?: string,
|
||||
/**
|
||||
* Is this the status of the item.
|
||||
*/
|
||||
status?: Status,
|
||||
/**
|
||||
* Is this the on Event triggered by the checkbox.
|
||||
*/
|
||||
handleChange?: ChangeEventHandler<HTMLInputElement>
|
||||
};
|
||||
|
||||
type TItem = {
|
||||
name: string,
|
||||
status: Status
|
||||
}
|
||||
|
||||
enum Status {
|
||||
TODO = 'TODO',
|
||||
DONE = 'DONE'
|
||||
}
|
||||
|
||||
export const getStatusClass = ({ status }: { status: Status }) => {
|
||||
switch (status) {
|
||||
case 'TODO':
|
||||
return 'to-do';
|
||||
case 'DONE':
|
||||
return 'done';
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const Item: FC<TItemProps> = ({
|
||||
name,
|
||||
status = Status.TODO,
|
||||
handleChange
|
||||
}) => {
|
||||
const classNames = joinClassNames(getStatusClass({ status }));
|
||||
return (
|
||||
<div className="round">
|
||||
<input
|
||||
id={name}
|
||||
type="checkbox"
|
||||
checked={status === Status.DONE}
|
||||
name={name}
|
||||
className={classNames}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<label htmlFor={name}/>
|
||||
<span className={classNames}>{name}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { Item, TItemProps, TItem, Status }
|
57
src/components/Item/style.scss
Normal file
57
src/components/Item/style.scss
Normal file
@ -0,0 +1,57 @@
|
||||
.round {
|
||||
position: relative;
|
||||
|
||||
label {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: 19px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 19px;
|
||||
}
|
||||
|
||||
label:after {
|
||||
border: 2px solid #fff;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
content: "";
|
||||
height: 6px;
|
||||
left: 2.5px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
transform: rotate(-45deg);
|
||||
width: 11px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label {
|
||||
background-color: #66bb6a;
|
||||
border-color: #66bb6a;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
margin-left: 10px;
|
||||
font-family: 'Roboto', 'sans-serif';
|
||||
color: #77838F;
|
||||
font-weight: 400;
|
||||
|
||||
&.done {
|
||||
text-decoration: line-through;
|
||||
color: #77838F;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
28
src/components/List/List.stories.tsx
Normal file
28
src/components/List/List.stories.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { List, Status } from '@components';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: 'List Design System/List',
|
||||
component: List,
|
||||
} as Meta<typeof List>;
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
||||
const Template: StoryFn<typeof List> = (args) => <List {...args} />;
|
||||
|
||||
export const Basic = Template.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
Basic.args = {
|
||||
list: [
|
||||
{
|
||||
name: 'Item 1',
|
||||
status: Status.TODO
|
||||
},
|
||||
{
|
||||
name: 'Item 2',
|
||||
status: Status.DONE
|
||||
}
|
||||
],
|
||||
placeholderInput: 'Add a Item',
|
||||
};
|
71
src/components/List/index.tsx
Normal file
71
src/components/List/index.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import React, { FC, MouseEventHandler, ChangeEventHandler } from 'react';
|
||||
import { TItem, Item, ButtonTypes, Button, Input } from '@components';
|
||||
import './style.scss';
|
||||
import { on } from 'events';
|
||||
|
||||
type TListProps = {
|
||||
/**
|
||||
* Is this the title of the card.
|
||||
*/
|
||||
list: TItem[]
|
||||
/**
|
||||
* Is this the title of the card.
|
||||
*/
|
||||
placeholderInput?: string
|
||||
/**
|
||||
* Is this the onChange event of the input
|
||||
*/
|
||||
onChangeInput?: ChangeEventHandler<HTMLInputElement>
|
||||
/**
|
||||
* Is this the onClick Event of the button.
|
||||
*/
|
||||
onClickAddItem?: MouseEventHandler<HTMLButtonElement> | undefined
|
||||
/**
|
||||
* Is this the onClick Event of the button.
|
||||
*/
|
||||
onClickRemoveItem?: MouseEventHandler<HTMLButtonElement> |undefined
|
||||
};
|
||||
|
||||
const List: FC<TListProps> = ({
|
||||
list,
|
||||
placeholderInput,
|
||||
onChangeInput,
|
||||
onClickAddItem,
|
||||
onClickRemoveItem
|
||||
}) => {
|
||||
return (
|
||||
<div className="List">
|
||||
<table>
|
||||
<tbody>
|
||||
{ list !== undefined && list.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td><Item name={item.name} status={item.status} /></td>
|
||||
<td>
|
||||
<div className="delete-button-container">
|
||||
<Button
|
||||
type={ButtonTypes.REMOVE}
|
||||
onClick={onClickRemoveItem}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<Input
|
||||
placeholder={placeholderInput}
|
||||
onChange={onChangeInput}
|
||||
/>
|
||||
</div>
|
||||
<div className="button-container">
|
||||
<Button
|
||||
type={ButtonTypes.ADD}
|
||||
onClick={onClickAddItem}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { List, TListProps }
|
40
src/components/List/style.scss
Normal file
40
src/components/List/style.scss
Normal file
@ -0,0 +1,40 @@
|
||||
.List {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 600px;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
background: #FFF;
|
||||
box-shadow: 0px 2px 48px 0px rgba(0, 0, 0, 0.08);
|
||||
//left: 50%;
|
||||
//transform: translateX(50%);
|
||||
|
||||
table {
|
||||
margin: 10px 0 30px 0;
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
padding: 5px 0 5px 0;
|
||||
border-bottom: 1px solid #E0E0E0;
|
||||
font-size: 14px;
|
||||
color: #4A4A4A;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
|
||||
.delete-button-container{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
left: 65%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
position: relative;
|
||||
left: 90%;
|
||||
top: 35px;
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Card } from '@components';
|
||||
|
||||
describe('Testing Card Component', () => {
|
||||
beforeEach(() => {
|
||||
cy.mount(<Card title='Test Title'><p>Test Content</p></Card>);
|
||||
})
|
||||
it('Show Title', () => {
|
||||
cy.get('div').contains('Test Title');
|
||||
})
|
||||
it('Show Child Component', () => {
|
||||
cy.get('p').contains('Test Content');
|
||||
})
|
||||
})
|
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { Card } from '@components';
|
||||
|
||||
describe('<App/> Component', () => {
|
||||
beforeEach(() => {
|
||||
// fetchMock.resetMocks();
|
||||
render(<Card title='Test Title'><p>Test Content</p></Card>)
|
||||
});
|
||||
it('Show Title', async () => {
|
||||
/* fetchMock.mockResponseOnce(JSON.stringify({
|
||||
//First Data Fetch
|
||||
data: 'data'
|
||||
})); */
|
||||
screen.getByText('Test Title')
|
||||
})
|
||||
it('Show Child Component', async () => {
|
||||
/* fetchMock.mockResponseOnce(JSON.stringify({
|
||||
//First Data Fetch
|
||||
data: 'data'
|
||||
})); */
|
||||
screen.getByText('Test Content')
|
||||
})
|
||||
})
|
@ -1 +1,7 @@
|
||||
export * from './Card';
|
||||
import '@styles/global.scss'
|
||||
|
||||
export * from './ContainerList';
|
||||
export * from './List';
|
||||
export * from './Item';
|
||||
export * from './Button';
|
||||
export * from './Input';
|
@ -8,7 +8,7 @@ import Plugin from './assets/plugin.svg';
|
||||
import Repo from './assets/repo.svg';
|
||||
import StackAlt from './assets/stackalt.svg';
|
||||
|
||||
<Meta title="Example/Introduction" />
|
||||
<Meta title="List Design System/Introduction" />
|
||||
|
||||
<style>
|
||||
{`
|
||||
|
1
src/styles/global.scss
Normal file
1
src/styles/global.scss
Normal file
@ -0,0 +1 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
|
1
src/utils/index.ts
Normal file
1
src/utils/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export const joinClassNames = (...classes: string[]) => classes.filter(className => className).join(' ')
|
@ -33,7 +33,10 @@
|
||||
"noImplicitAny": false,
|
||||
"paths": {
|
||||
"@components/*": ["src/components/*"],
|
||||
"@components": ["src/components"]
|
||||
"@components": ["src/components"],
|
||||
"@styles": ["src/styles"],
|
||||
"@utils/*": ["src/utils/*"],
|
||||
"@utils": ["src/utils"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
|
Loading…
Reference in New Issue
Block a user