![](https://www.politico.com/interactives/cdn/images/badge.svg)

@politico/interactive-style
===========================

This library is an ever-evolving implementation of [our design standards for
interactive projects][figma]. The goal of the library is to make it as easy and
seamless as possible to step from Figma into code. It should serve as
a one-stop shop for everything you need to build a POLITICO Interactive story,
whether you're working on an elections-specific project or not.

## Quick start

Looking to dive right in? 🚀

Install the library as a dependency, and then you can start using the various
pieces provided as you need them. Note that `v4` of this library is still in
pre-release, so you have to specify that that's what you want:

```
npm install "@politico/interactive-style@>=4.0.1-rc.0"
```

### Styles

You may want to include our standard CSS theme in your global stylesheet.

```css
@use "~@politico/interactive-style/int.scss";

@include int.theme();
```

That will give you a nice foundation on which to use more specific styles in
your components. All of our style utilities are provided as SCSS variables and
mixins, and we export them all from the `int.scss` stylesheet. The easiest way
to use things like our colors, our spacing variables, or our more complicated
mixins is to `@use` our main stylesheet and access what you need under the
`int` namespace:

```css
@use "~@politico/interactive-style/int.scss";

.container {
  color: int.$gray-90;

  @include int.sans($size: "300");

  @include int.is-desktop() {
    @include int.sans($size: "500");
  }
}
```

### JavaScript

This library also provides a host of components and utilities for use in your
JavaScript. Everything is available as a named export at the top level of the
library.

All of our components can be imported and used directly in your own components.

```jsx
// importing several components
import { Well, Grid, GridItem } from '@politico/interactive-style';

// using them in your component
<Well>
  <Grid>
    <GridItem>Column 1</GridItem>
    <GridItem>Column 2</GridItem>
  </Grid>
</Well>
```

And our hooks and utilites can be imported the same way.

```js
// importing a utility
import { sortBy } from '@politico/interactive-style';

// using it in a function or component
const items = [
  { name: 'Steph', number: 30 },
  { name: 'Klay', number: 11 },
  { name: 'Draymond', number: 23 },
];
const sortedItems = sortBy(items, ['name', 'number']);
```

## How to use the docs in Storybook

The package of documentation in Storybook includes two different kinds of docs:
guides and API documentation. The guides offer high-level introductions to
various concepts addressed by this library, like how our content follows a grid
to give the page consistent structure; all the guides are found under the
"GUIDES" header in the left nav. The API documentation offers more fine-grained
and exhaustive details on all the components, mixins, hooks, and utilities
provided by this library. If you're looking for an abstract description of our
typography system, you should probably start with the typography guide. If
you're looking for documentation on the arguments that the `sortBy` utility
accepts, you should look for its API documentation in the utilities section.

## Toward Reusability

This library is a result of the Toward Reusability project, [documented here in
Notion][notion]. The project was an effort to create a foundation for reusable
standards and components for any individual contributor in the POLITICO
Interactive News team to use as a basis for their work. The result is
a living, iterative system for the design and development of interactive
projects.

As our needs continue to evolve this project will need to evolve with them.
Every user of this system should feel empowered to identify shortcomings, gaps,
and opportunities for improvement or expansion — and they should also feel
empowered to contribute to meeting those needs.

## Questions, comments, feedback

Anna Wiederkehr and Andrew Milligan were the main contributors responsible for
the foundations of this library. Please direct your inquiries or concerns
towards them. The relevant stakeholders are Andrew McGill and Allan James
Vestal.

## Developing this library

[Clone the repo][repo] and install dependencies.

```shell
npm install
```

You can run [Storybook][] locally to see your changes as you develop them.

```shell
npm run storybook
```

Once it starts up, you should be able to see Storybook running at
http://localhost:6006.

You can run unit tests locally. We use unit tests to test easily testable
functions like utilities, and we use stories in Storybook to test React
components and to provide visual documentation for everything this library
provides. So don't be surprised if you run unit tests and only see utilities
being tested.

```shell
npm run test
```

You can also lint all of the JS and SCSS in the project.

```shell
npm run lint
```

### Dummy Election Data in Storybook

Two types of mock election data can be included in stories: randomly generated
data and data sourced from an AP results API snapshot.

#### Using AP data

In order to make an AP snapshot available for use as dummy data, retrieve it
from the API, make any adjustments/tweaks to it that you want, and then save it
in a JSON file in `.storybook/static/ap-snapshots`. For example, you might
take a snapshot and store it as

```shell
.storybook/static/ap-snapshots/2022-11-08-nm-gov-general.json
```

The path of the file from the `ap-snapshots` directory to the `.json` extension
will be used as the identifier of this snapshot in storybook, so this example
can be referenced as `2022-11-08-nm-gov-general`.

Once a snapshot is available, you can reference it in a story's dummy data
configuration like this:

```js
// in an index.stories.js
import { getElectionDataParameters } from 'Utils/storybook/withElectionData';

const parameters = getElectionDataParameters([{
  apSnapshot: '2022-11-08-nm-gov-general',
}]);
```

or using `withElectionData` like this:

```js
// in a specific story file
import { withElectionData } from 'Utils/storybook/withElectionData';

// define your story like normal
const MyStory = Template.bind({});

export default withElectionDataParameters(MyStory, [{
  apSnapshot: '2022-11-08-nm-gov-general',
}]);
```

### Helpful scripts

#### `makeComponent`

This library provides a `makeComponent` script to help with creating new
components from JSON blueprints. You can define a component blueprint in the
`blueprints` directory and then run the script with:

```shell
npm run makeComponent -- --blueprint blueprints/<MyBlueprint>.json
```

The blueprint should have the following structure:

```js
{
  "section": "elections", // the directory within components
  "name": "MyComponent", // the name of the component (pascal case)
  "description": "Tk...", // the doc comment describing the component
  "props": [
    {
      "name": "foo", // the name of the prop
      "description": "Tk...", // the doc comment describing the prop
      "type": "string", // the PropTypes type of the component
      "isRequired": true, // whether the prop is required
    },
    {
      "name": "bar",
      "description": "Tk...",
      "type": "bool",
      "default": false, // default value
    },
    {
      "name": "variant",
      "description": "Tk...",
      "type": "oneOf",
      "options": [ // the options for a `oneOf` type prop
        "a",
        "b",
        "c",
      ],
      "default": "a",
    },
  ],
  "stories": [
    {
      "name": "MyStoryName", // name of the story
      "args": { // prop values to pass to story (appropriately typed)
        "propName": "propValue",
        "expandable": "aggregationOnly"
      },
      "description": "Tk...", // description of the story
      "apSnapshot": "snap/shot" // name of AP snapshot for story
    },
  ]
}
```

Don't forget the extra `--` to pass flags to the script through npm!

## Publishing Storybook

You can publish a new version of Storybook with:

```shell
npm run docs:pub
```

If you only want to _build_ Storybook and not publish it, you can do that with:

```shell
npm run docs:build
```

## Publishing the Library

You can build the library with:

```shell
npm run build
```

If you want to run the build in watch mode so that it rebuilds every time you
change a file you can run:

```shell
npm run build:watch
```

You can release a new version of the library with:

```shell
npm run release
```

The release script accepts several arguments (remember to include `--` between
`npm run release` and your additional arguments):

- `--message` (or `-m`) lets you set a custom git commit message to describe
  the release. Note that your custom message will be automatically prefixed
  with the version number, so you if provided the message `"Hello world"` while
  releasing v1.0.0, the commit message will be `v1.0.0: Hello world`. By
  default the message will just be the new version number.

- `--step` (or `-s`) lets you specify how to increment the version number.
  Valid choices are `patch`, `minor`, `major`, `premajor`, `preminor`,
  `prepatch`, and `prerelease`. Note that `--version` takes precedence over
  `--step`. Generally choose `patch` (wich will increment the last number,
  i.e., `2.2.x`) if you're releasing a bug fix and choose `minor` (which will
  increment the second number, i.e., `2.x.2`) if you're releasing a new
  feature. The default is `patch`.

- `--version` (or `-v`) lets you specify a specific version number, useful if
  you want to skip a version for some reason, or provide more nuance to the
  semantic version. Note that `--version` takes precedence over `--step`.

- `--preid` lets you specify the pre-release identifier (i.e., `rc` in
  `2.0.1-rc.0`). This is `rc` by default. It's only used when you release
  a "pre" version using one of the `pre*` values for `step`.

The release script will automatically build the library, increment the version
number in `package.json`, commit the bumped version with a commit message that
includes the new version number, tag the commit with the version number,
publish the package to npm, and push the changes along with the new tag.

[Storybook]: https://storybook.js.org/
[figma]: https://www.figma.com/file/UZ7aW8pD6xWbiE3un0Gokr/DRAFT%3A-Reusability-Guidelines?node-id=0%3A1&t=Rvowo4oT5Q5YduCy-1
[notion]: https://www.notion.so/the-politico/Toward-Reusability-caef79efe8284c2d808a2bc4b3214e91
[repo]: https://github.com/The-Politico/politico-interactive-style
