The design system and react components for Westpac GEL
For the docs for the design system please go to
https://gel.westpacgroup.com.au/design-system
This repository consists of the following parts:
/brands/*
and /components/*
- The react design system components (published to npm)/website
- The nextjs website/website-backend
- The keystonejs instance/helpers/*
- Some utility scripts/nginx/*
- The backend nginx configurationThis repo is a monorepo.
Learn more about monorepos at https://monorepo.guide/.
To run this repo locally please use yarn.
cd path/to/repo
yarn && yarn prepare
Here you’ll find our contributing guidelines as well as how to add or edit a component.
To contribute to this repo please follow the steps listed below:
1. Fork the repository.
Fork the repo and checkout the develop branch.
2. Install the Dependencies.
Install the project dependencies with:
cd path/to/repo
yarn
3. Implement changes.
When implementing your changes please ensure that you follow modern web development best practices.
4. Format & Generate prop-types
Format your changes and Generate your Prop-Types for documentation:
yarn prop-types && yarn format
5. Test
Run the Format, Unit and Integration Tests with:
yarn test
6. Add a Changeset
Any Component changes will require a changeset
(This is how we manage versioning and changelogs).
To create a changeset run:
yarn changeset add
Make sure to follow SemVer convention and write a meaningful description of the change in the changelog.
7. Create a Pull Request
8. Review
Wait for your changes to be reviewed and approved.
9. Merge
The Maintainer will merge the Pull Request into the Develop branch.
10. Publish
The Maintainer will publish changes to NPM.
To add a new component (aka package), run the below command from the root of the project and then follow the prompts:
yarn new my-component-name
Note: replace my-component-name
with the component you wish to add.
This will create a new entry in the /components
directory with all of the files you need to get started and with all dependencies installed. Please note that this component will be TypeScript.
To edit a component, including if you’ve just added one using the steps above, use the below command from the root of the project:
yarn dev my-component-name
Note: replace my-component-name
with the component you wish to run.
This component can now be viewed on http://localhost:8080/
.
sh
.
├── LICENSE
├── README.md
├── package.json
├── yarn.lock
│
├── helper/
│ ├── .component-template/ # the starter files for when a new component is created via cli
│ │
│ ├── example/
│ │ ├── components/ # an assortment of components helping us build the example pages
│ │ ├── _utils.js # shared logic
│ │ ├── docs.js # entry file for `yarn docs` task
│ │ ├── docs.webpack.config.js # dynamic webpack config to run the `yarn docs` task
│ │ ├── index.html # the index.html file as entry point
│ │ ├── start.js # entry file for `yarn start` task
│ │ └── start.webpack.config.js # dynamic webpack config to run the `yarn start` task
│ │
│ ├── public/ # files in this folder will be moved into the docs/ folder
│ │
│ ├── tests/ # test specific files for reuse between component tests
│ │
│ ├── transformer/ # the transfomer files to convert tokens into platform data
│ │ ├── _utils.js # shared logic
│ │ └── web.js # transforms tokens to web
│ │
│ ├── buildExports.js # helps cypress testing of each component
│ ├── cli.js # helper file for cli like adding a new module
│ ├── ds-info.js # helper file to generate the GEL.json
│ └── tester.js # helps cypress testing of each component
│
├── components/ # all ds components that are published
│ ├── component1/ # more on the structure of components below
│ ├── component2/
│ └── component3/
│
├── brands/ # all brand components
│ ├── BOM/
│ │ ├── dist/ # distribution files (build artifact)
│ │ ├── overrides/ # all overrides files specific to this brand
│ │ ├── src/ # our source files
│ │ ├── tokens/ # token files
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── package.json
│ │ └── README.md
│ ├── BSA/
│ │ └── etc
│ └── WBC/
│ └── etc
│
├── website/ # files for the website
│
├── website-backend/ # files for the website backend
│
└── docs/ # the static files for the documentation (build artifact)
yarn
| install all dependencies |yarn prop-types
| generates the prop-types according to the interface created |yarn nuke
| removes all node_modules
for fresh start |yarn fresh
| removes all node_modules
and reinstalls them |yarn build
| build all dist folders for production |yarn build:dev
| build all dist for local consumption |yarn docs
| build docs for all components and run server |yarn docs:build
| build docs for all components to ./docs/
folder |yarn new [package-name]
| create a new specified empty component |yarn dev [package-name]
| start the example server of a component |yarn test
| runs tests |lint:format:fix
| runs prettier and eslint to format and lint all code |The design system components are spread between two folders:
.
├── brands/ # The brand components
└── components/ # The design system components including core
There are two different ways you can run the components locally:
jsx
imported from @westpac/core
and never depend on emotion
directly other than inside core itselfsh
.
├── CHANGELOG.md
├── README.md
├── LICENSE
├── package.json # scope: `@westpac/`
│
├── src/ # all the source
│ ├── overrides/ # all overrides files for each sub-component
│ ├── _util.js # for reused logic within the component [optional]
│ ├── index.js # only for exports
│ └── ComponentX.js # only for the components, can be multiple files
│
├── examples/ # the demo folder is for seeing the components in action
│ ├── _util.js # for reused logic within the examples [optional]
│ ├── 00-example.js # show-case props and variations
│ ├── 10-example.js # all files not starting with a dot or an underscore
│ └── 20-example.js # will be processes with `yarn start`
│
├── demos/ # the examples that can be embedded into the website
│ ├── example-x.js
│ ├── example-y.js
│ └── example-z.js
│
└── tests/ # test includes all tests
├── integration/
│ └── test.cypress.js # cypress test file for integration tests
└── unit/
└── unit.spec.js # jest test file for unit tests
yarn start
| start the example server |yarn test
| runs test headless |yarn test:dev
| runs test by opening cypress app |yarn test:integration
| runs integration tests |Multi-brand will be achieved by added a brand package that will be passed to the <GEL></GEL>
component
import { GEL } from '@westpac/core';
import brand from '@westpac/WBC';
export const App = () => <GEL brand={brand}>Your app</GEL>;
The brand package includes tokens and overrides and will be available to all packages inside the <GEL></GEL>
wrapper via context.
This allows us to be as consistent as can be within the same app.
It also separates out all things to do with theming into a single package.
The brand package does not need to know anything about its components.
But it can opt in.
COLORS
| Our colors including tints |LAYOUT
| Only breakpoints so far |PACKS
| Mostly typography packs for reuse and consistency |SPACING
| A function with minor scale to allow you to hit the grid |TYPE
| Font files and definitions |BRAND
| The current brand string |A consumer may choose to override a component in its build.
This can happen by adding the overrides into the same namespace as the component you wish to override.
import { Tabcordion } from '@westpac/tabcordion';
import { GEL } from '@westpac/core';
import brand from '@westpac/wbc';
brand['@westpac/tabcordion'].TabItem.styles = ( styles, state ) => { ...styles, border: 'red solid 2px' };
brand['@westpac/tabcordion'].TabRow.component = <TabRow ></TabRow>;
export const App = () => (
<GEL brand={brand}>
All instances of the <Tabcordion></Tabcordion> now include the override specified above.
No matter how many there are.
</GEL>
);
There may also a need to add an override only to a single instance of the component.
In that case you may add the override to the component directly via the overrides
prop each component has.
import { Tabcordion } from '@westpac/tabcordion';
import { GEL } from '@westpac/core';
import brand from '@westpac/wbc';
brand['@westpac/tabcordion'].Tabcordion.styles = ( styles, state ) => { ...styles, border: 'red solid 2px' };
const overrides = {
Tabcordion: {
styles: ( styles, state ) => { ...styles, border: 'blue solid 2px' },
},
};
export const App = () => (
<GEL brand={brand}>
<Tabcordion></Tabcordion> with red border
<Tabcordion overrides={overrides} ></Tabcordion> with blue border
<Tabcordion></Tabcordion> with red border
</GEL>
);
(💡 Overrides will be reconciled as a cascade from less-specific to most-specific.)
Every single component (including root component) have three items in their override object:
overrides = {
[name]: {
styles: (base-styles, state-props) => styles,
component: <React.Component></React.Component>
attributes: (base-attributes, state-props) => Object,
}
}
styles
| function
=> Object | A function that returns an object of css properties for emotion | (base-styles
,state/props
) base-styles
= the styles that would have been applied to the component, state/props
= all props and all known state (without setters) |attributes
| function
=> Object | A function that returns an object of attributes that will be spread onto the component | (base-attributes
,state/props
) base-attributes
= the attributes that would have been applied to the component, state/props
= all props and all known state (without setters) |component
| react component
| A react component which will receive all props | - |Components that are made up by other components like list
, breadcrumb
, button-group
, input-group
etc can be solely driven by the data
prop.
We also offer declarative APIs in-case a consumer wants to wrap a component.
<Breadcrumb>
<Crumb href="#/" text="Home" ></Crumb>
<Crumb href="#/personal-banking/" text="Personal" ></Crumb>
<Crumb href="#/credit-cards/" text="Credit cards" ></Crumb>
</Breadcrumb>
Is the same as:
<Breadcrumb
data={[
{ href: '#/', text: 'Home' },
{ href: '#/personal-banking/', text: 'Personal' },
{ href: '#/credit-cards/', text: 'Credit cards' },
]}
/>
We use the useFocus hook in the GEL
component.
You can @wilkowskidom/how-i-learned-to-stop-worrying-and-love-the-outline-7a35b3b49e7">read about the focus hook on medium.
The GEL
also adds the global focus styling from our PACKS.focus
token pack.
If you need to add it to something use:
':focus': {
...PACKS.focus,
},
However if you need a focus state that will persist across mouse users do something like this:
const { PACKS } = useBrand();
const focus = { ...PACKS.focus };
focus.outline += ' !important'; // adding `!important` will make sure the focus persists
<Component
css={{
':focus': { ...focus },
}}
></Component>;
index.js
| Export only public API |_utils.js
| For code shared between components (ignored in examples) [optional]
|ComponentX.js
| All component files are named after the exported component and pascal cased |00-*.js
| All files inside the examples/
folder are sorted by file name |*.js
| All jsx files are postfixed with .js
|*.spec.js
| All (jest) unit tests are postfixed with .spec.js
|tag
| When a component can be rendered as different tags |look
| When talking about the look of a component like success
or hero
|href
| When something points at a thing via a link |icon
iconLeft
iconRight
| For passing in an icon |disabled
or noBorder
| For passing boolean flags we use natural language and not is
or has
prefixes |size
| For the physical size of a component, should be: 'small', 'medium', 'large', 'xlarge'
|spacing
| For the whitespace size of a component, should be: 'small', 'medium', 'large', 'xlarge'
|value
| For when a component shows a value, often numbers but not only |selected
| For things inside lists that are being targeted. Like ButtonGroups
or CheckGroup
. Takes string or array |assistiveText
| For labeling things for assistive technology (generally renders using VisuallyHidden
or aria-label
depending on use case) |xsmall
small
medium
large
xlarge
| For t-shirt sizing |data
| A prop to drive a component-group from data alone |This build is running all the components examples/demos directly and nothing else.
It’s for development of a component and for testing it.
You run it via:
cd path/to/root/of/repo
yarn dev [component name]
The blender can generate human readable html and css from react and emotion components.
Read more about how you add blender support in the blender README.md.