├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── README.md ├── package.json ├── private ├── jest │ ├── componentsMock.js │ ├── fileMock.js │ └── setupTests.js └── storybook │ ├── config.js │ └── webpack.config.js ├── public ├── icon.png ├── index.html └── thumbnail.png ├── src-example ├── components │ ├── App.js │ ├── atoms │ │ ├── Atom │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Badge │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Block │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Button │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Caption │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Heading │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── HorizontalRule │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Icon │ │ │ ├── icons │ │ │ │ ├── arc.svg │ │ │ │ ├── atomic-design.svg │ │ │ │ ├── close.svg │ │ │ │ ├── copy.svg │ │ │ │ ├── dist.svg │ │ │ │ ├── docs.svg │ │ │ │ ├── github.svg │ │ │ │ ├── heart.svg │ │ │ │ ├── jest.svg │ │ │ │ ├── react-router.svg │ │ │ │ ├── react.svg │ │ │ │ ├── redux.svg │ │ │ │ └── webpack.svg │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Input │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Label │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Link │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── List │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── LogoImage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ ├── index.test.js │ │ │ └── logo.svg │ │ ├── Paragraph │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── PreformattedText │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Spinner │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── TableCell │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── TableRow │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ └── Tooltip │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ ├── index.js │ ├── molecules │ │ ├── Blockquote │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Feature │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Field │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── IconButton │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── IconLink │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Modal │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Molecule │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── PrimaryNavigation │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Slider │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ └── Table │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ ├── organisms │ │ ├── FeatureList │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Footer │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Header │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── Hero │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ └── Organism │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ ├── pages │ │ ├── GenericPage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── HomePage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ ├── NotFoundPage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ │ └── SamplePage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ ├── templates │ │ ├── GenericTemplate │ │ │ ├── index.js │ │ │ └── index.test.js │ │ └── PageTemplate │ │ │ ├── index.js │ │ │ └── index.test.js │ └── themes │ │ └── default.js ├── config.js └── index.js ├── src ├── components │ ├── App.js │ ├── index.js │ ├── pages │ │ └── HomePage │ │ │ ├── index.js │ │ │ ├── index.stories.js │ │ │ └── index.test.js │ └── themes │ │ └── default.js ├── config.js └── index.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "@babel/preset-react" 10 | ], 11 | "plugins": [ 12 | "react-hot-loader/babel", 13 | "@babel/plugin-syntax-dynamic-import", 14 | "@babel/plugin-syntax-import-meta", 15 | "@babel/plugin-proposal-class-properties", 16 | "@babel/plugin-proposal-json-strings", 17 | [ 18 | "@babel/plugin-proposal-decorators", 19 | { 20 | "legacy": true 21 | } 22 | ], 23 | "@babel/plugin-proposal-function-sent", 24 | "@babel/plugin-proposal-export-namespace-from", 25 | "@babel/plugin-proposal-numeric-separator", 26 | "@babel/plugin-proposal-throw-expressions", 27 | "@babel/plugin-proposal-export-default-from", 28 | "@babel/plugin-proposal-logical-assignment-operators", 29 | "@babel/plugin-proposal-optional-chaining", 30 | [ 31 | "@babel/plugin-proposal-pipeline-operator", 32 | { 33 | "proposal": "minimal" 34 | } 35 | ], 36 | "@babel/plugin-proposal-nullish-coalescing-operator", 37 | "@babel/plugin-proposal-do-expressions" 38 | ], 39 | "env": { 40 | "development": { 41 | "plugins": [ 42 | "@babel/plugin-transform-modules-commonjs", 43 | [ 44 | "styled-components", 45 | { 46 | "minify": false 47 | } 48 | ] 49 | ] 50 | }, 51 | "test": { 52 | "plugins": [ 53 | "@babel/plugin-transform-modules-commonjs" 54 | ] 55 | }, 56 | "production": { 57 | "plugins": [ 58 | "transform-react-remove-prop-types", 59 | [ 60 | "styled-components", 61 | { 62 | "displayName": false 63 | } 64 | ] 65 | ] 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb" 5 | ], 6 | "env": { 7 | "browser": true, 8 | "jest": true 9 | }, 10 | "globals": { 11 | "__DEV__": true, 12 | "__PROD__": true, 13 | "__DEBUG__": true, 14 | "__COVERAGE__": true, 15 | "__BASENAME__": true 16 | }, 17 | "settings": { 18 | "import/resolver": { 19 | "webpack": { 20 | "config": "webpack.config.js" 21 | } 22 | } 23 | }, 24 | "rules": { 25 | "semi": [2, "never"], 26 | "comma-dangle": [2, "always-multiline"], 27 | "max-len": 0, 28 | "no-shadow": 0, 29 | "arrow-body-style": 0, 30 | "global-require": 0, 31 | "no-unused-expressions": 0, 32 | "no-confusing-arrow": 0, 33 | "no-unused-vars": [2, { "ignoreRestSiblings": true }], 34 | "import/no-dynamic-require": 0, 35 | "import/no-extraneous-dependencies": 0, 36 | "import/prefer-default-export": 0, 37 | "react/require-default-props": 0, 38 | "react/forbid-prop-types": 0, 39 | "react/default-props-match-prop-types": 0, 40 | "react/jsx-filename-extension": [2, {"extensions": [".js", ".jsx"]}], 41 | "jsx-a11y/anchor-is-valid": [2, { 42 | "components": ["Link"], 43 | "specialLink": ["hrefLeft", "hrefRight", "to"], 44 | "aspects": ["noHref", "invalidHref", "preferButton"] 45 | }] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | yarn.lock merge=ours 2 | package-lock.json merge=ours 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .happypack 3 | dist 4 | *.log 5 | node_modules 6 | coverage 7 | webpack/webpack-assets.json 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | script: 5 | - npm run lint 6 | - npm test -- --coverage 7 | - npm run build 8 | cache: 9 | - yarn 10 | after_success: 11 | - bash <(curl -s https://codecov.io/bash) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | arclogo

3 | Build Status 4 | Coverage Status 5 | Gitter chat 6 |

7 | 8 | **ARc** (Atomic React) is a React starter kit based on the [Atomic Design](http://bradfrost.com/blog/post/atomic-web-design/) methodology. It's progressive, which means that you can start with the basic boilerplate and try the other features when you are comfortable. 9 | 10 | - **[Demo](https://arc.js.org)** 11 | - **[Documentation](https://github.com/diegohaz/arc/wiki)** 12 | 13 |
14 |
15 |

16 | If you find this useful, please check out Reakit, a toolkit for building composable UI with React. 17 |

18 |
19 |
20 | 21 | ## Branches 22 | 23 | - ### [`master`](https://github.com/diegohaz/arc) 24 | 25 | The basic stack with [React](https://facebook.github.io/react/), [Webpack](https://github.com/webpack/webpack), [react-router](https://github.com/ReactTraining/react-router) and [Jest](https://facebook.github.io/jest/). 26 | 27 | - ### [`redux`](https://github.com/diegohaz/arc/tree/redux) ([compare](https://github.com/diegohaz/arc/compare/master...redux?diff=split#files_bucket)) 28 | 29 | Master plus [redux](https://github.com/reactjs/redux), [redux-saga](https://github.com/yelouafi/redux-saga) and [redux-form](https://github.com/erikras/redux-form). 30 | 31 | - ### [`redux-ssr`](https://github.com/diegohaz/arc/tree/redux-ssr) ([compare](https://github.com/diegohaz/arc/compare/redux...redux-ssr?diff=split#files_bucket)) 32 | 33 | Redux plus [Server Side Rendering](https://github.com/reactjs/redux/blob/master/docs/recipes/ServerRendering.md) 34 | 35 | ## Why 36 | 37 | I've been a web developer for the past 14 years and after dealing with IE vs. Netscape wars, `` layouts and flash websites, I can say that we are now living in the best moment in web development. Web components are awesome and React makes it better. 38 | 39 | React encourages you to create very small and pure components. However, as your project grows, you will have an increasingly complex components folder. At some point, this will be really huge and hard to maintain. 40 | 41 | I had a React project with more than 100 components in the `components` folder. The first approach I tried to organize it was separating the components by domain (described [here](http://marmelab.com/blog/2015/12/17/react-directory-structure.html)), but I realized that most of my components didn't belong to any domain, but were shared. This meant that my problems just moved to the `commons` folder. 42 | 43 | The [Atomic Design](http://bradfrost.com/blog/post/atomic-web-design/) approach comes handy to solve this problem because it considers the reusability through composition, *which is actually what React is*. You will have your minimal/stylish components in one folder, pages in another and so on. 44 | 45 | ## Setup 46 | 47 | ### 1. Get the source code 48 | 49 | Just clone one of the ARc [branches](#branches): 50 | ```sh 51 | $ git clone -b master https://github.com/diegohaz/arc my-app 52 | $ cd my-app 53 | ``` 54 | 55 | You will probably want to remove ARc git history and start a brand new repository: 56 | ```sh 57 | $ rm -rf .git 58 | $ git init 59 | ``` 60 | 61 | ### 2. Install dependencies 62 | 63 | ```sh 64 | $ npm install 65 | ``` 66 | 67 | ### 3. Run the app 68 | 69 | ```sh 70 | $ npm run dev 71 | ``` 72 | 73 | It will start the development server with [HMR](https://webpack.github.io/docs/hot-module-replacement) on top of it. 74 | 75 | > [http://localhost:3000](http://localhost:3000) — Development server
76 | > [http://localhost:3001](http://localhost:3001) — Webpack assets server (for `redux-ssr` only)
77 | 78 | Now you can open [http://localhost:3000](http://localhost:3000) in browser and start developing. 79 | 80 | ## Contributing 81 | 82 | When submitting an issue, use the following patterns in the title for better understanding: 83 | ```bash 84 | [v0.3.1-redux] Something wrong is not right # the v0.3.1 release of the redux branch 85 | [redux] Something wrong is not right # the actual code of the redux branch 86 | Something wrong is right # general, related to master or not directly related to any branch 87 | ``` 88 | 89 | PRs are very appreciated. For bugs/features consider creating an issue before sending a PR. 90 | 91 | ## License 92 | 93 | MIT © [Diego Haz](https://github.com/diegohaz) 94 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arc", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "npm run dev", 7 | "env:dev": "cross-env NODE_ENV=development", 8 | "env:prod": "cross-env NODE_ENV=production", 9 | "env:example": "cross-env SOURCE=src-example", 10 | "test": "jest", 11 | "coverage": "npm test -- --coverage", 12 | "postcoverage": "opn coverage/lcov-report/index.html", 13 | "lint": "eslint src src-example private webpack.config.js", 14 | "storybook": "start-storybook -p 9001 -c private/storybook", 15 | "storybook:example": "npm run env:example -- npm run storybook", 16 | "dev": "npm run env:dev -- webpack-dev-server", 17 | "dev:example": "npm run env:example -- npm run dev", 18 | "build:clean": "rimraf \"dist/!(.git*|Procfile)**\"", 19 | "build:copy": "copyfiles -u 1 public/* public/**/* dist", 20 | "prebuild": "npm run build:clean && npm run build:copy", 21 | "build": "npm run env:prod -- webpack", 22 | "build:example": "npm run env:example -- npm run build" 23 | }, 24 | "jest": { 25 | "moduleDirectories": [ 26 | "src", 27 | "src-example", 28 | "node_modules" 29 | ], 30 | "moduleNameMapper": { 31 | "^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/private/jest/fileMock.js", 32 | "^components$": "/private/jest/componentsMock.js" 33 | }, 34 | "setupFiles": [ 35 | "/private/jest/setupTests.js" 36 | ] 37 | }, 38 | "devDependencies": { 39 | "@babel/core": "^7.0.0", 40 | "@babel/plugin-proposal-class-properties": "^7.0.0", 41 | "@babel/plugin-proposal-decorators": "^7.0.0", 42 | "@babel/plugin-proposal-do-expressions": "^7.0.0", 43 | "@babel/plugin-proposal-export-default-from": "^7.0.0", 44 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0", 45 | "@babel/plugin-proposal-function-sent": "^7.0.0", 46 | "@babel/plugin-proposal-json-strings": "^7.0.0", 47 | "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", 48 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", 49 | "@babel/plugin-proposal-numeric-separator": "^7.0.0", 50 | "@babel/plugin-proposal-optional-chaining": "^7.0.0", 51 | "@babel/plugin-proposal-pipeline-operator": "^7.0.0", 52 | "@babel/plugin-proposal-throw-expressions": "^7.0.0", 53 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 54 | "@babel/plugin-syntax-import-meta": "^7.0.0", 55 | "@babel/plugin-transform-modules-commonjs": "^7.0.0", 56 | "@babel/preset-env": "^7.0.0", 57 | "@babel/preset-react": "^7.0.0", 58 | "@storybook/addon-actions": "^4.1.4", 59 | "@storybook/react": "^4.1.4", 60 | "babel-core": "^7.0.0-bridge.0", 61 | "babel-eslint": "^10.0.1", 62 | "babel-jest": "^23.6.0", 63 | "babel-loader": "^8.0.5", 64 | "babel-plugin-styled-components": "^1.10.0", 65 | "babel-plugin-transform-react-remove-prop-types": "^0.4.21", 66 | "copyfiles": "^2.0.0", 67 | "cross-env": "^5.0.0", 68 | "enzyme": "^3.8.0", 69 | "enzyme-adapter-react-16": "^1.7.1", 70 | "eslint": "^5.12.0", 71 | "eslint-config-airbnb": "^17.1.0", 72 | "eslint-import-resolver-webpack": "^0.10.1", 73 | "eslint-plugin-import": "^2.2.0", 74 | "eslint-plugin-jsx-a11y": "^6.0.2", 75 | "eslint-plugin-react": "^7.0.1", 76 | "file-loader": "^3.0.1", 77 | "happypack": "^5.0.1", 78 | "html-webpack-plugin": "^3.2.0", 79 | "jest-cli": "^23.6.0", 80 | "opn-cli": "^4.0.0", 81 | "raw-loader": "^1.0.0", 82 | "rimraf": "^2.6.1", 83 | "uglifyjs-webpack-plugin": "^2.1.1", 84 | "url-loader": "^1.1.2", 85 | "webpack": "^4.28.3", 86 | "webpack-cli": "^3.2.0", 87 | "webpack-dev-server": "^3.1.14", 88 | "webpack-md5-hash": "^0.0.6" 89 | }, 90 | "dependencies": { 91 | "lodash": "^4.17.13", 92 | "prop-types": "^15.6.2", 93 | "react": "^16.7.0", 94 | "react-dom": "^16.7.0", 95 | "react-hot-loader": "^4.6.3", 96 | "react-modal": "^3.1.11", 97 | "react-router-dom": "^4.3.1", 98 | "styled-components": "^3.5.0-0", 99 | "styled-theme": "^0.3.3", 100 | "styled-tools": "^1.6.0" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /private/jest/componentsMock.js: -------------------------------------------------------------------------------- 1 | // https://github.com/diegohaz/arc/wiki/Testing-components 2 | import React from 'react' 3 | import PropTypes from 'prop-types' 4 | 5 | module.exports = new Proxy({}, { 6 | get: (target, property) => { 7 | const Mock = ({ children }) => {children} 8 | 9 | Mock.displayName = property 10 | Mock.propTypes = { 11 | children: PropTypes.any, 12 | } 13 | 14 | return Mock 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /private/jest/fileMock.js: -------------------------------------------------------------------------------- 1 | export default 'file' 2 | -------------------------------------------------------------------------------- /private/jest/setupTests.js: -------------------------------------------------------------------------------- 1 | import { configure } from 'enzyme' 2 | import Adapter from 'enzyme-adapter-react-16' 3 | 4 | configure({ adapter: new Adapter() }) 5 | -------------------------------------------------------------------------------- /private/storybook/config.js: -------------------------------------------------------------------------------- 1 | // https://github.com/diegohaz/arc/wiki/Storybook 2 | import React from 'react' 3 | import { configure, addDecorator } from '@storybook/react' 4 | import { BrowserRouter } from 'react-router-dom' 5 | import { ThemeProvider } from 'styled-components' 6 | import theme from 'components/themes/default' 7 | 8 | const req = require.context('components', true, /.stories.js$/) 9 | 10 | function loadStories() { 11 | req.keys().forEach(filename => req(filename)) 12 | } 13 | 14 | addDecorator(story => ( 15 | 16 | {story()} 17 | 18 | )) 19 | 20 | configure(loadStories, module) 21 | -------------------------------------------------------------------------------- /private/storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../webpack.config') 2 | 3 | module.exports = storybookBaseConfig => Object.assign({}, storybookBaseConfig, { 4 | resolve: Object.assign({}, storybookBaseConfig.resolve, { 5 | modules: baseConfig.resolve.modules, 6 | }), 7 | module: Object.assign({}, storybookBaseConfig.module, { 8 | rules: storybookBaseConfig.module.rules.concat(baseConfig.module.rules.slice(1)), 9 | }), 10 | }) 11 | -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegohaz/arc/c90e60c21bca877965e93142f23bf37c8456a122/public/icon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ARc - Atomic React 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /public/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegohaz/arc/c90e60c21bca877965e93142f23bf37c8456a122/public/thumbnail.png -------------------------------------------------------------------------------- /src-example/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Switch, Route } from 'react-router-dom' 3 | import { injectGlobal, ThemeProvider } from 'styled-components' 4 | 5 | import { HomePage, SamplePage, NotFoundPage } from 'components' 6 | 7 | // https://github.com/diegohaz/arc/wiki/Styling 8 | import theme from './themes/default' 9 | 10 | injectGlobal` 11 | body { 12 | margin: 0; 13 | } 14 | ` 15 | 16 | const App = () => { 17 | return ( 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default App 29 | -------------------------------------------------------------------------------- /src-example/components/atoms/Atom/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import styled from 'styled-components' 3 | import { font, palette } from 'styled-theme' 4 | 5 | const Atom = styled.span` 6 | font-family: ${font('primary')}; 7 | color: ${palette({ grayscale: 0 }, 1)}; 8 | ` 9 | 10 | Atom.propTypes = { 11 | palette: PropTypes.string, 12 | reverse: PropTypes.bool, 13 | } 14 | 15 | Atom.defaultProps = { 16 | palette: 'grayscale', 17 | } 18 | 19 | export default Atom 20 | -------------------------------------------------------------------------------- /src-example/components/atoms/Atom/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Atom from '.' 4 | 5 | storiesOf('Atom', module) 6 | .add('default', () => ( 7 | Hello 8 | )) 9 | .add('reverse', () => ( 10 | Hello 11 | )) 12 | -------------------------------------------------------------------------------- /src-example/components/atoms/Atom/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Atom from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | -------------------------------------------------------------------------------- /src-example/components/atoms/Badge/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import styled from 'styled-components' 3 | import { font, palette } from 'styled-theme' 4 | 5 | const Badge = styled.span` 6 | font-family: ${font('primary')}; 7 | font-size: 0.75rem; 8 | line-height: 1.5em; 9 | padding: 0.1em 0.3em; 10 | color: ${palette('grayscale', 0, true)}; 11 | background-color: ${palette(1)}; 12 | border-radius: 0.16667em; 13 | ` 14 | 15 | Badge.propTypes = { 16 | palette: PropTypes.string, 17 | reverse: PropTypes.bool, 18 | } 19 | 20 | Badge.defaultProps = { 21 | palette: 'primary', 22 | } 23 | 24 | export default Badge 25 | -------------------------------------------------------------------------------- /src-example/components/atoms/Badge/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Badge from '.' 4 | 5 | storiesOf('Badge', module) 6 | .add('default', () => ( 7 | Hello 8 | )) 9 | .add('reverse', () => ( 10 | Hello 11 | )) 12 | .add('another palette', () => ( 13 | Hello 14 | )) 15 | -------------------------------------------------------------------------------- /src-example/components/atoms/Badge/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Badge from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | -------------------------------------------------------------------------------- /src-example/components/atoms/Block/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import styled from 'styled-components' 3 | import { font, palette } from 'styled-theme' 4 | import { ifProp } from 'styled-tools' 5 | 6 | const Block = styled.div` 7 | font-family: ${font('primary')}; 8 | background-color: ${ifProp('opaque', palette(0, true), 'transparent')}; 9 | color: ${palette({ grayscale: 0 }, 1)}; 10 | ` 11 | 12 | Block.propTypes = { 13 | palette: PropTypes.string, 14 | reverse: PropTypes.bool, 15 | opaque: PropTypes.bool, 16 | } 17 | 18 | Block.defaultProps = { 19 | palette: 'grayscale', 20 | } 21 | 22 | export default Block 23 | -------------------------------------------------------------------------------- /src-example/components/atoms/Block/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Block from '.' 4 | 5 | storiesOf('Block', module) 6 | .add('default', () => ( 7 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 8 | )) 9 | .add('reverse', () => ( 10 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 11 | )) 12 | .add('palette', () => ( 13 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 14 | )) 15 | .add('palette reverse', () => ( 16 | 17 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 18 | 19 | )) 20 | .add('palette opaque', () => ( 21 | 22 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 23 | 24 | )) 25 | .add('palette opaque reverse', () => ( 26 | 27 | Officia aliqua reprehenderit fugiat occaecat quis non eiusmod. 28 | 29 | )) 30 | -------------------------------------------------------------------------------- /src-example/components/atoms/Block/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Block from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | -------------------------------------------------------------------------------- /src-example/components/atoms/Button/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, { css } from 'styled-components' 4 | import Link from 'react-router-dom/Link' 5 | import { font, palette } from 'styled-theme' 6 | import { ifProp } from 'styled-tools' 7 | 8 | const fontSize = ({ height }) => `${height / 40}rem` 9 | 10 | const backgroundColor = ({ transparent, disabled }) => transparent ? 'transparent' : palette(disabled ? 2 : 1) 11 | 12 | const foregroundColor = ({ transparent, disabled }) => transparent ? palette(disabled ? 2 : 1) : palette('grayscale', 0, true) 13 | 14 | const hoverBackgroundColor = ({ disabled, transparent }) => !disabled && !transparent && palette(0) 15 | const hoverForegroundColor = ({ disabled, transparent }) => !disabled && transparent && palette(0) 16 | 17 | const styles = css` 18 | display: inline-flex; 19 | font-family: ${font('primary')}; 20 | align-items: center; 21 | white-space: nowrap; 22 | font-size: ${fontSize}; 23 | border: 0.0625em solid ${ifProp('transparent', 'currentcolor', 'transparent')}; 24 | height: 2.5em; 25 | justify-content: center; 26 | text-decoration: none; 27 | cursor: ${ifProp('disabled', 'default', 'pointer')}; 28 | appearance: none; 29 | padding: 0 1em; 30 | border-radius: 0.125em; 31 | box-sizing: border-box; 32 | pointer-events: ${ifProp('disabled', 'none', 'auto')}; 33 | transition: background-color 250ms ease-out, color 250ms ease-out, border-color 250ms ease-out; 34 | background-color: ${backgroundColor}; 35 | color: ${foregroundColor}; 36 | 37 | &:hover, &:focus, &:active { 38 | background-color: ${hoverBackgroundColor}; 39 | color: ${hoverForegroundColor}; 40 | } 41 | 42 | &:focus { 43 | outline: none 44 | } 45 | ` 46 | 47 | const StyledLink = styled(({ 48 | disabled, transparent, reverse, palette, height, theme, ...props 49 | }) => )`${styles}` 50 | 51 | const Anchor = styled.a`${styles}` 52 | const StyledButton = styled.button`${styles}` 53 | 54 | const Button = ({ type, ...props }) => { 55 | const { to, href } = props 56 | if (to) { 57 | return 58 | } if (href) { 59 | return 60 | } 61 | return 62 | } 63 | 64 | Button.propTypes = { 65 | disabled: PropTypes.bool, 66 | palette: PropTypes.string, 67 | transparent: PropTypes.bool, 68 | reverse: PropTypes.bool, 69 | height: PropTypes.number, 70 | type: PropTypes.string, 71 | to: PropTypes.string, 72 | href: PropTypes.string, 73 | } 74 | 75 | Button.defaultProps = { 76 | palette: 'primary', 77 | type: 'button', 78 | height: 40, 79 | } 80 | 81 | export default Button 82 | -------------------------------------------------------------------------------- /src-example/components/atoms/Button/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Button from '.' 4 | 5 | storiesOf('Button', module) 6 | .add('default', () => ( 7 | 8 | )) 9 | .add('reverse', () => ( 10 | 11 | )) 12 | .add('another palette', () => ( 13 | 14 | )) 15 | .add('disabled', () => ( 16 | 17 | )) 18 | .add('transparent', () => ( 19 | 20 | )) 21 | .add('height', () => ( 22 | 23 | )) 24 | .add('link', () => ( 25 | 26 | )) 27 | -------------------------------------------------------------------------------- /src-example/components/atoms/Button/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Button from '.' 4 | 5 | const wrap = (props = {}) => shallow(
8 | )) 9 | .add('reverse', () => ( 10 | 11 | )) 12 | -------------------------------------------------------------------------------- /src-example/components/atoms/Caption/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Caption from '.' 4 | 5 | const wrap = (props = {}) => shallow(} 23 | {head && {head}} 24 | {foot && {foot}} 25 | {children} 26 | 27 | ) 28 | } 29 | 30 | Table.propTypes = { 31 | caption: PropTypes.string, 32 | head: PropTypes.node, 33 | foot: PropTypes.node, 34 | children: PropTypes.any, 35 | reverse: PropTypes.bool, 36 | } 37 | 38 | export default Table 39 | -------------------------------------------------------------------------------- /src-example/components/molecules/Table/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { Table } from 'components' 4 | 5 | storiesOf('Table', module) 6 | .add('default', () => ( 7 |
HelloHello) 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | -------------------------------------------------------------------------------- /src-example/components/atoms/Heading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, { css } from 'styled-components' 4 | import { font, palette } from 'styled-theme' 5 | 6 | const fontSize = ({ level }) => `${0.75 + (1 * (1 / level))}rem` 7 | 8 | const styles = css` 9 | font-family: ${font('primary')}; 10 | font-weight: 500; 11 | font-size: ${fontSize}; 12 | margin: 0; 13 | margin-top: 0.85714em; 14 | margin-bottom: 0.57142em; 15 | color: ${palette({ grayscale: 0 }, 1)}; 16 | ` 17 | 18 | const Heading = styled(({ 19 | level, children, reverse, palette, theme, ...props 20 | }) => React.createElement(`h${level}`, props, children))`${styles}` 21 | 22 | Heading.propTypes = { 23 | level: PropTypes.number, 24 | children: PropTypes.node, 25 | palette: PropTypes.string, 26 | reverse: PropTypes.bool, 27 | } 28 | 29 | Heading.defaultProps = { 30 | level: 1, 31 | palette: 'grayscale', 32 | } 33 | 34 | export default Heading 35 | -------------------------------------------------------------------------------- /src-example/components/atoms/Heading/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Heading from '.' 4 | 5 | storiesOf('Heading', module) 6 | .add('default', () => ( 7 | Id tempor duis non esse commodo fugiat excepteur nostrud. 8 | )) 9 | .add('palette', () => ( 10 | Id tempor duis non esse commodo fugiat excepteur nostrud. 11 | )) 12 | .add('palette reverse', () => ( 13 | 14 | Id tempor duis non esse commodo fugiat excepteur nostrud. 15 | 16 | )) 17 | .add('level 2', () => ( 18 | Id tempor duis non esse commodo fugiat excepteur nostrud. 19 | )) 20 | .add('level 3', () => ( 21 | Id tempor duis non esse commodo fugiat excepteur nostrud. 22 | )) 23 | -------------------------------------------------------------------------------- /src-example/components/atoms/Heading/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Heading from '.' 4 | 5 | const wrap = (props = {}) => shallow().dive() 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | 17 | it('renders h1 by default', () => { 18 | const wrapper = wrap() 19 | expect(wrapper.find('h1')).toHaveLength(1) 20 | }) 21 | 22 | it('renders hLevel when level is passed in', () => { 23 | const wrapper = wrap({ level: 2 }) 24 | expect(wrapper.find('h2')).toHaveLength(1) 25 | }) 26 | -------------------------------------------------------------------------------- /src-example/components/atoms/HorizontalRule/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import styled from 'styled-components' 3 | import { palette } from 'styled-theme' 4 | 5 | const HorizontalRule = styled.hr` 6 | border: 1px solid ${palette(1, true)}; 7 | border-width: 0 0 1px; 8 | width: 100%; 9 | ` 10 | 11 | HorizontalRule.propTypes = { 12 | palette: PropTypes.string, 13 | reverse: PropTypes.bool, 14 | } 15 | 16 | HorizontalRule.defaultProps = { 17 | palette: 'grayscale', 18 | } 19 | 20 | export default HorizontalRule 21 | -------------------------------------------------------------------------------- /src-example/components/atoms/HorizontalRule/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import HorizontalRule from '.' 4 | 5 | storiesOf('HorizontalRule', module) 6 | .add('default', () => ( 7 | 8 | )) 9 | .add('palette', () => ( 10 | 11 | )) 12 | .add('palette reverse', () => ( 13 | 14 | )) 15 | -------------------------------------------------------------------------------- /src-example/components/atoms/HorizontalRule/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import HorizontalRule from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders props when passed in', () => { 8 | const wrapper = wrap({ id: 'foo' }) 9 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 10 | }) 11 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/arc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/atomic-design.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/dist.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/docs.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/jest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/react-router.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/react.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/redux.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/icons/webpack.svg: -------------------------------------------------------------------------------- 1 | 2 | icon-square-big 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/index.js: -------------------------------------------------------------------------------- 1 | // https://github.com/diegohaz/arc/wiki/Example-components#icon 2 | import React from 'react' 3 | import PropTypes from 'prop-types' 4 | import styled from 'styled-components' 5 | import { palette } from 'styled-theme' 6 | import { ifProp } from 'styled-tools' 7 | 8 | const fontSize = ({ width, height }) => { 9 | const size = width || height 10 | return size ? `${size / 16}rem` : '1.25em' 11 | } 12 | 13 | const Wrapper = styled.span` 14 | display: inline-block; 15 | font-size: ${fontSize}; 16 | color: ${ifProp('palette', palette({ grayscale: 0 }, 1), 'currentcolor')}; 17 | width: 1em; 18 | height: 1em; 19 | margin: 0.1em; 20 | box-sizing: border-box; 21 | 22 | & > svg { 23 | width: 100%; 24 | height: 100%; 25 | fill: currentcolor; 26 | stroke: currentcolor; 27 | } 28 | ` 29 | 30 | const Icon = ({ icon, ...props }) => { 31 | const svg = require(`!raw-loader!./icons/${icon}.svg`) 32 | return 33 | } 34 | 35 | Icon.propTypes = { 36 | icon: PropTypes.string.isRequired, 37 | width: PropTypes.number, 38 | height: PropTypes.number, 39 | palette: PropTypes.string, 40 | reverse: PropTypes.bool, 41 | } 42 | 43 | export default Icon 44 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/index.stories.js: -------------------------------------------------------------------------------- 1 | // https://github.com/diegohaz/arc/wiki/Example-components#icon 2 | import React from 'react' 3 | import { storiesOf } from '@storybook/react' 4 | import Icon from '.' 5 | 6 | storiesOf('Icon', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('palette', () => ( 11 | 12 | )) 13 | .add('palette reverse', () => ( 14 | 15 | )) 16 | .add('height', () => ( 17 | 18 | )) 19 | -------------------------------------------------------------------------------- /src-example/components/atoms/Icon/index.test.js: -------------------------------------------------------------------------------- 1 | // https://github.com/diegohaz/arc/wiki/Example-components#icon 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | import Icon from '.' 5 | 6 | const wrap = (props = {}) => shallow().dive() 7 | 8 | it('renders with different combination of props', () => { 9 | wrap({ height: 40 }) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | -------------------------------------------------------------------------------- /src-example/components/atoms/Input/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import styled, { css } from 'styled-components' 4 | import { font, palette } from 'styled-theme' 5 | import { ifProp } from 'styled-tools' 6 | 7 | const fontSize = ({ height }) => `${height / 35.5555555556}rem` 8 | 9 | const styles = css` 10 | font-family: ${font('primary')}; 11 | display: block; 12 | width: 100%; 13 | margin: 0; 14 | box-sizing: border-box; 15 | font-size: ${fontSize}; 16 | padding: ${ifProp({ type: 'textarea' }, '0.4444444444em', '0 0.4444444444em')}; 17 | height: ${ifProp({ type: 'textarea' }, 'auto', '2.2222222222em')}; 18 | color: ${palette('grayscale', 0)}; 19 | background-color: ${palette('grayscale', 0, true)}; 20 | border: 1px solid ${ifProp('invalid', palette('danger', 2), palette('grayscale', 3))}; 21 | border-radius: 2px; 22 | 23 | &[type=checkbox], &[type=radio] { 24 | display: inline-block; 25 | border: 0; 26 | border-radius: 0; 27 | width: auto; 28 | height: auto; 29 | margin: 0 0.2rem 0 0; 30 | } 31 | ` 32 | 33 | const StyledTextarea = styled.textarea`${styles}` 34 | const StyledSelect = styled.select`${styles}` 35 | const StyledInput = styled.input`${styles}` 36 | 37 | const Input = ({ ...props }) => { 38 | const { type } = props 39 | if (type === 'textarea') { 40 | return 41 | } if (type === 'select') { 42 | return 43 | } 44 | return 45 | } 46 | 47 | Input.propTypes = { 48 | type: PropTypes.string, 49 | reverse: PropTypes.bool, 50 | height: PropTypes.number, 51 | invalid: PropTypes.bool, 52 | } 53 | 54 | Input.defaultProps = { 55 | type: 'text', 56 | height: 40, 57 | } 58 | 59 | export default Input 60 | -------------------------------------------------------------------------------- /src-example/components/atoms/Input/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Input from '.' 4 | 5 | storiesOf('Input', module) 6 | .add('default', () => ( 7 | 8 | )) 9 | .add('reverse', () => ( 10 | 11 | )) 12 | .add('height', () => ( 13 | 14 | )) 15 | .add('invalid', () => ( 16 | 17 | )) 18 | .add('type textarea', () => ( 19 | 20 | )) 21 | .add('type checkbox', () => ( 22 | 23 | )) 24 | .add('type radio', () => ( 25 | 26 | )) 27 | .add('type select', () => ( 28 | 29 | 30 | 31 | 32 | 33 | )) 34 | -------------------------------------------------------------------------------- /src-example/components/atoms/Input/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Input from '.' 4 | 5 | const wrap = (props = {}) => shallow().dive() 6 | 7 | it('renders props when passed in', () => { 8 | const wrapper = wrap({ type: 'text' }) 9 | expect(wrapper.find({ type: 'text' })).toHaveLength(1) 10 | }) 11 | 12 | it('renders input by default', () => { 13 | const wrapper = wrap() 14 | expect(wrapper.find('input')).toHaveLength(1) 15 | }) 16 | 17 | it('renders select when type is select', () => { 18 | const wrapper = wrap({ type: 'select' }) 19 | expect(wrapper.find('select')).toHaveLength(1) 20 | }) 21 | 22 | it('renders textarea when type is textarea', () => { 23 | const wrapper = wrap({ type: 'textarea' }) 24 | expect(wrapper.find('textarea')).toHaveLength(1) 25 | }) 26 | -------------------------------------------------------------------------------- /src-example/components/atoms/Label/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import styled from 'styled-components' 3 | import { font, palette } from 'styled-theme' 4 | 5 | const Label = styled.label` 6 | font-family: ${font('primary')}; 7 | color: ${palette('grayscale', 1)}; 8 | font-size: 1rem; 9 | line-height: 2em; 10 | ` 11 | 12 | Label.propTypes = { 13 | reverse: PropTypes.bool, 14 | } 15 | 16 | export default Label 17 | -------------------------------------------------------------------------------- /src-example/components/atoms/Label/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import Label from '.' 4 | 5 | storiesOf('Label', module) 6 | .add('default', () => ( 7 | 8 | )) 9 | .add('reverse', () => ( 10 | 11 | )) 12 | -------------------------------------------------------------------------------- /src-example/components/atoms/Label/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Label from '.' 4 | 5 | const wrap = (props = {}) => shallow({caption}
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
Cell 1Cell 2Cell 3
Cell 1Cell 2Cell 3
19 | )) 20 | .add('with head', () => ( 21 | 24 | 25 | 26 | 27 | 28 | )} 29 | > 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
Heading 1Heading 2Heading 3
Cell 1Cell 2Cell 3
Cell 1Cell 2Cell 3
41 | )) 42 | .add('with foot', () => ( 43 | 46 | 47 | 48 | 49 | 50 | )} 51 | > 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
Footer 1Footer 2Footer 3
Cell 1Cell 2Cell 3
Cell 1Cell 2Cell 3
63 | )) 64 | .add('with caption', () => ( 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
Cell 1Cell 2Cell 3
Cell 1Cell 2Cell 3
77 | )) 78 | -------------------------------------------------------------------------------- /src-example/components/molecules/Table/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Table from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders children when passed in', () => { 8 | const wrapper = wrap({ children: 'test' }) 9 | expect(wrapper.contains('test')).toBe(true) 10 | }) 11 | 12 | it('renders props when passed in', () => { 13 | const wrapper = wrap({ id: 'foo' }) 14 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 15 | }) 16 | 17 | it('renders caption when passed in', () => { 18 | const wrapper = wrap({ caption: 'test caption' }) 19 | expect(wrapper.contains('test caption')).toBe(true) 20 | }) 21 | 22 | it('renders head when passed in', () => { 23 | const wrapper = wrap({ head: 'test head' }) 24 | expect(wrapper.contains('test head')).toBe(true) 25 | }) 26 | 27 | it('renders foot when passed in', () => { 28 | const wrapper = wrap({ foot: 'test foot' }) 29 | expect(wrapper.contains('test foot')).toBe(true) 30 | }) 31 | -------------------------------------------------------------------------------- /src-example/components/organisms/FeatureList/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | 4 | import { 5 | Feature, Link, Heading, Paragraph, 6 | } from 'components' 7 | 8 | const Grid = styled.div` 9 | display: flex; 10 | flex-flow: row wrap; 11 | > * { 12 | width: calc(50% - 2rem); 13 | @media screen and (max-width: 640px) { 14 | width: 100%; 15 | } 16 | } 17 | ` 18 | 19 | const StyledHeading = styled(Heading)` 20 | text-align: center; 21 | ` 22 | 23 | const Description = styled(Paragraph)` 24 | text-align: center; 25 | margin: 2rem; 26 | @media screen and (max-width: 640px) { 27 | margin: 1rem; 28 | } 29 | ` 30 | 31 | const StyledFeature = styled(Feature)` 32 | margin: 1rem; 33 | @media screen and (max-width: 640px) { 34 | margin: 0; 35 | } 36 | ` 37 | 38 | const FeatureList = ({ ...props }) => ( 39 |
40 | Basic stack 41 | 42 | It includes everything necessary to build a typical web app with focus on productivity and developer experience. 43 |
44 | Learn more about the recommended workflow 45 |
46 | 47 | 53 | The Facebook's JavaScript library for building user interfaces using components. 54 | 55 | 61 | The most popular declarative routing library for React and React Native. 62 | 63 | 69 | The awesome module bundler with 70 | {' '} 71 | Hot Module Replacement 72 | {' '} 73 | enabled. 74 | 75 | 81 | The great testing framework used by Facebook to test all their Javascript code. 82 | 83 | 84 | Optional features 85 | 86 | Features separated into another branches so you can use them only if you need to. 87 | 88 | 89 | 95 | The predictable state container for JavaScript apps. 96 | 97 | 103 | Write once and run on both server and client. 104 | 105 | 106 |
107 | ) 108 | 109 | export default FeatureList 110 | -------------------------------------------------------------------------------- /src-example/components/organisms/FeatureList/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { FeatureList } from 'components' 4 | 5 | storiesOf('FeatureList', module) 6 | .add('default', () => ( 7 | 8 | )) 9 | -------------------------------------------------------------------------------- /src-example/components/organisms/FeatureList/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import FeatureList from '.' 4 | 5 | const wrap = (props = {}) => shallow() 6 | 7 | it('renders props when passed in', () => { 8 | const wrapper = wrap({ id: 'foo' }) 9 | expect(wrapper.find({ id: 'foo' })).toHaveLength(1) 10 | }) 11 | -------------------------------------------------------------------------------- /src-example/components/organisms/Footer/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | import { palette } from 'styled-theme' 4 | 5 | import { Paragraph, Link, Icon } from 'components' 6 | 7 | const Wrapper = styled.div` 8 | background-color: ${palette('grayscale', 1, true)}; 9 | padding: 2rem; 10 | ` 11 | 12 | const Credits = styled(Paragraph)` 13 | vertical-align: center; 14 | text-align: center; 15 | margin: 0; 16 | ` 17 | 18 | const Footer = (props) => { 19 | return ( 20 | 21 | 22 | Made with 23 | {' '} 24 | 25 | {' '} 26 | by 27 | {' '} 28 | Haz 29 | 30 | 31 | ) 32 | } 33 | 34 | export default Footer 35 | -------------------------------------------------------------------------------- /src-example/components/organisms/Footer/index.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { Footer } from 'components' 4 | 5 | storiesOf('Footer', module) 6 | .add('default', () => ( 7 |