Thanks so much for helping us develop this project and being a part of the Buffer community. Here are a few guidelines that will help you along the way.
Buffer Shared-Components is an open source project, so pull requests are always welcome, although we also recommend opening an issue to discuss your ideas/changes it with the maintainers.
When in doubt, it's best to keep your pull requests small, by not bundling more than one feature or bug fix per pull request :).
All stable releases are tagged (view tags), and the main
branch represents the latest development version of the library.
Patches or hotfix releases are prepared on an independent branch.
Please create a new branch from an up to date main on your fork.
- Fork the repository on Github
- Clone your fork to your local machine
git clone [email protected]:<yourname>/bufferapp/ui.git
- Create a branch
git checkout -b my-topic-branch
- Make your changes, lint, then push to to GitHub with
git push --set-upstream origin my-topic-branch
. - Visit GitHub and make your pull request.
If you have an existing local repository, please update it before you start, to minimise the chance of merge conflicts.
git remote add upstream [email protected]:bufferapp/ui.git
git checkout main
git pull upstream main
git checkout -b my-topic-branch
yarn
The documentation site is built with Shared-Components and contains examples of all the components. To get started:
yarn start
You can now access the documentation site locally. This script generates the documentation site and watches any changes in the app in order to hot reload the documentation.
For testing we're using automated snapshot testing with jest-auto-snapshots
. In order to create a new snapshot test, just create the test file for the given component and add:
import snap from 'jest-auto-snapshots';
import MyComponent from '../MyComponent';
snap(MyComponent, '../MyComponent.tsx');
This will generate snapshot tests for all the different possible rendering state of that component by detecting the different prop types that component uses.
Tests can be run with yarn test
.
To build the package locally, run:
yarn build:lib
Before you publish your code, make sure to update the changelog in documentation/markdown/GettingStarted/CHANGELOG.md
with the version your code will take and the changes included.
To publish your code changes, you can run the following command from the root of the package:
yarn run publish {major|minor|patch}
this will automatically tag the release, generate a build, and deploy to npm and github with your changes.
Under the hood, this runs the script scripts/publish.sh
Please follow the coding style of the project. We use eslint, so if possible, enable linting in your editor to get real-time feedback. The linting rules can be run manually with the following command yarn lint
.
Our latest coding style is compositional as opposed to inheritance based. For an example see the latest added components in the changelog and try to steer away from prop-heavy components, please :)
Our components are organized in folders, in the following structure:
src/ # root
+-- components/ # components root
+-- MyComponent/ # component root
-- MyComponent.jsx # React component
-- MyComponent.test.js # Component's test file
-- index.js # default export
-- style.js # component's CSS
+-- docs/ # documentation site components
When creating a new component, please follow the same structure and create a .jsx
file for the React component, index.js
file with the default export (we need this to be able to have nice imports in our components),
a style.js
with all the style variations for that component, and test.js
with the snapshot test configuration explained in the Test section.
Here are the basic steps:
- Create a new folder with the component name under components
- In that folder create:
ComponentName.jsx
file with the component code,index.js
with the default export,style.js
with components styles using styled-components libraryComponentName.test.js
with a snapshot test
- The documentation site should be automatically refreshed and you should see your new component there
- In the examples folder create a new folder named after your component
- add a new file for each version of your component, named
ExampleVersion.jsx
- add a new file for each version of your component, named
- Make sure you add your new component to the list in
documentation/markdown/UI.md
For component styling, we're using the styled-components library. In the Button
component example, styles for each button variation (primary
, secondary
, text
...)
and size (large
, small
, default
) are defined in the style.js
file. Those styles are then imported in the main Button component in order to construct the styled-component
like this:
const ButtonStyled = style.div`
${Styles.buttonbase};
${props => Styles[props.size]};
${props => Styles[props.type]};
`;
Please make sure to use the color, font, border, etc. variables instead of fixed values in CSS. In case the variable you need is not defined, feel free to add it in the corresponding file.
When you add new folder in components, the documentation system will automatically pick it up and read from the comments and PropTypes in order to create the documentation. To make the documentation complete, there are a few steps needed for every new component created:
- Make sure the name of the component file is the same as the name of the folder it's located
- Add a main component description above the component name
- Add a comment for every Prop type
- Add default prop types
- in the
docs/examples
folder create a newfolder named after the component- in that folder create a new
ExampleComponentType.jsx
file that contains all the different variations of that component, for example
import React from 'react'; import Button from '@bufferapp/components/Button'; /** Primary type buttons */ export default function ExamplePrimary() { return [ <Button type="primary" size="large" onClick={() => {}}>Primary Large</Button>, <Button type="primary" onClick={() => {}}>Primary Button</Button>, <Button type="primary" size="small" onClick={() => {}}>Primary Small</Button>, ]; }
- this will be shown as three different primary buttons in the documentation together with the code examples
- in that folder create a new
All of our Icon components (in components/Icon/Icons/**
) are pulled, processed, and automagically ✨ generated from a Figma file. This is done with the gen:icons
command.
👉 https://www.figma.com/file/D9T6BuWxbTVKhlDU8faZSQ9G/
Before you can run this script you need to get a Figma personal access token and place it in an .env
file in the ui
directory. This file and token is unique to you and should never be commited.
To get your access token, go to Figma.com and click your name in the top-left to open 'Account Settings' (See screenshot). Once there click the button to 'Create a new personal access token' (Screenshot). Copy the new token and paste it into a file called .env
inside the ui
folder, like so:
FIGMA_ACCESS_TOKEN=<your-token>
You'll also need to make sure you have access to the file containing our icons (see link above). If you don't have access talk to someone on the #prod-design channel in Slack. |
Now that you have your token, you can run the script to create / update the Icon components! You only need to do this if icons have been added or changed in the Figma file.
$ yarn gen:icons
Note: ESLint Fix is applied as a part of this process, so make sure you've got its CLI installed
To help you out the script will automatically check the lastModified
time on the Figma file and compare it what's in the local icon cache. If the Figma file is newer, it'll pull down the new data, otherwise it'll build the icons based on the cache.
Once the icons are generated you can commit and push them as you would any other code changes.
- We fetch the Icon data from the Figma API as SVG (if cached data is out-of-date.)
- We prompt the user to choose the frame that contains the icons.
- We process the SVGs with
svgo
and also convert them to a React-compatible JSX syntax. - As part of the processing we remove all
stroke
andfill
colors. This ensures we can redefine the icon colors when they're used in React. - We generate the component name for each icon absed on the name of the layer in Figma. We convert to
CamelCase
and remove anyico-
oricon-
prefixs. Ex.ico-arrow-down
becomesArrowDown
.
There are a few important things to keep in mind when adding or changing new Icons in Figma.
- As long as you add your new icon as layer next to all the other icons, it will be visible to our automatic script. Feel free to create other artboards for WIP / non-flattened icons if needed, since the script lets the user pick the artboard to generate from.
- Make sure you flatten all your shapes. So instead of compound shapes or masks just use the path tools to subtract as needed and create a flattened shape.
- Flatten strokes. Right click and click "Outline stroke" in Figma so that these export correctly.
- Ensure the icon layer is
16x16
in size. - tl:dr; Honestly, most of the issues we see are fixed if you outline strokes. 😉
When you're done adding or changing icons be sure to let an engineer in the #proj-design-system channel know, so we can run the command to regenerate them next chance we get.
By contributing your code to the bufferapp/ui GitHub repository, you agree to license your contribution under the MIT license.