# Contributing to Axiom Component Library

## General

1. Create branch - follow the branching guidelines: `git checkout -b user/[username]/[branch-name]`
2. Make and commit your changes
    - If you're creating a **NEW** component in src/components, you'll need to do the following 3 things:
        1. Add it to the public component interface (src/main.js)
        2. Add to the type definition file (types/templates/module-declaration.d.ts). This makes consumers aware of the component and its types.
        3. Add an entry for the CSS (src/oui/\_oui-partials.scss)
3. `git push` your changes to GitHub
4. [Open a pull request](https://github.com/optimizely/axiom/compare) of your branch, add at least one reviewer
5. Review the results of Chromatic's visual regression tests. See below for [more info about VRT](#-using-chromatic-visual-regression-testing-vrt)
6. Once you've merged your PR, please follow the instructions to [Release a New Version](https://github.com/optimizely/axiom/blob/devel/CONTRIBUTING.md#ship-release-a-new-version).

## Writing Components

-   Use Typescript and add descriptions for the props.
    _Example:_

    ```ts
    export interface GridProps {
        /** Child elements. */
        children?: any;
        /** CSS class names. */
        className?: string;
        /** Ref to the component. */
        ref?: Ref<HTMLElement>;
        /** Customize the tag element (defaults to 'div'). */
        tag?: ElementType;
    }
    ```

-   Don't use default exports.
    _Example:_

    -   Prefer this:

        ```tsx
        export const Grid: FunctionComponent<GridProps>;
        ```

    -   Avoid this:

        ```tsx
        export default Grid;
        ```

-   Prefer composition over props. It's not always obvious when a value should be a prop or child element. Do your best to make the component easy to use, and allow the users to create their own level of abstraction.
    _Example:_

    -   Prefer this:

        ```tsx
        <Button>Button Label</Button>
        ```

    -   Avoid this:

        ```tsx
        <Button label="Button Label" />
        ```

-   Component names must be written in PascalCase.
-   Component must have its name as a `class` on the root element, written in kebab-case and prefixed with `axiom`.
    _Example: The component `Grid` will have the class `axiom-grid`._

-   Make it possible for teams to add customizations when necessary without being blocked:

    -   Accept an optional `className`. The string should be appended to the components existing class.
        _Example: `<Grid className="approve"...>` renders `class="axiom-grid approve"`._
    -   Pass down any extra props to the root element.
        \_Example: `<Grid ohHello="but why?"/>` should pass on the `ohHello` prop to the underlying component.

        ```tsx
        // This example demonstrates how to support customization.

        interface GridProps {
            /** CSS class names. */
            className?: string;
        }

        export const Grid: FunctionComponent<GridProps> = forwardRef(
            ({ className, ...props }, ref: Ref<HTMLElement>) => (
                <div className={classNames("axiom-grid", className)} {...props} />
            )
        );
        ```

-   Add Storybook stories to demonstrate component functionality.
-   Use the component's name for the file names (not `index`), and use the extension `.tsx` instead of `js`.
    -   `grid.tsx`
    -   `grid.test.tsx`
    -   `grid.story.tsx`
    -   `grid.scss`
-   Make sure to sync your component's name with UX. Component names in the Axiom component library should match those in the guidelines and Figma.

## Using Chromatic Visual Regression Testing (VRT)

Each pull request will automatically trigger a build in Chromatic to visually test every Storybook story. After the checks finish running on your PR, be sure to address any discrepancies in Chromatic, either by accepting the new snapshot (thus making it the new baseline) or denying the change and fixing any issues in your PR. For more information, refer to the [Chromatic documentation](https://docs.chromaticqa.com/).

### Disabling Chromatic for a Story

Sometimes you don't want Chromatic to run on a particular story, either because you are expecting changes or the story is repetitive. In this case, you can use a parameter on the story to disable chromatic:

```
stories.addParameters({ chromatic: { disable: true } });
```

### VRT for Dates

To prevent stories from failing VRT tests due to system time being used, consider setting the time in the story itself or disabling chromatic for that story if manually setting the time is not applicable.

## Creating a Release

1. Get the latest code: `git checkout master && git pull && git checkout devel && git pull`
2. Run `yarn axiom release --dry-run` to get the version number of the release
3. From devel, create a release branch: `git checkout -b release/x.x.x`, where `x.x.x` is the version from the previous step
4. Run `yarn axiom release`. This will automatically do the following:
    - Bump the version number following semantic versioning
    - Update the changelog
5. Verify that everything looks correct and do a release commit: `git add . && git commit -m 'release: Axiom vx.x.x'`
    - If a lot of corrections were needed, push the release branch to github and open a PR to master
    - Otherwise, merge directly to master locally: `git checkout master && git merge release/x.x.x`
6. Tag the release `git tag -a vx.x.x -m "release: Axiom vx.x.x"` and push `git push --follow-tags`
    - In case you need to delete the tag remotely: `git push --delete origin vx.x.x`
7. Merge master branch into devel and push devel
8. [Create a new release on GitHub](https://github.com/optimizely/axiom/releases/new):
   - Select the new tag version
   - Leave “Release title” blank
   - Paste in new release contributions from the `CHANGELOG.md` release notes into the Description field
   - Click Publish Release
9. Check if the release was successful:
   - Check [NPM](https://www.npmjs.com/package/optimizely-oui) for the updated release.
   - If it seems to stall, check [travis](https://travis-ci.com/github/optimizely/axiom/builds) and make sure no errors occurred.
10. You're done!
