├── .babelrc ├── .gitignore ├── .prettierrc ├── .storybook ├── main.js ├── manager.js ├── theme.js └── utils.js ├── README.md ├── components └── index.js ├── package-lock.json ├── package.json ├── rollup.config.js └── utils ├── helpers.js ├── index.js ├── theme.js └── units.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": false 4 | } 5 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../components/**/*.stories.js'], 3 | }; 4 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import 'storybook-addon-jsx/register'; 2 | import '@storybook/addon-knobs/register'; 3 | import { addons } from '@storybook/addons'; 4 | import theme from './theme'; 5 | 6 | addons.setConfig({ 7 | theme, 8 | }); 9 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming/create'; 2 | 3 | export default create({ 4 | base: 'light', 5 | 6 | colorPrimary: '#0070F3', 7 | colorSecondary: '#146DD6', 8 | 9 | // UI 10 | appBg: '#fff', 11 | appContentBg: '#fff', 12 | appBorderColor: '#ddd', 13 | appBorderRadius: 5, 14 | 15 | // Typography 16 | fontBase: '"Open Sans", sans-serif', 17 | fontCode: 'monospace', 18 | 19 | // Text colors 20 | textColor: '#333', 21 | textInverseColor: 'rgba(255,255,255,0.9)', 22 | 23 | // Toolbar default and active colors 24 | barTextColor: '#333', 25 | barSelectedColor: '#999', 26 | barBg: '#eaeaea', 27 | 28 | // Form colors 29 | inputBg: 'white', 30 | inputBorder: 'silver', 31 | inputTextColor: 'black', 32 | inputBorderRadius: 5, 33 | 34 | brandTitle: 'My component library', 35 | brandUrl: 'https://ademola.adegbuyi.me', 36 | brandImage: '', 37 | }); 38 | -------------------------------------------------------------------------------- /.storybook/utils.js: -------------------------------------------------------------------------------- 1 | import { jsxDecorator } from 'storybook-addon-jsx'; 2 | import { withKnobs } from '@storybook/addon-knobs'; 3 | 4 | const decorators = [jsxDecorator, withKnobs]; 5 | 6 | export default decorators; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # component-library 2 | An example on how to create a component library with React and Emotion 3 | -------------------------------------------------------------------------------- /components/index.js: -------------------------------------------------------------------------------- 1 | // Hi there! Let's get started 💃 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smashing-mag-component-library", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/mag-component-library.js", 6 | "module": "dist/mag-component-library.es.js", 7 | "scripts": { 8 | "build": "rollup -c", 9 | "bundle-size": "cat dist/mag-component-library.js | gzip | wc -c", 10 | "storybook": "start-storybook -p 9000 -c .storybook" 11 | }, 12 | "engines": { 13 | "node": ">=10.0.0" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "dependencies": { 19 | "polished": "^3.6.5" 20 | }, 21 | "devDependencies": { 22 | "@babel/preset-env": "^7.11.0", 23 | "@babel/preset-react": "^7.10.4", 24 | "@emotion/core": "^10.0.28", 25 | "@emotion/styled": "^10.0.27", 26 | "@rollup/plugin-commonjs": "^15.0.0", 27 | "@rollup/plugin-node-resolve": "^9.0.0", 28 | "@storybook/addon-knobs": "^6.0.10", 29 | "@storybook/addons": "^6.0.10", 30 | "@storybook/react": "^6.0.10", 31 | "@storybook/theming": "^6.0.10", 32 | "babel-loader": "^8.1.0", 33 | "emotion-theming": "^10.0.27", 34 | "react": "^16.13.1", 35 | "react-dom": "^16.13.1", 36 | "rollup": "^2.26.0", 37 | "rollup-plugin-babel": "^4.4.0", 38 | "rollup-plugin-terser": "^7.0.0", 39 | "storybook-addon-jsx": "^7.3.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import babel from 'rollup-plugin-babel'; 3 | import { terser } from 'rollup-plugin-terser'; 4 | import commonjs from '@rollup/plugin-commonjs'; 5 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 6 | 7 | const pkg = JSON.parse( 8 | fs.readFileSync('./package.json', { encoding: 'utf-8' }) 9 | ); 10 | 11 | export default { 12 | input: 'components', 13 | external: ['react', '@emotion/core', '@emotion/styled'], 14 | plugins: [ 15 | babel({ 16 | exclude: 'node_modules/**', 17 | }), 18 | commonjs(), 19 | nodeResolve({ browser: true }), 20 | terser(), 21 | ], 22 | output: [ 23 | { 24 | file: pkg.main, 25 | format: 'cjs', 26 | sourcemap: true, 27 | }, 28 | { 29 | file: pkg.module, 30 | format: 'es', 31 | sourcemap: true, 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /utils/helpers.js: -------------------------------------------------------------------------------- 1 | export const isObjectEmpty = (obj) => { 2 | return Object.keys(obj).length === 0; 3 | }; 4 | -------------------------------------------------------------------------------- /utils/index.js: -------------------------------------------------------------------------------- 1 | export * from './units'; 2 | export * from './helpers'; 3 | export * from './theme'; 4 | -------------------------------------------------------------------------------- /utils/theme.js: -------------------------------------------------------------------------------- 1 | import { spacing } from './units'; 2 | 3 | const white = '#fff'; 4 | const black = '#111'; 5 | 6 | const palette = { 7 | common: { 8 | black, 9 | white, 10 | }, 11 | primary: { 12 | main: '#0070F3', 13 | light: '#146DD6', 14 | contrastText: white, 15 | }, 16 | error: { 17 | main: '#A51C30', 18 | light: '#A7333F', 19 | contrastText: white, 20 | }, 21 | grey: { 22 | 100: '#EAEAEA', 23 | 200: '#C9C5C5', 24 | 300: '#888', 25 | 400: '#666', 26 | }, 27 | }; 28 | 29 | const shadows = { 30 | 0: 'none', 31 | 1: '0px 5px 10px rgba(0, 0, 0, 0.12)', 32 | 2: '0px 8px 30px rgba(0, 0, 0, 0.24)', 33 | }; 34 | 35 | const typography = { 36 | fontFamily: 37 | "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', sans-serif", 38 | }; 39 | 40 | const shape = { 41 | borderRadius: spacing['xxsmall'], 42 | }; 43 | 44 | export const theme = { 45 | palette, 46 | shadows, 47 | typography, 48 | shape, 49 | }; 50 | -------------------------------------------------------------------------------- /utils/units.js: -------------------------------------------------------------------------------- 1 | import { rem } from 'polished'; 2 | 3 | export const spacing = { 4 | none: 0, 5 | xxsmall: rem('4px'), 6 | xsmall: rem('8px'), 7 | small: rem('12px'), 8 | medium: rem('20px'), 9 | gutter: rem('24px'), 10 | large: rem('32px'), 11 | xlarge: rem('48px'), 12 | xxlarge: rem('96px'), 13 | }; 14 | 15 | export const fontSizes = { 16 | xsmall: '0.79rem', 17 | small: '0.889rem', 18 | medium: '1rem', 19 | large: '1.125rem', 20 | xlarge: '1.266rem', 21 | xxlarge: '1.424rem', 22 | }; 23 | --------------------------------------------------------------------------------