3.11.1 • Published 9 months ago

@nxtdtc/dtc-component-library v3.11.1

Weekly downloads
120
License
-
Repository
-
Last release
9 months ago

DTC Component Library

A shared component library for common components shared across micro-frontends. These components have been created in conjunction with the Design team, using our universal design system. This enables us to create, update, and maintain storefront components in a centralized place. Component styles specific to a particular brand are primarily configured via that brand's design system and translated into a config file.

Table of Contents

Getting Started Brand Style Config File Styling Components with Styled Components Storybook Landing Page Components Development Process

QA/Integration Process

Versioning/Publishing Useful Libraries

Getting Started


npm install will install all necessary packages - be sure you are using Node >= 10

npm start will start webpack and evaluate changes in real time. This can be useful when linking with another app to test a new component or change.

npm run storybook will open a tab with storybook running on port 6006. Storybook is especially useful for building components in isolation and testing different permutations of props.

Brand Style Config File


Each brand has it's own config file, which lives in the config directory, and the shape of this config file should be uniform across all brands. This enables the components to transform their style based on the config file defined via the ThemeProvider component that should wrap the entire application that wishes to use these components.The config file selected depends on the value passed into the ThemeProvider (see example below).

import { ThemeProvider } from '@nxtdtc/dtc-component-library';

const Main = () => {
  return (
    <ThemeProvider theme="bri">
      <App />
    </ThemeProvider>
  );
};

The config file is composed of one large object that houses properties that define specific styles for that component. Each property within the larger object should correspond to the name of the component that it serves (see example below). All brands should have an identical config file layout so that components can access values in a uniform way.

import { colorPalette } from './colors';
const { ...colors } = colorPalette;
import { fonts, backupFontStack } from './fonts';

const config = {
  Button: {
    sizes: {
      default: {
        fontSize: '18px',
        padding: '11px 32px'
      }
    },
    primary: {
      backgroundColor: colors.CTA_BLUE,
      color: colors.WHITE,
      borderRadius: '8px',
      fontFamily: `${fonts.bodyMed}, ${backupFontStack.sans}`,
      fontWeight: 500,
      border: `2px solid ${colors.PRIMARY}`,
      lineHeight: '23.4px',
      letterSpacing: '0px',
      disabledBackgroundColor: colors.DARK_GRAY,
      disabledBorder: `2px solid ${colors.DARK_GRAY}`,
      cursor: 'pointer',
      hoverBackgroundColor: colors.CTA_BLUE_HOVER
    }
  },
  Link: {
    small: {
      fontFamily: `${fonts.bodyMed}, ${backupFontStack.sans}`,
      fontWeight: 500,
      fontSize: '12px',
      lineHeight: '18px',
      textDecoration: 'underline',
      color: colors.SECONDARY,
      hoverTextColor: colors.CTA_BLUE_HOVER
    },
    large: {
      fontFamily: `${fonts.bodyMed}, ${backupFontStack.sans}`,
      fontWeight: 500,
      fontSize: '16px',
      lineHeight: '24px',
      textDecoration: 'underline',
      color: colors.SECONDARY,
      hoverTextColor: colors.CTA_BLUE_HOVER
    }
  }
};

This object is consumable in each component via the withTheme HOC. This HOC grabs the config file provided by the ThemeProvider context and maps the name of the component to the corresponding property in the config file object. Any component that uses this HOC will have the themeProps prop accessible to them, which will equate to the object contained in the config file that corresponds to that specific component. One can then iterate through the themeProps object to extract the values needed for that component (see example below).

import React from 'react';
import withTheme from '../withTheme';

const Button = ({ themeProps }) => (
  <button
    style={{ backgroundColor: themeProps?.primary?.backgroundColor }}
  ></button>
);

export default withTheme(Button);

Styling Components with Styled Components


styled-components is used to style our components. This allows each component to have their own style file (Component.style.js) within the component's directory. The themeProps prop is typically passed into the component created by styled-components so that those style attributes can be applied to that component (see example below). Learn more about styled-components here: https://styled-components.com/

Button.js

import React from 'react';
import withTheme from '../withTheme';
import { StyledButton, TextContainer } from './Button.style';

const Button = ({ themeProps, disabled, variant }) => (
  <StyledButton
    disabled={disabled}
    variant={variant}
    themeProps={themeProps}
  ></StyledButton>
);

export default withTheme(Button);

Button.style.js

import styled from 'styled-components';

export const StyledButton = styled.button`
  background: ${({ disabled, themeProps, variant }) => {
    if (variant !== 'primary' && disabled) {
      return themeProps?.[variant]?.backgroundColor;
    }
    if (disabled) {
      return themeProps?.[variant]?.disabledBackgroundColor;
    }
    return themeProps?.[variant]?.backgroundColor;
  }};
`;

Storybook


Storybook allows us to develop and document the functionality of our components in isolation while also providing an interface in which developers and members from design or product can interact with these components. Each component should have a corresponding Component.stories.js file in it's directory. You can run storybook locally by running npm run storybook in the terminal.

Storybook Environments:

Stage: http://stage-clx-dtc-comp-lib.s3-website.us-east-2.amazonaws.com

Prod: http://clx-dtc-comp-lib.s3-website.us-east-2.amazonaws.com

Controls

Configurations for each component's Storybook stories take place in the component's directory under the file Component.stories.js. controls are Storybook's way to make the component's props interactive and dynamic, so that the person interacting with the component can see the different variations of this component. If a variation can not be made accessible through the component's controls, then an additional story for that component should be created to showcase that variation. You can read more about controls here: https://storybook.js.org/docs/react/essentials/controls

Stories

A story captures the rendered state of a UI component. It's a function that returns a component's state given a set of arguments. Stories are generated by creating an instance of the component with pre-populated args or props (see the example below). You can read more about stories here: https://storybook.js.org/docs/react/writing-stories/introduction

import React from 'react';

import { Button } from './Button';

export default {
  title: 'Button',
  component: Button
};

export const Main = (args) => <Button {...args}>Button</Button>;

Main.args = {
  variant: 'primary',
  size: 'large',
  noHover: true
};

Development Process


Create a new feature branch from the master branch. Follow the coding standards defined below:

Coding Standards


Each component will have it's own directory. Each directory should contain the following files:

  • index.js (where the component is exported)
  • Component.js (where the component is created)
  • Component.style.js (where the component is styled)
  • Component.spec.js (where unit tests for the component are written)
  • Component.stories.js (where Storybook stories are created)
  • README.md (documentation for the component)
index.js

As an optimization tehcnique, we use the @loadable/component library to split each component into it's own chunk when webpack bundles and serves the code to the storefront. Each component should be "chunked", then exported (see example below)

import React from 'react';
import loadable from '@loadable/component';

const ComponentTemp = loadable(() =>
  import(/* webpackChunkName: "ComponentChunk" */ './Component')
);

const Component = (props) => <ComponentTemp {...props} />;

export { Component };
Component.js

This file is where the component is created. Most components will use the withTheme HOC. This file should only contain logic specific to that component. Anything having to do with styling the component should remain in the corresponding Component.style.js file. All components' prop types should be verified via the prop-types library. All required and default props should be defined with this library as well. Flexibility to override styles when needed is necessary with most components. Please ensure that there is a style prop that can override key elements in the component.

Component.style.js

This file is where styling via styled-components should take place. All components created here should be exported and consumed in the Component.js file.

Component.spec.js

All components are required to have unit tests and should meet the following standards:

  • Each component needs a test and our pipeline will fail if any test fails or if test coverage is not met
  • Tests should replicate behavior in consumers
  • Tests should cover edge cases and non-happy paths (how could this break?)
  • Developers need to flag components that need manual QA and which sites should be tested
  • npm-link to consumer to make sure a component is working as expected

If the component uses the useMediaQuery hook, the mockMatchMedia function should be imported and executed before each test suite is run (see example below).

import Component from './Component';
import { render, mockMatchMedia } from '../../../testHelpers';

describe('Component', () => {
  beforeEach(() => {
    mockMatchMedia();
  });

  it('renders in the DOM correctly', async () => {
    const { getByTestId } = render(<Component text="hello" />);

    const myComponent = await getByTestId('my-component');
    expect(myComponent).toBeTruthy();
  });
});
README.md

All components are required to have a corresponding README, which documents what the component does, all of it's props (along with what the prop is used for and it's data type), the default props the component may have, an example of how the component is used, and any other additional information that may be useful for devs and members of other teams. The README will be brought into Storybook as a story (see example below).

Component.stories.js

All components will have controls and stories configured in this file. Please refer to the section above in this doc about Storybook for more information.

Useful Commands

npm install will install all necessary packages - be sure you are using Node >= 10

npm start will start webpack and evaluate changes in real time. This can be useful when linking with another app to test a new component or change.

npm run storybook will open a tab with storybook running on port 6006. Storybook is especially useful for building components in isolation and testing different permutations of props.

npm test will run the test suite

npm run coverage will run the test suite and output a coverage file at /coverage/lcov-report/index.html

npm run generate lib-component will take you through a series of questions that will result in a new directory being created for a new component containing all the necessary files for that component.


To Link With an Existing Project

You will want to test your changes as they would appear in the front end using this library. You can achieve this using npm link

In the component library terminal - npm link

In the front end application terminal - npm link @nxtdtc/dtc-component-library

If you run into issues it's best to nuke all node_modules in your front end app, reinstall and then re-link the library.

QA / Integration Process


New Components

If a new component has been created, please go through following steps for QA:

  • npm link your component into the storefront throughout development to ensure it is working as expected in the storefront
  • Submit a PR to stage and assign the PR to the dev assigned to review the corresponding ticket.
  • Once the dev has approved the PR, merge the branch into the stage environment.
  • Verify that your branch has been merged and deployed to the stage environment.
  • Notify members of the design team in the #designsystems Slack channel that this component is ready for design QA - provide a link to the component story on stage. Assign the Jira ticket to the member of the design team that wishes to review the work.
  • Once your work is approved by design, merge your branch into the master branch. Ensure that it has been successfully and merged and deployed.
  • Publish a new version of the component library in the master branch (view versioning instructions below).
  • Create a new ticket in Jira to integrate this new library version and to replace all necessary components in the storefront with the component library component.
  • Move this new ticket to the top of the backlogs in Jira. It will be assigned to a dev in the upcoming sprint.

In the ticket created for the consumer:

  • Update the package.json of the appropriate consumer
  • Include references to the new component
  • Update/create any integration tests to ensure component is working as expected in the consumer
  • Once the code is approved by a developer, the component is ready for manual QA in the consumer

Update Existing Components

If you are updating an existing component, please go through the following steps for QA:

  • npm link your component into the storefront throughout development to ensure it is working as expected in the storefront
  • Submit a PR to stage and assign the PR to the dev assigned to review the corresponding ticket.
  • Once the dev has approved the PR, merge the branch into the stage environment.
  • Verify that your branch has been merged and deployed to the stage environment and that it is working as expected.
  • Merge your branch into the master branch. Ensure that it has been successfully and merged and deployed.
  • Publish a new version of the component library in the master branch (view versioning instructions below).
  • Go into the storefront you wish to update the component in and create a feature branch. Update the component library version and ensure the component is working as expected.
  • Follow the normal development process for storefront features.

Versioning and Publishing


After your PR is approved and merged to master, cut a new version of the library and publish to our npm repository.

npm version minor|patch|major

minor should be used for the majority of changes which should be any NON-BREAKING change

major should be used for any BREAKING change and you and the reviewer should agree on whether this version upgrade is appropriate or not

patch should be reserved for hotfixes. For example, if we have recently published v1.3.0 but our front end app is using v1.2.0 and has a breaking error but we do not want the changes included in v1.3.0 then we will need to branch off v1.2.0 and make a patch to fix the issue introduced in this version without introducing unwanted changes in the most recent version.

After successfully creating the new version, publish it to npm using the following command: npm publish

To check that npm is now up to date with the most recent version, view this package on NPM. The Last Publish and Version sections should reflect recent changes.

Useful Libraries


3.10.1

9 months ago

3.10.0

9 months ago

3.10.2

9 months ago

3.11.0

9 months ago

3.11.1

9 months ago

4.4.0

1 year ago

4.3.0

1 year ago

3.9.1

1 year ago

4.6.0

11 months ago

4.2.0

1 year ago

4.5.0

12 months ago

4.5.1

12 months ago

4.1.2

1 year ago

4.1.1

1 year ago

3.6.0

1 year ago

4.0.0

1 year ago

3.9.0

1 year ago

4.0.1-0

1 year ago

3.7.1

1 year ago

3.7.0

1 year ago

4.0.0-beta.3

1 year ago

4.0.0-beta.0

1 year ago

4.0.1-beta.1

1 year ago

1.18.0

3 years ago

2.46.0

2 years ago

2.23.1

2 years ago

2.27.0

2 years ago

2.11.0

2 years ago

2.34.0

2 years ago

2.4.0

3 years ago

2.30.0

2 years ago

2.8.0

2 years ago

1.21.0

3 years ago

2.0.1

3 years ago

2.0.0

3 years ago

3.2.2

2 years ago

3.2.1

2 years ago

3.2.0

2 years ago

2.19.0

2 years ago

2.9.2

2 years ago

2.9.1

2 years ago

2.15.0

2 years ago

2.34.1

2 years ago

2.45.0

2 years ago

2.22.0

2 years ago

2.41.0

2 years ago

1.19.0

3 years ago

2.49.0

2 years ago

2.26.0

2 years ago

2.10.1

2 years ago

2.3.0

3 years ago

2.33.0

2 years ago

2.10.0

2 years ago

2.7.0

3 years ago

2.3.4

3 years ago

2.3.6

3 years ago

2.3.5

3 years ago

3.1.0

2 years ago

3.5.0

1 year ago

2.18.0

2 years ago

2.37.0

2 years ago

2.14.0

2 years ago

2.21.0

2 years ago

2.44.0

2 years ago

2.40.0

2 years ago

1.16.0

3 years ago

2.29.0

2 years ago

2.25.0

2 years ago

2.48.0

2 years ago

2.32.0

2 years ago

2.2.1

3 years ago

2.2.0

3 years ago

2.32.2

2 years ago

2.2.3

3 years ago

2.32.1

2 years ago

2.2.2

3 years ago

2.6.0

3 years ago

3.4.0

1 year ago

2.31.1-beta.0

2 years ago

2.3.8

3 years ago

2.3.7

3 years ago

2.17.0

2 years ago

3.0.0

2 years ago

2.36.0

2 years ago

2.13.2

2 years ago

2.32.3

2 years ago

2.13.0

2 years ago

2.36.1

1 year ago

2.13.1

2 years ago

2.43.0

2 years ago

2.20.0

2 years ago

1.17.0

3 years ago

2.28.0

2 years ago

2.47.0

2 years ago

2.31.0

2 years ago

2.12.0

2 years ago

2.5.0

3 years ago

2.1.0

3 years ago

1.20.0

3 years ago

3.3.0

1 year ago

2.39.0

2 years ago

2.35.0

2 years ago

2.16.0

2 years ago

2.12.1

2 years ago

2.42.0

2 years ago

2.23.0

2 years ago

1.15.0

3 years ago

1.5.1-dc-4651.0

3 years ago

1.14.0

3 years ago

1.12.0

3 years ago

1.11.0

3 years ago

1.13.0

3 years ago

1.11.1

3 years ago

1.9.1

3 years ago

1.9.0

3 years ago

1.7.0

3 years ago

1.10.1

3 years ago

1.10.0

3 years ago

1.6.1

3 years ago

1.6.0

3 years ago

1.5.1-dc-4518.0

3 years ago

1.5.0

3 years ago

1.4.0

3 years ago

1.3.0

3 years ago

1.2.0

3 years ago

1.1.0

3 years ago

1.0.0

3 years ago

0.46.0

3 years ago

0.44.2

3 years ago

0.46.1

3 years ago

0.44.1

3 years ago

0.46.1-0

3 years ago

0.48.4

3 years ago

0.47.3

3 years ago

0.47.4

3 years ago

0.47.1

3 years ago

0.47.2

3 years ago

0.47.0

3 years ago

0.45.0

3 years ago

0.44.0

3 years ago

0.43.0

3 years ago

0.42.0

3 years ago

0.41.0

3 years ago

0.40.0

3 years ago

0.39.0

3 years ago

0.38.0

3 years ago

0.37.0

3 years ago

0.36.0

3 years ago

0.35.0

3 years ago

0.34.1

3 years ago

0.34.0

3 years ago

0.33.0

3 years ago

0.32.0

3 years ago

0.31.0

3 years ago

0.30.0

3 years ago

0.29.0

3 years ago

0.28.0

3 years ago

0.27.0

3 years ago

0.26.0

3 years ago

0.25.0

3 years ago

0.24.0

3 years ago

0.21.0

3 years ago

0.23.0

3 years ago

0.22.0

3 years ago

0.20.0

3 years ago

0.19.0

3 years ago

0.17.0

3 years ago

0.18.0

3 years ago

0.16.0

3 years ago

0.15.0

3 years ago

0.13.0

3 years ago

0.14.0

3 years ago

0.12.0

3 years ago

0.11.0

3 years ago

0.10.0

3 years ago

0.9.0

3 years ago

0.8.0

3 years ago

0.7.1

3 years ago

0.7.0

3 years ago

0.6.0

3 years ago

0.5.0

3 years ago

0.4.0

3 years ago

0.3.2

3 years ago

0.3.1

3 years ago

0.3.0

3 years ago

0.2.1

4 years ago

0.2.0

4 years ago