├── .changeset ├── README.md └── config.js ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── TODO.md ├── babel.config.js ├── design-system └── textfield │ ├── CHANGELOG.md │ ├── package.json │ └── src │ └── index.tsx ├── elemental-ui ├── button │ ├── package.json │ └── src │ │ └── index.tsx ├── checkbox │ ├── package.json │ └── src │ │ └── index.tsx ├── radio │ ├── package.json │ └── src │ │ └── index.tsx ├── reset │ ├── package.json │ └── src │ │ └── index.tsx ├── textarea │ ├── package.json │ └── src │ │ └── index.tsx └── textinput │ ├── package.json │ └── src │ └── index.tsx ├── package.json ├── site ├── .gitignore ├── README.md ├── build-manifest.js ├── components │ └── HtmlHead.tsx ├── manifest.json ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages │ ├── _app.tsx │ └── index.tsx ├── static │ └── favicons │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ └── safari-pinned-tab.svg ├── tsconfig.json └── yarn.lock ├── tsconfig.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with mono-repos or single package repos to help you verion and release your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) 4 | 5 | We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 6 | -------------------------------------------------------------------------------- /.changeset/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | Hey, welcome to the changeset config! This file has been generated 3 | for you with the default configs we use, and some comments around 4 | what options mean, so that it's easy to customise your workflow. 5 | 6 | You should update this as you need to craft your workflow. 7 | 8 | Config provided by a CI command takes precedence over the contents of this file. 9 | 10 | If a config option isn't present here, we will fall back to the defaults. 11 | */ 12 | 13 | const changesetOptions = { 14 | // If true, we will automatically commit the changeset when the command is run 15 | commit: false, 16 | }; 17 | 18 | // This function takes information about a changeset to generate an entry for it in your 19 | // changelog. We provide the full changeset object as well as the version. 20 | // It may be a good idea to replace the commit hash with a link to the commit. 21 | 22 | /* the default shape is: 23 | ### Bump Type 24 | 25 | - GIT_HASH: A summary message you wrote, indented? 26 | */ 27 | 28 | const getReleaseLine = async (changeset, type) => { 29 | const [firstLine, ...futureLines] = changeset.summary 30 | .split('\n') 31 | .map(l => l.trimRight()); 32 | 33 | return `- ${changeset.commit}: ${firstLine}\n${futureLines 34 | .map(l => ` ${l}`) 35 | .join('\n')}`; 36 | }; 37 | 38 | // This function takes information about what dependencies we are updating in the package. 39 | // It provides an array of related changesets, as well as the dependencies updated. 40 | 41 | /* 42 | - Updated dependencies: [ABCDEFG]: 43 | - Updated dependencies: [HIJKLMN]: 44 | - dependencyA@1.0.1 45 | - dependencyb@1.2.0 46 | */ 47 | const getDependencyReleaseLine = async (changesets, dependenciesUpdated) => { 48 | if (dependenciesUpdated.length === 0) return ''; 49 | 50 | const changesetLinks = changesets.map( 51 | changeset => `- Updated dependencies [${changeset.commit}]:` 52 | ); 53 | 54 | const updatedDepenenciesList = dependenciesUpdated.map( 55 | dependency => ` - ${dependency.name}@${dependency.version}` 56 | ); 57 | 58 | return [...changesetLinks, ...updatedDepenenciesList].join('\n'); 59 | }; 60 | 61 | const versionOptions = { 62 | // If true, we will automatically commit the version updating when the command is run 63 | commit: false, 64 | // Adds a skipCI flag to the commit - only valid if `commit` is also true. 65 | skipCI: false, 66 | // Do not modify the `changelog.md` files for packages that are updated 67 | updateChangelog: true, 68 | // A function that returns a string. It takes in options about a change. This allows you to customise your changelog entries 69 | getReleaseLine, 70 | // A function that returns a string. It takes in options about when a pacakge is updated because 71 | getDependencyReleaseLine, 72 | // An array of arrays that defines packages that are linked. 73 | // Linked packages are packages that should be at the same version when they're released. 74 | // If you've used Lerna to version packages before, this is very similar. 75 | linked: [[]], 76 | }; 77 | 78 | const publishOptions = { 79 | // This sets whether unpublished packages are public by default. We err on the side of caution here. 80 | public: true, 81 | }; 82 | 83 | module.exports = { 84 | versionOptions, 85 | changesetOptions, 86 | publishOptions, 87 | }; 88 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | lint: 4 | docker: 5 | - image: circleci/node:10.6.0 6 | working_directory: ~/repo 7 | steps: 8 | - checkout 9 | - restore_cache: 10 | keys: 11 | - v2-dependencies-{{ checksum "yarn.lock" }} 12 | # fallback to using the latest cache if no exact match is found 13 | - v2-dependencies- 14 | - run: 15 | name: Install 16 | command: yarn install --pure-lockfile 17 | - run: 18 | name: 'ESLint' 19 | command: yarn eslint . 20 | types: 21 | docker: 22 | - image: circleci/node:10.6.0 23 | working_directory: ~/repo 24 | steps: 25 | - checkout 26 | - restore_cache: 27 | keys: 28 | - v2-dependencies-{{ checksum "yarn.lock" }} 29 | # fallback to using the latest cache if no exact match is found 30 | - v2-dependencies- 31 | - run: 32 | name: Install 33 | command: yarn install --pure-lockfile 34 | - run: 35 | name: 'Type Checking' 36 | command: yarn tsc 37 | 38 | release: 39 | docker: 40 | - image: circleci/node:10.6.0 41 | working_directory: ~/repo 42 | steps: 43 | - checkout 44 | - restore_cache: 45 | keys: 46 | - v2-dependencies-{{ checksum "yarn.lock" }} 47 | # fallback to using the latest cache if no exact match is found 48 | - v2-dependencies- 49 | - run: 50 | name: Install 51 | command: yarn install --pure-lockfile 52 | - run: 53 | name: 'Release' 54 | command: yarn experimental-changesets-auto-release 55 | 56 | workflows: 57 | version: 2 58 | test: 59 | jobs: 60 | - lint 61 | - types 62 | release: 63 | jobs: 64 | - release: 65 | filters: 66 | branches: 67 | only: master 68 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard", "standard-react", "prettier", "prettier/react"], 3 | "plugins": ["prettier"], 4 | "parser": "babel-eslint", 5 | "rules": { 6 | "prettier/prettier": "error", 7 | "react/prop-types": 0, 8 | "react/no-unused-prop-types": 0, 9 | "standard/computed-property-even-spacing": 0, 10 | "no-template-curly-in-string": 0, 11 | "camelcase": 0, 12 | "import/no-duplicates": 0, 13 | "import/no-unresolved": 2 14 | }, 15 | "env": { 16 | "browser": true 17 | }, 18 | "overrides": [ 19 | { 20 | "files": ["*.test.js", "**/__tests__/**"], 21 | "env": { 22 | "jest": true 23 | } 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # misc 7 | .DS_Store 8 | .env 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | dist/ 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thinkmill Pty Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Systems Framework: Raison d’être 2 | 3 | ## Mission Statement 4 | 5 | To make building, maintaining and distributing your design-system simpler. 6 | 7 | ## The Problem 8 | 9 | Design systems, help us efficiently apply and distribute our design opinions throughout our products. This efficiency helps us create user experiences that are more consistent across products, which lends to opportunities for cohesive interoperability. (Bitbucket and Jira for example or MacOS and iOS) 10 | 11 | A substantial amount of effort in setting up design-systems is spent implementing and (usually) repeating functionality around: 12 | 13 | - Accessibility standards 14 | - Interaction and state management 15 | - Platform dependent best practices 16 | - Compositional API 17 | 18 | These are often times the same or very similar across most design-systems. 19 | 20 | ## Design Systems as a composition 21 | 22 | The conventional way of looking at a design-system is a library of Components, associated documentation and patterns. However we can also think of them as a composition of design / thematic options over encapsulated functionality. 23 | 24 | ``` 25 | ds = f(t) 26 | ``` 27 | 28 | Our hypothesis is that by providing building blocks that represent `f` , we empower design-system authors to focus more of their energy on the bespoke aspects of their design-system, and not on the boiler-plate. 29 | 30 | ## Shared tooling and not just components 31 | 32 | Best practices around building and maintaining design systems don’t just extend to the creation of components, but also to things like: 33 | 34 | - Build processes 35 | - Versioning and Publishing workflows 36 | - Documentation artifacts - website - technical documentation (prop-types, tokens etc) - conceptual documentation - usage documentation (upgrade guides, how-too) - live examples - code snippets 37 | - Documentation best practices 38 | - Development environments 39 | 40 | The aim of DSF is not just to make _*building*_ your components easier, but also building and maintaining your _*design-system*_. This means providing: 41 | 42 | - Build tooling and guidelines 43 | - Documentation tooling and guidelines 44 | - Components 45 | - Utilities for _*building*_ components 46 | - Versioning and Publishing tools. 47 | 48 | Not every design system should be built in the same way, but where possible we want to empower design-system authors by sharing tools that make building design-systems simpler and faster. 49 | 50 | # Design Systems Framework Patterns 51 | 52 | ## RenderProps 53 | 54 | ## Components API 55 | 56 | ## Styles API 57 | 58 | ## Working on Design Systems Framework inside another project 59 | 60 | To iterate on DSF while working on another project without having to publish DSF after every change, you can use [`link-monorepos-badly`](https://github.com/mitchellhamilton/link-monorepos-badly). 61 | 62 | Make sure you've done an install in DSF and your project. 63 | 64 | ```bash 65 | # From your clone of the DSF repo 66 | yarn 67 | cd ../another-project 68 | # If you're using Yarn Workspaces in your project 69 | yarn 70 | # If you're using Bolt in your project 71 | bolt 72 | ``` 73 | 74 | Install `link-monorepos-badly` globally 75 | 76 | ```bash 77 | yarn global add link-monorepos-badly 78 | ``` 79 | 80 | Now you can use `link-monorepos-badly` to link packages into your project 81 | 82 | ```bash 83 | link-monorepos-badly link ../design-system 84 | ``` 85 | 86 | When you're done linking, you can unlink and reinstall the packages 87 | 88 | ```bash 89 | link-monorepos-badly unlink ../design-system 90 | # If you're using Yarn Workspaces in your project 91 | yarn 92 | # If you're using Bolt in your project 93 | bolt 94 | ``` 95 | 96 | Once a new release of DSF has happened, you can upgrade all the DSF packages with the `upgrade` command 97 | 98 | ```bash 99 | link-monorepos-badly upgrade ../design-system 100 | # If you're using Yarn Workspaces in your project 101 | yarn 102 | # If you're using Bolt in your project 103 | bolt 104 | ``` 105 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # design-system 2 | 3 | ## TODO 4 | 5 | ### Infra: 6 | - [ ] Setup CI 7 | - [ ] Setup Netlify and integrate with CI 8 | - [ ] Setup build step for non website workspaces. 9 | - [ ] Integrate with change-sets 10 | - [ ] Setup initial dev workflow with Next.js 11 | - [ ] Setup dev loop external of Next.js site* 12 | 13 | ### Unstyled Components: 14 | - [ ] Button 15 | - [ ] Textfield 16 | - [ ] ??? 17 | ### Elemental Components: 18 | - [ ] Button 19 | - [ ] Textfield 20 | 21 | \* = probably not high priority till we decide to make this thing public) 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-env', 4 | '@babel/preset-react', 5 | '@babel/preset-typescript', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /design-system/textfield/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @design-system/textfield 2 | 3 | ## 0.1.2 4 | 5 | ### Patch Changes 6 | 7 | - af4c756: Convert to TypeScript 8 | 9 | ## 0.1.1 10 | 11 | ### Patch Changes 12 | 13 | - 10564ac: Change to test release automation 14 | -------------------------------------------------------------------------------- /design-system/textfield/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-system/textfield", 3 | "version": "0.1.2", 4 | "main": "dist/textfield.cjs.js", 5 | "module": "dist/textfield.esm.js", 6 | "license": "MIT", 7 | "dependencies": { 8 | "@babel/runtime": "^7.4.3", 9 | "@emotion/core": "^10.0.7", 10 | "@types/react": "^16.8.23" 11 | }, 12 | "peerDependencies": { 13 | "react": "^16.8.9" 14 | }, 15 | "devDependencies": { 16 | "react": "^16.8.9", 17 | "react-dom": "^16.8.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /design-system/textfield/src/index.tsx: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | 3 | import { useState, useRef } from 'react'; 4 | import { jsx, CSSObject } from '@emotion/core'; 5 | 6 | type BaseProps = { 7 | isDisabled: boolean; 8 | isReadOnly: boolean; 9 | isRequired: boolean; 10 | isInvalid: boolean; 11 | }; 12 | 13 | type StyleProps = BaseProps & { 14 | isFocused: boolean; 15 | } & React.InputHTMLAttributes; 16 | 17 | type StyleFunc = (props: StyleProps) => CSSObject; 18 | 19 | const inputWrapperStyles: StyleFunc = props => ({ 20 | display: 'flex', 21 | background: 'white', 22 | flex: '1 0 auto', 23 | boxSizing: 'border-box', 24 | }); 25 | const inputStyles: StyleFunc = props => ({ 26 | width: '100%', 27 | }); 28 | 29 | type StylesProp = { 30 | [K in keyof TypeOfDefaultStyles]?: ( 31 | defaultStyles: CSSObject, 32 | props: StyleProps 33 | ) => CSSObject; 34 | }; 35 | 36 | const defaultStyles = { 37 | input: inputStyles, 38 | inputWrapper: inputWrapperStyles, 39 | } as const; 40 | 41 | type Props = Partial & 42 | React.InputHTMLAttributes & { 43 | styles?: StylesProp; 44 | }; 45 | 46 | const Textfield = ({ 47 | styles, 48 | isDisabled = false, 49 | isReadOnly = false, 50 | isRequired = false, 51 | isInvalid = false, 52 | ...rest 53 | }: Props) => { 54 | const [isFocused, setFocused] = useState(false); 55 | const inputEl = useRef(null); 56 | 57 | const getStyles = ( 58 | key: keyof typeof defaultStyles, 59 | styleProps: StyleProps 60 | ) => { 61 | // If there's an existing styles prop 62 | // check for styles[key](theme[key](styleProps)) 63 | // otherwise just return theme[key](styleProps); 64 | const defaultStyle = defaultStyles[key](styleProps); 65 | 66 | return styles && styles[key] 67 | ? styles[key](defaultStyle, styleProps) 68 | : defaultStyle; 69 | }; 70 | 71 | const handleOnFocus = (event: React.FocusEvent) => { 72 | setFocused(true); 73 | if (rest.onFocus) { 74 | rest.onFocus(event); 75 | } 76 | }; 77 | 78 | const handleOnBlur = (event: React.FocusEvent) => { 79 | setFocused(false); 80 | if (rest.onBlur) { 81 | rest.onBlur(event); 82 | } 83 | }; 84 | 85 | const styleProps = { 86 | isDisabled, 87 | isFocused, 88 | isReadOnly, 89 | isRequired, 90 | isInvalid, 91 | ...rest, 92 | }; 93 | 94 | return ( 95 |
96 | 106 |
107 | ); 108 | }; 109 | 110 | export default Textfield; 111 | -------------------------------------------------------------------------------- /elemental-ui/button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@elemental-ui/button", 3 | "version": "0.0.1", 4 | "main": "dist/button.cjs.js", 5 | "module": "dist/button.esm.js", 6 | "author": "Thinkmill", 7 | "license": "MIT", 8 | "dependencies": { 9 | "@babel/runtime": "^7.4.3", 10 | "@emotion/core": "^10.0.7", 11 | "@types/react": "^16.8.23" 12 | }, 13 | "peerDependencies": { 14 | "react": "^16.8.9" 15 | }, 16 | "devDependencies": { 17 | "react": "^16.8.9" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /elemental-ui/button/src/index.tsx: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx } from '@emotion/core'; 3 | 4 | const defaultInputStyles = (state: Record) => ({ 5 | display: 'inline-block', 6 | }); 7 | 8 | const defaults: Record = { 9 | Input: { 10 | component: (props: Record) => 18 |

Checkbox

19 | 20 | 21 |

Radio

22 | 23 | 24 |

Textarea

25 |