├── .eslintignore ├── .eslintrc.js ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── feature.md │ ├── question.md │ └── regression.md ├── PULL_REQUEST_TEMPLATE.md └── SUPPORT.md ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── config └── rollup.js ├── jest.config.js ├── lerna.json ├── netlify.toml ├── package.json ├── packages ├── core-em │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ └── src │ │ └── index.js ├── core-sc │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ └── src │ │ └── index.js └── shared │ ├── .eslintrc.json │ └── core │ ├── Alert.js │ ├── Box.js │ ├── Button.js │ ├── Card.js │ ├── Checkbox.js │ ├── Form.js │ ├── Input.js │ ├── Menu.js │ ├── Normalize.js │ ├── Radio.js │ ├── Select.js │ ├── Separator.js │ ├── Switch.js │ ├── Text.js │ ├── Textarea.js │ ├── index.js │ ├── theme │ ├── common │ │ ├── border.js │ │ ├── color.js │ │ ├── index.js │ │ ├── mixins.js │ │ ├── transition.js │ │ ├── typography.js │ │ └── zIndices.js │ └── form.js │ └── util │ ├── colors.js │ ├── factories.js │ ├── hooks.js │ ├── index.js │ ├── interop.js │ ├── misc.js │ ├── scales.js │ ├── system.js │ ├── transitions.js │ └── variants.js ├── resources ├── smooth-ui-logo-dark.png ├── smooth-ui-logo-horizontal.png ├── smooth-ui-logo-simple.png ├── smooth-ui-logo.png └── smooth-ui-logo.sketch ├── scripts └── pkg.js ├── website ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .nvmrc ├── README.md ├── _redirects ├── gatsby-config.js ├── gatsby-node.js ├── package.json ├── src │ ├── components │ │ ├── Engine.js │ │ ├── Props.js │ │ └── layout.js │ ├── images │ │ ├── home-logo-dark.png │ │ ├── home-logo.png │ │ ├── logo.png │ │ └── social.jpg │ ├── pages │ │ ├── 404.mdx │ │ ├── docs │ │ │ ├── accessibility.mdx │ │ │ ├── alert.mdx │ │ │ ├── as-property.mdx │ │ │ ├── box.mdx │ │ │ ├── browser-compatibility.mdx │ │ │ ├── button.mdx │ │ │ ├── card.mdx │ │ │ ├── checkbox.mdx │ │ │ ├── dark-mode.mdx │ │ │ ├── extend-styles.mdx │ │ │ ├── form.mdx │ │ │ ├── getting-started.mdx │ │ │ ├── input.mdx │ │ │ ├── introduction.mdx │ │ │ ├── menu.mdx │ │ │ ├── migrate-from-v10.mdx │ │ │ ├── normalize.mdx │ │ │ ├── radio.mdx │ │ │ ├── refs.mdx │ │ │ ├── select.mdx │ │ │ ├── separator.mdx │ │ │ ├── switch.mdx │ │ │ ├── system.mdx │ │ │ ├── text.mdx │ │ │ ├── textarea.mdx │ │ │ └── theming.mdx │ │ └── index.mdx │ └── utils │ │ └── prism.js └── yarn.lock └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | styleguide/ 4 | .docz/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['airbnb', 'prettier', 'prettier/react'], 4 | parser: 'babel-eslint', 5 | env: { 6 | browser: true, 7 | jest: true, 8 | }, 9 | plugins: ['react-hooks'], 10 | rules: { 11 | 'react/jsx-filename-extension': ['error', { extensions: ['.js'] }], 12 | 'react/forbid-prop-types': 'off', 13 | 'react/prop-types': 'off', 14 | 'react/require-default-props': 'off', 15 | 'react/sort-comp': 'off', 16 | 'react/destructuring-assignment': 'off', 17 | 'react/forbid-foreign-prop-types': 'off', 18 | 'react/jsx-props-no-spreading': 'off', 19 | 20 | 'react-hooks/rules-of-hooks': 'error', 21 | 'react-hooks/exhaustive-deps': 'warn', 22 | 23 | 'import/prefer-default-export': 'off', 24 | 'import/no-extraneous-dependencies': 'off', 25 | 26 | 'no-plusplus': 'off', 27 | 'no-return-assign': 'off', 28 | 'no-param-reassign': 'off', 29 | 'no-nested-ternary': 'off', 30 | 'no-shadow': 'off', 31 | 'default-case': 'off', 32 | 'no-underscore-dangle': ['off', { allow: ['__smoothUI', '__scTheme'] }], 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: neoziro 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 👉 [Please follow one of these issue templates](https://github.com/smooth-code/smooth-ui/issues/new/choose) 👈 2 | 3 | Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates. 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | ## 🐛 Bug Report 7 | 8 | A clear and concise description of what the bug is. 9 | 10 | ## To Reproduce 11 | 12 | Steps to reproduce the behavior: 13 | 14 | ## Expected behavior 15 | 16 | A clear and concise description of what you expected to happen. 17 | 18 | ## Link to repl or repo (highly encouraged) 19 | 20 | Please provide a minimal repository on GitHub. 21 | 22 | Issues without a reproduction link are likely to stall. 23 | 24 | ## Run `npx envinfo --system --binaries --npmPackages @smooth-ui/core-sc,@smooth-ui/core-em,styled-components,@emotion/core,@emotion/styled,emotion-theming --markdown --clipboard` 25 | 26 | Paste the results here: 27 | 28 | ```bash 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Proposal 3 | about: Submit a proposal for a new feature 4 | --- 5 | 6 | ## 🚀 Feature Proposal 7 | 8 | A clear and concise description of what the feature is. 9 | 10 | ## Motivation 11 | 12 | Please outline the motivation for the proposal. 13 | 14 | ## Example 15 | 16 | Please provide an example for how this feature would be used. 17 | 18 | ## Pitch 19 | 20 | Why does this feature belong in the Jest Puppeteer ecosystem? 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💬 Questions / Help 3 | about: If you have questions, please read full readme first 4 | --- 5 | 6 | ## 💬 Questions and Help 7 | 8 | Smooth UI project is young, but please before asking your question: 9 | 10 | - Read carefully the README of the project 11 | - Search if your answer has already been answered in old issues 12 | 13 | After you can submit your question and we will be happy to help you! 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/regression.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💥 Regression Report 3 | about: Report unexpected behavior that worked in previous versions 4 | --- 5 | 6 | ## 💥 Regression Report 7 | 8 | A clear and concise description of what the regression is. 9 | 10 | ## Last working version 11 | 12 | Worked up to version: 13 | 14 | Stopped working in version: 15 | 16 | ## To Reproduce 17 | 18 | Steps to reproduce the behavior: 19 | 20 | ## Expected behavior 21 | 22 | A clear and concise description of what you expected to happen. 23 | 24 | ## Link to repl or repo (highly encouraged) 25 | 26 | Please provide a minimal repository on GitHub. 27 | 28 | Issues without a reproduction link are likely to stall. 29 | 30 | ## Run `npx envinfo --system --binaries --npmPackages @smooth-ui/core-sc,@smooth-ui/core-em,styled-components,@emotion/core,@emotion/styled,emotion-theming --markdown --clipboard` 31 | 32 | Paste the results here: 33 | 34 | ```bash 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Summary 4 | 5 | 6 | 7 | ## Test plan 8 | 9 | 10 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | Please read carefully [the documentation](https://smooth-ui.smooth-code.com) before asking questions. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .docz/ 4 | .vscode/ 5 | .size-snapshot.json -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package.json 4 | CHANGELOG.md 5 | .docz/ 6 | website/public 7 | website/.cache -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "semi": false 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 8 5 | 6 | script: 7 | - yarn ci 8 | 9 | notifications: 10 | email: false 11 | 12 | cache: 13 | yarn: true 14 | directories: 15 | - "node_modules" 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@smooth-code.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | Smooth UI is a small project, it is widely used but has not a lot of contributors. We're still working out the kinks to make contributing to this project as easy and transparent as possible, but we're not quite there yet. Hopefully this document makes the process for contributing clear and answers some questions that you may have. 4 | 5 | ## [Code of Conduct](https://github.com/smooth-code/smooth-ui/blob/master/CODE_OF_CONDUCT.md) 6 | 7 | We expect project participants to adhere to our Code of Conduct. Please read [the full text](https://github.com/smooth-code/smooth-ui/blob/master/CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated. 8 | 9 | ## Open Development 10 | 11 | All work on Smooth UI happens directly on [GitHub](/). Both core team members and external contributors send pull requests which go through the same review process. 12 | 13 | ### Workflow and Pull Requests 14 | 15 | _Before_ submitting a pull request, please make sure the following is done… 16 | 17 | 1. Fork the repo and create your branch from `master`. A guide on how to fork a repository: https://help.github.com/articles/fork-a-repo/ 18 | 19 | Open terminal (e.g. Terminal, iTerm, Git Bash or Git Shell) and type: 20 | 21 | ```sh-session 22 | $ git clone https://github.com//smooth-ui 23 | $ cd smooth-ui 24 | $ git checkout -b my_branch 25 | ``` 26 | 27 | Note: Replace `` with your GitHub username 28 | 29 | 2. Smooth UI uses [Yarn](https://code.fb.com/web/yarn-a-new-package-manager-for-javascript/) for running development scripts. If you haven't already done so, please [install yarn](https://yarnpkg.com/en/docs/install). 30 | 31 | 3. Run `yarn install`. On Windows: To install [Yarn](https://yarnpkg.com/en/docs/install#windows-tab) on Windows you may need to download either node.js or Chocolatey
32 | 33 | ```sh 34 | yarn install 35 | ``` 36 | 37 | To check your version of Yarn and ensure it's installed you can type: 38 | 39 | ```sh 40 | yarn --version 41 | ``` 42 | 43 | 4. If you've added code that should be tested, add tests. You can use watch mode that continuously transforms changed files to make your life easier. 44 | 45 | ```sh 46 | # build packages continuously: 47 | yarn dev 48 | # in website folder have to run: 49 | yarn && yarn dev 50 | # each time you want to update the documentation to reflect your change, use: 51 | yarn update-website 52 | ``` 53 | 54 | 5. If you've changed APIs, update the documentation. 55 | 56 | 6. Ensure the linting is good via `yarn lint`. 57 | 58 | ```sh-session 59 | $ yarn lint 60 | ``` 61 | 62 | 7. Ensure the test suite passes via `yarn test`. 63 | 64 | ```sh-session 65 | $ yarn test 66 | ``` 67 | 68 | ## Bugs 69 | 70 | ### Where to Find Known Issues 71 | 72 | We will be using GitHub Issues for our public bugs. We will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new issue, try to make sure your problem doesn't already exist. 73 | 74 | ### Reporting New Issues 75 | 76 | The best way to get your bug fixed is to provide a reduced test case. Please provide a public repository with a runnable example. 77 | 78 | ## Code Conventions 79 | 80 | Please follow the `.prettierrc` in the project. 81 | 82 | ## License 83 | 84 | By contributing to SVGR, you agree that your contributions will be licensed under its MIT license. 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Smooth Code 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > **Warning** This project is deprecated and no longer maintained. 2 | 3 |

4 | 5 | smooth-ui 6 | 7 |

8 |

Modern React UI library. Code less, do more.

9 | 10 | [![Build Status][build-badge]][build] 11 | [![Version][version-badge]][package] 12 | [![MIT License][license-badge]][license] 13 | [![Small size][size-badge]][build-min] 14 | 15 | ```sh 16 | npm install @smooth-ui/core-sc reakit styled-components 17 | ``` 18 | 19 | or 20 | 21 | ```sh 22 | npm install @smooth-ui/core-em reakit @emotion/core @emotion/styled emotion-theming 23 | ``` 24 | 25 | Smooth UI is a style system / UI library for [React](https://reactjs.org/). It works with [Styled Components 💅](https://www.styled-components.com) or [Emotion 👩‍🎤](https://emotion.sh/). 26 | 27 | It is focused on developer experience, productivity. You can focus on what you want to build instead of on how to build it. 28 | 29 | ## [Docs](https://smooth-ui.smooth-code.com/) 30 | 31 | **See the documentation at [smooth-ui.smooth-code.com](https://smooth-ui.smooth-code.com/)** for more information about using Smooth UI! 32 | 33 | ## Sponsors 34 | 35 | [](https://www.browserstack.com/) 36 | 37 | BrowserStack allows us to test in real browsers. 38 | 39 | ## License 40 | 41 | Licensed under the MIT License, Copyright © 2018-present Smooth Code. 42 | 43 | See [LICENSE](./LICENSE) for more information. 44 | 45 | [build-badge]: https://img.shields.io/travis/smooth-code/smooth-ui/master.svg?style=flat-square 46 | [build]: https://travis-ci.org/smooth-code/smooth-ui 47 | [version-badge]: https://img.shields.io/npm/v/@smooth-ui/core-sc.svg?style=flat-square 48 | [package]: https://www.npmjs.com/package/@smooth-ui/core-sc 49 | [license-badge]: https://img.shields.io/npm/l/@smooth-ui/core-sc.svg?style=flat-square 50 | [license]: https://github.com/smooth-code/smooth-ui/blob/master/LICENSE 51 | [size-badge]: https://img.badgesize.io/https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui-core-sc.min.js?compression=gzip&style=flat-square 52 | [build-min]: https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui.min.js 53 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const { STYLED_ENGINE = 'styled-components', NODE_ENV } = process.env 2 | 3 | function getStyledEnginePlugins() { 4 | if (NODE_ENV === 'test') return [] 5 | 6 | switch (STYLED_ENGINE) { 7 | case 'emotion': 8 | return ['babel-plugin-emotion'] 9 | case 'styled-components': 10 | return [['babel-plugin-styled-components', { displayName: false }]] 11 | default: 12 | return [] 13 | } 14 | } 15 | 16 | module.exports = api => { 17 | api.cache(true) 18 | 19 | const config = { 20 | presets: [ 21 | ['@babel/preset-env', { loose: true, modules: false }], 22 | '@babel/preset-react', 23 | ], 24 | plugins: [ 25 | ...getStyledEnginePlugins(), 26 | [ 27 | 'babel-plugin-transform-rename-import', 28 | { 29 | replacements: [ 30 | { 31 | original: '(.*)xstyled/x$', 32 | replacement: `$1xstyled/${STYLED_ENGINE}`, 33 | }, 34 | ], 35 | }, 36 | ], 37 | ['@babel/plugin-proposal-class-properties', { loose: true }], 38 | ], 39 | } 40 | 41 | if (NODE_ENV === 'test') { 42 | return { 43 | ...config, 44 | plugins: [ 45 | ...config.plugins, 46 | ['@babel/plugin-transform-modules-commonjs', { loose: true }], 47 | ], 48 | } 49 | } 50 | 51 | return config 52 | } 53 | -------------------------------------------------------------------------------- /config/rollup.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import nodeResolve from 'rollup-plugin-node-resolve' 3 | import babel from 'rollup-plugin-babel' 4 | import replace from 'rollup-plugin-replace' 5 | import commonjs from 'rollup-plugin-commonjs' 6 | import { terser } from 'rollup-plugin-terser' 7 | import { sizeSnapshot } from 'rollup-plugin-size-snapshot' 8 | 9 | export const getRollupConfig = ({ pwd, buildName, name }) => { 10 | const SOURCE_DIR = path.resolve(pwd, 'src') 11 | const DIST_DIR = path.resolve(pwd, 'dist') 12 | const input = `${SOURCE_DIR}/index.js` 13 | const external = id => !id.startsWith('.') && !id.startsWith('/') 14 | const getBabelOptions = ({ useESModules }) => ({ 15 | exclude: '**/node_modules/**', 16 | runtimeHelpers: true, 17 | configFile: path.join(pwd, '../../babel.config.js'), 18 | plugins: [ 19 | 'babel-plugin-annotate-pure-calls', 20 | ['@babel/plugin-transform-runtime', { useESModules }], 21 | ], 22 | }) 23 | 24 | const globals = { 25 | polished: 'polished', 26 | 'prop-types': 'PropTypes', 27 | 'prop-desc': 'PropDesc', 28 | 'emotion-theming': 'emotionTheming', 29 | '@emotion/core': 'emotion', 30 | '@emotion/styled': 'styled', 31 | '@xstyled/styled-components': 'xstyled', 32 | '@xstyled/emotion': 'xstyled', 33 | react: 'React', 34 | 'react-dom': 'ReactDom', 35 | 'styled-components': 'styled', 36 | } 37 | 38 | const umdConfig = { 39 | input, 40 | output: { 41 | file: `${DIST_DIR}/${buildName}.umd.js`, 42 | format: 'umd', 43 | name, 44 | globals, 45 | }, 46 | external: Object.keys(globals), 47 | plugins: [ 48 | babel(getBabelOptions({ useESModules: false })), 49 | nodeResolve(), 50 | commonjs({ 51 | namedExports: { 52 | '../../node_modules/body-scroll-lock/lib/bodyScrollLock.min.js': [ 53 | 'disableBodyScroll', 54 | 'enableBodyScroll', 55 | ], 56 | }, 57 | }), 58 | replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), 59 | ], 60 | } 61 | 62 | const minConfig = { 63 | input, 64 | output: { 65 | file: `${DIST_DIR}/${buildName}.min.js`, 66 | format: 'umd', 67 | name, 68 | globals, 69 | }, 70 | external: Object.keys(globals), 71 | plugins: [ 72 | babel(getBabelOptions({ useESModules: true })), 73 | nodeResolve(), 74 | commonjs({ 75 | namedExports: { 76 | '../../node_modules/body-scroll-lock/lib/bodyScrollLock.min.js': [ 77 | 'disableBodyScroll', 78 | 'enableBodyScroll', 79 | ], 80 | }, 81 | }), 82 | replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), 83 | terser(), 84 | ], 85 | } 86 | 87 | const cjsConfig = { 88 | input, 89 | output: { file: `${DIST_DIR}/${buildName}.cjs.js`, format: 'cjs' }, 90 | external, 91 | plugins: [ 92 | nodeResolve(), 93 | babel(getBabelOptions({ useESModules: false })), 94 | sizeSnapshot(), 95 | ], 96 | } 97 | 98 | const esmConfig = { 99 | input, 100 | output: { file: `${DIST_DIR}/${buildName}.es.js`, format: 'esm' }, 101 | external, 102 | plugins: [ 103 | nodeResolve(), 104 | babel(getBabelOptions({ useESModules: true })), 105 | sizeSnapshot(), 106 | ], 107 | } 108 | 109 | if (process.env.WATCH_MODE) { 110 | return [esmConfig, cjsConfig] 111 | } 112 | 113 | return [esmConfig, cjsConfig, umdConfig, minConfig] 114 | } 115 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transformIgnorePatterns: ['.*(node_modules)(?!.*@smooth-ui.*).*$'], 3 | transform: { 4 | '^.+\\.jsx?$': 'babel-jest', 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.3.0", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "11.1.5", 7 | "npmClient": "yarn", 8 | "useWorkspaces": true 9 | } 10 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "website" 3 | command = "yarn build" 4 | publish = "website/public" 5 | 6 | [context.production] 7 | command = "yarn build:pp" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "packages/*" 5 | ], 6 | "scripts": { 7 | "build": "lerna run build", 8 | "dev": "WATCH_MODE=true lerna run --parallel build -- --watch", 9 | "update-website": "cp -r ./packages/core-sc/dist ./website/node_modules/smooth-ui-sc-next && cp -r ./packages/core-em/dist ./website/node_modules/smooth-ui-em-next", 10 | "ci": "yarn lint && yarn test && yarn build && bundlesize && yarn tsc:check || true", 11 | "format": "prettier --write \"**/*.{js,json,md,mdx}\"", 12 | "lint": "eslint .", 13 | "release": "lerna publish --conventional-commits --force-publish=* && conventional-github-releaser --preset angular", 14 | "pre-release": "lerna publish prerelease --force-publish=* && conventional-github-releaser --preset angular", 15 | "test": "jest" 16 | }, 17 | "bundlesize": [ 18 | { 19 | "path": "./packages/core-em/dist/smooth-ui-core-em.min.js", 20 | "maxSize": "25 kB" 21 | }, 22 | { 23 | "path": "./packages/core-sc/dist/smooth-ui-core-sc.min.js", 24 | "maxSize": "23 kB" 25 | } 26 | ], 27 | "devDependencies": { 28 | "@babel/cli": "^7.7.0", 29 | "@babel/core": "^7.7.2", 30 | "@babel/plugin-external-helpers": "^7.2.0", 31 | "@babel/plugin-proposal-class-properties": "^7.7.0", 32 | "@babel/plugin-transform-modules-commonjs": "^7.7.0", 33 | "@babel/plugin-transform-runtime": "^7.6.2", 34 | "@babel/preset-env": "^7.7.1", 35 | "@babel/preset-react": "^7.7.0", 36 | "@emotion/core": "^10.0.22", 37 | "@emotion/styled": "^10.0.23", 38 | "@xstyled/emotion": "^1.15.0", 39 | "@xstyled/styled-components": "^1.15.0", 40 | "@xstyled/system": "^1.14.0", 41 | "babel-eslint": "^10.0.2", 42 | "babel-jest": "^24.8.0", 43 | "babel-plugin-annotate-pure-calls": "^0.4.0", 44 | "babel-plugin-emotion": "^10.0.23", 45 | "babel-plugin-styled-components": "^1.10.6", 46 | "babel-plugin-transform-rename-import": "^2.3.0", 47 | "bundlesize": "^0.18.0", 48 | "conventional-github-releaser": "^3.1.3", 49 | "cross-env": "^6.0.3", 50 | "emotion-theming": "^10.0.19", 51 | "eslint": "^6.6.0", 52 | "eslint-config-airbnb": "^18.0.1", 53 | "eslint-config-prettier": "^6.7.0", 54 | "eslint-plugin-import": "^2.18.2", 55 | "eslint-plugin-jsx-a11y": "^6.2.3", 56 | "eslint-plugin-react": "^7.16.0", 57 | "eslint-plugin-react-hooks": "^2.3.0", 58 | "jest": "^24.8.0", 59 | "lerna": "^3.19.0", 60 | "prettier": "^1.19.1", 61 | "react": "^16.12.0", 62 | "react-dom": "^16.12.0", 63 | "reakit": "^1.0.0-beta.12", 64 | "rollup": "^1.27.4", 65 | "rollup-plugin-babel": "^4.3.3", 66 | "rollup-plugin-commonjs": "^10.0.2", 67 | "rollup-plugin-node-resolve": "^5.2.0", 68 | "rollup-plugin-replace": "^2.2.0", 69 | "rollup-plugin-size-snapshot": "^0.10.0", 70 | "rollup-plugin-terser": "^5.1.2", 71 | "shx": "^0.3.2", 72 | "styled-components": "^4.4.1" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/core-em/.npmignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/dist/**/*.js 3 | *.test.js -------------------------------------------------------------------------------- /packages/core-em/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [11.1.5](https://github.com/smooth-code/smooth-ui/compare/v11.1.4...v11.1.5) (2019-12-27) 7 | 8 | **Note:** Version bump only for package @smooth-ui/core-em 9 | 10 | 11 | 12 | 13 | 14 | ## [11.1.4](https://github.com/smooth-code/smooth-ui/compare/v11.1.3...v11.1.4) (2019-11-23) 15 | 16 | **Note:** Version bump only for package @smooth-ui/core-em 17 | 18 | 19 | 20 | 21 | 22 | ## [11.1.3](https://github.com/smooth-code/smooth-ui/compare/v11.1.2...v11.1.3) (2019-11-22) 23 | 24 | **Note:** Version bump only for package @smooth-ui/core-em 25 | 26 | 27 | 28 | 29 | 30 | ## [11.1.2](https://github.com/smooth-code/smooth-ui/compare/v11.1.1...v11.1.2) (2019-11-22) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * fix internal theme usage ([fc74682](https://github.com/smooth-code/smooth-ui/commit/fc74682c5f1fdac73b507f3d90018840a38cdcdf)) 36 | 37 | 38 | 39 | 40 | 41 | ## [11.1.1](https://github.com/smooth-code/smooth-ui/compare/v11.1.0...v11.1.1) (2019-09-27) 42 | 43 | **Note:** Version bump only for package @smooth-ui/core-em 44 | 45 | 46 | 47 | 48 | 49 | ## [11.0.2](https://github.com/smooth-code/smooth-ui/compare/v11.0.1...v11.0.2) (2019-08-30) 50 | 51 | **Note:** Version bump only for package @smooth-ui/core-em 52 | 53 | 54 | 55 | 56 | 57 | ## [11.0.1](https://github.com/smooth-code/smooth-ui/compare/v11.0.0...v11.0.1) (2019-08-27) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * remove smooth-ui system ([baf257f](https://github.com/smooth-code/smooth-ui/commit/baf257f)) 63 | 64 | 65 | 66 | 67 | 68 | # [10.1.0](https://github.com/smooth-code/smooth-ui/compare/v10.0.7...v10.1.0) (2019-05-04) 69 | 70 | 71 | ### Features 72 | 73 | * remove types ([#136](https://github.com/smooth-code/smooth-ui/issues/136)) ([6c5cd4d](https://github.com/smooth-code/smooth-ui/commit/6c5cd4d)) 74 | 75 | 76 | 77 | 78 | 79 | ## [10.0.7](https://github.com/smooth-code/smooth-ui/compare/v10.0.6...v10.0.7) (2019-04-17) 80 | 81 | **Note:** Version bump only for package @smooth-ui/core-em 82 | 83 | 84 | 85 | 86 | 87 | ## [10.0.6](https://github.com/smooth-code/smooth-ui/compare/v10.0.5...v10.0.6) (2019-04-09) 88 | 89 | **Note:** Version bump only for package @smooth-ui/core-em 90 | 91 | 92 | 93 | 94 | 95 | ## [10.0.5](https://github.com/smooth-code/smooth-ui/compare/v10.0.4...v10.0.5) (2019-04-09) 96 | 97 | **Note:** Version bump only for package @smooth-ui/core-em 98 | 99 | 100 | 101 | 102 | 103 | ## [10.0.4](https://github.com/smooth-code/smooth-ui/compare/v10.0.3...v10.0.4) (2019-04-05) 104 | 105 | **Note:** Version bump only for package @smooth-ui/core-em 106 | 107 | 108 | 109 | 110 | 111 | ## [10.0.3](https://github.com/smooth-code/smooth-ui/compare/v10.0.2...v10.0.3) (2019-03-29) 112 | 113 | **Note:** Version bump only for package @smooth-ui/core-em 114 | 115 | 116 | 117 | 118 | 119 | ## [10.0.2](https://github.com/smooth-code/smooth-ui/compare/v10.0.1...v10.0.2) (2019-03-21) 120 | 121 | **Note:** Version bump only for package @smooth-ui/core-em 122 | 123 | 124 | 125 | 126 | 127 | ## [10.0.1](https://github.com/smooth-code/smooth-ui/compare/v10.0.0...v10.0.1) (2019-03-21) 128 | 129 | **Note:** Version bump only for package @smooth-ui/core-em 130 | 131 | 132 | 133 | 134 | 135 | # [10.0.0](https://github.com/smooth-code/smooth-ui/compare/v9.1.0...v10.0.0) (2019-03-20) 136 | 137 | 138 | ### Features 139 | 140 | * popover, tooltips, responsive grid, hooks ([#122](https://github.com/smooth-code/smooth-ui/issues/122)) ([7bc0b8c](https://github.com/smooth-code/smooth-ui/commit/7bc0b8c)) 141 | 142 | 143 | ### BREAKING CHANGES 144 | 145 | * - React v16.8+ is now required (hooks inside) 146 | - Grid, Col and Row `gutter` prop is now based on system, **be careful**! 147 | - Toggler now returns an array `[toggled, onToggle]` instead of an object 148 | 149 | 150 | 151 | 152 | 153 | # [9.1.0](https://github.com/smooth-code/smooth-ui/compare/v9.0.2...v9.1.0) (2019-03-07) 154 | 155 | **Note:** Version bump only for package @smooth-ui/core-em 156 | 157 | 158 | 159 | 160 | 161 | ## [9.0.2](https://github.com/smooth-code/smooth-ui/compare/v9.0.1...v9.0.2) (2019-02-20) 162 | 163 | **Note:** Version bump only for package @smooth-ui/core-em 164 | 165 | 166 | 167 | 168 | 169 | ## [9.0.1](https://github.com/smooth-code/smooth-ui/compare/v9.0.0...v9.0.1) (2019-02-04) 170 | 171 | **Note:** Version bump only for package @smooth-ui/core-em 172 | 173 | 174 | 175 | 176 | 177 | # [9.0.0](https://github.com/smooth-code/smooth-ui/compare/v8.1.0...v9.0.0) (2019-02-04) 178 | 179 | 180 | ### Bug Fixes 181 | 182 | * **types:** fix TypeScript definitions ([#108](https://github.com/smooth-code/smooth-ui/issues/108)) ([87eda0b](https://github.com/smooth-code/smooth-ui/commit/87eda0b)) 183 | 184 | 185 | ### Features 186 | 187 | * simplify core & remove theme dependency ([cec1029](https://github.com/smooth-code/smooth-ui/commit/cec1029)) 188 | 189 | 190 | ### BREAKING CHANGES 191 | 192 | * - `prop` utility has been removed 193 | - Undocumented utilities are no longer exported 194 | - `controlFocus` has been renamed `baseFocus`, `controlFocus` is only 195 | for controls (when control prop is `true`) 196 | - `mixin` function is no longer available, also mixins have changed 197 | 198 | **Mixins:** 199 | 200 | Previously mixins were called using `mixin` helper: 201 | 202 | ```js 203 | import { styled, mixin } from '@smooth-ui/core-sc' 204 | 205 | const Styled = styled.div` 206 | color: ${mixin('colorLevel', 'red', 5)}; 207 | ` 208 | ``` 209 | 210 | All mixins are now exported: 211 | 212 | ```js 213 | import { styled, colorLevel } from '@smooth-ui/core-sc' 214 | 215 | const Styled = styled.div` 216 | color: ${colorLevel('red', 5)}; 217 | ` 218 | ``` 219 | 220 | **Theme** 221 | 222 | Theme is no longer required, Smooth UI will work well without theme and 223 | you can override only needed properties without having to load the 224 | entire theme. 225 | 226 | The benefit from that approach is that code splitting is fully 227 | efficient, if you use only one component in Smooth UI you will load only 228 | theme primitives of this component. 229 | 230 | The size of a result bundle that is using only a `Button`: 231 | 232 | ``` 233 | 202K bundle-smooth-ui-v8.js 234 | 194K bundle-smooth-ui-v9.js 235 | 65K bundle-smooth-ui-v8.js.gz 236 | 63K bundle-smooth-ui-v9.js.gz 237 | ``` 238 | 239 | As you can see the bundle has been reduced of 8K (no gzip) and of 2K 240 | (gzip). 241 | 242 | 243 | 244 | 245 | 246 | # [8.1.0](https://github.com/smooth-code/smooth-ui/compare/v8.0.1...v8.1.0) (2019-01-22) 247 | 248 | 249 | ### Features 250 | 251 | * add scroll-lock to modals, fixes [#25](https://github.com/smooth-code/smooth-ui/issues/25) ([#103](https://github.com/smooth-code/smooth-ui/issues/103)) ([23f35dd](https://github.com/smooth-code/smooth-ui/commit/23f35dd)) 252 | 253 | 254 | 255 | 256 | 257 | ## [8.0.1](https://github.com/smooth-code/smooth-ui/compare/v8.0.0...v8.0.1) (2019-01-17) 258 | 259 | **Note:** Version bump only for package @smooth-ui/core-em 260 | 261 | 262 | 263 | 264 | 265 | # [8.0.0](https://github.com/smooth-code/smooth-ui/compare/v7.1.1...v8.0.0) (2019-01-16) 266 | 267 | 268 | ### Features 269 | 270 | * support emotion 10 & remove hacks ([#93](https://github.com/smooth-code/smooth-ui/issues/93)) ([d311640](https://github.com/smooth-code/smooth-ui/commit/d311640)) 271 | 272 | 273 | ### BREAKING CHANGES 274 | 275 | * `OriginalComponent.withComponent(NewComponent)` is replaced by `uiAs(OriginalComponent, NewComponent)` 276 | 277 | `as={NewComponent}` is replaced by `uiAs={NewComponent}` 278 | 279 | `globalStyle()` is now replaced by `Normalize` component 280 | 281 | 282 | 283 | 284 | 285 | ## [7.1.1](https://github.com/smooth-code/smooth-ui/compare/v7.1.0...v7.1.1) (2019-01-11) 286 | 287 | **Note:** Version bump only for package @smooth-ui/core-em 288 | 289 | # [7.1.0](https://github.com/smooth-code/smooth-ui/compare/v7.0.5...v7.1.0) (2019-01-07) 290 | 291 | ### Features 292 | 293 | - add TypeScript definitions ([#87](https://github.com/smooth-code/smooth-ui/issues/87)) ([ab8c033](https://github.com/smooth-code/smooth-ui/commit/ab8c033)) 294 | 295 | ## [7.0.5](https://github.com/smooth-code/smooth-ui/compare/v7.0.4...v7.0.5) (2018-11-11) 296 | 297 | **Note:** Version bump only for package @smooth-ui/core-em 298 | 299 | ## [7.0.4](https://github.com/smooth-code/smooth-ui/compare/v7.0.3...v7.0.4) (2018-11-01) 300 | 301 | **Note:** Version bump only for package @smooth-ui/core-em 302 | 303 | ## [7.0.3](https://github.com/smooth-code/smooth-ui/compare/v7.0.2...v7.0.3) (2018-10-24) 304 | 305 | ### Bug Fixes 306 | 307 | - **modals:** replace focus-trap by focus-lock ([#69](https://github.com/smooth-code/smooth-ui/issues/69)) ([77872db](https://github.com/smooth-code/smooth-ui/commit/77872db)) 308 | 309 | ## [7.0.2](https://github.com/smooth-code/smooth-ui/compare/v7.0.1...v7.0.2) (2018-10-23) 310 | 311 | ### Bug Fixes 312 | 313 | - **sc:** fix withComponent API ([#68](https://github.com/smooth-code/smooth-ui/issues/68)) ([0f59029](https://github.com/smooth-code/smooth-ui/commit/0f59029)) 314 | 315 | ## [7.0.1](https://github.com/smooth-code/smooth-ui/compare/v7.0.0...v7.0.1) (2018-10-19) 316 | 317 | **Note:** Version bump only for package @smooth-ui/core-em 318 | 319 | # [7.0.0](https://github.com/smooth-code/smooth-ui/compare/v6.0.2...v7.0.0) (2018-10-18) 320 | 321 | ### Features 322 | 323 | - make modals accessible ([#65](https://github.com/smooth-code/smooth-ui/issues/65)) ([e37c708](https://github.com/smooth-code/smooth-ui/commit/e37c708)), closes [#31](https://github.com/smooth-code/smooth-ui/issues/31) [#26](https://github.com/smooth-code/smooth-ui/issues/26) [#25](https://github.com/smooth-code/smooth-ui/issues/25) 324 | 325 | ### BREAKING CHANGES 326 | 327 | - "persistent" prop has been removed from Modal, Modal are now 328 | non-persistent. 329 | 330 | "sui-modal-backdrop" has been removed, it is now "sui-modal". 331 | 332 | ## [6.0.2](https://github.com/smooth-code/smooth-ui/compare/v6.0.1...v6.0.2) (2018-10-17) 333 | 334 | **Note:** Version bump only for package @smooth-ui/core-em 335 | 336 | ## [6.0.1](https://github.com/smooth-code/smooth-ui/compare/v6.0.0...v6.0.1) (2018-10-17) 337 | 338 | **Note:** Version bump only for package @smooth-ui/core-em 339 | 340 | # [6.0.0](https://github.com/smooth-code/smooth-ui/compare/v5.1.3...v6.0.0) (2018-10-17) 341 | 342 | ### Features 343 | 344 | - flatten style & remove classNames ([34dd3fc](https://github.com/smooth-code/smooth-ui/commit/34dd3fc)) 345 | - support styled-components v4 ([b25675a](https://github.com/smooth-code/smooth-ui/commit/b25675a)) 346 | 347 | ### BREAKING CHANGES 348 | 349 | - - styled-components v4 is required 350 | 351 | * `.extend` has been removed, please use `styled()` instead 352 | * `component` prop has been removed, please use `as` instead 353 | 354 | - A lot of classes have been removed. 355 | 356 | Introduced a new default size "md". 357 | 358 | 359 | 360 | ## [5.1.3](https://github.com/smooth-code/smooth-ui/compare/v5.1.2...v5.1.3) (2018-09-26) 361 | 362 | **Note:** Version bump only for package @smooth-ui/core-em 363 | 364 | 365 | 366 | ## [5.1.2](https://github.com/smooth-code/smooth-ui/compare/v5.1.1...v5.1.2) (2018-09-17) 367 | 368 | **Note:** Version bump only for package @smooth-ui/core-em 369 | -------------------------------------------------------------------------------- /packages/core-em/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | smooth-ui 4 | 5 |

6 |

Modern React UI library. Code less, do more.

7 | 8 | [![Build Status][build-badge]][build] 9 | [![Version][version-badge]][package] 10 | [![MIT License][license-badge]][license] 11 | [![Small size][size-badge]][build-min] 12 | 13 | ```sh 14 | npm install @smooth-ui/core-em reakit @emotion/core @emotion/styled emotion-theming 15 | ``` 16 | 17 | Smooth UI is a style system / UI library for [React](https://reactjs.org/). It works with [Styled Components 💅](https://www.styled-components.com) or [Emotion 👩‍🎤](https://emotion.sh/). 18 | 19 | It is focused on developer experience, productivity. You can focus on what you want to build instead of on how to build it. 20 | 21 | ## [Docs](https://smooth-ui.smooth-code.com/) 22 | 23 | **See the documentation at [smooth-ui.smooth-code.com](https://smooth-ui.smooth-code.com/)** for more information about using Smooth UI! 24 | 25 | ## License 26 | 27 | Licensed under the MIT License, Copyright © 2018-present Smooth Code. 28 | 29 | See [LICENSE](./LICENSE) for more information. 30 | 31 | [build-badge]: https://img.shields.io/travis/smooth-code/smooth-ui.svg?style=flat-square 32 | [build]: https://travis-ci.org/smooth-code/smooth-ui 33 | [version-badge]: https://img.shields.io/npm/v/@smooth-ui/core-sc.svg?style=flat-square 34 | [package]: https://www.npmjs.com/package/@smooth-ui/core-sc 35 | [license-badge]: https://img.shields.io/npm/l/@smooth-ui/core-sc.svg?style=flat-square 36 | [license]: https://github.com/smooth-code/smooth-ui/blob/master/LICENSE 37 | [size-badge]: https://img.badgesize.io/https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui.min.js?compression=gzip&style=flat-square 38 | [build-min]: https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui.min.js 39 | -------------------------------------------------------------------------------- /packages/core-em/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@smooth-ui/core-em", 3 | "description": "Modern React UI Library", 4 | "version": "11.1.5", 5 | "keywords": [ 6 | "emotion", 7 | "ui", 8 | "ui-components", 9 | "react", 10 | "material-ui", 11 | "bootstrap" 12 | ], 13 | "sideEffects": false, 14 | "main": "dist/smooth-ui-core-em.cjs.js", 15 | "module": "dist/smooth-ui-core-em.es.js", 16 | "author": "Greg Bergé ", 17 | "license": "MIT", 18 | "scripts": { 19 | "build": "cross-env STYLED_ENGINE=emotion BABEL_ENV=rollup rollup -c", 20 | "prebuild": "shx rm -rf dist", 21 | "prepublishOnly": "yarn build" 22 | }, 23 | "publishConfig": { 24 | "access": "public" 25 | }, 26 | "dependencies": { 27 | "@babel/runtime": "^7.7.2", 28 | "@xstyled/emotion": "^1.15.0", 29 | "@xstyled/util": "^1.14.0", 30 | "polished": "^3.4.2", 31 | "prop-desc": "^1.0.0", 32 | "prop-types": "^15.7.2", 33 | "react-flatten-children": "^1.0.0", 34 | "react-merge-refs": "^1.0.0" 35 | }, 36 | "peerDependencies": { 37 | "@emotion/core": "^10.0.0", 38 | "@emotion/styled": "^10.0.0", 39 | "emotion-theming": "^10.0.0", 40 | "react": ">=16.8.0", 41 | "react-dom": ">=16.8.0", 42 | "reakit": ">=1.0.0-beta.6 <2.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/core-em/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { getRollupConfig } from '../../config/rollup' 2 | import pkg from './package.json' 3 | 4 | export default getRollupConfig({ 5 | pwd: __dirname, 6 | name: 'smoothUI', 7 | buildName: 'smooth-ui-core-em', 8 | pkg, 9 | }) 10 | -------------------------------------------------------------------------------- /packages/core-em/src/index.js: -------------------------------------------------------------------------------- 1 | export * from '../../shared/core/index' 2 | -------------------------------------------------------------------------------- /packages/core-sc/.npmignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/dist/**/*.js 3 | *.test.js -------------------------------------------------------------------------------- /packages/core-sc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [11.1.5](https://github.com/smooth-code/smooth-ui/compare/v11.1.4...v11.1.5) (2019-12-27) 7 | 8 | **Note:** Version bump only for package @smooth-ui/core-sc 9 | 10 | 11 | 12 | 13 | 14 | ## [11.1.4](https://github.com/smooth-code/smooth-ui/compare/v11.1.3...v11.1.4) (2019-11-23) 15 | 16 | **Note:** Version bump only for package @smooth-ui/core-sc 17 | 18 | 19 | 20 | 21 | 22 | ## [11.1.3](https://github.com/smooth-code/smooth-ui/compare/v11.1.2...v11.1.3) (2019-11-22) 23 | 24 | **Note:** Version bump only for package @smooth-ui/core-sc 25 | 26 | 27 | 28 | 29 | 30 | ## [11.1.2](https://github.com/smooth-code/smooth-ui/compare/v11.1.1...v11.1.2) (2019-11-22) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * fix internal theme usage ([fc74682](https://github.com/smooth-code/smooth-ui/commit/fc74682c5f1fdac73b507f3d90018840a38cdcdf)) 36 | 37 | 38 | 39 | 40 | 41 | ## [11.1.1](https://github.com/smooth-code/smooth-ui/compare/v11.1.0...v11.1.1) (2019-09-27) 42 | 43 | **Note:** Version bump only for package @smooth-ui/core-sc 44 | 45 | 46 | 47 | 48 | 49 | ## [11.0.2](https://github.com/smooth-code/smooth-ui/compare/v11.0.1...v11.0.2) (2019-08-30) 50 | 51 | **Note:** Version bump only for package @smooth-ui/core-sc 52 | 53 | 54 | 55 | 56 | 57 | ## [11.0.1](https://github.com/smooth-code/smooth-ui/compare/v11.0.0...v11.0.1) (2019-08-27) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * remove smooth-ui system ([baf257f](https://github.com/smooth-code/smooth-ui/commit/baf257f)) 63 | 64 | 65 | 66 | 67 | 68 | # [10.1.0](https://github.com/smooth-code/smooth-ui/compare/v10.0.7...v10.1.0) (2019-05-04) 69 | 70 | 71 | ### Features 72 | 73 | * remove types ([#136](https://github.com/smooth-code/smooth-ui/issues/136)) ([6c5cd4d](https://github.com/smooth-code/smooth-ui/commit/6c5cd4d)) 74 | 75 | 76 | 77 | 78 | 79 | ## [10.0.7](https://github.com/smooth-code/smooth-ui/compare/v10.0.6...v10.0.7) (2019-04-17) 80 | 81 | **Note:** Version bump only for package @smooth-ui/core-sc 82 | 83 | 84 | 85 | 86 | 87 | ## [10.0.6](https://github.com/smooth-code/smooth-ui/compare/v10.0.5...v10.0.6) (2019-04-09) 88 | 89 | **Note:** Version bump only for package @smooth-ui/core-sc 90 | 91 | 92 | 93 | 94 | 95 | ## [10.0.5](https://github.com/smooth-code/smooth-ui/compare/v10.0.4...v10.0.5) (2019-04-09) 96 | 97 | **Note:** Version bump only for package @smooth-ui/core-sc 98 | 99 | 100 | 101 | 102 | 103 | ## [10.0.4](https://github.com/smooth-code/smooth-ui/compare/v10.0.3...v10.0.4) (2019-04-05) 104 | 105 | **Note:** Version bump only for package @smooth-ui/core-sc 106 | 107 | 108 | 109 | 110 | 111 | ## [10.0.3](https://github.com/smooth-code/smooth-ui/compare/v10.0.2...v10.0.3) (2019-03-29) 112 | 113 | **Note:** Version bump only for package @smooth-ui/core-sc 114 | 115 | 116 | 117 | 118 | 119 | ## [10.0.2](https://github.com/smooth-code/smooth-ui/compare/v10.0.1...v10.0.2) (2019-03-21) 120 | 121 | **Note:** Version bump only for package @smooth-ui/core-sc 122 | 123 | 124 | 125 | 126 | 127 | ## [10.0.1](https://github.com/smooth-code/smooth-ui/compare/v10.0.0...v10.0.1) (2019-03-21) 128 | 129 | **Note:** Version bump only for package @smooth-ui/core-sc 130 | 131 | 132 | 133 | 134 | 135 | # [10.0.0](https://github.com/smooth-code/smooth-ui/compare/v9.1.0...v10.0.0) (2019-03-20) 136 | 137 | 138 | ### Features 139 | 140 | * popover, tooltips, responsive grid, hooks ([#122](https://github.com/smooth-code/smooth-ui/issues/122)) ([7bc0b8c](https://github.com/smooth-code/smooth-ui/commit/7bc0b8c)) 141 | 142 | 143 | ### BREAKING CHANGES 144 | 145 | * - React v16.8+ is now required (hooks inside) 146 | - Grid, Col and Row `gutter` prop is now based on system, **be careful**! 147 | - Toggler now returns an array `[toggled, onToggle]` instead of an object 148 | 149 | 150 | 151 | 152 | 153 | # [9.1.0](https://github.com/smooth-code/smooth-ui/compare/v9.0.2...v9.1.0) (2019-03-07) 154 | 155 | **Note:** Version bump only for package @smooth-ui/core-sc 156 | 157 | 158 | 159 | 160 | 161 | ## [9.0.2](https://github.com/smooth-code/smooth-ui/compare/v9.0.1...v9.0.2) (2019-02-20) 162 | 163 | **Note:** Version bump only for package @smooth-ui/core-sc 164 | 165 | 166 | 167 | 168 | 169 | ## [9.0.1](https://github.com/smooth-code/smooth-ui/compare/v9.0.0...v9.0.1) (2019-02-04) 170 | 171 | **Note:** Version bump only for package @smooth-ui/core-sc 172 | 173 | 174 | 175 | 176 | 177 | # [9.0.0](https://github.com/smooth-code/smooth-ui/compare/v8.1.0...v9.0.0) (2019-02-04) 178 | 179 | 180 | ### Bug Fixes 181 | 182 | * **types:** fix TypeScript definitions ([#108](https://github.com/smooth-code/smooth-ui/issues/108)) ([87eda0b](https://github.com/smooth-code/smooth-ui/commit/87eda0b)) 183 | 184 | 185 | ### Features 186 | 187 | * simplify core & remove theme dependency ([cec1029](https://github.com/smooth-code/smooth-ui/commit/cec1029)) 188 | 189 | 190 | ### BREAKING CHANGES 191 | 192 | * - `prop` utility has been removed 193 | - Undocumented utilities are no longer exported 194 | - `controlFocus` has been renamed `baseFocus`, `controlFocus` is only 195 | for controls (when control prop is `true`) 196 | - `mixin` function is no longer available, also mixins have changed 197 | 198 | **Mixins:** 199 | 200 | Previously mixins were called using `mixin` helper: 201 | 202 | ```js 203 | import { styled, mixin } from '@smooth-ui/core-sc' 204 | 205 | const Styled = styled.div` 206 | color: ${mixin('colorLevel', 'red', 5)}; 207 | ` 208 | ``` 209 | 210 | All mixins are now exported: 211 | 212 | ```js 213 | import { styled, colorLevel } from '@smooth-ui/core-sc' 214 | 215 | const Styled = styled.div` 216 | color: ${colorLevel('red', 5)}; 217 | ` 218 | ``` 219 | 220 | **Theme** 221 | 222 | Theme is no longer required, Smooth UI will work well without theme and 223 | you can override only needed properties without having to load the 224 | entire theme. 225 | 226 | The benefit from that approach is that code splitting is fully 227 | efficient, if you use only one component in Smooth UI you will load only 228 | theme primitives of this component. 229 | 230 | The size of a result bundle that is using only a `Button`: 231 | 232 | ``` 233 | 202K bundle-smooth-ui-v8.js 234 | 194K bundle-smooth-ui-v9.js 235 | 65K bundle-smooth-ui-v8.js.gz 236 | 63K bundle-smooth-ui-v9.js.gz 237 | ``` 238 | 239 | As you can see the bundle has been reduced of 8K (no gzip) and of 2K 240 | (gzip). 241 | 242 | 243 | 244 | 245 | 246 | # [8.1.0](https://github.com/smooth-code/smooth-ui/compare/v8.0.1...v8.1.0) (2019-01-22) 247 | 248 | 249 | ### Features 250 | 251 | * add scroll-lock to modals, fixes [#25](https://github.com/smooth-code/smooth-ui/issues/25) ([#103](https://github.com/smooth-code/smooth-ui/issues/103)) ([23f35dd](https://github.com/smooth-code/smooth-ui/commit/23f35dd)) 252 | 253 | 254 | 255 | 256 | 257 | ## [8.0.1](https://github.com/smooth-code/smooth-ui/compare/v8.0.0...v8.0.1) (2019-01-17) 258 | 259 | **Note:** Version bump only for package @smooth-ui/core-sc 260 | 261 | 262 | 263 | 264 | 265 | # [8.0.0](https://github.com/smooth-code/smooth-ui/compare/v7.1.1...v8.0.0) (2019-01-16) 266 | 267 | 268 | ### Features 269 | 270 | * support emotion 10 & remove hacks ([#93](https://github.com/smooth-code/smooth-ui/issues/93)) ([d311640](https://github.com/smooth-code/smooth-ui/commit/d311640)) 271 | 272 | 273 | ### BREAKING CHANGES 274 | 275 | * `OriginalComponent.withComponent(NewComponent)` is replaced by `uiAs(OriginalComponent, NewComponent)` 276 | 277 | `as={NewComponent}` is replaced by `uiAs={NewComponent}` 278 | 279 | `globalStyle()` is now replaced by `Normalize` component 280 | 281 | 282 | 283 | 284 | 285 | ## [7.1.1](https://github.com/smooth-code/smooth-ui/compare/v7.1.0...v7.1.1) (2019-01-11) 286 | 287 | **Note:** Version bump only for package @smooth-ui/core-sc 288 | 289 | # [7.1.0](https://github.com/smooth-code/smooth-ui/compare/v7.0.5...v7.1.0) (2019-01-07) 290 | 291 | ### Features 292 | 293 | - add TypeScript definitions ([#87](https://github.com/smooth-code/smooth-ui/issues/87)) ([ab8c033](https://github.com/smooth-code/smooth-ui/commit/ab8c033)) 294 | 295 | ## [7.0.5](https://github.com/smooth-code/smooth-ui/compare/v7.0.4...v7.0.5) (2018-11-11) 296 | 297 | **Note:** Version bump only for package @smooth-ui/core-sc 298 | 299 | ## [7.0.4](https://github.com/smooth-code/smooth-ui/compare/v7.0.3...v7.0.4) (2018-11-01) 300 | 301 | **Note:** Version bump only for package @smooth-ui/core-sc 302 | 303 | ## [7.0.3](https://github.com/smooth-code/smooth-ui/compare/v7.0.2...v7.0.3) (2018-10-24) 304 | 305 | ### Bug Fixes 306 | 307 | - **modals:** replace focus-trap by focus-lock ([#69](https://github.com/smooth-code/smooth-ui/issues/69)) ([77872db](https://github.com/smooth-code/smooth-ui/commit/77872db)) 308 | 309 | ## [7.0.2](https://github.com/smooth-code/smooth-ui/compare/v7.0.1...v7.0.2) (2018-10-23) 310 | 311 | ### Bug Fixes 312 | 313 | - **sc:** fix withComponent API ([#68](https://github.com/smooth-code/smooth-ui/issues/68)) ([0f59029](https://github.com/smooth-code/smooth-ui/commit/0f59029)) 314 | 315 | ## [7.0.1](https://github.com/smooth-code/smooth-ui/compare/v7.0.0...v7.0.1) (2018-10-19) 316 | 317 | **Note:** Version bump only for package @smooth-ui/core-sc 318 | 319 | # [7.0.0](https://github.com/smooth-code/smooth-ui/compare/v6.0.2...v7.0.0) (2018-10-18) 320 | 321 | ### Features 322 | 323 | - make modals accessible ([#65](https://github.com/smooth-code/smooth-ui/issues/65)) ([e37c708](https://github.com/smooth-code/smooth-ui/commit/e37c708)), closes [#31](https://github.com/smooth-code/smooth-ui/issues/31) [#26](https://github.com/smooth-code/smooth-ui/issues/26) [#25](https://github.com/smooth-code/smooth-ui/issues/25) 324 | 325 | ### BREAKING CHANGES 326 | 327 | - "persistent" prop has been removed from Modal, Modal are now 328 | non-persistent. 329 | 330 | "sui-modal-backdrop" has been removed, it is now "sui-modal". 331 | 332 | ## [6.0.2](https://github.com/smooth-code/smooth-ui/compare/v6.0.1...v6.0.2) (2018-10-17) 333 | 334 | **Note:** Version bump only for package @smooth-ui/core-sc 335 | 336 | ## [6.0.1](https://github.com/smooth-code/smooth-ui/compare/v6.0.0...v6.0.1) (2018-10-17) 337 | 338 | **Note:** Version bump only for package @smooth-ui/core-sc 339 | 340 | # [6.0.0](https://github.com/smooth-code/smooth-ui/compare/v5.1.3...v6.0.0) (2018-10-17) 341 | 342 | ### Features 343 | 344 | - flatten style & remove classNames ([34dd3fc](https://github.com/smooth-code/smooth-ui/commit/34dd3fc)) 345 | - support styled-components v4 ([b25675a](https://github.com/smooth-code/smooth-ui/commit/b25675a)) 346 | 347 | ### BREAKING CHANGES 348 | 349 | - - styled-components v4 is required 350 | 351 | * `.extend` has been removed, please use `styled()` instead 352 | * `component` prop has been removed, please use `as` instead 353 | 354 | - A lot of classes have been removed. 355 | 356 | Introduced a new default size "md". 357 | 358 | 359 | 360 | ## [5.1.3](https://github.com/smooth-code/smooth-ui/compare/v5.1.2...v5.1.3) (2018-09-26) 361 | 362 | **Note:** Version bump only for package @smooth-ui/core-sc 363 | 364 | 365 | 366 | ## [5.1.2](https://github.com/smooth-code/smooth-ui/compare/v5.1.1...v5.1.2) (2018-09-17) 367 | 368 | **Note:** Version bump only for package @smooth-ui/core-sc 369 | -------------------------------------------------------------------------------- /packages/core-sc/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | smooth-ui 4 | 5 |

6 |

Modern React UI library. Code less, do more.

7 | 8 | [![Build Status][build-badge]][build] 9 | [![Version][version-badge]][package] 10 | [![MIT License][license-badge]][license] 11 | [![Small size][size-badge]][build-min] 12 | 13 | ```sh 14 | npm install @smooth-ui/core-sc reakit styled-components 15 | ``` 16 | 17 | Smooth UI is a style system / UI library for [React](https://reactjs.org/). It works with [Styled Components 💅](https://www.styled-components.com) or [Emotion 👩‍🎤](https://emotion.sh/). 18 | 19 | It is focused on developer experience, productivity. You can focus on what you want to build instead of on how to build it. 20 | 21 | ## [Docs](https://smooth-ui.smooth-code.com/) 22 | 23 | **See the documentation at [smooth-ui.smooth-code.com](https://smooth-ui.smooth-code.com/)** for more information about using Smooth UI! 24 | 25 | ## License 26 | 27 | Licensed under the MIT License, Copyright © 2018-present Smooth Code. 28 | 29 | See [LICENSE](./LICENSE) for more information. 30 | 31 | [build-badge]: https://img.shields.io/travis/smooth-code/smooth-ui.svg?style=flat-square 32 | [build]: https://travis-ci.org/smooth-code/smooth-ui 33 | [version-badge]: https://img.shields.io/npm/v/@smooth-ui/core-sc.svg?style=flat-square 34 | [package]: https://www.npmjs.com/package/@smooth-ui/core-sc 35 | [license-badge]: https://img.shields.io/npm/l/@smooth-ui/core-sc.svg?style=flat-square 36 | [license]: https://github.com/smooth-code/smooth-ui/blob/master/LICENSE 37 | [size-badge]: https://img.badgesize.io/https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui.min.js?compression=gzip&style=flat-square 38 | [build-min]: https://unpkg.com/@smooth-ui/core-sc/dist/smooth-ui.min.js 39 | -------------------------------------------------------------------------------- /packages/core-sc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@smooth-ui/core-sc", 3 | "description": "Modern React UI Library", 4 | "version": "11.1.5", 5 | "keywords": [ 6 | "styled-components", 7 | "ui", 8 | "ui-components", 9 | "react", 10 | "material-ui", 11 | "bootstrap" 12 | ], 13 | "sideEffects": false, 14 | "main": "dist/smooth-ui-core-sc.cjs.js", 15 | "module": "dist/smooth-ui-core-sc.es.js", 16 | "author": "Greg Bergé ", 17 | "license": "MIT", 18 | "scripts": { 19 | "build": "cross-env STYLED_ENGINE=styled-components BABEL_ENV=rollup rollup -c", 20 | "prebuild": "shx rm -rf dist", 21 | "prepublishOnly": "yarn build" 22 | }, 23 | "publishConfig": { 24 | "access": "public" 25 | }, 26 | "dependencies": { 27 | "@babel/runtime": "^7.7.2", 28 | "@xstyled/styled-components": "^1.15.0", 29 | "@xstyled/util": "^1.14.0", 30 | "polished": "^3.4.2", 31 | "prop-desc": "^1.0.0", 32 | "prop-types": "^15.7.2", 33 | "react-flatten-children": "^1.0.0", 34 | "react-merge-refs": "^1.0.0" 35 | }, 36 | "peerDependencies": { 37 | "react": ">=16.8.0", 38 | "react-dom": ">=16.8.0", 39 | "reakit": ">=1.0.0-beta.6 <2.0.0", 40 | "styled-components": "^4.0.0" 41 | }, 42 | "devDependencies": { 43 | "@xstyled/styled-components": "^1.10.0", 44 | "@xstyled/system": "^1.14.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/core-sc/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { getRollupConfig } from '../../config/rollup' 2 | import pkg from './package.json' 3 | 4 | export default getRollupConfig({ 5 | pwd: __dirname, 6 | name: 'smoothUI', 7 | buildName: 'smooth-ui-core-sc', 8 | pkg, 9 | }) 10 | -------------------------------------------------------------------------------- /packages/core-sc/src/index.js: -------------------------------------------------------------------------------- 1 | export * from '../../shared/core/index' 2 | -------------------------------------------------------------------------------- /packages/shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-unresolved": ["error", { "ignore": ["@xstyled/x"] }] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/shared/core/Alert.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { darken } from 'polished' 3 | import { th, system } from '@xstyled/system' 4 | import { node, oneOf, string, oneOfType } from 'prop-desc' 5 | import { 6 | css, 7 | createComponent, 8 | getSystemPropTypes, 9 | VARIANTS, 10 | colorLevel, 11 | } from './util' 12 | import * as theme from './theme/common' 13 | 14 | export const Alert = createComponent({ 15 | name: 'Alert', 16 | render: ({ as: As = 'p', ...props }) => , 17 | theme: [ 18 | theme, 19 | { 20 | colorLevels: { 21 | Alert: { 22 | color: 6, 23 | backgroundColor: -10, 24 | borderColor: -9, 25 | }, 26 | }, 27 | components: { 28 | Alert: p => { 29 | const baseColor = 30 | p.variant === null ? null : th.color(p.variant || 'primary')(p) 31 | const textColorLevel = th('colorLevels.Alert.color')(p) 32 | const backgroundColorLevel = th('colorLevels.Alert.backgroundColor')( 33 | p, 34 | ) 35 | const borderColorLevel = th('colorLevels.Alert.borderColor')(p) 36 | const color = colorLevel(baseColor, textColorLevel)(p) 37 | const backgroundColor = colorLevel(baseColor, backgroundColorLevel)(p) 38 | const borderColor = colorLevel(baseColor, borderColorLevel)(p) 39 | const hrColor = darken(0.05, color) 40 | return css` 41 | font-family: ${th.font('base')(p)}; 42 | position: relative; 43 | padding: 12rpx 20rpx; 44 | margin-bottom: 16rpx; 45 | border: 1rpx; 46 | border-color: transparent; 47 | border-radius: ${th.radius('base')(p)}; 48 | color: ${color}; 49 | background-color: ${backgroundColor}; 50 | border-color: ${borderColor}; 51 | 52 | hr { 53 | border-top-color: ${hrColor}; 54 | } 55 | 56 | && { 57 | ${system(p)} 58 | } 59 | ` 60 | }, 61 | }, 62 | }, 63 | ], 64 | propTypes: { 65 | children: node, 66 | variant: oneOfType([oneOf(VARIANTS), string]) 67 | .defaultTo('primary') 68 | .desc('Control the color variant of the component.'), 69 | ...getSystemPropTypes(system), 70 | }, 71 | }) 72 | -------------------------------------------------------------------------------- /packages/shared/core/Box.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import flattenChildren from 'react-flatten-children' 3 | import { Box } from '@xstyled/x' 4 | import { system } from '@xstyled/system' 5 | import { getSystemPropTypes } from './util' 6 | 7 | export { Box } 8 | 9 | Box.propTypes = getSystemPropTypes(system) 10 | 11 | export function Boxer({ children, ...props }) { 12 | return flattenChildren(children).map(child => ( 13 | 14 | {child} 15 | 16 | )) 17 | } 18 | 19 | Boxer.propTypes = getSystemPropTypes(system) 20 | -------------------------------------------------------------------------------- /packages/shared/core/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { darken, transparentize } from 'polished' 3 | import { Button as ReakitButton } from 'reakit/Button' 4 | import { th, system } from '@xstyled/system' 5 | import { node, bool, oneOf, string, oneOfType } from 'prop-desc' 6 | import * as theme from './theme/common' 7 | import * as formTheme from './theme/form' 8 | import { 9 | css, 10 | SCALES, 11 | VARIANTS, 12 | createComponent, 13 | getSystemPropTypes, 14 | colorYik, 15 | safeTransition, 16 | } from './util' 17 | 18 | export const Button = createComponent({ 19 | name: 'Button', 20 | render: ({ variant, outline, ...props }) => { 21 | return 22 | }, 23 | theme: [ 24 | theme, 25 | formTheme, 26 | { 27 | borderWidths: { 28 | button: SCALES.reduce((obj, scale) => { 29 | obj[scale] = 0 30 | return obj 31 | }, {}), 32 | }, 33 | components: { 34 | Button: p => { 35 | const { outline } = p 36 | const scale = p.scale || 'base' 37 | const baseColor = 38 | p.variant === null ? null : th.color(p.variant || 'primary')(p) 39 | const px = th.space(`textFormControl.x.${scale}`)(p) 40 | const py = th.space(`textFormControl.y.${scale}`)(p) 41 | return css` 42 | display: inline-block; 43 | z-index: ${th.zIndex('control')(p)}; 44 | font-family: ${th.font('base')(p)}; 45 | font-size: ${th.fontSize(scale)(p)}; 46 | padding: ${py} ${px}; 47 | border-radius: ${th.radius(scale)(p)}; 48 | line-height: ${th.lineHeight(`formControl.${scale}`)(p)}; 49 | border-width: ${th.borderWidth(`button.${scale}`)(p)}; 50 | cursor: ${p.disabled ? 'initial' : 'pointer'}; 51 | ${safeTransition('base')(p)}; 52 | 53 | /* When used as link */ 54 | text-decoration: none; 55 | 56 | &[type='button'] { 57 | appearance: none; 58 | } 59 | 60 | &:disabled { 61 | opacity: 0.8; 62 | } 63 | 64 | ${baseColor && 65 | !outline && 66 | css` 67 | color: ${colorYik(baseColor)(p)}; 68 | background-color: ${baseColor}; 69 | 70 | &:focus { 71 | ${p.theme.mixins.controlFocus(baseColor)(p)}; 72 | } 73 | 74 | &:not(:disabled):hover, 75 | &:not(:disabled):active { 76 | color: ${colorYik(baseColor)(p)}; 77 | background-color: ${darken(0.05, baseColor)}; 78 | } 79 | `(p)} 80 | 81 | ${baseColor && 82 | outline && 83 | css` 84 | color: ${darken(0.05, baseColor)}; 85 | background-color: transparent; 86 | border: 1; 87 | border-color: ${baseColor}; 88 | 89 | &:focus { 90 | ${p.theme.mixins.controlFocus(baseColor)(p)}; 91 | border-color: ${baseColor}; 92 | } 93 | 94 | &:not(:disabled):hover, 95 | &:not(:disabled):active { 96 | color: ${darken(0.1, baseColor)}; 97 | border-color: ${darken(0.05, baseColor)}; 98 | background-color: ${transparentize(0.8, baseColor)}; 99 | } 100 | `} 101 | 102 | && { 103 | ${system(p)} 104 | } 105 | ` 106 | }, 107 | }, 108 | }, 109 | ], 110 | propTypes: { 111 | children: node, 112 | disabled: bool.desc('Same as the HTML attribute.'), 113 | focusable: bool.desc( 114 | 'When an element is `disabled`, it may still be `focusable`. It works similarly to `readOnly` on form elements. In this case, only `aria-disabled` will be set.', 115 | ), 116 | scale: oneOf(SCALES).desc('Control the size of the component.'), 117 | variant: oneOfType([oneOf(VARIANTS), string]) 118 | .defaultTo('primary') 119 | .desc('Control the color variant of the component.'), 120 | ...getSystemPropTypes(system), 121 | }, 122 | }) 123 | -------------------------------------------------------------------------------- /packages/shared/core/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { th, system } from '@xstyled/system' 3 | import { node } from 'prop-desc' 4 | import { css, createComponent, getSystemPropTypes } from './util' 5 | import * as theme from './theme/common' 6 | 7 | export const Card = createComponent({ 8 | name: 'Card', 9 | render: ({ as: As = 'div', ...props }) => , 10 | theme: [ 11 | theme, 12 | { 13 | components: { 14 | Card: p => { 15 | return css` 16 | position: relative; 17 | display: flex; 18 | flex-direction: column; 19 | min-width: 0; 20 | word-wrap: break-word; 21 | background-color: ${th.color('lighter')(p)}; 22 | background-clip: border-box; 23 | border: 0.0625rem solid; 24 | border-color: ${th.color('highlightBorder')(p)}; 25 | border-radius: ${th.radius('base')(p)}; 26 | font-family: ${th.font('base')(p)}; 27 | 28 | && { 29 | ${system(p)} 30 | } 31 | ` 32 | }, 33 | }, 34 | }, 35 | ], 36 | propTypes: { 37 | children: node, 38 | ...getSystemPropTypes(system), 39 | }, 40 | }) 41 | 42 | export const CardBody = createComponent({ 43 | name: 'CardBody', 44 | render: ({ as: As = 'div', ...props }) => , 45 | theme: [ 46 | theme, 47 | { 48 | components: { 49 | CardBody: p => { 50 | return css` 51 | flex: 1 1 auto; 52 | padding: 20rpx; 53 | 54 | && { 55 | ${system(p)} 56 | } 57 | ` 58 | }, 59 | }, 60 | }, 61 | ], 62 | propTypes: { 63 | children: node, 64 | ...getSystemPropTypes(system), 65 | }, 66 | }) 67 | 68 | export const CardTitle = createComponent({ 69 | name: 'CardTitle', 70 | render: ({ as: As = 'div', ...props }) => , 71 | theme: [ 72 | theme, 73 | { 74 | components: { 75 | CardTitle: p => { 76 | return css` 77 | margin-bottom: 12rpx; 78 | 79 | && { 80 | ${system(p)} 81 | } 82 | ` 83 | }, 84 | }, 85 | }, 86 | ], 87 | propTypes: { 88 | children: node, 89 | ...getSystemPropTypes(system), 90 | }, 91 | }) 92 | 93 | export const CardText = createComponent({ 94 | name: 'CardText', 95 | render: ({ as: As = 'p', ...props }) => , 96 | theme: [ 97 | theme, 98 | { 99 | components: { 100 | CardText: p => { 101 | return css` 102 | &:last-child { 103 | margin-bottom: 0; 104 | } 105 | 106 | && { 107 | ${system(p)} 108 | } 109 | ` 110 | }, 111 | }, 112 | }, 113 | ], 114 | propTypes: { 115 | children: node, 116 | ...getSystemPropTypes(system), 117 | }, 118 | }) 119 | 120 | export const CardHeader = createComponent({ 121 | name: 'CardHeader', 122 | render: ({ as: As = 'div', ...props }) => , 123 | theme: [ 124 | theme, 125 | { 126 | components: { 127 | CardHeader: p => { 128 | const baseRadius = th.radius('base')(p) 129 | return css` 130 | padding: 0.75rem 1.25rem; 131 | margin-bottom: 0; /* Removes the default margin-bottom of */ 132 | background-color: ${th.color('highlightBackground')(p)}; 133 | border-bottom: 0.0625rem solid; 134 | border-bottom-color: ${th.color('highlightBorder')(p)}; 135 | 136 | &:first-child { 137 | border-radius: calc(${baseRadius} - 1px) calc(${baseRadius} - 1px) 138 | 0 0; 139 | } 140 | 141 | && { 142 | ${system(p)} 143 | } 144 | ` 145 | }, 146 | }, 147 | }, 148 | ], 149 | propTypes: { 150 | children: node, 151 | ...getSystemPropTypes(system), 152 | }, 153 | }) 154 | 155 | export const CardFooter = createComponent({ 156 | name: 'CardFooter', 157 | render: ({ as: As = 'div', ...props }) => , 158 | theme: [ 159 | theme, 160 | { 161 | components: { 162 | CardFooter: p => { 163 | const baseRadius = th.radius('base')(p) 164 | return css` 165 | padding: 0.75rem 1.25rem; 166 | background-color: ${th.color('highlightBackground')(p)}; 167 | border-top: 0.0625rem solid; 168 | border-top-color: ${th.color('highlightBorder')(p)}; 169 | 170 | &:last-child { 171 | border-radius: 0 0 calc(${baseRadius} - 1px) 172 | calc(${baseRadius} - 1px); 173 | } 174 | 175 | && { 176 | ${system(p)} 177 | } 178 | ` 179 | }, 180 | }, 181 | }, 182 | ], 183 | propTypes: { 184 | children: node, 185 | ...getSystemPropTypes(system), 186 | }, 187 | }) 188 | 189 | export const CardImg = createComponent({ 190 | name: 'CardImg', 191 | render: ({ as: As = 'img', ...props }) => , 192 | theme: [ 193 | theme, 194 | { 195 | components: { 196 | CardImg: p => { 197 | const baseRadius = th.radius('base')(p) 198 | return css` 199 | flex-shrink: 0; /* For IE: https://github.com/twbs/bootstrap/issues/29396 */ 200 | width: 100%; /* Required because we use flexbox and this inherently applies align-self: stretch */ 201 | 202 | &:first-child { 203 | border-radius: calc(${baseRadius} - 1px) calc(${baseRadius} - 1px) 204 | 0 0; 205 | } 206 | 207 | &:last-child { 208 | border-radius: 0 0 calc(${baseRadius} - 1px) 209 | calc(${baseRadius} - 1px); 210 | } 211 | 212 | && { 213 | ${system(p)} 214 | } 215 | ` 216 | }, 217 | }, 218 | }, 219 | ], 220 | propTypes: { 221 | children: node, 222 | ...getSystemPropTypes(system), 223 | }, 224 | }) 225 | -------------------------------------------------------------------------------- /packages/shared/core/Checkbox.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable react-hooks/rules-of-hooks */ 3 | import React from 'react' 4 | import { Checkbox as ReakitCheckbox } from 'reakit/Checkbox' 5 | import { th, system } from '@xstyled/system' 6 | import { func, bool, oneOf, node } from 'prop-desc' 7 | import * as theme from './theme/common' 8 | import * as formTheme from './theme/form' 9 | import { 10 | css, 11 | SCALES, 12 | safeTransition, 13 | createComponent, 14 | getSystemPropTypes, 15 | } from './util' 16 | import { useFormGroupControlProps } from './Form' 17 | 18 | export { useCheckboxState } from 'reakit/Checkbox' 19 | 20 | export const CheckboxGroup = createComponent({ 21 | name: 'CheckboxGroup', 22 | render: ({ as: As = 'fieldset', ...props }) => { 23 | return 24 | }, 25 | theme: { 26 | components: { 27 | CheckboxGroup: p => { 28 | return css` 29 | padding: 0; 30 | border: 0; 31 | 32 | &[aria-orientation='horizontal'] > [data-form-check] { 33 | display: inline-flex; 34 | margin-right: 1em; 35 | } 36 | 37 | && { 38 | ${system(p)} 39 | } 40 | ` 41 | }, 42 | }, 43 | }, 44 | propTypes: { 45 | children: node, 46 | 'aria-orientation': oneOf(['vertical', 'horizontal']).desc( 47 | 'Specify the orientation of the checkbox group.', 48 | ), 49 | ...getSystemPropTypes(system), 50 | }, 51 | }) 52 | 53 | const validationStyle = color => p => { 54 | return css` 55 | &[aria-checked='true'] { 56 | border-color: ${color}; 57 | background-color: ${color}; 58 | } 59 | 60 | &:focus { 61 | border-color: ${color}; 62 | ${p.theme.mixins.controlFocus(color)(p)}; 63 | } 64 | `(p) 65 | } 66 | 67 | const noop = () => {} 68 | 69 | const BaseCheckbox = React.forwardRef(function BaseCheckbox( 70 | { type, checked, disabled, id, name, value, ...props }, 71 | ref, 72 | ) { 73 | const inputRef = React.useRef() 74 | const handleInputFocus = React.useCallback(() => { 75 | inputRef.current.parentElement.focus() 76 | }, []) 77 | return ( 78 |
79 | 91 | 92 | 96 | 97 |
98 | ) 99 | }) 100 | 101 | export const Checkbox = createComponent({ 102 | name: 'Checkbox', 103 | render: ({ as = BaseCheckbox, ...props }) => { 104 | const controlProps = useFormGroupControlProps(props) 105 | return 106 | }, 107 | theme: [ 108 | theme, 109 | formTheme, 110 | { 111 | sizes: { 112 | checkbox: { 113 | container: { 114 | xs: '10rpx', 115 | sm: '12rpx', 116 | base: '16rpx', 117 | lg: '22rpx', 118 | xl: '28rpx', 119 | }, 120 | checkmark: { 121 | xs: '6rpx', 122 | sm: '8rpx', 123 | base: '10rpx', 124 | lg: '14rpx', 125 | xl: '18rpx', 126 | }, 127 | }, 128 | }, 129 | components: { 130 | Checkbox: p => { 131 | const scale = p.scale || 'base' 132 | const validColor = th.color('form.valid')(p) 133 | const invalidColor = th.color('form.invalid')(p) 134 | const containerSize = th.size(`checkbox.container.${scale}`)(p) 135 | const checkmarkSize = th.size(`checkbox.checkmark.${scale}`)(p) 136 | return css` 137 | display: inline-flex; 138 | align-items: center; 139 | justify-content: center; 140 | position: relative; 141 | width: ${containerSize}; 142 | height: ${containerSize}; 143 | z-index: ${th.zIndex('control')(p)}; 144 | background-color: ${th.color('formControl.background')(p)}; 145 | border-radius: ${th.radius(scale)(p)}; 146 | border-style: solid; 147 | border-width: ${th.borderWidth(`formControl.${scale}`)(p)}; 148 | border-color: ${th.color('formControl.border')(p)}; 149 | ${safeTransition('base')(p)}; 150 | 151 | input { 152 | top: 0; 153 | left: 0; 154 | width: 100%; 155 | cursor: inherit; 156 | height: 100%; 157 | margin: 0; 158 | opacity: 0; 159 | padding: 0; 160 | position: absolute; 161 | } 162 | 163 | [data-checkmark] { 164 | height: ${checkmarkSize}; 165 | width: ${checkmarkSize}; 166 | pointer-events: none; 167 | transform: scale(0); 168 | transform-origin: center; 169 | color: ${th.color('white')(p)}; 170 | ${safeTransition('base')(p)}; 171 | } 172 | 173 | &[aria-checked='true'] { 174 | background-color: ${th.color('primary')(p)}; 175 | border-color: transparent; 176 | 177 | > svg { 178 | transform: scale(1); 179 | } 180 | } 181 | 182 | &:focus { 183 | ${p.theme.mixins.controlFocus(th.color('primary')(p))(p)}; 184 | } 185 | 186 | &[aria-disabled] { 187 | opacity: 0.6; 188 | } 189 | 190 | &[aria-invalid='true'] { 191 | ${validationStyle(invalidColor)(p)}; 192 | } 193 | 194 | &[aria-invalid='false'] { 195 | ${validationStyle(validColor)(p)}; 196 | } 197 | 198 | && { 199 | ${system(p)} 200 | } 201 | ` 202 | }, 203 | }, 204 | }, 205 | ], 206 | propTypes: { 207 | checked: bool.desc( 208 | "Checkbox's checked state. If present, it's used instead of state.", 209 | ), 210 | disabled: bool.desc('Same as the HTML attribute.'), 211 | focusable: bool.desc( 212 | 'When an element is `disabled`, it may still be `focusable`. It works similarly to `readOnly` on form elements. In this case, only `aria-disabled` will be set.', 213 | ), 214 | onChange: func.desc('Same as the "checkbox" `onChange` prop.'), 215 | scale: oneOf(SCALES) 216 | .desc('Control the size of the component.') 217 | .defaultTo('base'), 218 | ...getSystemPropTypes(system), 219 | }, 220 | }) 221 | -------------------------------------------------------------------------------- /packages/shared/core/Form.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-use-before-define */ 2 | /* eslint-disable react-hooks/rules-of-hooks */ 3 | import React from 'react' 4 | import { system, th } from '@xstyled/system' 5 | import { node, oneOf } from 'prop-desc' 6 | import { 7 | css, 8 | scale, 9 | SCALES, 10 | createComponent, 11 | getSystemPropTypes, 12 | useRandomId, 13 | } from './util' 14 | import * as formTheme from './theme/form' 15 | import * as theme from './theme/common' 16 | 17 | export function createFieldsGroupContext(type) { 18 | const FieldsGroupContext = React.createContext() 19 | 20 | function useFieldsGroupState() { 21 | return React.useContext(FieldsGroupContext) 22 | } 23 | 24 | function useCreateFieldsGroupState(baseId) { 25 | const randomId = useRandomId(type) 26 | const id = baseId || randomId 27 | const [labels, setLabels] = React.useState({}) 28 | const registerLabel = React.useCallback((name, id) => { 29 | setLabels(labels => ({ 30 | ...labels, 31 | [name]: id, 32 | })) 33 | }, []) 34 | const unregisterLabel = React.useCallback(name => { 35 | setLabels(labels => { 36 | const newLabels = { ...labels } 37 | delete newLabels[name] 38 | return newLabels 39 | }) 40 | }, []) 41 | return React.useMemo( 42 | () => ({ 43 | id, 44 | labels, 45 | registerLabel, 46 | unregisterLabel, 47 | }), 48 | [id, labels, registerLabel, unregisterLabel], 49 | ) 50 | } 51 | 52 | function Provider({ id, children }) { 53 | const fieldsGroupState = useCreateFieldsGroupState(id) 54 | return ( 55 | 56 | {children} 57 | 58 | ) 59 | } 60 | 61 | function useRegisterLabel(name, id) { 62 | const fieldsGroupState = useFieldsGroupState() 63 | const hasFormState = Boolean(fieldsGroupState) 64 | const { registerLabel, unregisterLabel } = fieldsGroupState || {} 65 | React.useEffect(() => { 66 | if (name && id && hasFormState) { 67 | registerLabel(name, id) 68 | return () => { 69 | unregisterLabel(name) 70 | } 71 | } 72 | return undefined 73 | }, [name, id, hasFormState, registerLabel, unregisterLabel]) 74 | } 75 | 76 | function getControlId(fieldsGroupId, name) { 77 | return `${fieldsGroupId}-${name}` 78 | } 79 | 80 | function getLabelId(controlId) { 81 | return controlId && `${controlId}-label` 82 | } 83 | 84 | function useControlId(name, baseId) { 85 | const fieldsGroupState = useFieldsGroupState() 86 | const id = React.useMemo(() => { 87 | if (baseId) return baseId 88 | if (fieldsGroupState && name) 89 | return getControlId(fieldsGroupState.id, name) 90 | return null 91 | }, [fieldsGroupState, name, baseId]) 92 | return id 93 | } 94 | 95 | function useControlProps(props) { 96 | const fieldsGroupState = useFieldsGroupState() 97 | const id = useControlId(props.name, props.id) 98 | const labelId = 99 | (props.name && fieldsGroupState && fieldsGroupState.labels[props.name]) || 100 | null 101 | return { 102 | ...props, 103 | id, 104 | 'aria-labelledby': props['aria-labelledby'] || labelId, 105 | } 106 | } 107 | 108 | function useLabelProps({ name, ...props }) { 109 | const controlId = useControlId(name) 110 | const labelId = getLabelId(controlId) 111 | useRegisterLabel(name, labelId) 112 | return { id: labelId, htmlFor: controlId, ...props } 113 | } 114 | 115 | return { 116 | Provider, 117 | useControlProps, 118 | useLabelProps, 119 | } 120 | } 121 | 122 | const { 123 | Provider: FormProvider, 124 | useControlProps: useFormControlProps, 125 | useLabelProps: useFormLabelProps, 126 | } = createFieldsGroupContext('form') 127 | 128 | const { 129 | Provider: FromGroupProvider, 130 | useControlProps: useFormGroupControlProps, 131 | useLabelProps: useFormGroupLabelProps, 132 | } = createFieldsGroupContext('group') 133 | 134 | export { FromGroupProvider, useFormGroupControlProps, useFormControlProps } 135 | 136 | export const Form = createComponent({ 137 | name: 'Form', 138 | render: ({ as: As = 'form', ...props }) => { 139 | const role = As === 'form' ? null : 'form' 140 | return ( 141 | 142 | 143 | 144 | ) 145 | }, 146 | theme: { 147 | components: { 148 | Form: p => { 149 | return css` 150 | && { 151 | ${system(p)} 152 | } 153 | ` 154 | }, 155 | }, 156 | }, 157 | propTypes: { 158 | children: node, 159 | ...getSystemPropTypes(system), 160 | }, 161 | }) 162 | 163 | export const FormField = createComponent({ 164 | name: 'FormField', 165 | render: ({ as: As = 'div', ...props }) => , 166 | theme: { 167 | space: { 168 | formField: { 169 | bottom: scale('1rem', th.space('formField.bottom.base')), 170 | }, 171 | }, 172 | components: { 173 | FormField: p => { 174 | const { scale = 'base' } = p 175 | const mb = th.space(`formField.bottom.${scale}`)(p) 176 | return css` 177 | margin-bottom: ${mb}; 178 | 179 | && { 180 | ${system(p)} 181 | } 182 | ` 183 | }, 184 | }, 185 | }, 186 | propTypes: { 187 | children: node, 188 | scale: oneOf(SCALES) 189 | .desc('Control the size of the component.') 190 | .defaultTo('base'), 191 | ...getSystemPropTypes(system), 192 | }, 193 | }) 194 | 195 | export const FormFieldLabel = createComponent({ 196 | name: 'FormFieldLabel', 197 | render: ({ as: As = 'label', scale, ...props }) => { 198 | const labelProps = useFormLabelProps(props) 199 | return 200 | }, 201 | theme: [ 202 | theme, 203 | formTheme, 204 | { 205 | space: { 206 | formFieldLabel: { 207 | bottom: scale('0.5rem', th.space('formFieldLabel.bottom.base')), 208 | }, 209 | }, 210 | }, 211 | { 212 | components: { 213 | FormFieldLabel: p => { 214 | const { scale = 'base' } = p 215 | const py = th.space(`textFormControl.y.${scale}`)(p) 216 | const mb = th.space(`formFieldLabel.bottom.${scale}`)(p) 217 | return css` 218 | font-family: ${th.font('base')(p)}; 219 | font-size: ${th.fontSize(scale)(p)}; 220 | display: inline-block; 221 | margin-bottom: ${mb}; 222 | font-weight: ${th.fontWeight('medium')(p)}; 223 | 224 | ${p.col && 225 | css` 226 | padding-top: calc(${py} + 1px); 227 | padding-bottom: calc(${py} + 1px); 228 | margin-bottom: 0; 229 | `(p)} 230 | 231 | [aria-disabled='true'] ~ & { 232 | opacity: 0.6; 233 | } 234 | 235 | && { 236 | ${system(p)} 237 | } 238 | ` 239 | }, 240 | }, 241 | }, 242 | ], 243 | propTypes: { 244 | children: node, 245 | scale: oneOf(SCALES) 246 | .desc('Control the size of the component.') 247 | .defaultTo('base'), 248 | ...getSystemPropTypes(system), 249 | }, 250 | }) 251 | 252 | export const FormCheck = createComponent({ 253 | name: 'FormCheck', 254 | render: ({ as: As = 'div', ...props }) => { 255 | return ( 256 | 257 | 258 | 259 | ) 260 | }, 261 | theme: { 262 | components: { 263 | FormCheck: p => { 264 | return css` 265 | display: flex; 266 | align-items: center; 267 | 268 | && { 269 | ${system(p)} 270 | } 271 | ` 272 | }, 273 | }, 274 | }, 275 | propTypes: { 276 | children: node, 277 | }, 278 | }) 279 | 280 | export const FormCheckLabel = createComponent({ 281 | name: 'FormCheckLabel', 282 | render: ({ as: As = 'label', ...props }) => { 283 | const labelProps = useFormGroupLabelProps(props) 284 | return 285 | }, 286 | theme: [ 287 | theme, 288 | formTheme, 289 | { 290 | space: { 291 | formCheckLabel: { 292 | left: scale('0.375rem', th.space('formCheckLabel.left.base')), 293 | }, 294 | }, 295 | }, 296 | { 297 | components: { 298 | FormCheckLabel: p => { 299 | const { scale = 'base' } = p 300 | const pl = th.space(`formCheckLabel.left.${scale}`)(p) 301 | return css` 302 | font-family: ${th.font('base')(p)}; 303 | font-size: ${th.fontSize(scale)(p)}; 304 | padding-left: ${pl}; 305 | 306 | [aria-disabled='true'] ~ & { 307 | opacity: 0.6; 308 | } 309 | ` 310 | }, 311 | }, 312 | }, 313 | ], 314 | propTypes: { 315 | children: node, 316 | scale: oneOf(SCALES) 317 | .desc('Control the size of the component.') 318 | .defaultTo('base'), 319 | ...getSystemPropTypes(system), 320 | }, 321 | }) 322 | -------------------------------------------------------------------------------- /packages/shared/core/Input.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import React from 'react' 3 | import { th, system } from '@xstyled/system' 4 | import { node, bool, oneOf } from 'prop-desc' 5 | import * as theme from './theme/common' 6 | import * as formTheme from './theme/form' 7 | import { 8 | css, 9 | SCALES, 10 | createComponent, 11 | getSystemPropTypes, 12 | safeTransition, 13 | } from './util' 14 | import { useFormControlProps } from './Form' 15 | 16 | const validationStyle = color => p => 17 | css` 18 | border-color: ${color}; 19 | 20 | &:focus { 21 | border-color: ${color}; 22 | ${p.theme.mixins.controlFocus(color)(p)} 23 | } 24 | `(p) 25 | 26 | export const Input = createComponent({ 27 | name: 'Input', 28 | render: ({ as: As = 'input', ...props }) => { 29 | const controlProps = useFormControlProps(props) 30 | return 31 | }, 32 | theme: [ 33 | theme, 34 | formTheme, 35 | { 36 | components: { 37 | Input: p => { 38 | const scale = p.scale || 'base' 39 | const px = th.space(`textFormControl.x.${scale}`)(p) 40 | const py = th.space(`textFormControl.y.${scale}`)(p) 41 | const validColor = th.color('form.valid')(p) 42 | const invalidColor = th.color('form.invalid')(p) 43 | return css` 44 | display: block; 45 | appearance: none; 46 | width: 100%; 47 | z-index: ${th.zIndex('control')(p)}; 48 | font-family: ${th.font('base')(p)}; 49 | font-size: ${th.fontSize(scale)(p)}; 50 | border-width: ${th.borderWidth(`formControl.${scale}`)(p)}; 51 | border-color: ${th.color('formControl.border')(p)}; 52 | border-style: solid; 53 | line-height: ${th.lineHeight(`formControl.${scale}`)(p)}; 54 | color: ${th.color('formControl.text')(p)}; 55 | background-color: ${th.color('formControl.background')(p)}; 56 | padding: ${py} ${px}; 57 | line-height: ${th.lineHeight(`button.${scale}`)(p)}; 58 | border-radius: ${th.radius(scale)(p)}; 59 | ${safeTransition('base')(p)}; 60 | 61 | &[type='number'] { 62 | padding-right: 6rpx; 63 | } 64 | 65 | &::placeholder { 66 | color: ${th.color('formControl.placeholder')(p)}; 67 | } 68 | 69 | &:disabled { 70 | background-color: ${th.color('formControl.disabled.background')( 71 | p, 72 | )}; 73 | color: ${th.color('formControl.disabled.text')(p)}; 74 | } 75 | 76 | &:focus { 77 | ${p.theme.mixins.controlFocus(th.color('primary')(p))(p)} 78 | } 79 | 80 | &[aria-invalid='true'] { 81 | ${validationStyle(invalidColor)(p)}; 82 | } 83 | 84 | &[aria-invalid='false'] { 85 | ${validationStyle(validColor)(p)}; 86 | } 87 | 88 | && { 89 | ${system(p)}; 90 | } 91 | ` 92 | }, 93 | }, 94 | }, 95 | ], 96 | propTypes: { 97 | children: node, 98 | disabled: bool, 99 | scale: oneOf(SCALES), 100 | ...getSystemPropTypes(system), 101 | }, 102 | }) 103 | -------------------------------------------------------------------------------- /packages/shared/core/Menu.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | useMenuState, 4 | Menu as ReakitMenu, 5 | MenuItem as ReakitMenuItem, 6 | MenuDisclosure as ReakitMenuDisclosure, 7 | MenuSeparator as ReakitMenuSeparator, 8 | } from 'reakit/Menu' 9 | import { system, th } from '@xstyled/system' 10 | import { node } from 'prop-desc' 11 | import { Button } from './Button' 12 | import { Separator } from './Separator' 13 | import { css, createComponent, getSystemPropTypes } from './util' 14 | import * as theme from './theme/common' 15 | 16 | export { useMenuState } 17 | 18 | export const Menu = createComponent({ 19 | name: 'Menu', 20 | render: props => ( 21 | 26 | ), 27 | theme: [ 28 | theme, 29 | { 30 | components: { 31 | Menu: p => { 32 | return css` 33 | border: 0.0625rem solid; 34 | border-color: ${th.color('highlightBorder')(p)}; 35 | font-family: ${th.font('base')(p)}; 36 | background-color: ${th.color('lighter')(p)}; 37 | border-radius: ${th.radius('base')(p)}; 38 | padding: 0.5rem 0.25rem; 39 | z-index: 999; 40 | 41 | &:focus { 42 | outline: none; 43 | } 44 | 45 | &[data-animated='true'] { 46 | transition: ${th.transition('base')(p)}; 47 | transition-property: opacity; 48 | display: block !important; 49 | 50 | &[hidden][data-animating='false'] { 51 | display: none !important; 52 | } 53 | 54 | &[hidden], 55 | &[data-animating='true']:not([hidden]) { 56 | opacity: 0; 57 | } 58 | 59 | &:not([hidden]), 60 | &[hidden][data-animating='true'] { 61 | opacity: 1; 62 | } 63 | } 64 | ` 65 | }, 66 | }, 67 | }, 68 | ], 69 | propTypes: { 70 | children: node, 71 | ...getSystemPropTypes(system), 72 | }, 73 | }) 74 | 75 | export const MenuItem = createComponent({ 76 | name: 'MenuItem', 77 | render: props => , 78 | theme: [ 79 | theme, 80 | { 81 | components: { 82 | MenuItem: p => { 83 | return css` 84 | appearance: none; 85 | background-color: transparent; 86 | padding: 8rpx; 87 | border: 0; 88 | border-radius: ${th.radius('base')(p)}; 89 | color: ${th.color('light700')(p)}; 90 | font-size: 14rpx; 91 | display: block; 92 | width: 100%; 93 | text-align: left; 94 | transition: ${th.transition('base')(p)}; 95 | transition-property: background-color; 96 | cursor: pointer; 97 | /* For links */ 98 | text-decoration: none; 99 | 100 | &[type='button'] { 101 | appearance: none; 102 | } 103 | 104 | &:focus, 105 | &:hover { 106 | outline: none; 107 | background-color: ${th.color('highlightBackground')(p)}; 108 | } 109 | 110 | &[disabled], 111 | &[aria-disabled='true'] { 112 | color: ${th.color('light500')(p)}; 113 | cursor: default; 114 | 115 | &:hover { 116 | background-color: transparent; 117 | } 118 | } 119 | ` 120 | }, 121 | }, 122 | }, 123 | ], 124 | propTypes: { 125 | children: node, 126 | ...getSystemPropTypes(system), 127 | }, 128 | }) 129 | 130 | const MenuItemDisclosure = React.forwardRef((props, ref) => { 131 | return 132 | }) 133 | 134 | export const MenuDisclosure = createComponent({ 135 | name: 'MenuDisclosure', 136 | theme, 137 | render: ({ as: asProp, ...props }) => { 138 | const as = 139 | asProp || (props.role === 'menuitem' ? MenuItemDisclosure : Button) 140 | return 141 | }, 142 | propTypes: Button.propTypes, 143 | }) 144 | 145 | export const MenuSeparator = createComponent({ 146 | name: 'MenuSeparator', 147 | theme, 148 | render: ({ as = Separator, ...props }) => ( 149 | 150 | ), 151 | propTypes: Separator.propTypes, 152 | }) 153 | -------------------------------------------------------------------------------- /packages/shared/core/Normalize.js: -------------------------------------------------------------------------------- 1 | import { normalize } from 'polished' 2 | import { createGlobalStyle } from '@xstyled/x' 3 | import { fonts } from './theme/common' 4 | 5 | export const Normalize = createGlobalStyle` 6 | ${normalize()} 7 | 8 | html, body { 9 | font-family: ${fonts.base}; 10 | -webkit-font-smoothing: antialiased; 11 | } 12 | 13 | * { 14 | box-sizing: border-box; 15 | } 16 | ` 17 | -------------------------------------------------------------------------------- /packages/shared/core/Radio.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable react-hooks/rules-of-hooks */ 3 | import React from 'react' 4 | import { 5 | Radio as ReakitRadio, 6 | RadioGroup as ReakitRadioGroup, 7 | } from 'reakit/Radio' 8 | import { th, system } from '@xstyled/system' 9 | import { node, string, any, bool, oneOf } from 'prop-desc' 10 | import * as theme from './theme/common' 11 | import * as formTheme from './theme/form' 12 | import { 13 | css, 14 | createComponent, 15 | getSystemPropTypes, 16 | SCALES, 17 | safeTransition, 18 | } from './util' 19 | import { useFormGroupControlProps } from './Form' 20 | 21 | export { useRadioState } from 'reakit/Radio' 22 | 23 | export const RadioGroup = createComponent({ 24 | name: 'RadioGroup', 25 | render: props => { 26 | return 27 | }, 28 | theme: { 29 | components: { 30 | RadioGroup: p => { 31 | return css` 32 | padding: 0; 33 | border: 0; 34 | 35 | &[aria-orientation='horizontal'] > [data-form-check] { 36 | display: inline-flex; 37 | margin-right: 1em; 38 | } 39 | 40 | && { 41 | ${system(p)} 42 | } 43 | ` 44 | }, 45 | }, 46 | }, 47 | propTypes: { 48 | children: node, 49 | 'aria-orientation': oneOf(['vertical', 'horizontal']).desc( 50 | 'Specify the orientation of the radio group.', 51 | ), 52 | ...getSystemPropTypes(system), 53 | }, 54 | }) 55 | 56 | const validationStyle = color => p => 57 | css` 58 | &[aria-checked='true'] { 59 | border-color: ${color}; 60 | background-color: ${color}; 61 | } 62 | 63 | &:focus { 64 | border-color: ${color}; 65 | ${p.theme.mixins.controlFocus(color)(p)}; 66 | } 67 | `(p) 68 | 69 | const noop = () => {} 70 | 71 | const BaseRadio = React.forwardRef(function BaseRadio( 72 | { type, checked, disabled, id, name, value, ...props }, 73 | ref, 74 | ) { 75 | const inputRef = React.useRef() 76 | const handleInputFocus = React.useCallback(() => { 77 | inputRef.current.parentElement.focus() 78 | }, []) 79 | return ( 80 |
81 | 93 |
94 |
95 | ) 96 | }) 97 | 98 | export const Radio = createComponent({ 99 | name: 'Radio', 100 | render: ({ as = BaseRadio, ...props }) => { 101 | const controlProps = useFormGroupControlProps(props) 102 | return 103 | }, 104 | theme: [ 105 | theme, 106 | formTheme, 107 | { 108 | sizes: { 109 | radio: { 110 | container: { 111 | xs: '10rpx', 112 | sm: '12rpx', 113 | base: '16rpx', 114 | lg: '22rpx', 115 | xl: '28rpx', 116 | }, 117 | checkmark: { 118 | xs: '6rpx', 119 | sm: '8rpx', 120 | base: '10rpx', 121 | lg: '14rpx', 122 | xl: '18rpx', 123 | }, 124 | }, 125 | }, 126 | components: { 127 | Radio: p => { 128 | const scale = p.scale || 'base' 129 | const validColor = th.color('form.valid')(p) 130 | const invalidColor = th.color('form.invalid')(p) 131 | const containerSize = th.size(`radio.container.${scale}`)(p) 132 | const checkmarkSize = th.size(`radio.checkmark.${scale}`)(p) 133 | return css` 134 | display: inline-flex; 135 | align-items: center; 136 | justify-content: center; 137 | position: relative; 138 | width: ${containerSize}; 139 | height: ${containerSize}; 140 | z-index: ${th.zIndex('control')(p)}; 141 | background-color: ${th.color('formControl.background')(p)}; 142 | border-radius: 50%; 143 | border-style: solid; 144 | border-width: ${th.borderWidth(`formControl.${scale}`)(p)}; 145 | border-color: ${th.color('formControl.border')(p)}; 146 | ${safeTransition('base')(p)}; 147 | 148 | & > input { 149 | top: 0; 150 | left: 0; 151 | width: 100%; 152 | cursor: inherit; 153 | height: 100%; 154 | margin: 0; 155 | opacity: 0; 156 | padding: 0; 157 | position: absolute; 158 | } 159 | 160 | & > [data-checkmark] { 161 | height: ${checkmarkSize}; 162 | width: ${checkmarkSize}; 163 | pointer-events: none; 164 | transform: scale(0); 165 | transform-origin: center; 166 | border-radius: 50%; 167 | background-color: ${th.color('primary')(p)}; 168 | ${safeTransition('base')(p)}; 169 | } 170 | 171 | &[aria-checked='true'] > [data-checkmark] { 172 | transform: scale(1); 173 | } 174 | 175 | &:focus { 176 | ${p.theme.mixins.controlFocus(th.color('primary')(p))(p)}; 177 | } 178 | 179 | &[aria-disabled] { 180 | opacity: 0.6; 181 | } 182 | 183 | &[aria-invalid='true'] { 184 | ${validationStyle(invalidColor)(p)}; 185 | } 186 | 187 | &[aria-invalid='false'] { 188 | ${validationStyle(validColor)(p)}; 189 | } 190 | 191 | && { 192 | ${system(p)} 193 | } 194 | ` 195 | }, 196 | }, 197 | }, 198 | ], 199 | propTypes: { 200 | checked: bool.desc('Same as the `checked` attribute.'), 201 | disabled: bool.desc('Same as the HTML attribute.'), 202 | focusable: bool.desc( 203 | 'When an element is `disabled`, it may still be `focusable`. It works similarly to `readOnly` on form elements. In this case, only `aria-disabled` will be set.', 204 | ), 205 | stopId: string.desc('Element ID.'), 206 | value: any.desc('Same as the value attribute.'), 207 | scale: oneOf(SCALES), 208 | ...getSystemPropTypes(system), 209 | }, 210 | }) 211 | -------------------------------------------------------------------------------- /packages/shared/core/Select.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import React from 'react' 3 | import { th, system } from '@xstyled/system' 4 | import { node, bool, oneOf } from 'prop-desc' 5 | import * as theme from './theme/common' 6 | import * as formTheme from './theme/form' 7 | import { 8 | css, 9 | SCALES, 10 | createComponent, 11 | getSystemPropTypes, 12 | safeTransition, 13 | } from './util' 14 | import { useFormControlProps } from './Form' 15 | 16 | const validationStyle = color => p => 17 | css` 18 | border-color: ${color}; 19 | 20 | &:focus { 21 | border-color: ${color}; 22 | ${p.theme.mixins.controlFocus(color)(p)} 23 | } 24 | `(p) 25 | 26 | export const Select = createComponent({ 27 | name: 'Select', 28 | render: ({ as: As = 'select', ...props }) => { 29 | const controlProps = useFormControlProps(props) 30 | return 31 | }, 32 | theme: [ 33 | theme, 34 | formTheme, 35 | { 36 | components: { 37 | Select: p => { 38 | const scale = p.scale || 'base' 39 | const px = th.space(`textFormControl.x.${scale}`)(p) 40 | const py = th.space(`textFormControl.y.${scale}`)(p) 41 | const validColor = th.color('form.valid')(p) 42 | const invalidColor = th.color('form.invalid')(p) 43 | return css` 44 | display: block; 45 | appearance: none; 46 | width: 100%; 47 | z-index: ${th.zIndex('control')(p)}; 48 | font-family: ${th.font('base')(p)}; 49 | font-size: ${th.fontSize(scale)(p)}; 50 | border-width: ${th.borderWidth(`formControl.${scale}`)(p)}; 51 | border-color: ${th.color('formControl.border')(p)}; 52 | border-style: solid; 53 | line-height: ${th.lineHeight(`formControl.${scale}`)(p)}; 54 | color: ${th.color('formControl.text')(p)}; 55 | background-color: ${th.color('formControl.background')(p)}; 56 | background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") 57 | no-repeat right 0.75rem center/8px 10px; 58 | padding: ${py} ${px}; 59 | line-height: ${th.lineHeight(`formControl.${scale}`)(p)}; 60 | border-radius: ${th.radius(scale)(p)}; 61 | ${safeTransition('base')(p)}; 62 | 63 | &::placeholder { 64 | color: ${th.color('formControl.placeholder')(p)}; 65 | } 66 | 67 | &:disabled { 68 | background-color: ${th.color('formControl.disabled.background')( 69 | p, 70 | )}; 71 | color: ${th.color('formControl.disabled.text')(p)}; 72 | } 73 | 74 | &:focus { 75 | ${p.theme.mixins.controlFocus(th.color('primary')(p))(p)} 76 | } 77 | 78 | &[aria-invalid='true'] { 79 | ${validationStyle(invalidColor)(p)}; 80 | } 81 | 82 | &[aria-invalid='false'] { 83 | ${validationStyle(validColor)(p)}; 84 | } 85 | 86 | && { 87 | ${system(p)} 88 | } 89 | ` 90 | }, 91 | }, 92 | }, 93 | ], 94 | propTypes: { 95 | children: node, 96 | disabled: bool, 97 | scale: oneOf(SCALES), 98 | ...getSystemPropTypes(system), 99 | }, 100 | }) 101 | -------------------------------------------------------------------------------- /packages/shared/core/Separator.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { system } from '@xstyled/system' 3 | import { Separator as ReakitSeparator } from 'reakit' 4 | import { node, oneOf } from 'prop-desc' 5 | import { css, createComponent, getSystemPropTypes } from './util' 6 | import * as theme from './theme/common' 7 | 8 | export const Separator = createComponent({ 9 | name: 'Separator', 10 | render: props => , 11 | theme: [ 12 | theme, 13 | { 14 | components: { 15 | Separator: p => { 16 | return css` 17 | border: 0; 18 | border-top: 0.0625rem solid rgba(0, 0, 0, 0.125); 19 | 20 | && { 21 | ${system(p)} 22 | } 23 | ` 24 | }, 25 | }, 26 | }, 27 | ], 28 | propTypes: { 29 | children: node, 30 | orientation: oneOf(['horizontal', 'vertical']), 31 | ...getSystemPropTypes(system), 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /packages/shared/core/Switch.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable react-hooks/rules-of-hooks */ 3 | import React from 'react' 4 | import { lighten } from 'polished' 5 | import { Checkbox as ReakitCheckbox } from 'reakit/Checkbox' 6 | import { th, system } from '@xstyled/system' 7 | import { func, bool, oneOf } from 'prop-desc' 8 | import * as theme from './theme/common' 9 | import * as formTheme from './theme/form' 10 | import { 11 | css, 12 | SCALES, 13 | createComponent, 14 | getSystemPropTypes, 15 | safeTransition, 16 | } from './util' 17 | import { useFormGroupControlProps } from './Form' 18 | 19 | const noop = () => {} 20 | 21 | const BaseSwitch = React.forwardRef(function BaseSwitch( 22 | { 23 | labeled, 24 | onLabel = 'ON', 25 | offLabel = 'OFF', 26 | type, 27 | checked, 28 | disabled, 29 | id, 30 | name, 31 | value, 32 | ...props 33 | }, 34 | ref, 35 | ) { 36 | const inputRef = React.useRef() 37 | const handleInputFocus = React.useCallback(() => { 38 | inputRef.current.parentElement.focus() 39 | }, []) 40 | return ( 41 |
42 |
43 | {labeled &&
{onLabel}
} 44 |
45 | {labeled &&
{offLabel}
} 46 |
47 | 59 |
60 | ) 61 | }) 62 | 63 | export const Switch = createComponent({ 64 | name: 'Switch', 65 | render: ({ as = BaseSwitch, scale, ...props }) => { 66 | const controlProps = useFormGroupControlProps(props) 67 | return 68 | }, 69 | theme: [ 70 | theme, 71 | formTheme, 72 | { 73 | fontSizes: { 74 | switch: { 75 | xs: '2rpx', 76 | sm: '5rpx', 77 | base: '9rpx', 78 | lg: '12rpx', 79 | xl: '18rpx', 80 | }, 81 | }, 82 | sizes: { 83 | switch: { 84 | container: { 85 | width: { 86 | xs: '24rpx', 87 | sm: '32rpx', 88 | base: '48rpx', 89 | lg: '72rpx', 90 | xl: '108rpx', 91 | }, 92 | height: { 93 | xs: '12rpx', 94 | sm: '16rpx', 95 | base: '24rpx', 96 | lg: '36rpx', 97 | xl: '54rpx', 98 | }, 99 | ball: { 100 | xs: '8rpx', 101 | sm: '12rpx', 102 | base: '18rpx', 103 | lg: '28rpx', 104 | xl: '40rpx', 105 | }, 106 | }, 107 | }, 108 | }, 109 | components: { 110 | Switch: p => { 111 | const scale = p.scale || 'base' 112 | const width = th.size(`switch.container.width.${scale}`)(p) 113 | const height = th.size(`switch.container.height.${scale}`)(p) 114 | const ballSize = th.size(`switch.container.ball.${scale}`)(p) 115 | return css` 116 | display: inline-block; 117 | position: relative; 118 | z-index: ${th.zIndex('control')(p)}; 119 | font-family: ${th.font('base')(p)}; 120 | border-radius: ${th.radius('34rpx')(p)}; 121 | width: ${width}; 122 | height: ${height}; 123 | background-color: ${th.color('light300')(p)}; 124 | overflow: hidden; 125 | cursor: pointer; 126 | border-width: ${th.borderWidth(`formControl.base`)(p)}; 127 | border-color: ${th.color('formControl.border')(p)}; 128 | border-style: solid; 129 | font-size: ${th.fontSize(`switch.${scale}`)(p)}; 130 | font-weight: ${th.fontWeight('extraBold')(p)}; 131 | ${safeTransition('base')(p)}; 132 | 133 | input { 134 | top: 0; 135 | left: 0; 136 | width: 100%; 137 | cursor: inherit; 138 | height: 100%; 139 | margin: 0; 140 | opacity: 0; 141 | padding: 0; 142 | position: absolute; 143 | z-index: 1; 144 | } 145 | 146 | [data-switch-content] { 147 | display: flex; 148 | align-items: center; 149 | height: 100%; 150 | pointer-events: none; 151 | ${safeTransition('base')(p)}; 152 | } 153 | 154 | [data-switch-ball] { 155 | flex-shrink: 0; 156 | background-color: ${th.color('light500')(p)}; 157 | border-radius: 50%; 158 | width: ${ballSize}; 159 | height: ${ballSize}; 160 | margin: 0 6%; 161 | ${safeTransition('base')(p)}; 162 | } 163 | 164 | [data-switch-label] { 165 | position: absolute; 166 | width: calc(${width} / 2); 167 | text-align: center; 168 | line-height: ${height}; 169 | user-select: none; 170 | overflow: hidden; 171 | } 172 | 173 | [data-switch-label='on'] { 174 | left: -50%; 175 | color: ${th.color('primary')(p)}; 176 | } 177 | 178 | [data-switch-label='off'] { 179 | right: 0; 180 | color: ${th.color('gray900')(p)}; 181 | } 182 | 183 | &:focus { 184 | ${p.theme.mixins.controlFocus(th.color('primary')(p))(p)}; 185 | } 186 | 187 | &[aria-checked='true'] { 188 | background-color: ${lighten(0.3, th.color('primary')(p))}; 189 | border-color: transparent; 190 | 191 | [data-switch-content] { 192 | transform: translateX(calc(${width} - ${ballSize} - 12%)); 193 | } 194 | 195 | [data-switch-ball] { 196 | background-color: ${th.color('primary')(p)}; 197 | } 198 | } 199 | 200 | &[aria-disabled='true'] { 201 | opacity: 0.6; 202 | } 203 | 204 | && { 205 | ${system(p)} 206 | } 207 | ` 208 | }, 209 | }, 210 | }, 211 | ], 212 | propTypes: { 213 | checked: bool.desc( 214 | "Checkbox's checked state. If present, it's used instead of state.", 215 | ), 216 | disabled: bool.desc('Same as the HTML attribute.'), 217 | focusable: bool.desc( 218 | 'When an element is `disabled`, it may still be `focusable`. It works similarly to `readOnly` on form elements. In this case, only `aria-disabled` will be set.', 219 | ), 220 | onChange: func.desc('Same as the "checkbox" `onChange` prop.'), 221 | scale: oneOf(SCALES) 222 | .desc('Control the size of the component.') 223 | .defaultTo('base'), 224 | ...getSystemPropTypes(system), 225 | }, 226 | }) 227 | -------------------------------------------------------------------------------- /packages/shared/core/Text.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import React from 'react' 3 | import { node, number, string, oneOfType, oneOf } from 'prop-desc' 4 | import mergeRefs from 'react-merge-refs' 5 | import { th, system } from '@xstyled/system' 6 | import { css, createComponent, getSystemPropTypes } from './util' 7 | import * as theme from './theme/common' 8 | 9 | function ellipsis({ lines = Infinity }) { 10 | if (lines === Infinity) return null 11 | return css` 12 | display: -webkit-box; 13 | -webkit-line-clamp: ${lines}; 14 | -webkit-box-orient: vertical; 15 | overflow: hidden; 16 | white-space: normal; 17 | ` 18 | } 19 | 20 | const isServer = typeof window === 'undefined' 21 | 22 | function useUniversalLayoutEffect(callback, deps) { 23 | return isServer 24 | ? React.useEffect(callback, deps) 25 | : React.useLayoutEffect(callback, deps) 26 | } 27 | 28 | export const TEXT_VARIANTS = [ 29 | 'h1', 30 | 'h2', 31 | 'h3', 32 | 'h4', 33 | 'h5', 34 | 'h6', 35 | 'display-1', 36 | 'display-2', 37 | 'display-3', 38 | 'display-4', 39 | ] 40 | 41 | export const Text = createComponent({ 42 | name: 'Text', 43 | render: ( 44 | { as: asProp, ref, lines = Infinity, ...props }, 45 | { theme, variant }, 46 | ) => { 47 | const variantConfig = variant ? theme.texts[variant] : null 48 | const As = asProp || (variantConfig && variantConfig.defaultAs) || 'span' 49 | const localRef = React.useRef() 50 | const [height, setHeight] = React.useState(null) 51 | useUniversalLayoutEffect(() => { 52 | if (!window.getComputedStyle || lines === Infinity) return 53 | const style = window.getComputedStyle(localRef.current) 54 | const lineHeight = parseInt(style.lineHeight, 10) 55 | const height = (lineHeight / 16) * lines 56 | setHeight(`${height}rem`) 57 | }, [lines]) 58 | return ( 59 | 64 | ) 65 | }, 66 | theme: [ 67 | theme, 68 | { 69 | texts: { 70 | h1: { 71 | defaultAs: 'h1', 72 | style: css` 73 | font-weight: bold; 74 | font-size: 2.5rem; 75 | margin-top: 0; 76 | margin-bottom: 0.4em; 77 | `, 78 | }, 79 | h2: { 80 | defaultAs: 'h2', 81 | style: css` 82 | font-weight: 600; 83 | font-size: 2rem; 84 | margin-top: 0; 85 | margin-bottom: 0.4em; 86 | `, 87 | }, 88 | h3: { 89 | defaultAs: 'h3', 90 | style: css` 91 | font-weight: 600; 92 | font-size: 1.75rem; 93 | margin-top: 0; 94 | margin-bottom: 0.4em; 95 | `, 96 | }, 97 | h4: { 98 | defaultAs: 'h4', 99 | style: css` 100 | font-weight: 600; 101 | font-size: 1.5rem; 102 | margin-top: 0; 103 | margin-bottom: 0.4em; 104 | `, 105 | }, 106 | h5: { 107 | defaultAs: 'h5', 108 | style: css` 109 | font-weight: 600; 110 | font-size: 1.25rem; 111 | margin-top: 0; 112 | margin-bottom: 0.4em; 113 | `, 114 | }, 115 | h6: { 116 | defaultAs: 'h6', 117 | style: css` 118 | font-weight: 600; 119 | font-size: 1rem; 120 | margin-top: 0; 121 | margin-bottom: 0.4em; 122 | `, 123 | }, 124 | 'display-1': { 125 | defaultAs: 'h1', 126 | style: css` 127 | font-weight: 300; 128 | font-size: 6rem; 129 | margin-top: 0; 130 | margin-bottom: 0.4em; 131 | `, 132 | }, 133 | 'display-2': { 134 | defaultAs: 'h2', 135 | style: css` 136 | font-weight: 300; 137 | font-size: 5.5rem; 138 | margin-top: 0; 139 | margin-bottom: 0.4em; 140 | `, 141 | }, 142 | 'display-3': { 143 | defaultAs: 'h3', 144 | style: css` 145 | font-weight: 300; 146 | font-size: 4.4rem; 147 | margin-top: 0; 148 | margin-bottom: 0.4em; 149 | `, 150 | }, 151 | 'display-4': { 152 | defaultAs: 'h4', 153 | style: css` 154 | font-weight: 300; 155 | font-size: 3.5rem; 156 | margin-top: 0; 157 | margin-bottom: 0.4em; 158 | `, 159 | }, 160 | }, 161 | components: { 162 | Text: p => { 163 | const variantConfig = p.variant ? p.theme.texts[p.variant] : null 164 | return css` 165 | font-family: ${th.font('base')(p)}; 166 | ${ellipsis(p)} 167 | ${variantConfig ? variantConfig.style : null} 168 | 169 | && { 170 | ${system(p)} 171 | } 172 | ` 173 | }, 174 | }, 175 | }, 176 | ], 177 | propTypes: { 178 | children: node, 179 | lines: number.desc('Control the number of lines to display'), 180 | variants: oneOfType([oneOf(TEXT_VARIANTS), string]) 181 | .defaultTo('primary') 182 | .desc('Control the color variant of the component.'), 183 | ...getSystemPropTypes(system), 184 | }, 185 | }) 186 | -------------------------------------------------------------------------------- /packages/shared/core/Textarea.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import React from 'react' 3 | import { Input } from './Input' 4 | import { useFormControlProps } from './Form' 5 | import { createInnerComponent } from './util' 6 | 7 | const InnerTextarea = createInnerComponent({ 8 | name: 'Textarea', 9 | render: ({ as: As = 'textarea', ...props }) => { 10 | const controlProps = useFormControlProps(props) 11 | return 12 | }, 13 | }) 14 | 15 | export const Textarea = Input.withComponent(InnerTextarea) 16 | Textarea.propTypes = Input.propTypes 17 | -------------------------------------------------------------------------------- /packages/shared/core/index.js: -------------------------------------------------------------------------------- 1 | import * as theme from './theme/common' 2 | 3 | export * from './Alert' 4 | export * from './Button' 5 | export * from './Box' 6 | export * from './Card' 7 | export * from './Checkbox' 8 | export * from './Form' 9 | export * from './Separator' 10 | export * from './Input' 11 | export * from './Menu' 12 | export * from './Normalize' 13 | export * from './Radio' 14 | export * from './Select' 15 | export * from './Text' 16 | export * from './Textarea' 17 | export * from './Switch' 18 | export * from './util' 19 | export { theme } 20 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/border.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-use-before-define */ 2 | import { th } from '@xstyled/system' 3 | import { scale } from '../../util' 4 | 5 | export const radii = scale(th.px('4rpx'), th.radius('base')) 6 | export const borderWidths = scale(th.px('1rpx'), th.borderWidth('base')) 7 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/color.js: -------------------------------------------------------------------------------- 1 | import { th } from '@xstyled/system' 2 | import { transparentize } from 'polished' 3 | 4 | export const colors = { 5 | black: '#000', 6 | white: '#fff', 7 | 8 | gray100: '#f8f9fa', 9 | gray200: '#e9ecef', 10 | gray300: '#dee2e6', 11 | gray400: '#ced4da', 12 | gray500: '#adb5bd', 13 | gray600: '#6c757d', 14 | gray700: '#495057', 15 | gray800: '#343a40', 16 | gray900: '#212529', 17 | 18 | blue: '#007bff', 19 | indigo: '#6610f2', 20 | purple: '#6f42c1', 21 | pink: '#e83e8c', 22 | red: '#dc3545', 23 | brick: '#bd4932', 24 | orange: '#fd7e14', 25 | yellow: '#ffc107', 26 | green: '#28a745', 27 | teal: '#20c997', 28 | cyan: '#17a2b8', 29 | 30 | primary: th.color('brick'), 31 | secondary: th.color('gray600'), 32 | success: th.color('green'), 33 | info: th.color('cyan'), 34 | warning: th.color('yellow'), 35 | danger: th.color('red'), 36 | light: th.color('gray100'), 37 | dark: th.color('gray800'), 38 | 39 | lighter: th.color('white'), 40 | light100: th.color('gray100'), 41 | light200: th.color('gray200'), 42 | light300: th.color('gray300'), 43 | light400: th.color('gray400'), 44 | light500: th.color('gray500'), 45 | light600: th.color('gray600'), 46 | light700: th.color('gray700'), 47 | light800: th.color('gray800'), 48 | light900: th.color('gray900'), 49 | darker: th.color('black'), 50 | highlightBackground: p => transparentize(0.96, th.color('darker')(p)), 51 | highlightBorder: p => transparentize(0.875, th.color('darker')(p)), 52 | 53 | form: { 54 | valid: th.color('success'), 55 | invalid: th.color('danger'), 56 | }, 57 | 58 | modes: { 59 | dark: { 60 | lighter: th.color('black'), 61 | darker: th.color('white'), 62 | light100: th.color('gray900'), 63 | light200: th.color('gray800'), 64 | light300: th.color('gray700'), 65 | light400: th.color('gray600'), 66 | light500: th.color('gray500'), 67 | light600: th.color('gray400'), 68 | light700: th.color('gray300'), 69 | light800: th.color('gray200'), 70 | light900: th.color('gray100'), 71 | }, 72 | }, 73 | } 74 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/index.js: -------------------------------------------------------------------------------- 1 | export * from './border' 2 | export * from './color' 3 | export * from './mixins' 4 | export * from './typography' 5 | export * from './transition' 6 | export * from './zIndices' 7 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/mixins.js: -------------------------------------------------------------------------------- 1 | import { transparentize, lighten } from 'polished' 2 | import { th } from '@xstyled/system' 3 | import { css } from '../../util/interop' 4 | 5 | export const mixins = { 6 | baseFocus: color => p => { 7 | const colorValue = th.color(color)(p) 8 | return css` 9 | outline: 0; 10 | border-color: ${lighten(0.25, colorValue)}; 11 | box-shadow: 0 0 ${th.px('2rpx')(p)} ${transparentize(0.1, colorValue)}; 12 | `(p) 13 | }, 14 | controlFocus: color => p => { 15 | const colorValue = th.color(color)(p) 16 | return css` 17 | outline: 0; 18 | border-color: ${lighten(0.25, colorValue)}; 19 | box-shadow: 0 0 0 ${th.px('4rpx')(p)} ${transparentize(0.75, colorValue)}; 20 | `(p) 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/transition.js: -------------------------------------------------------------------------------- 1 | export const transitions = { 2 | base: '.2s ease-in-out', 3 | } 4 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/typography.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-use-before-define */ 2 | import { th } from '@xstyled/system' 3 | import { scale, SCALES } from '../../util' 4 | 5 | export const fontSizes = scale('1rem', th.fontSize('base')) 6 | 7 | export const fonts = { 8 | base: 9 | '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif', 10 | } 11 | 12 | // From https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#Common_weight_name_mapping 13 | export const fontWeights = { 14 | thin: 100, 15 | extraLight: 200, 16 | light: 300, 17 | normal: 400, 18 | medium: 500, 19 | semiBold: 600, 20 | bold: 700, 21 | extraBold: 800, 22 | black: 900, 23 | } 24 | 25 | export const lineHeights = SCALES.reduce( 26 | (obj, scale) => { 27 | obj[scale] = 1.5 28 | return obj 29 | }, 30 | { button: {} }, 31 | ) 32 | -------------------------------------------------------------------------------- /packages/shared/core/theme/common/zIndices.js: -------------------------------------------------------------------------------- 1 | export const zIndices = { 2 | control: 1, 3 | } 4 | -------------------------------------------------------------------------------- /packages/shared/core/theme/form.js: -------------------------------------------------------------------------------- 1 | import { th } from '@xstyled/system' 2 | import { SCALES } from '../util' 3 | import { colors as baseColors, lineHeights as baseLineHeight } from './common' 4 | 5 | export const space = { 6 | textFormControl: { 7 | x: { 8 | xs: '4rpx', 9 | sm: '8rpx', 10 | base: '10rpx', 11 | lg: '14rpx', 12 | xl: '18rpx', 13 | }, 14 | y: { 15 | xs: '3rpx', 16 | sm: '4rpx', 17 | base: '6rpx', 18 | lg: '8rpx', 19 | xl: '10rpx', 20 | }, 21 | }, 22 | } 23 | 24 | export const colors = { 25 | ...baseColors, 26 | formControl: { 27 | background: th.color('lighter'), 28 | border: th.color('light400'), 29 | text: th.color('light900'), 30 | placeholder: th.color('light600'), 31 | disabled: { 32 | background: th.color('light100'), 33 | text: th.color('light900'), 34 | }, 35 | }, 36 | } 37 | 38 | export const borderWidths = { 39 | formControl: SCALES.reduce((obj, scale) => { 40 | obj[scale] = '1rpx' 41 | return obj 42 | }, {}), 43 | } 44 | 45 | export const lineHeights = { 46 | ...baseLineHeight, 47 | formControl: SCALES.reduce((obj, scale) => { 48 | obj[scale] = th.lineHeight(scale) 49 | return obj 50 | }, {}), 51 | } 52 | -------------------------------------------------------------------------------- /packages/shared/core/util/colors.js: -------------------------------------------------------------------------------- 1 | import { mix, getContrast } from 'polished' 2 | import { th } from '@xstyled/system' 3 | 4 | export const colorLevel = (color, level) => p => { 5 | const colorInterval = p.theme.colorInterval || 0.08 6 | const baseColor = level > 0 ? th.color('darker')(p) : th.color('lighter')(p) 7 | const absLevel = Math.abs(level) 8 | return mix(absLevel * colorInterval, baseColor, color) 9 | } 10 | 11 | const defaultColor = (name, defaultValue) => p => { 12 | const value = th.color(name)(p) 13 | if (value === name) return defaultValue 14 | return value 15 | } 16 | 17 | export const colorYik = color => p => { 18 | const darkValue = defaultColor('yik.dark', '#111')(p) 19 | const lightValue = defaultColor('yik.light', '#fff')(p) 20 | const colorValue = th.color(color)(p) 21 | const darkContrast = getContrast(colorValue, darkValue) 22 | const lightContrast = getContrast(colorValue, lightValue) 23 | return darkContrast < lightContrast + 4 ? lightValue : darkValue 24 | } 25 | -------------------------------------------------------------------------------- /packages/shared/core/util/factories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled, { useTheme } from '@xstyled/x' 3 | import { omit } from '@xstyled/util' 4 | import { systemProps } from './system' 5 | import { mergeClone } from './misc' 6 | 7 | const omittedProps = ['as', 'forwardedAs', 'variant', 'scale', ...systemProps] 8 | 9 | function useProps(props) { 10 | const as = props.as || props.forwardedAs || undefined 11 | return { as, safeProps: omit(props, omittedProps) } 12 | } 13 | 14 | const cacheSupported = 15 | typeof Map !== 'undefined' && typeof WeakMap !== 'undefined' 16 | const caches = cacheSupported ? new WeakMap() : null 17 | function getThemeCache(theme) { 18 | if (caches.has(theme)) return caches.get(theme) 19 | const cache = {} 20 | caches.set(theme, cache) 21 | return cache 22 | } 23 | 24 | function computeTheme(baseTheme, customTheme) { 25 | const theme = mergeClone(baseTheme, customTheme) 26 | if (!theme.colors || !theme.colors.modes) return theme 27 | return { 28 | ...theme, 29 | colors: { 30 | ...theme.colors, 31 | ...theme.colors.modes[theme.colorMode || theme.__colorMode], 32 | }, 33 | } 34 | } 35 | 36 | function getTheme(name, baseTheme, customTheme) { 37 | const themeCache = getThemeCache(customTheme) 38 | themeCache[name] = themeCache[name] || computeTheme(baseTheme, customTheme) 39 | return themeCache[name] 40 | } 41 | 42 | export function createInnerComponent({ name, render, theme: baseTheme = {} }) { 43 | const InnerComponent = React.forwardRef(function InnerComponent(props, ref) { 44 | const customTheme = useTheme() 45 | const theme = getTheme(name, baseTheme, customTheme) 46 | const { as, safeProps } = useProps(props) 47 | return render({ ref, as, ...safeProps }, { theme, ...props }) 48 | }) 49 | InnerComponent.displayName = name 50 | return InnerComponent 51 | } 52 | 53 | export function createComponent({ 54 | name, 55 | render, 56 | theme: themeArg = {}, 57 | propTypes, 58 | }) { 59 | const baseTheme = Array.isArray(themeArg) ? mergeClone(...themeArg) : themeArg 60 | const InnerComponent = createInnerComponent({ 61 | name, 62 | render, 63 | theme: baseTheme, 64 | }) 65 | const Component = styled(InnerComponent)` 66 | ${p => { 67 | const theme = getTheme(name, baseTheme, p.theme) 68 | const props = { ...p, theme } 69 | const componentStyle = theme.components ? theme.components[name] : null 70 | return componentStyle ? componentStyle(props) : null 71 | }} 72 | ` 73 | Component.displayName = `styled(${name})` 74 | Component.propTypes = propTypes 75 | return Component 76 | } 77 | -------------------------------------------------------------------------------- /packages/shared/core/util/hooks.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export function useRandomId(prefix) { 4 | return React.useMemo( 5 | () => 6 | `${prefix ? `${prefix}-` : ''}${Math.random() 7 | .toString(36) 8 | .substring(7)}`, 9 | [prefix], 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /packages/shared/core/util/index.js: -------------------------------------------------------------------------------- 1 | export * from './colors' 2 | export * from './factories' 3 | export * from './hooks' 4 | export * from './interop' 5 | export * from './misc' 6 | export * from './scales' 7 | export * from './system' 8 | export * from './transitions' 9 | export * from './variants' 10 | -------------------------------------------------------------------------------- /packages/shared/core/util/interop.js: -------------------------------------------------------------------------------- 1 | import { css as baseCss } from '@xstyled/x' 2 | 3 | export function css(...args) { 4 | const result = baseCss(...args) 5 | if (typeof result === 'function') return result 6 | return () => result 7 | } 8 | -------------------------------------------------------------------------------- /packages/shared/core/util/misc.js: -------------------------------------------------------------------------------- 1 | import { merge } from '@xstyled/util' 2 | 3 | export function mergeClone(...args) { 4 | return args.reduce((result, obj) => merge(result, obj), {}) 5 | } 6 | -------------------------------------------------------------------------------- /packages/shared/core/util/scales.js: -------------------------------------------------------------------------------- 1 | import { modularScale } from 'polished' 2 | 3 | export const SCALES = ['xs', 'sm', 'base', 'lg', 'xl'] 4 | 5 | export function scale(base, baseGetter, ratio) { 6 | return { 7 | xs: p => modularScale(-2, baseGetter(p), ratio), 8 | sm: p => modularScale(-1, baseGetter(p), ratio), 9 | base, 10 | lg: p => modularScale(1, baseGetter(p), ratio), 11 | xl: p => modularScale(2, baseGetter(p), ratio), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/shared/core/util/system.js: -------------------------------------------------------------------------------- 1 | import { oneOfType, number, string, object, bool } from 'prop-desc' 2 | 3 | export const systemProps = [ 4 | 'background', 5 | 'backgroundColor', 6 | 'backgroundImage', 7 | 'backgroundSize', 8 | 'backgroundPosition', 9 | 'backgroundRepeat', 10 | 'opacity', 11 | 'overflow', 12 | 'transition', 13 | 'border', 14 | 'borderTop', 15 | 'borderTopColor', 16 | 'borderRight', 17 | 'borderRightColor', 18 | 'borderBottom', 19 | 'borderBottomColor', 20 | 'borderLeft', 21 | 'borderLeftColor', 22 | 'borderColor', 23 | 'borderWidth', 24 | 'borderStyle', 25 | 'borderRadius', 26 | 'boxShadow', 27 | 'display', 28 | 'alignItems', 29 | 'alignContent', 30 | 'justifyContent', 31 | 'justifyItems', 32 | 'flexWrap', 33 | 'flexBasis', 34 | 'flexDirection', 35 | 'flex', 36 | 'justifySelf', 37 | 'alignSelf', 38 | 'order', 39 | 'gridGap', 40 | 'gridColumnGap', 41 | 'gridRowGap', 42 | 'gridColumn', 43 | 'gridRow', 44 | 'gridAutoFlow', 45 | 'gridAutoColumns', 46 | 'gridAutoRows', 47 | 'gridTemplateColumns', 48 | 'gridTemplateRows', 49 | 'gridTemplateAreas', 50 | 'gridArea', 51 | 'display', 52 | 'width', 53 | 'height', 54 | 'maxWidth', 55 | 'maxHeight', 56 | 'minWidth', 57 | 'minHeight', 58 | 'size', 59 | 'verticalAlign', 60 | 'position', 61 | 'zIndex', 62 | 'top', 63 | 'right', 64 | 'bottom', 65 | 'left', 66 | 'margin', 67 | 'm', 68 | 'marginTop', 69 | 'mt', 70 | 'marginRight', 71 | 'mr', 72 | 'marginBottom', 73 | 'mb', 74 | 'marginLeft', 75 | 'ml', 76 | 'mx', 77 | 'my', 78 | 'padding', 79 | 'p', 80 | 'paddingTop', 81 | 'pt', 82 | 'paddingRight', 83 | 'pr', 84 | 'paddingBottom', 85 | 'pb', 86 | 'paddingLeft', 87 | 'pl', 88 | 'px', 89 | 'py', 90 | 'fontFamily', 91 | 'fontSize', 92 | 'lineHeight', 93 | 'fontWeight', 94 | 'textAlign', 95 | 'letterSpacing', 96 | 'color', 97 | 'textTransform', 98 | 'row', 99 | 'col', 100 | ] 101 | 102 | const systemPropTypes = { 103 | row: [bool, object], 104 | col: [bool, number, string, object], 105 | } 106 | 107 | export function getSystemPropTypes(system) { 108 | if (!system) return {} 109 | return system.meta.props.reduce((obj, prop) => { 110 | obj[prop] = oneOfType( 111 | systemPropTypes[prop] || [number, string, object], 112 | ).desc( 113 | '[xstyled] See xstyled documentation', 114 | ) 115 | return obj 116 | }, {}) 117 | } 118 | -------------------------------------------------------------------------------- /packages/shared/core/util/transitions.js: -------------------------------------------------------------------------------- 1 | import { th } from '@xstyled/system' 2 | import { css } from './interop' 3 | 4 | export const transitionEnabled = true 5 | 6 | export const transition = value => p => { 7 | if (p.theme.transitionEnabled === false) return null 8 | return css` 9 | transition: ${th.transition(value)(p)}; 10 | 11 | @media screen and (prefers-reduced-motion: reduce) { 12 | transition: none; 13 | } 14 | `(p) 15 | } 16 | 17 | export const safeTransition = value => p => { 18 | const transitionValue = transition(value)(p) 19 | if (!transitionValue) return null 20 | return css` 21 | ${transitionValue}; 22 | transition-property: color, border-style, border-color, visibility, 23 | background, background-color, text-decoration, box-shadow, transform, 24 | opacity; 25 | `(p) 26 | } 27 | -------------------------------------------------------------------------------- /packages/shared/core/util/variants.js: -------------------------------------------------------------------------------- 1 | export const VARIANTS = [ 2 | 'primary', 3 | 'secondary', 4 | 'success', 5 | 'info', 6 | 'warning', 7 | 'danger', 8 | 'light', 9 | 'dark', 10 | ] 11 | -------------------------------------------------------------------------------- /resources/smooth-ui-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/resources/smooth-ui-logo-dark.png -------------------------------------------------------------------------------- /resources/smooth-ui-logo-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/resources/smooth-ui-logo-horizontal.png -------------------------------------------------------------------------------- /resources/smooth-ui-logo-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/resources/smooth-ui-logo-simple.png -------------------------------------------------------------------------------- /resources/smooth-ui-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/resources/smooth-ui-logo.png -------------------------------------------------------------------------------- /resources/smooth-ui-logo.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/resources/smooth-ui-logo.sketch -------------------------------------------------------------------------------- /scripts/pkg.js: -------------------------------------------------------------------------------- 1 | const pkg = require('../package.json') 2 | 3 | const { STYLED_ENGINE } = process.env 4 | 5 | const packageNames = { 6 | emotion: '@smooth-ui/core-em', 7 | 'styled-components': '@smooth-ui/core-sc', 8 | } 9 | 10 | pkg.name = packageNames[STYLED_ENGINE] 11 | pkg.peerDependencies = { 12 | ...pkg.peerDependencies, 13 | ...pkg.enginePeerDependencies[STYLED_ENGINE], 14 | } 15 | 16 | delete pkg.enginePeerDependencies 17 | delete pkg.bundlesize 18 | 19 | process.stdout.write(JSON.stringify(pkg, null, 2)) 20 | -------------------------------------------------------------------------------- /website/.eslintignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | node_modules/ 3 | /public/ -------------------------------------------------------------------------------- /website/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-unresolved": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | node_modules/ 3 | /public/ -------------------------------------------------------------------------------- /website/.nvmrc: -------------------------------------------------------------------------------- 1 | 12 -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Smooth UI website 2 | 3 | [Documentation site](https://www.smooth-code.com/open-source/loadable-components/) for [xstyled](https://github.com/smooth-code/loadable-components). This website is running on [gatsbyjs](gatsbyjs.org). 4 | 5 | ## Getting Started 6 | 7 | To install and run the docs site locally: 8 | 9 | ```bash 10 | yarn 11 | yarn dev 12 | ``` 13 | 14 | Then, open your favorite browser to [localhost:8000](http://localhost:8000/). GraphiQL runs at [localhost:8000/\_\_\_graphql](http://localhost:8000/___graphql). 15 | 16 | ## Contributing 17 | 18 | Build the site to test locally. 19 | 20 | ```bash 21 | yarn build 22 | ``` 23 | 24 | Serve the build. 25 | 26 | ```bash 27 | yarn serve 28 | ``` 29 | 30 | Then, open your favorite browser to [localhost:9000](http://localhost:9000/) to verify everything looks correct. 31 | -------------------------------------------------------------------------------- /website/_redirects: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/website/_redirects -------------------------------------------------------------------------------- /website/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | { 4 | resolve: 'smooth-doc', 5 | options: { 6 | name: 'Smooth UI', 7 | slug: 'smooth-ui', 8 | author: 'Greg Bergé', 9 | siteUrl: 'https://www.smooth-code.com/open-source/smooth-ui', 10 | description: 11 | 'Modern UI library for React. Focused on productivity, flexibility and accessibility.', 12 | github: 'https://github.com/smooth-code/smooth-ui', 13 | menu: ['Getting Started', 'Customization', 'Components', 'Advanced'], 14 | nav: [{ title: 'Docs', url: '/docs/' }], 15 | codeFundProperty: 430, 16 | theme: { 17 | useCustomProperties: false, 18 | }, 19 | }, 20 | }, 21 | { 22 | resolve: `gatsby-plugin-layout`, 23 | options: { 24 | component: require.resolve(`./src/components/layout`), 25 | }, 26 | }, 27 | { 28 | resolve: '@bundle-analyzer/gatsby-plugin', 29 | options: { 30 | token: '0f76d516797d28b3eac9999c701186d94360c766', 31 | }, 32 | }, 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /website/gatsby-node.js: -------------------------------------------------------------------------------- 1 | module.exports.createPages = ({ actions }) => { 2 | actions.createRedirect({ 3 | fromPath: `/docs/`, 4 | toPath: `/docs/getting-started/`, 5 | redirectInBrowser: true, 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gatsby build && cp _redirects public/", 5 | "build:pp": "gatsby build --prefix-paths && cp _redirects public/", 6 | "dev": "gatsby develop", 7 | "serve": "gatsby serve" 8 | }, 9 | "dependencies": { 10 | "@bundle-analyzer/gatsby-plugin": "^0.5.1", 11 | "@emotion/core": "^10.0.22", 12 | "@emotion/styled": "^10.0.23", 13 | "@smooth-ui/core-sc": "^10.1.0", 14 | "emotion-theming": "^10.0.19", 15 | "gatsby": "^2.18.2", 16 | "gatsby-plugin-layout": "^1.1.15", 17 | "react": "^16.12.0", 18 | "react-dom": "^16.12.0", 19 | "reakit": "^1.0.0-beta.12", 20 | "smooth-code-landers": "^1.3.2", 21 | "smooth-doc": "^2.14.2", 22 | "smooth-ui-em-next": "npm:@smooth-ui/core-em@canary", 23 | "smooth-ui-sc-next": "npm:@smooth-ui/core-sc@canary", 24 | "styled-components": "^4.4.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /website/src/components/Engine.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | // TODO implement a way to modify code in smooth-doc 4 | 5 | const EngineContext = React.createContext() 6 | 7 | export function EngineProvider({ children }) { 8 | const [engine, setEngine] = React.useState('@smooth-ui/core-sc') 9 | const value = React.useMemo(() => ({ engine, setEngine }), [engine]) 10 | return ( 11 | {children} 12 | ) 13 | } 14 | 15 | export function useEngine() { 16 | return React.useContext(EngineContext) 17 | } 18 | -------------------------------------------------------------------------------- /website/src/components/Props.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/anchor-is-valid */ 2 | import React from 'react' 3 | import styled from '@xstyled/styled-components' 4 | import { th } from '@xstyled/system' 5 | import { Tooltip } from '@smooth-ui/core-sc' 6 | 7 | const Table = styled.table` 8 | display: table !important; 9 | background-color: transparent; 10 | border-collapse: collapse; 11 | color: text; 12 | overflow-y: hidden; 13 | overflow-x: initial; 14 | width: 100%; 15 | font-size: 14; 16 | padding: 0; 17 | border-spacing: 0; 18 | border-style: hidden; 19 | table-layout: auto; 20 | border-radius: 4; 21 | box-shadow: ${th.color('border')} 0 0 0 1px; 22 | ` 23 | 24 | const Thead = styled.thead` 25 | color: text; 26 | background-color: secondary-bg; 27 | text-align: left; 28 | ` 29 | 30 | const Th = styled.th` 31 | font-weight: 400; 32 | padding: 20; 33 | 34 | &:first-child { 35 | border-radius: 4 0 0; 36 | } 37 | 38 | &:last-child { 39 | border-radius: 0 4 0; 40 | } 41 | ` 42 | 43 | const Tbody = styled.tbody` 44 | > tr { 45 | border-top: 1; 46 | border-color: border; 47 | } 48 | ` 49 | 50 | const Td = styled.td` 51 | line-height: 2; 52 | font-weight: 200; 53 | padding: 12 20; 54 | ` 55 | 56 | const GROUP_REGEXP = /^\[(.*)]\s+/ 57 | 58 | function sanitizeDescription(description) { 59 | return description && description.replace(GROUP_REGEXP, '') 60 | } 61 | 62 | function getGroup(meta) { 63 | if (!meta.description) return null 64 | const matches = meta.description.match(GROUP_REGEXP) 65 | if (!matches) return null 66 | return matches[1] 67 | } 68 | 69 | export function Props({ of }) { 70 | const properties = React.useMemo( 71 | () => 72 | Object.entries(of.propTypes).reduce((properties, [name, prop]) => { 73 | const group = getGroup(prop.__meta) || 'default' 74 | properties[group] = properties[group] || [] 75 | properties[group].push([name, prop]) 76 | return properties 77 | }, {}), 78 | [], 79 | ) 80 | const [groupsState, setGroupsState] = React.useState(() => 81 | Object.keys(properties).reduce((state, group) => { 82 | if (group === 'default') return state 83 | properties[group] = properties[group] || [] 84 | properties[group].push() 85 | return { ...state, [group]: false } 86 | }, []), 87 | ) 88 | return ( 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | {Object.entries(properties).map(([group, propTypes]) => { 101 | return ( 102 | 103 | {group !== 'default' && ( 104 | 105 | 119 | 120 | )} 121 | {propTypes.map(([name, prop]) => { 122 | const meta = prop.__meta 123 | const propType = meta.toString() 124 | const tooltip = propType !== meta.type.name 125 | const group = getGroup(meta) 126 | if (group && group !== 'default' && !groupsState[group]) 127 | return null 128 | return ( 129 | 130 | 131 | 143 | 144 | 145 | 151 | ) 152 | })} 153 | 154 | ) 155 | })} 156 | 157 |
PropertyTypeRequiredDefaultDescription
106 | { 109 | event.preventDefault() 110 | setGroupsState(state => ({ 111 | ...state, 112 | [group]: !state[group], 113 | })) 114 | }} 115 | > 116 | {groupsState[group] ? 'Hide' : 'Show'} {group} properties 117 | 118 |
{name} 132 | {tooltip ? ( 133 | 134 | {tooltip && ( 135 | {propType} 136 | )} 137 | {meta.type.name} 138 | 139 | ) : ( 140 | propType 141 | )} 142 | {meta.required ? 'true' : 'false'}{meta.defaultValue ? meta.defaultValue.value : '-'} 150 |
158 | ) 159 | } 160 | -------------------------------------------------------------------------------- /website/src/components/layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { LiveConfig } from 'smooth-doc/components' 3 | import styled, * as sc from 'styled-components' 4 | import * as xstyledSc from '@xstyled/styled-components' 5 | import * as xstyledEm from '@xstyled/emotion' 6 | import * as smoothUISc from 'smooth-ui-sc-next' 7 | import * as smoothUIEm from 'smooth-ui-em-next' 8 | 9 | export default function Layout({ children }) { 10 | return ( 11 | <> 12 | 22 | {children} 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /website/src/images/home-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/website/src/images/home-logo-dark.png -------------------------------------------------------------------------------- /website/src/images/home-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/website/src/images/home-logo.png -------------------------------------------------------------------------------- /website/src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/website/src/images/logo.png -------------------------------------------------------------------------------- /website/src/images/social.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smooth-code/smooth-ui/ad2e9a20c0dcf0da49fab09ade2c7bb8e3145b56/website/src/images/social.jpg -------------------------------------------------------------------------------- /website/src/pages/404.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Not Found 3 | --- 4 | 5 | import { NotFound } from 'smooth-doc/components' 6 | 7 | 8 | -------------------------------------------------------------------------------- /website/src/pages/docs/accessibility.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accessibility 3 | menu: Getting Started 4 | order: 30 5 | --- 6 | 7 | # Accessibility 8 | 9 | Smooth UI is an accessibility first library, which follows all [WAI-ARIA practices](https://www.w3.org/TR/wai-aria-practices/). 10 | All components are rigourously following the specification and implement all best practices in order to make your application usable by everyone. 11 | 12 | ## WAI-ARIA 13 | 14 | Thanks to [Reakit](https://reakit.io), all components follow [WAI-ARIA practices](https://www.w3.org/TR/wai-aria-practices/). Some examples: 15 | 16 | - `Alert` has the role `alert` 17 | - `Button` click is triggered when `space` key is pressed when focused 18 | - `Input` automatically adds `aria-labelledby` when a label is specified 19 | - ... 20 | 21 | ## Transitions 22 | 23 | ### Reduce motion preference 24 | 25 | All components implement [reduced motion media query](https://css-tricks.com/introduction-reduced-motion-media-query/), it means they respect users' settings. 26 | 27 | A utility called `transition` is available to implement your own accessible transitions: 28 | 29 | ```jsx live noInline 30 | import styled from '@xstyled/styled-components' 31 | import { transition } from '@smooth-ui/core-sc' 32 | 33 | const AccessibleButton = styled.button` 34 | background-color: red; 35 | ${transition('background-color 200ms')}; 36 | 37 | &:hover { 38 | background-color: blue; 39 | } 40 | ` 41 | 42 | function Example() { 43 | return Hello world 44 | } 45 | 46 | /* 47 | CSS injected in the page will be: 48 | 49 | background-color: red; 50 | transition: background-color 200ms; 51 | @media screen and (prefers-reduced-motion: reduce) { 52 | transition: none; 53 | } 54 | 55 | &:hover { 56 | background-color: blue; 57 | } 58 | */ 59 | 60 | render() 61 | ``` 62 | 63 | ### Turn off all transitions 64 | 65 | You can also choose to turn off all transitions by setting `transitionEnabled` to `false` in the theme. See [theming guide](/docs/theming/). 66 | 67 | ## Font size 68 | 69 | All components are implemented using `rem` unit. They adapt base font size defined by the user in the browser. To know more about rem vs px, you can read [this article](https://engageinteractive.co.uk/blog/em-vs-rem-vs-px). 70 | 71 | You can also use [xstyled transformers](https://www.smooth-code.com/open-source/xstyled/docs/transformers/) to automatically convert `rem` to `px` in all your styles. 72 | 73 | ## Font family 74 | 75 | Smooth UI doesn't come with any font, it uses the default font of the user operating system. Usually operating systems are comfortable and chosen by the user. It is also faster, no font is loaded. 76 | 77 | To know more about system font stack, you can read [this article](https://css-tricks.com/snippets/css/system-font-stack/). 78 | -------------------------------------------------------------------------------- /website/src/pages/docs/alert.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Alert 3 | menu: Components 4 | order: 10 5 | --- 6 | 7 | import { Alert } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Alert 11 | 12 | ## Variants 13 | 14 | Set variants using `variant` prop. All colors defined in your theme (or not) can be used. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Alert, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | 23 | This is a primary alert—check it out! 24 | This is a secondary alert—check it out! 25 | This is a success alert—check it out! 26 | This is a danger alert—check it out! 27 | This is a warning alert—check it out! 28 | This is a info alert—check it out! 29 | This is a light alert—check it out! 30 | This is a dark alert—check it out! 31 | Custom color 32 | 33 | ) 34 | } 35 | 36 | render() 37 | ``` 38 | 39 | ## Accessibility 40 | 41 | `Alert` follows [WAI-ARIA Alert Pattern](https://www.w3.org/TR/wai-aria-practices/#alert). 42 | 43 | - The role `alert` is automatically added 44 | 45 | ## API 46 | 47 | ### Alert 48 | 49 | 50 | -------------------------------------------------------------------------------- /website/src/pages/docs/as-property.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Use "as" prop 3 | menu: Advanced 4 | order: 20 5 | --- 6 | 7 | # The "as" property 8 | 9 | Sometimes you may want to use a component but the resulting HTML tag is not the good one. Or you want to use a `Button` with another component like [the `Link` from React Router](https://reacttraining.com/react-router/web/api/Link). 10 | 11 | ## Usage 12 | 13 | Every components accepts a `forwardedAs` property, it defines the underlying component used in each component. 14 | 15 | An example of an `Alert` that uses `span` as a component. 16 | 17 | ```jsx live noInline 18 | import React from 'react' 19 | import { Alert } from '@smooth-ui/core-sc' 20 | 21 | function Example() { 22 | return ( 23 | 24 | A span alert 25 | 26 | ) 27 | } 28 | 29 | render() 30 | ``` 31 | 32 | > The `as` property is reserved to `styled-components`, use `forwardedAs` to replace the underlying component. 33 | -------------------------------------------------------------------------------- /website/src/pages/docs/box.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Box 3 | menu: Components 4 | order: 20 5 | --- 6 | 7 | import { Box, Boxer } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Box 11 | 12 | `Box` is a base component which includes all [xstyled](https://www.smooth-code.com/open-source/xstyled/docs/system-components/)' system props. You could code your entire application using this component! 13 | 14 | ## Box 15 | 16 | `Box` is a div with superpowers. 17 | 18 | ```jsx live noInline 19 | import React from 'react' 20 | import { Box } from '@smooth-ui/core-sc' 21 | 22 | function Example() { 23 | return ( 24 | 31 | ) 32 | } 33 | 34 | render() 35 | ``` 36 | 37 | The above example creates a red div with: 38 | 39 | - A background with color "primary" 40 | - A width of `100%` on mobile, `50%` on desktop 41 | - A height of `100px` 42 | - A padding of `16px` 43 | - A `marginLeft` and a `marginRight` of `50%` 44 | 45 | [Read more about system](/docs/system/) 46 | 47 | ## Boxer 48 | 49 | `Boxer` wraps all children in a `Box` with props applied to each `Box`. 50 | 51 | The following example wraps the two `div` in a container with a vertical margin of `10px`: 52 | 53 | ```jsx live noInline 54 | import React from 'react' 55 | import { Boxer } from '@smooth-ui/core-sc' 56 | 57 | function Example() { 58 | return ( 59 | 60 |
Hello
61 |
World
62 |
63 | ) 64 | } 65 | 66 | render() 67 | ``` 68 | 69 | ## API 70 | 71 | ### Box 72 | 73 | 74 | 75 | ### Boxer 76 | 77 | 78 | -------------------------------------------------------------------------------- /website/src/pages/docs/browser-compatibility.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Compatibility 3 | menu: Getting Started 4 | order: 40 5 | --- 6 | 7 | # Compatibility 8 | 9 | ## Browser Support 10 | 11 | Smooth-UI relies on [browsers supported by Styled Components](https://www.styled-components.com/docs/faqs#which-browsers-are-supported) or browsers supported by Emotion (probably the same). 12 | 13 | Supported Browsers: IE11, IE 9+ (with Map + Set polyfills), Chrome, Firefox (and derivatives), Edge, and Safari. 14 | -------------------------------------------------------------------------------- /website/src/pages/docs/button.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Button 3 | menu: Components 4 | order: 30 5 | --- 6 | 7 | import { Button } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Button 11 | 12 | ## Variants 13 | 14 | Set variants using `variant` prop. All colors defined in your theme (or not) can be used. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Button, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ) 36 | } 37 | 38 | render() 39 | ``` 40 | 41 | ## Outline 42 | 43 | Add `outline` prop to use the outline variant of buttons. 44 | 45 | ```jsx live noInline 46 | import React from 'react' 47 | import { Button, Boxer } from '@smooth-ui/core-sc' 48 | 49 | function Example() { 50 | return ( 51 | 52 | 53 | 56 | 59 | 62 | 65 | 68 | 71 | 74 | 77 | 80 | 83 | 84 | ) 85 | } 86 | 87 | render() 88 | ``` 89 | 90 | ## Scales 91 | 92 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 93 | 94 | ```jsx live noInline 95 | import React from 'react' 96 | import { Button, Boxer } from '@smooth-ui/core-sc' 97 | 98 | function Example() { 99 | return ( 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | ) 108 | } 109 | 110 | render() 111 | ``` 112 | 113 | ## Disabled 114 | 115 | Disable using `disabled` prop. 116 | 117 | ```jsx live noInline 118 | import React from 'react' 119 | import { Button } from '@smooth-ui/core-sc' 120 | 121 | function Example() { 122 | return ( 123 | 126 | ) 127 | } 128 | 129 | render() 130 | ``` 131 | 132 | ## Accessibility 133 | 134 | `Button` uses [Reakit Button](https://reakit.io/docs/button/) under the hood, it means it follows [WAI-ARIA Button Pattern](https://www.w3.org/TR/wai-aria-practices/#button). 135 | 136 | [Read more about accessibility on Reakit](https://reakit.io/docs/button/#accessibility). 137 | 138 | ## API 139 | 140 | ### Button 141 | 142 | 143 | -------------------------------------------------------------------------------- /website/src/pages/docs/card.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Card 3 | menu: Components 4 | order: 35 5 | --- 6 | 7 | import { 8 | Card, 9 | CardBody, 10 | CardTitle, 11 | CardHeader, 12 | CardFooter, 13 | } from 'smooth-ui-sc-next' 14 | import { Props } from '../../components/Props' 15 | 16 | # Card 17 | 18 | Cards provide a flexible and extensible content container with multiple variants and options. 19 | 20 | ## Basic 21 | 22 | ```jsx live noInline 23 | import React from 'react' 24 | import { 25 | Card, 26 | CardBody, 27 | CardTitle, 28 | CardImg, 29 | Text, 30 | Button, 31 | } from '@smooth-ui/core-sc' 32 | 33 | function Example() { 34 | return ( 35 | 36 | 37 | 38 | 39 | My card Title 40 | 41 | Some text 42 | 45 | 46 | 47 | ) 48 | } 49 | 50 | render() 51 | ``` 52 | 53 | ## Header and Footer 54 | 55 | ```jsx live noInline 56 | import React from 'react' 57 | import { 58 | Card, 59 | CardBody, 60 | CardTitle, 61 | CardHeader, 62 | CardFooter, 63 | Text, 64 | Button, 65 | } from '@smooth-ui/core-sc' 66 | 67 | function Example() { 68 | return ( 69 | 70 | This is a card header 71 | 72 | 73 | My card Title 74 | 75 | Some text 76 | 79 | 80 | This is a card footer 81 | 82 | ) 83 | } 84 | 85 | render() 86 | ``` 87 | 88 | ## Accessibility 89 | 90 | There is no specific accessibility issue with cards. 91 | 92 | ## API 93 | 94 | ### Card 95 | 96 | 97 | 98 | ### CardHeader 99 | 100 | 101 | 102 | ### CardBody 103 | 104 | 105 | 106 | ### CardTitle 107 | 108 | 109 | 110 | ### CardFooter 111 | 112 | 113 | -------------------------------------------------------------------------------- /website/src/pages/docs/checkbox.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Checkbox 3 | menu: Components 4 | order: 40 5 | --- 6 | 7 | import { Checkbox, CheckboxGroup } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Checkbox 11 | 12 | ## Basic 13 | 14 | It receives the same props as controlled inputs, such as `checked` and `onChange`. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Checkbox, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | const [checked, setChecked] = React.useState(false) 22 | const toggle = () => setChecked(!checked) 23 | return ( 24 | 27 | ) 28 | } 29 | 30 | render() 31 | ``` 32 | 33 | ## useCheckboxState 34 | 35 | For convenience, [Reakit provides a `useCheckboxState`](https://reakit.io/docs/checkbox/#usecheckboxstate) that already implements the state logic. 36 | 37 | ```jsx live noInline 38 | import React from 'react' 39 | import { Checkbox, useCheckboxState } from '@smooth-ui/core-sc' 40 | 41 | function Example() { 42 | const checkbox = useCheckboxState() 43 | return ( 44 | 47 | ) 48 | } 49 | 50 | render() 51 | ``` 52 | 53 | ## Sizes 54 | 55 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 56 | 57 | ```jsx live noInline 58 | import React from 'react' 59 | import { 60 | Checkbox, 61 | useCheckboxState, 62 | FormCheck, 63 | FormCheckLabel, 64 | Boxer, 65 | } from '@smooth-ui/core-sc' 66 | 67 | function Example() { 68 | const checkbox = useCheckboxState() 69 | return ( 70 | 71 | 72 | 73 | 74 | Extra small 75 | 76 | 77 | 78 | 79 | 80 | Small 81 | 82 | 83 | 84 | 85 | 86 | Base (default) 87 | 88 | 89 | 90 | 91 | 92 | Large 93 | 94 | 95 | 96 | 97 | 98 | Extra large 99 | 100 | 101 | 102 | ) 103 | } 104 | 105 | render() 106 | ``` 107 | 108 | ## Disabled 109 | 110 | Disable using `disabled` prop. 111 | 112 | ```jsx live noInline 113 | import React from 'react' 114 | import { 115 | Checkbox, 116 | FormCheck, 117 | FormCheckLabel, 118 | useCheckboxState, 119 | } from '@smooth-ui/core-sc' 120 | 121 | function Example() { 122 | const checkbox = useCheckboxState({ state: true }) 123 | return ( 124 | 125 | 126 | Disabled 🤷‍♂️ 127 | 128 | ) 129 | } 130 | 131 | render() 132 | ``` 133 | 134 | ## Accessibility 135 | 136 | `Checkbox` uses [Reakit Checkbox](https://reakit.io/docs/checkbox) under the hood, it means it follows [WAI-ARIA Checkbox Pattern](https://www.w3.org/TR/wai-aria-practices/#checkbox). 137 | 138 | `CheckboxGroup` follows [WAI_ARIA Checkbox Group Pattern](https://www.w3.org/TR/2016/WD-wai-aria-practices-1.1-20160317/examples/checkbox/checkbox-2.html). 139 | 140 | [Read more about accessibility on Reakit](https://reakit.io/docs/checkbox/#accessibility). 141 | 142 | ## API 143 | 144 | ### useCheckboxState 145 | 146 | See [Reakit documentation](https://reakit.io/docs/checkbox/#usecheckboxstate-1). 147 | 148 | ### Checkbox 149 | 150 | 151 | 152 | `Switch` also includes a bunch of state properties, see [Reakit documentation](https://reakit.io/docs/checkbox/#checkbox). 153 | 154 | ### CheckboxGroup 155 | 156 | 157 | -------------------------------------------------------------------------------- /website/src/pages/docs/dark-mode.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dark Mode 3 | menu: Customization 4 | order: 15 5 | --- 6 | 7 | # Dark Mode 8 | 9 | Dark Mode is built-in Smooth UI, every components have their dark mode. 10 | 11 | ## Use with xstyled color modes 12 | 13 | xstyled has a [built-in support for color modes and dark mode](https://www.smooth-code.com/open-source/xstyled/docs/color-modes/). If you use it, Smooth UI is already compatible except one thing: custom properties. Smooth UI is very dynamic and it is yet possible to achieve everything using custom properties. 14 | 15 | To disable it, [set `useCustomProperties` to `false` in your theme](https://www.smooth-code.com/open-source/xstyled/docs/color-modes/#turn-off-custom-properties). 16 | 17 | ## Use dark mode without xstyled 18 | 19 | To enable dark mode, add a theme and specify `colorMode: 'dark'`: 20 | 21 | ```jsx live noInline 22 | import React from 'react' 23 | import { ThemeProvider } from 'styled-components' 24 | import { Alert } from '@smooth-ui/core-sc' 25 | 26 | const darkTheme = { 27 | colorMode: 'dark', 28 | } 29 | 30 | const lightTheme = { 31 | colorMode: 'light', 32 | } 33 | 34 | render( 35 |
36 | 37 | Dark Alert 38 | 39 | 40 | Light Alert 41 | 42 |
, 43 | ) 44 | ``` 45 | 46 | See [theming documentation](/docs/theming/). 47 | -------------------------------------------------------------------------------- /website/src/pages/docs/extend-styles.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Extend Styles 3 | menu: Customization 4 | order: 20 5 | --- 6 | 7 | # Extend Styles 8 | 9 | Smooth UI’s power lies in its ability to easily extend components’ styles. 10 | 11 | ## Use system props 12 | 13 | System props are probably the easiest way to extend a component. 14 | 15 | For example, you can define the width of a button: 16 | 17 | ```jsx live noInline 18 | import React from 'react' 19 | import { Button } from '@smooth-ui/core-sc' 20 | 21 | function Example() { 22 | return 23 | } 24 | 25 | render() 26 | ``` 27 | 28 | See [system props documentation](/docs/system/) to learn how to use it. 29 | 30 | ## Local override using style 31 | 32 | Inline styles are still a good approach for a lot of use-cases. They can be used for very specific changes that don't need media queries or auto-prefixer. All components supports inline style using `style` property. 33 | 34 | An example of inline style to change the `padding` of a button: 35 | 36 | ```jsx live noInline 37 | import React from 'react' 38 | import { Button } from '@smooth-ui/core-sc' 39 | 40 | function Example() { 41 | return 42 | } 43 | 44 | render() 45 | ``` 46 | 47 | ## Override values in theme 48 | 49 | To extend style, the cleanest way is probably to use the theming feature of Smooth UI. It allows you to change global settings that will impact all components. 50 | 51 | Example of possible changes using theme: 52 | 53 | - Modify `primary` color 54 | - Modify breakpoints 55 | - Modify form control margins 56 | - Modify the focus glow on controls 57 | - ... 58 | 59 | For example, you can change the primary color: 60 | 61 | ```jsx live noInline 62 | import React from 'react' 63 | import { ThemeProvider } from 'styled-components' 64 | import { Button } from '@smooth-ui/core-sc' 65 | 66 | const theme = { 67 | colors: { 68 | primary: 'blue', 69 | }, 70 | } 71 | 72 | function Example() { 73 | return 74 | } 75 | 76 | render( 77 | 78 | 79 | , 80 | ) 81 | ``` 82 | 83 | See [theming documentation](/docs/theming/) to learn how to use theme. 84 | 85 | ## Override components style in theme 86 | 87 | All components can be overrided directly in the theme. 88 | 89 | In the following example, the alert is now just something colored in `red`: 90 | 91 | ```jsx live noInline 92 | import React from 'react' 93 | import { css, ThemeProvider } from 'styled-components' 94 | import { Alert } from '@smooth-ui/core-sc' 95 | 96 | const theme = { 97 | components: { 98 | Alert: p => css` 99 | color: red; 100 | `, 101 | }, 102 | } 103 | 104 | function Example() { 105 | return Hello world 106 | } 107 | 108 | render( 109 | 110 | 111 | , 112 | ) 113 | ``` 114 | 115 | See [theming documentation](/docs/theming/) to learn how to use theme. 116 | 117 | ## Local override using `css` prop 118 | 119 | [Styled Components](https://www.styled-components.com/docs/api#css-prop) and [Emotion](https://emotion.sh/docs/css-prop) both support the `css` property. This is a simple method to extend component style. 120 | 121 | ```jsx 122 | 129 | ``` 130 | 131 | ## Local extend using styled 132 | 133 | You can override any CSS property of the original component using `styled`. It creates a new component and doesn't affect other components. 134 | 135 | An example of a `BorderedButton` extended from a `Button`: 136 | 137 | ```jsx live noInline 138 | import React from 'react' 139 | import styled from 'styled-components' 140 | import { Button } from '@smooth-ui/core-sc' 141 | 142 | const BorderedButton = styled(Button)` 143 | border: 2px solid black; 144 | 145 | &:hover { 146 | border-color: blue; 147 | } 148 | ` 149 | 150 | function Example() { 151 | return Hello world 152 | } 153 | 154 | render() 155 | ``` 156 | 157 | ## Extend components deeply 158 | 159 | Some components are more complex than a `Button`. The `Switch` for example is a component that includes several elements: a container, a ball... All of these elements have their own classes. To extend it, just use the browser inspector, pick the class and override it 👌. 160 | 161 | An example of a custom `Switch` with a black ball 🎱. 162 | 163 | ```jsx live noInline 164 | import React from 'react' 165 | import styled from 'styled-components' 166 | import { Switch, useCheckboxState } from '@smooth-ui/core-sc' 167 | 168 | const BlackBallSwitch = styled(Switch)` 169 | [data-switch-ball] { 170 | background-color: black !important; 171 | } 172 | ` 173 | 174 | function Example() { 175 | const checkbox = useCheckboxState() 176 | return 177 | } 178 | 179 | render() 180 | ``` 181 | -------------------------------------------------------------------------------- /website/src/pages/docs/getting-started.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | menu: Getting Started 4 | order: 20 5 | --- 6 | 7 | # Getting Started 8 | 9 | ## Installation 10 | 11 | First you have to make a choice between [styled-components](https://styled-components.com) and [emotion](https://emotion.sh). 12 | If you don't know either, it is easier to start with [styled-components](https://styled-components.com). 13 | 14 | ### Styled Components 15 | 16 | ```bash 17 | npm install @smooth-ui/core-sc reakit styled-components 18 | ``` 19 | 20 | ### Emotion 21 | 22 | ```bash 23 | npm install @smooth-ui/core-em reakit @emotion/core @emotion/styled emotion-theming 24 | ``` 25 | 26 | ## Usage 27 | 28 | There is no required setup to use Smooth UI, it exposes ready to use components. 29 | 30 | You can use components in your React app: 31 | 32 | ```jsx live noInline 33 | import React from 'react' 34 | import { Button } from '@smooth-ui/core-sc' 35 | 36 | function Example() { 37 | return 38 | } 39 | 40 | render() 41 | ``` 42 | 43 | > Even if it is not strictly required, it is strongly recommended to add `Normalize` to your application, see [guide](/docs/normalize/). 44 | -------------------------------------------------------------------------------- /website/src/pages/docs/input.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Input 3 | menu: Components 4 | order: 60 5 | --- 6 | 7 | import { Input } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Input 11 | 12 | ## Sizes 13 | 14 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Input, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ) 30 | } 31 | 32 | render() 33 | ``` 34 | 35 | ## Types 36 | 37 | All HTML5 types are supported, `"number"` is adapted. 38 | 39 | ```jsx live noInline 40 | import React from 'react' 41 | import { Input } from '@smooth-ui/core-sc' 42 | 43 | function Example() { 44 | return 45 | } 46 | 47 | render() 48 | ``` 49 | 50 | ## Disabled 51 | 52 | Disable using `disabled` prop. 53 | 54 | ```jsx live noInline 55 | import React from 'react' 56 | import { Input } from '@smooth-ui/core-sc' 57 | 58 | function Example() { 59 | return 60 | } 61 | 62 | render() 63 | ``` 64 | 65 | ## Validation 66 | 67 | - Set validation using `aria-invalid` or `aria-invalid={false}` 68 | 69 | ```jsx live noInline 70 | import React from 'react' 71 | import { Input, Boxer } from '@smooth-ui/core-sc' 72 | 73 | function Example() { 74 | return ( 75 | 76 | 77 | 78 | 79 | 80 | ) 81 | } 82 | 83 | render() 84 | ``` 85 | 86 | ## Accessibility 87 | 88 | `Input` uses a native HTML `input`, it means it is totally accessible on all devices. 89 | 90 | ## API 91 | 92 | ### Input 93 | 94 | 95 | -------------------------------------------------------------------------------- /website/src/pages/docs/introduction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | menu: Getting Started 4 | order: 10 5 | --- 6 | 7 | # Introduction 8 | 9 | Smooth UI is a modern UI library for React, focused on accessibility, productivity and flexibility. It works with [Styled Components 💅](https://styled-components.com) or [Emotion 👩‍🎤](https://emotion.sh). 10 | 11 | It is focused on developer experience, productivity. You can focus on what you want to build instead of on how to build it. 12 | 13 | ## Accessbility 14 | 15 | Smooth UI components follow [WAI-ARIA practices](https://www.w3.org/TR/wai-aria-practices/). It uses [Reakit](https://reakit.io/)'s magic to provide the best accessibility. 16 | If you are interested by all accessibility features, [read the full accessibility guide](/docs/accessibility/). 17 | 18 | ## Productivity 19 | 20 | Smooth UI is built by [Smooth Code](https://smooth-code.com), a dev studio specialized in React. We build new React projects every day. Smooth UI is the result of two years of research in term of being productive and building beautiful and accessible UIs. 21 | Smooth UI does not contain a lot of components but has a powerful solid base with [xstyled](https://www.smooth-code.com/open-source/xstyled/). It adds superpower to your components with [system props](/docs/system/). You can build a complete UI without writing any line of CSS. 22 | 23 | ## Flexibility 24 | 25 | Smooth UI is compatible with [Styled Components 💅](https://styled-components.com) and [Emotion 👩‍🎤](https://emotion.sh). You can use it in all your React projects, with [Next](https://nextjs.org/), [Gatbsy](https://gatsbyjs.org), or any other application! 26 | Smooth UI also has a powerful [theming feature](/docs/theming/) that gives you an entire control over the styling of the components, you can tweak literally everything! 27 | -------------------------------------------------------------------------------- /website/src/pages/docs/menu.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Menu 3 | menu: Components 4 | order: 65 5 | --- 6 | 7 | import { 8 | Menu, 9 | MenuItem, 10 | MenuDisclosure, 11 | MenuSeparator, 12 | } from 'smooth-ui-sc-next' 13 | import { Props } from '../../components/Props' 14 | 15 | # Menu 16 | 17 | Accessible `Menu` component. 18 | 19 | ## Basic 20 | 21 | ```jsx live noInline 22 | import React from 'react' 23 | import { 24 | useMenuState, 25 | Menu, 26 | MenuItem, 27 | MenuDisclosure, 28 | MenuSeparator, 29 | } from '@smooth-ui/core-sc' 30 | 31 | function Example() { 32 | const menu = useMenuState() 33 | return ( 34 | <> 35 | Preferences 36 | 37 | Settings 38 | 39 | Extensions 40 | 41 | 42 | Keyboard shortcuts 43 | 44 | 45 | ) 46 | } 47 | 48 | render() 49 | ``` 50 | 51 | ## Animated 52 | 53 | Make it animated using `unstable_animated` attribute in `useMenuState`. 54 | 55 | ```jsx live noInline 56 | import React from 'react' 57 | import { 58 | useMenuState, 59 | Menu, 60 | MenuItem, 61 | MenuDisclosure, 62 | MenuSeparator, 63 | } from '@smooth-ui/core-sc' 64 | 65 | function Example() { 66 | const menu = useMenuState({ unstable_animated: true }) 67 | return ( 68 | <> 69 | Preferences 70 | 71 | Settings 72 | 73 | Extensions 74 | 75 | 76 | Keyboard shortcuts 77 | 78 | 79 | ) 80 | } 81 | 82 | render() 83 | ``` 84 | 85 | ## Submenu 86 | 87 | Make it animated using `unstable_animated` attribute in `useMenuState`. 88 | 89 | ```jsx live noInline 90 | import React from 'react' 91 | import { 92 | useMenuState, 93 | Menu, 94 | MenuItem, 95 | MenuDisclosure, 96 | MenuSeparator, 97 | } from '@smooth-ui/core-sc' 98 | 99 | const PreferencesMenu = React.forwardRef((props, ref) => { 100 | const menu = useMenuState() 101 | return ( 102 | <> 103 | 104 | Preferences 105 | 106 | 107 | Settings 108 | 109 | Extensions 110 | 111 | 112 | Keyboard shortcuts 113 | 114 | 115 | ) 116 | }) 117 | 118 | function Example() { 119 | const menu = useMenuState() 120 | return ( 121 | <> 122 | Code 123 | 124 | About Visual Studio Code 125 | Check for Updates... 126 | 127 | 128 | 129 | 130 | ) 131 | } 132 | 133 | render() 134 | ``` 135 | 136 | ## Accessibility 137 | 138 | `Menu` uses [Reakit Menu](https://reakit.io/docs/menu/) under the hood, it means it follows WAI-ARIA Pattern. 139 | 140 | [Read more about Menu accessibility on Reakit](https://reakit.io/docs/menu/#accessibility). 141 | 142 | ## API 143 | 144 | ### Menu 145 | 146 | 147 | -------------------------------------------------------------------------------- /website/src/pages/docs/migrate-from-v10.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Migrate from v10 3 | menu: Getting Started 4 | order: 50 5 | --- 6 | 7 | # Migrate from v10 8 | 9 | Smooth UI v11 is a big breaking change and the migration from v10 could be difficult. This guide will help you achieve it. 10 | 11 | ## Previous documentation 12 | 13 | The previous documentation is still accessible and will remain accessible on this url: 14 | 15 | https://smooth-ui-v10.smooth-code.com 16 | 17 | ## System 18 | 19 | `@smooth-ui/system` is replaced by [`@xstyled/system`](https://www.smooth-code.com/open-source/xstyled/). The behaviour is the same and everything is documented. 20 | 21 | ## Normalize 22 | 23 | - No breaking change. 24 | 25 | ## Theming 26 | 27 | Smooth UI v11 follows [xstyled theme specification]([a new theme specification](https://www.smooth-code.com/open-source/xstyled/docs/theme-specification/)). 28 | 29 | `ThemeProvider` has no breaking change, it still uses the one provided either by `styled-component` or by `emotion-theming`. 30 | 31 | ## Emotion 32 | 33 | Smooth UI v11 is still compatible with emotion. 34 | 35 | ## Forms 36 | 37 | Form layouts have been reimplemented to improve accessibility, [see new `Form` documentation](https://www.smooth-code.com/open-source/smooth-ui/docs/form/). 38 | 39 | - `FormGroup` becomes `FormField` 40 | - `Label` becomes `FormFieldLabel` 41 | - `control` prop is no longer required 42 | 43 | ## Grid 44 | 45 | - `Grid` is gone, you can reimplement it: 46 | 47 | ```jsx 48 | // Example of a custom `Grid` component 49 | const Grid = styled.div` 50 | margin: 0 auto; 51 | max-width: 800px; 52 | padding: 0 20px; 53 | ` 54 | ``` 55 | 56 | - `Row` and `Col` are now available everywhere as `row` and `col` property, [see xstyled documentation](https://www.smooth-code.com/open-source/xstyled/docs/system-props/#xgrids). 57 | 58 | ```jsx 59 | // v10 60 | import { Grid, Row, Col } from '@smooth-ui/core-sc' 61 | 62 | function Example() { 63 | return ( 64 | 65 | 66 | 67 | One 68 | 69 | 70 | Two 71 | 72 | 73 | Three 74 | 75 | 76 | 77 | ) 78 | } 79 | 80 | // v11 81 | import { Box } from '@smooth-ui/core-sc' 82 | 83 | function Example() { 84 | return ( 85 | 86 | 87 | One 88 | Two 89 | Three 90 | 91 | 92 | ) 93 | } 94 | ``` 95 | 96 | ## Components 97 | 98 | ### Alert 99 | 100 | No breaking change, you have nothing to migrate. 101 | 102 | ### Box 103 | 104 | - `Box` comes now from [@xstyled/system](https://www.smooth-code.com/open-source/xstyled/docs/system-components/#use-the-box-component) but for convenience it is also re-exported from `@smooth-ui/core-sc` and `@smooth-ui/core-em`. 105 | - It implements [a new theme specification](https://www.smooth-code.com/open-source/xstyled/docs/theme-specification/) 106 | 107 | ### Button 108 | 109 | - `Button` uses [Reakit Button](https://reakit.io/docs/button/) to improve its accessibility 110 | - Property `size` is now `scale` 111 | 112 | ### Checkbox 113 | 114 | - `Checkbox` uses [Reakit Checkbox](https://reakit.io/docs/checkbox/) to improve its accessiblity 115 | - Property `size` is now `scale` 116 | - Property `valid` is now `aria-invalid` (inversed) 117 | 118 | ### FormCheck 119 | 120 | - Property `inline` is gone, you can now use `aria-orientation` on `RadioGroup` or `CheckboxGroup` 121 | 122 | ### Input 123 | 124 | - Property `size` is now `scale` 125 | - Property `valid` is now `aria-invalid` (inversed) 126 | 127 | ### Modal 128 | 129 | - `Modal` is gone, you have to implement your own with [Reakit Dialog](https://reakit.io/docs/dialog/) 130 | 131 | ### Popover 132 | 133 | - `Popover` is gone, you have to implement your own with [Reakit Popover](https://reakit.io/docs/popover/) 134 | 135 | ### Radio 136 | 137 | - `Radio` uses [Reakit Radio](https://reakit.io/docs/radio/) to improve its accessiblity 138 | - It now requires a `RadioGroup` and a `useRadioState` to work 139 | - Property `size` is now `scale` 140 | - Property `valid` is now `aria-invalid` (inversed) 141 | 142 | ### Select 143 | 144 | - Property `size` is now `scale` 145 | - Property `valid` is now `aria-invalid` (inversed) 146 | 147 | ### Switch 148 | 149 | - The inner component has changed, if you style it, you have to adapt it 150 | 151 | ### Textarea 152 | 153 | - Property `size` is now `scale` 154 | - Property `valid` is now `aria-invalid` (inversed) 155 | 156 | ### Tooltip 157 | 158 | - `Tooltip` is gone, you have to implement your own with [Reakit Tooltip](https://reakit.io/docs/tooltip/) 159 | 160 | ### Typography 161 | 162 | - `Typography` is gone, you have to implement your own 163 | 164 | ## Utilities 165 | 166 | ### Breakpoint 167 | 168 | The utility has been removed, you can do it with a `Box`: 169 | 170 | ```jsx 171 | // v10 172 | 173 | Displayed down to md 174 | 175 | 176 | // v11 177 | 178 | Displayed down to md 179 | 180 | ``` 181 | 182 | ```jsx 183 | // v10 184 | 185 | Displayed up to md 186 | 187 | 188 | // v11 189 | 190 | Displayed up to md 191 | 192 | ``` 193 | 194 | ### SwitchState 195 | 196 | `SwitchState` is gone, use directly [Reakit Checkbox](https://reakit.io/docs/checkbox/) to implement the same kind of behaviour. 197 | 198 | ### Toggler 199 | 200 | `Toggler` is gone, use [React.useState](https://reactjs.org/docs/hooks-state.html) instead. 201 | 202 | ```jsx 203 | // v10 204 | import { Toggler } from '@smooth-ui/core-sc' 205 | 206 | function Example() { 207 | return ( 208 | 209 | {([toggled, onToggle]) => ( 210 | 211 | )} 212 | 213 | ) 214 | } 215 | 216 | // v11 217 | import React from 'react' 218 | 219 | function Example() { 220 | const [toggled, setToggled] = React.useState(true) 221 | return ( 222 | 225 | ) 226 | } 227 | ``` 228 | 229 | ### styled & css 230 | 231 | `styled` and `css` are no longer exported from `@smooth-ui/core-sc` / `@smooth-ui/core-em`, you can import them from from `@xstyled/styled-components` / `@xstyled/emotion` if you want to use it. 232 | 233 | **Styled Components:** 234 | 235 | ```jsx 236 | // v10 237 | import { styled, css } from '@smooth-ui/core-sc' 238 | 239 | // v11 240 | import styled, { css } from '@xstyled/styled-components' 241 | ``` 242 | 243 | **Emotion:** 244 | 245 | ```jsx 246 | // v10 247 | import { styled, css } from '@smooth-ui/core-em' 248 | 249 | // v11 250 | import styled, { css } from '@xstyled/emotion' 251 | ``` 252 | 253 | ### th 254 | 255 | `th` utility is now exported from `@xstyled/system` and [it is improved](https://www.smooth-code.com/open-source/xstyled/docs/system-utilities/#theme-getters). 256 | 257 | ```jsx 258 | // v10 259 | import { th } from '@smooth-ui/core-sc' 260 | 261 | // v11 262 | import { th } from '@xstyled/system' 263 | ``` 264 | 265 | ### unit, px 266 | 267 | `unit` and `px` are not longer exported. Use `th.px` instead. 268 | 269 | ```jsx 270 | // v10 271 | import { th } from '@smooth-ui/core-sc' 272 | 273 | css` 274 | font-size: ${px(10)}; 275 | ` 276 | 277 | // v11 278 | import { th } from '@xstyled/system' 279 | 280 | css` 281 | font-size: ${th.px(10)}; 282 | ` 283 | ``` 284 | 285 | ### up, down, between 286 | 287 | Responsive utilities are now exported from `@xstyled/system`, [see documentation](https://www.smooth-code.com/open-source/xstyled/docs/system-utilities/#responsive-utilities). 288 | 289 | ```jsx 290 | // v10 291 | import { up, down, between } from '@smooth-ui/core-sc' 292 | 293 | // v11 294 | import { up, down, between } from '@xstyled/system' 295 | ``` 296 | -------------------------------------------------------------------------------- /website/src/pages/docs/normalize.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Normalize 3 | menu: Components 4 | order: 70 5 | --- 6 | 7 | # Normalize 8 | 9 | Smooth UI includes a `Normalize` component, it is strongly recommended to use it. Several global CSS codes are injected: 10 | 11 | - Normalize abnormalities across browsers, see [polished `normalize`](https://polished.js.org/docs/#normalize). 12 | - Enable theme fonts, by default [System fonts](https://css-tricks.com/snippets/css/system-font-stack/) are used. 13 | - Set `box-sizing` to `border-box`, [most of time it is easier for you](https://www.paulirish.com/2012/box-sizing-border-box-ftw/). 14 | 15 | ## Usage 16 | 17 | Import `Normalize` from `@smooth-ui/core-sc` or `@smooth-ui/core-em`, then add it to the root of your application. 18 | 19 | ```jsx 20 | import React from 'react' 21 | import { Normalize } from '@smooth-ui/core-sc' 22 | 23 | function App() { 24 | return ( 25 | <> 26 | 27 | {/* Your code ... */} 28 | 29 | ) 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /website/src/pages/docs/radio.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Radio 3 | menu: Components 4 | order: 80 5 | --- 6 | 7 | import { Radio, RadioGroup } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Radio 11 | 12 | ## Basic 13 | 14 | ```jsx live noInline 15 | import React from 'react' 16 | import { Radio, RadioGroup, Boxer, useRadioState } from '@smooth-ui/core-sc' 17 | 18 | function Example() { 19 | const radio = useRadioState() 20 | return ( 21 | 22 | 23 | 26 | 29 | 32 | 33 | 34 | ) 35 | } 36 | 37 | render() 38 | ``` 39 | 40 | ## Sizes 41 | 42 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 43 | 44 | ```jsx live noInline 45 | import React from 'react' 46 | import { 47 | Radio, 48 | RadioGroup, 49 | Boxer, 50 | FormCheck, 51 | FormCheckLabel, 52 | useRadioState, 53 | } from '@smooth-ui/core-sc' 54 | 55 | function Example() { 56 | const radio = useRadioState() 57 | const toggle = () => setChecked(!checked) 58 | return ( 59 | 60 | 61 | 62 | 63 | 64 | Extra small 65 | 66 | 67 | 68 | 69 | 70 | Small 71 | 72 | 73 | 74 | 75 | 76 | Default 77 | 78 | 79 | 80 | 81 | 82 | Large 83 | 84 | 85 | 86 | 87 | 88 | Extra large 89 | 90 | 91 | 92 | 93 | ) 94 | } 95 | 96 | render() 97 | ``` 98 | 99 | ## Disabled 100 | 101 | Disable using `disabled` prop. 102 | 103 | ```jsx live noInline 104 | import React from 'react' 105 | import { Radio, RadioGroup, Boxer, useRadioState } from '@smooth-ui/core-sc' 106 | 107 | function Example() { 108 | const radio = useRadioState() 109 | return ( 110 | 111 | 114 | 115 | ) 116 | } 117 | 118 | render() 119 | ``` 120 | 121 | ## Accessibility 122 | 123 | Radio uses [Reakit Radio](https://reakit.io/docs/radio) under the hood, it means it follows [WAI-ARIA Radio Button/Group Pattern](https://www.w3.org/TR/wai-aria-practices/#radiobutton). 124 | 125 | [Read more about accessibility on Reakit](https://reakit.io/docs/radio/#accessibility). 126 | 127 | ## API 128 | 129 | ### useRadioState 130 | 131 | See [Reakit documentation](https://reakit.io/docs/radio/#useradiostate). 132 | 133 | ### Radio 134 | 135 | 136 | 137 | `Radio` also includes a bunch of state properties, see [Reakit documentation](https://reakit.io/docs/radio/#radio). 138 | 139 | ### RadioGroup 140 | 141 | 142 | -------------------------------------------------------------------------------- /website/src/pages/docs/refs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Refs 3 | menu: Advanced 4 | order: 30 5 | --- 6 | 7 | # Refs 8 | 9 | Accessing `ref` is useful in a lot of cases: animation library, accessing DOM... All Smooth UI components implement `React.forwardRef` to give you access to the underlying DOM component. 10 | 11 | ## Usage 12 | 13 | Passing a `ref` prop to a Smooth UI component will give you the ref of the DOM node. 14 | 15 | ```jsx live noInline 16 | import React from 'react' 17 | import { Input, Button } from '@smooth-ui/core-sc' 18 | 19 | function Example() { 20 | const ref = React.useRef() 21 | return ( 22 | <> 23 | 24 | 25 | 26 | ) 27 | } 28 | 29 | render() 30 | ``` 31 | -------------------------------------------------------------------------------- /website/src/pages/docs/select.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Select 3 | menu: Components 4 | order: 90 5 | --- 6 | 7 | import { Select } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Select 11 | 12 | ## Sizes 13 | 14 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Select, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | 23 | 26 | 29 | 32 | 35 | 38 | 39 | ) 40 | } 41 | 42 | render() 43 | ``` 44 | 45 | ## Disabled 46 | 47 | Disable using `disabled` prop. 48 | 49 | ```jsx live noInline 50 | import React from 'react' 51 | import { Select } from '@smooth-ui/core-sc' 52 | 53 | function Example() { 54 | return ( 55 | 58 | ) 59 | } 60 | 61 | render() 62 | ``` 63 | 64 | ## Validation 65 | 66 | - Set validation using `aria-invalid` or `aria-invalid={false}` 67 | 68 | ```jsx live noInline 69 | import React from 'react' 70 | import { Select, Boxer } from '@smooth-ui/core-sc' 71 | 72 | function Example() { 73 | return ( 74 | 75 | 78 | 81 | 84 | 85 | ) 86 | } 87 | 88 | render() 89 | ``` 90 | 91 | ## Accessibility 92 | 93 | `Select` uses a native HTML `select`, it means it is totally accessible on all devices. 94 | 95 | ## API 96 | 97 | ### Select 98 | 99 | 100 | -------------------------------------------------------------------------------- /website/src/pages/docs/separator.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Separator 3 | menu: Components 4 | order: 95 5 | --- 6 | 7 | import { Separator } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Separator 11 | 12 | The `Separator` represents a thematic break between paragraph-level elements: for example, a change of scene in a story, or a shift of topic within a section. 13 | 14 | ## Basic 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Text, Separator } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | <> 23 | One TextaragraTexth 24 | 25 | Another paragraph 26 | 27 | ) 28 | } 29 | 30 | render() 31 | ``` 32 | 33 | ## Accessibility 34 | 35 | - It uses the `hr` HTML5 element. 36 | - It automatically set `aria-orientation` to `horizontal`. 37 | - It has role `separator`. 38 | 39 | ## API 40 | 41 | ### Separator 42 | 43 | 44 | -------------------------------------------------------------------------------- /website/src/pages/docs/switch.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Switch 3 | menu: Components 4 | order: 100 5 | --- 6 | 7 | import { Switch } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Switch 11 | 12 | ## Basic 13 | 14 | It receives the same props as controlled inputs, such as `checked` and `onChange`. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Switch, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | const [checked, setChecked] = React.useState(false) 22 | const toggle = () => setChecked(!checked) 23 | return 24 | } 25 | 26 | render() 27 | ``` 28 | 29 | ## useCheckboxState 30 | 31 | A `Switch` acts as a checkbox, so `useCheckboxState` is usable exactly like on a `Checkbox`. 32 | 33 | ```jsx live noInline 34 | import React from 'react' 35 | import { Switch, useCheckboxState } from '@smooth-ui/core-sc' 36 | 37 | function Example() { 38 | const checkbox = useCheckboxState() 39 | return 40 | } 41 | 42 | render() 43 | ``` 44 | 45 | ## Sizes 46 | 47 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 48 | 49 | ```jsx live noInline 50 | import React from 'react' 51 | import { 52 | Switch, 53 | useCheckboxState, 54 | FormCheck, 55 | FormCheckLabel, 56 | Boxer, 57 | } from '@smooth-ui/core-sc' 58 | 59 | function Example() { 60 | const checkbox = useCheckboxState() 61 | return ( 62 | 63 | 64 | 65 | 66 | Extra small 67 | 68 | 69 | 70 | 71 | 72 | Small 73 | 74 | 75 | 76 | 77 | 78 | Base (default) 79 | 80 | 81 | 82 | 83 | 84 | Large 85 | 86 | 87 | 88 | 89 | 90 | Extra large 91 | 92 | 93 | 94 | ) 95 | } 96 | 97 | render() 98 | ``` 99 | 100 | ## Disabled 101 | 102 | Disable using `disabled` prop. 103 | 104 | ```jsx live noInline 105 | import React from 'react' 106 | import { Switch, useCheckboxState } from '@smooth-ui/core-sc' 107 | 108 | function Example() { 109 | const checkbox = useCheckboxState({ state: true }) 110 | return 111 | } 112 | 113 | render() 114 | ``` 115 | 116 | ## With labels 117 | 118 | Add labels using `labeled` props. Set custom labels using `labelOn` and `labelOff`. 119 | 120 | ```jsx live noInline 121 | import React from 'react' 122 | import { Switch, Boxer, useCheckboxState } from '@smooth-ui/core-sc' 123 | 124 | function Example() { 125 | const checkbox = useCheckboxState() 126 | return ( 127 | 128 | 129 | 130 | 131 | ) 132 | } 133 | 134 | render() 135 | ``` 136 | 137 | ## Accessibility 138 | 139 | `Switch` uses [Reakit Checkbox](https://reakit.io/docs/checkbox) under the hood, it means it follows [WAI-ARIA Checkbox Pattern](https://www.w3.org/TR/wai-aria-practices/#checkbox). 140 | 141 | [Read more about accessibility on Reakit](https://reakit.io/docs/checkbox/#accessibility). 142 | 143 | ## API 144 | 145 | ### useCheckboxState 146 | 147 | See [Reakit documentation](https://reakit.io/docs/checkbox/#usecheckboxstate-1). 148 | 149 | ### Switch 150 | 151 | 152 | 153 | `Switch` also includes a bunch of state properties, see [Reakit documentation](https://reakit.io/docs/checkbox/#checkbox). 154 | -------------------------------------------------------------------------------- /website/src/pages/docs/system.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: System 3 | menu: Advanced 4 | order: 10 5 | --- 6 | 7 | # System 8 | 9 | Smooth UI implements [xstyled system](https://www.smooth-code.com/open-source/xstyled/docs/system-props/) in all components. It gives you real power to style your application in a declarative way. 10 | 11 | ## Use system props 12 | 13 | System props gives you an opportunity to modify all styles directly from props. 14 | 15 | For example, you can easily change the `backgroundColor` and the horizontal `padding` of a `Button`: 16 | 17 | ```jsx live noInline 18 | import React from 'react' 19 | import { Button } from '@smooth-ui/core-sc' 20 | 21 | function Example() { 22 | return ( 23 | 26 | ) 27 | } 28 | 29 | render() 30 | ``` 31 | 32 | You can see all possibility offered by system properties on [xstyled documentation](https://www.smooth-code.com/open-source/xstyled/docs/system-props/). 33 | -------------------------------------------------------------------------------- /website/src/pages/docs/text.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Text 3 | menu: Components 4 | order: 105 5 | --- 6 | 7 | import { Text } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Text 11 | 12 | Text makes your text fit in your boxes will built-in ellipsis support. 13 | 14 | ## Basic 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Text, Box } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return This is a simple text, nothing fancy. 22 | } 23 | 24 | render() 25 | ``` 26 | 27 | ## Headings 28 | 29 | Text component has built-in variants for `h*` elements. 30 | 31 | ```jsx live noInline 32 | import React from 'react' 33 | import { Text, Boxer } from '@smooth-ui/core-sc' 34 | 35 | function Example() { 36 | return ( 37 | 38 | h1. Heading 39 | h2. Heading 40 | h3. Heading 41 | h4. Heading 42 | h5. Heading 43 | h6. Heading 44 | 45 | ) 46 | } 47 | 48 | render() 49 | ``` 50 | 51 | ### Customize Headings 52 | 53 | Variant and semantic are two different things, you could use a variant `h1` and choose to use a `h2` tag using `forwardedAs`. In the following example, we use `div` for each of them. 54 | 55 | ```jsx live noInline 56 | import React from 'react' 57 | import { Text, Boxer } from '@smooth-ui/core-sc' 58 | 59 | function Example() { 60 | return ( 61 | 62 | 63 | h1. Heading 64 | 65 | 66 | h2. Heading 67 | 68 | 69 | h3. Heading 70 | 71 | 72 | h4. Heading 73 | 74 | 75 | h5. Heading 76 | 77 | 78 | h6. Heading 79 | 80 | 81 | ) 82 | } 83 | 84 | render() 85 | ``` 86 | 87 | ## Display Headings 88 | 89 | Traditional heading elements are designed to work best in the meat of your page content. When you need a heading to stand out, consider using a display heading—a larger, slightly more opinionated heading style. Keep in mind these headings are not responsive by default. 90 | 91 | ```jsx live noInline 92 | import React from 'react' 93 | import { Text, Boxer } from '@smooth-ui/core-sc' 94 | 95 | function Example() { 96 | return ( 97 | 98 | Display 1 99 | Display 2 100 | Display 3 101 | Display 4 102 | 103 | ) 104 | } 105 | 106 | render() 107 | ``` 108 | 109 | ## Add a new variant 110 | 111 | Variants are defined in `texts` section of your theme, you can add a variant by [customizing your theme](/docs/theming/). 112 | 113 | ```jsx live noInline 114 | import React from 'react' 115 | import { css, ThemeProvider } from 'styled-components' 116 | import { Text } from '@smooth-ui/core-sc' 117 | 118 | const theme = { 119 | texts: { 120 | 'comic-title': { 121 | // If you don't specify a `forwardedAs` in your component, it will use this one 122 | // by default it uses a `span` 123 | defaultAs: 'h1', 124 | style: css` 125 | font-family: 'comic sans ms', sans-serif; 126 | font-size: 5rem; 127 | `, 128 | }, 129 | }, 130 | } 131 | 132 | function Example() { 133 | return Hello world 134 | } 135 | 136 | render( 137 | 138 | 139 | , 140 | ) 141 | ``` 142 | 143 | ## Ellispis & multilines 144 | 145 | Make your text fit on one line or several lines using `lines` property. 146 | 147 | ```jsx live noInline 148 | import React from 'react' 149 | import { Text, Box, Separator } from '@smooth-ui/core-sc' 150 | 151 | function Example() { 152 | return ( 153 | 154 | This text should fit on one line. 155 | 156 | 157 | This text should fit on two lines, and takes the space of two lines. 158 | 159 | 160 | ) 161 | } 162 | 163 | render() 164 | ``` 165 | 166 | ## Accessibility 167 | 168 | - The ellipsis uses [line-clamp](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp), it means your text stay in the page and is visible by screen reader. 169 | - By default, variants induces the HTML element that will be used, but your are free to use yours. 170 | 171 | ## API 172 | 173 | ### Text 174 | 175 | 176 | -------------------------------------------------------------------------------- /website/src/pages/docs/textarea.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Textarea 3 | menu: Components 4 | order: 110 5 | --- 6 | 7 | import { Textarea } from 'smooth-ui-sc-next' 8 | import { Props } from '../../components/Props' 9 | 10 | # Textarea 11 | 12 | ## Sizes 13 | 14 | Set scales using `scale` prop like `"xs"`, `"sm"`, `"lg"` or `"xl"`. The default scale is `"base"`. 15 | 16 | ```jsx live noInline 17 | import React from 'react' 18 | import { Textarea, Boxer } from '@smooth-ui/core-sc' 19 | 20 | function Example() { 21 | return ( 22 | 23 |