# Patchwork Implementers' Guide

So, you need to add something to Patchwork. Here's the skinny.

## Where do I put my Component?

There are a few spots in the repo where you could put your shiny new component. Here's how to decide:

##### Is it from the design team's widget library in Sketch/Abstract?

Put it in `/core`

Where in core? Wherever the component lives in Abstract / Zeplin.

- if the component is in the Actions page in Abstract, it should go into `/core/actions/component_name`
- if the component is in the Templates page in Abstract, it should go into `/core/templates/component_name`
  ^ these folders may not be created yet, but for any new components that are added, they should follow this folder structure

The `component_name` is subjective, if it's called `Actions/Buttons/Secondary/Disabled`, a good name for it may be `./actions/secondary-button`, where `disabled` is a prop.

##### Is it a straight up port of something in Fabric, Terminal, or ws-directives?

Put it in `/legacy`

##### Is it a low-level, general purpose, simple thing?

Put it in `/primitives`

##### Is it a special case for a fancy one-off design?

Keep it in your micro app. Or, if it's used in more than one place, but it's not in the Design Widget Library, put it in `/one-off`.

##### Is it a cross-cutting concern?

E.g. a set of props that could apply to a bunch of different components, it might be a good candidate for a `mixin`. Post in #patchwork (Slack) and discuss.

## We're doing CSS _HOW_?

This lib is using [Styled Components](https://www.styled-components.com/) for CSS. As of 2018 this has become a fairly mainstream approach for React in particular. It provides:

- a syntax that is CSS, not weird CSS-in-JS stuff
- but which allows you to use JS to compute things if needed
- and which scopes your styles to your component,
- but which has a powerful theming mechanism built-in.

Basically styled components gives you the ability to attach CSS rules to a JSX element:

```js
import styled from 'styled-components';

const RidiculousParagraph = styled.p`
  font-size: 400px;
  border: dotted 1000px;
  border-radius: 100%;
  font-family: 'Papyrus'; // Try to avoid non-theme custom fonts in real life.
`;

const RidiculousComponent = () => (
  <RidiculousParagraph>But Papyrus looks so profesh</RidiculousParagraph>
);
```

You can also extend another styled component if you want to make a variant of it:

```js
const SlightlyLessRidiculousParagraph = RidiculousParagraph.extend`
  border: none;
`;
```

Or wrap a regular React component:

```js
import { LoadingIndicator } from '../primitives';

const BorderedLoadingIndicator = styled(LoadingIndicator)`
  border: dashed purple 10px;
`;
```

**But SCSS was so POWERFUL**

So is JavaScript:

```js
import { LoadingIndicator } from '../primitives';
import { Color } from 'colors';

const computeColorFromProps = props =>
  Color(props.theme.colors.secondary.default)
    .darken(0.5)
    .rgb()
    .string();

const BorderedLoadingIndicator = styled(LoadingIndicator)`
  border: dashed ${computeColorFromProps} 10px;
`;
```

The dream is to have the scoping of React, the power of JavaScript, and the familiarity of CSS.

## Anatomy of a Component

> Tip: Use the Generator (`yarn generate`)

AKA "Seth y u make so many _files_"

I don't go to this level when writing React components in app code. In app code, simplicity is best. However because patchwork is a shared library that generates its own documentation, there are a few extra bells and whistles that I like to put on its component implementations.

Here's how I like to roll in this repo specifically:

- `/core/amazing-thing/AMAZING_THING.mkd`: docs that show up for the info button in story book.
- `/core/amazing-thing/amazing-thing.proptypes.js`: Flow types for the component so your editor/CI yells at you when you pass an invalid prop. React proptypes for the component so your _browser_ yells at you when you pass an invalid prop. Also so storybook can document your props. And also so patchwork can be consumed by Atlas, which doesn't do Flow (yet).
- `/core/amazing-thing/amazing-thing.story.js`: usage examples for Storybook.
- `/core/amazing-thing/amazing-thing.css-rules.js`: when I have dynamically computed values for CSS rules in a component, I group them in this file to keep the clutter out of the main component file.
- `/core/amazing-thing/index.js`: the component implementation. Should show at a glance what the JSX and CSS is. This is so designers don't need to learn the entire internet in order to make quick adjustments to a component's DOM or styles.

Here's an example index.js:

```js
// @flow
import styled from 'styled-components';
import type { TextProps } from './text.proptypes';
import { textPropTypes } from './text.proptypes';
import type { PatchworkComponent } from '../../../types';
import { getSpacingRules } from '../../../mixins/spacing';
import { getForegroundColor } from './text.css-rules';
import {
  getTextAlign,
  getFontSize,
  getFontStyle,
  getFontFamily,
  getTextDecoration,
  getTextTransform,
} from '../../../mixins/typography';

// The component itself.  Note how clear the CSS is.
// Also note the flow type: PatchworkComponent<TextProps>
export const Text: PatchworkComponent<TextProps> = styled.p.attrs({
  style: getSpacingRules,
})`
  color: ${getForegroundColor};
  text-align: ${getTextAlign};
  font-size: ${getFontSize};
  font-style: ${getFontStyle};
  font-family: ${getFontFamily};
  text-decoration: ${getTextDecoration};
  text-transform: ${getTextTransform};
`;

// Always set a display name so React devtools shows the component properly.
Text.displayName = 'Text';

// Enable runtime prop checking in React devtools
Text.propTypes = textPropTypes;
```

## Mixins: Cross-Cutting Concerns

The files in the `src/mixins` folder provide common sets of logic and property types that can be 'mixed in' to more than one type of component.

#### Example: Using the Spacing Mixin:

If you're writing a new Patchwork component that needs to support the `spacing` property, don't rewrite all that logic from scratch: 'mix it in':

```js
import type { SpacingProps } from '../../mixins/spacing';
import { spacingPropTypes } from '../../mixins/spacing';

// Mix in the flow typedefs for the spacing prop.
type MyComponentProps = {
  /* ... */
} & SpacingProps;

// Use the getSpacingRules utility to generate the correct CSS.
export const MyComponent = ({ theme, spacing }: SpacingProp & ThemeProps) => (
  <div style={{ ...getSpacingRules({ theme, spacing }) }}>{/* ... */}</div>
);

// Mix in the react PropTypes for the spacing prop.
MyComponent.propTypes = {
  /* ... */
  ...spacingPropTypes,
};
```

## Whitelabeling and Colors

TL;DR: custom colors NO BUENO

Read and understand Patchwork's [color system concepts](https://github.com/wealthsimple/patchwork/blob/master/src/mixins/branding/BRANDING.mkd). Then use `getColor` from `theme/theme.utils` to set any CSS props that require a color.

## Translations

Patchwork itself has no concept of a string table. It's up to micro-apps themselves to define their string tables and pass the translated strings into patchwork components.

This means **you can't have hard-coded strings in patchwork's JSX**.

How should we pass strings in then?

The convention we're using is based on [render props](https://reactjs.org/docs/render-props.html):

**Definition:**

```js
import type { TranslatedContent } from '../types';
import { TranslatedContentPropTypes } from '../types';

type MyProps = {
  title: TranslatedContent,
  content: TranslatedContent,
};

const MyPropTypes = PropTypes({
  title: TranslatedContentPropTypes,
  content: TranslatedContentPropTypes,
});

export const MyComponent = ({ title, content }: MyPropTypes) => (
  <Box>
    <Head3>{title}</Head3>
    <Text> {content}</Text>
  </Box>
);
MyComponent.propTypes = MyPropTypes;
```

**Usage:**

`TranslatedContent` is defined such that it can be a string, a `FormattedMessage` element, or a `FormattedHtmlMessage` element:

```js
import { injectIntl } from 'react-intl';

const ImUsinUrComponentWithStrings = injectIntl(({ intl }) => (
  <MyComponent
    title={intl.formatMessage({ id: 'foo:bar' })}
    content={intl.formatMessage({ id: 'foo:baz' })}
  />
));
```

```js
import { FormattedMessage } from 'react-intl';

const ImUsinUrComponentWithFormattedMessage = () => (
  <MyComponent
    title={<FormattedMessage id="foo:bar" />}
    content={<FormattedMessage id="foo:baz" />}
  />
);
```

```js
import { FormattedHTMLMessage } from 'react-intl';

const ImUsinUrComponentWithFormattedHTMLMessage = () => (
  <MyComponent
    title={<FormattedHTMLMessage id="foo:bar" />}
    content={<FormattedHTMLMessage id="foo:baz" />}
  />
);
```
