Benefits Data Trust Component Library
About
The BDT component library is intended to provide a solid foundation of reusable and composable UI components from which to build front end BDT applications.
- By "solid," we mean that the components are highly reliable, in that breaking changes are as infrequent as possible and managed carefully with semver, and that they are well-tested and coded.
- By "reusable," we mean that the components are intended to serve as basic building blocks that we can employ multiple times in multiple applications
- By "composable," we mean that we keep components as small and single-purpose as possible. When each component is specific and makes very few assumptions about its use, it allows us to build larger sets out of the smaller pieces we've created.
Ex:
<Section>
<List>
<ListItem><Link>foo</Link></ListItem>
<ListItem><Typography>bar</Typography></ListItem>
<ListItem>baz</ListItem>
<ListItem><Button>qux</Button></ListItem>
</List>
</Section>
As opposed to:
<Section
listComponent={List}
list={[
{
type: "link",
text: "foo"
},
{
type: "text",
text: "bar"
},
{
type: "none",
text: "bar"
},
{
type: "button",
text: "qux"
}
]}
/>
In the second case, the API is doing too much work to contain too much functionality. It is difficult to modify, reuse, and build larger components in unexpected ways. For example, what it we wanted to use nested sections and lists? In the first, we can mix and match at will because none of the components makes any assumptions about its children, and it is more clear how it can be used from just the basic knowledge of the component name and purpose.
Multi-package mono repo
In order to allow components and packages to be updated regularly without forcing an update to the entire library (risking a lot of breakage in the process), we structure the project as a mono repo with many packages, where each component is its own package. What this means is that the components are added to package.json separately:
devDependencies": {
"@bdtrust-component-library/accordion": "^1.8.7",
"@bdtrust-component-library/button": "^2.0.1",
"@bdtrust-component-library/label": "3.5.0",
...
}
import Accordion from '@bdtrust-component-library/accordion';
import Button from '@bdtrust-component-library/button';
import Label from '@bdtrust-component-library/label';
We use the rush project to help manage our mono repo.
See the following links for additional information and the how and why:
First time setup
- Use only
yarn
for running scripts, in order to avoid some unexpected conflicts with different .lock
files. - Run
yarn start
to start Storybook and review components. - Run
npm install g @microsoft/rush
to install rush. We use global install because rush does not like to assume the existence of a package file when doing any initial setup.
- You will likely not need to run the following. Check with project maintainers if you think you might need to run this. If performing a fresh install, with no "common" folder, but an existing repo,
rush init --overwrite-existing
will get everything started.
Development
- If using the component generator (to create a simple scaffolding with all the right files in place), you must install yeoman globally:
npm install -g yo`
cd src/generator-component
npm link
- Run
yarn create:component
. You will be prompted for the component name. Enter for instance Accordion
(make sure it is camel cased) and the generator script will create a new component under src
with all the right files in place (component, index file, story for storybook, test files, config files, etc.). - Customize the component to your liking. It is always a good idea to have at least one test that makes sure the component actually renders (using react testing library is preferred for consistency). The index.ts should not have to be modified as it exports the component and its types only.
- Add the package to the "projects" array in the
rush.json
file. - When adding/updating any package.json files, run
rush update
.
Styling
- The styling scaffolding is done with the help of Tailwind CSS, a utility library that adds consistency for the design system. The configuration file is
tailwind.config.js
and contains our theme information overrides/custom values (global variables for spacing, typography etc). The default values can be found here. - The library uses CSS Modules in order to scope the css.
- These values are imported in
src/base.css
and are shared through all components. - Each component can use any of the tailwind classes with the
@apply
rule in the component's .module.css
, along with additional css not handled by Tailwind.
Publishing (WORK IN PROGRESS)
Note: Publishing means a number of things here:
- Pushing to master
- Pushing a new tag
- Create a release in github with change notes (and API documentation if it introduces a new component or updates an old one)
- Publishing the scoped package to npm
Note: Before publishing packages, you must have an npm account and be added to the organization in order to publish scoped packages. If you are publishing a new scoped package, you may need to use the official BDT npm user account/email.
When publishing a component, we need to make sure we are using the latest, safest code. This means that we need to have master up to date and make sure that no tests are failing.
- Make sure
develop
branch is up to date with your local changes. - Run
yarn safe-commit
to run all the tests one last time. - Run
git checkout master && git merge develop
to update master branch. - Run
rush change
to add change notes and rush publish
to publish packages. - Once published, all changes will be updated in public storybook.
- Make sure to update
develop
branch with release tag commit when finished publishing. - Add release notes in github, as copious as necessary Releases (many projects will be relying on these to determine if there are any breaking changes).
IDE Setup
If needed/wanted, it is possible to configure your IDE to recognize tailwind custom atImports (@tailwind, @apply, @variants, @responsive, @screen). See this link for an example.
Additionally, if using VSCode, Tailwind CSS IntelliSense
is helpful to get name completion while developing.