├── .eslintignore ├── example ├── .env ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── index.html ├── src │ ├── App.test.js │ ├── setupTests.js │ ├── reportWebVitals.js │ ├── App.js │ └── index.js ├── .gitignore ├── package.json └── README.md ├── .gitignore ├── src ├── _variables.scss ├── components │ ├── Button │ │ ├── index.ts │ │ ├── Button.module.scss │ │ ├── Button.types.ts │ │ ├── Button.tsx │ │ ├── Button.test.tsx │ │ └── Button.stories.tsx │ ├── TestComponent │ │ ├── index.ts │ │ ├── TestComponent.types.ts │ │ ├── TestComponent.module.scss │ │ ├── TestCompoenent.tsx │ │ ├── TestComponent.stories.tsx │ │ └── TestComponent.test.tsx │ └── index.ts ├── declarations.d.ts ├── styles.scss └── _normalize.scss ├── jest.setup.ts ├── .editorconfig ├── .storybook ├── preview.ts └── main.ts ├── README.md ├── jest.config.js ├── tsconfig.json ├── .eslintrc.json ├── rollup.config.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /example/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .vscode -------------------------------------------------------------------------------- /src/_variables.scss: -------------------------------------------------------------------------------- 1 | $primary: goldenrod; 2 | -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export { Button as default } from './Button'; 2 | -------------------------------------------------------------------------------- /src/components/TestComponent/index.ts: -------------------------------------------------------------------------------- 1 | export { TestComponent as default } from './TestCompoenent'; 2 | -------------------------------------------------------------------------------- /example/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MomenSherif/react-lib-boilerplate/HEAD/example/public/favicon.ico -------------------------------------------------------------------------------- /example/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MomenSherif/react-lib-boilerplate/HEAD/example/public/logo192.png -------------------------------------------------------------------------------- /example/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MomenSherif/react-lib-boilerplate/HEAD/example/public/logo512.png -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TestComponent } from './TestComponent'; 2 | export { default as Button } from './Button'; 3 | -------------------------------------------------------------------------------- /src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.scss' { 2 | const content: { [className: string]: string }; 3 | export = content; 4 | } 5 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | @import './normalize'; 3 | 4 | html { 5 | font-size: 62.5%; 6 | } 7 | 8 | body { 9 | font-size: 1.6rem; 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | charset = utf-8 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import App from "./App"; 3 | 4 | test("renders learn react link", () => { 5 | render(); 6 | }); 7 | -------------------------------------------------------------------------------- /src/components/TestComponent/TestComponent.types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type TestComponentProps = { 4 | /** 5 | * Theme colors 6 | */ 7 | theme: 'primary' | 'secondary'; 8 | children?: React.ReactNode; 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/Button/Button.module.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | all: unset; 3 | display: inline-block; 4 | padding: 10px 20px; 5 | background-color: goldenrod; 6 | color: white; 7 | 8 | &.secondary { 9 | background-color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Button/Button.types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type ButtonProps = { 4 | variant: 'primary' | 'secondary'; 5 | children?: React.ReactNode; 6 | type: 'button' | 'submit' | 'reset'; 7 | } & React.HTMLProps; 8 | -------------------------------------------------------------------------------- /example/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/components/TestComponent/TestComponent.module.scss: -------------------------------------------------------------------------------- 1 | .test-component { 2 | background-color: white; 3 | border: 1px solid black; 4 | padding: 16px; 5 | width: 360px; 6 | text-align: center; 7 | 8 | &.test-component-secondary { 9 | background-color: black; 10 | color: white; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import { Parameters } from '@storybook/react'; 2 | import '../src/styles.scss'; 3 | 4 | export const parameters: Parameters = { 5 | actions: { argTypesRegex: '^on[A-Z].*' }, 6 | layout: 'padded', 7 | options: { 8 | storySort: (a, b) => 9 | a[1].kind === b[1].kind 10 | ? 0 11 | : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }), 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /example/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/components/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ButtonProps } from './Button.types'; 4 | import styles from './Button.module.scss'; 5 | 6 | // * Storybook can not catch default export types 7 | export const Button: React.FC = ({ 8 | variant, children, className, ...rest 9 | }) => ( 10 | 17 | ); 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📦 React Component Library Startup Files 2 | 3 | ## `🎉Rollup - TS - Jest - React Testing Library - SCSS 🎉` 4 | 5 | 6 | |Scripts 💻 | npm run ... | 7 | |---------------------------|--| 8 | | Setup *first time only*| setup| 9 | | Development | dev | 10 | | Storybook | storybook| 11 | | Production | build | 12 | | Testing | test:watch| 13 | 14 | 15 | **If setup didn't go well, Insatll dependencies manually** 16 | 17 | 18 | 19 | 1. npm i 20 | 2. npm run build 21 | 3. cd example 22 | 4. npm i 23 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import { TestComponent } from "react-component-lib"; 2 | function App() { 3 | return ( 4 |
5 |
6 |

Hello From Mo'men 🐱‍👤

7 |

8 | 9 | Github Repo 10 | 11 | ⭐ will be appreciated ❤ 12 |

13 |
14 | 15 |
16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /src/components/TestComponent/TestCompoenent.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { TestComponentProps } from './TestComponent.types'; 4 | import styles from './TestComponent.module.scss'; 5 | 6 | // * Storybook can no't catch default export types 7 | export const TestComponent: React.FC = ({ theme, children }) => ( 8 |
12 |

Test Component 😢

13 | {children} 14 |
15 | ); 16 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['./src'], 3 | setupFilesAfterEnv: ['./jest.setup.ts'], 4 | moduleFileExtensions: ['ts', 'tsx', 'js'], 5 | testPathIgnorePatterns: ['node_modules/'], 6 | transform: { 7 | '^.+\\.tsx?$': 'ts-jest', 8 | }, 9 | testMatch: ['**/*.test.(ts|tsx)'], 10 | moduleNameMapper: { 11 | // Mocks out all these file formats when tests are run 12 | '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 13 | 'identity-obj-proxy', 14 | '\\.(css|less|scss|sass)$': 'identity-obj-proxy', 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "react-component-lib/dist/styles.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root") 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/Button/Button.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import userEvent from '@testing-library/user-event'; 4 | 5 | import { Button } from './Button'; 6 | 7 | describe(', 14 | ); 15 | const button = screen.getByRole('button', { name: /click me/i }); 16 | userEvent.click(button); 17 | expect(mockedFn).toBeCalledTimes(1); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "dist", 5 | "module": "esnext", 6 | "target": "es5", 7 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 8 | "jsx": "react", 9 | "moduleResolution": "node", 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": true, 12 | "noImplicitReturns": true, 13 | "noUnusedParameters": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true 16 | }, 17 | "include": ["src/**/*"], 18 | "exclude": [ 19 | "node_modules", 20 | "build", 21 | "src/**/*.stories.tsx", 22 | "src/**/*.test.tsx", 23 | "src/utils" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/components/Button/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Story, Meta } from '@storybook/react'; 3 | 4 | import Button from '.'; 5 | import { ButtonProps } from './Button.types'; 6 | 7 | export default { 8 | title: 'Button', 9 | component: Button, 10 | } as Meta; 11 | 12 | const Template: Story = (args) =>