import { Meta } from '@storybook/addon-docs';

<Meta title="Docs/Getting Started/Styling components" />

# Styling components

 *note: "components" in the current document refers to both atoms and components*

 We follow the BEM methodology to structure our CSS.

## Basic namespacing

Each React component has styles defined in its own .scss file and imported in the component file:

`import './styles/MyComponent.scss';`

The styles for a component are always namespaced with the component's namespace through use of the `namingTools.js` util:

`const n = createNamespace('MyComponent');`

You can then use this namespace `n` to attach classes and modifiers to any HTML element that needs it within the component. To do so, prefix the camel-case inflexed namespace to an identifier:

`<div {...n('someElement').props}>` results in `<div class="myComponent_someElement">`

The SCSS would look like this:

```
.myComponent {
	&_someElement {
		margin-bottom: 20px;
	}
}
```

Note that the `n` function always returns an object. Ensure that the `props` property is spread within the element's props to apply.

### Modifiers

Add different modifiers to an element's classes through the second argument of the naming tools:

`<div {...n('someElement', 'foo').props}>` results in `<div class="myComponent_someElement myComponent_someElement--foo">`

The argument can also be an array of modifiers:

`<div {...n('someElement', ['foo', 'bar']).props}>` 
 results in
`<div class="myComponent_someElement myComponent_someElement--foo myComponent_someElement--bar">`

### CSS Variables

Some values cannot be known at compile time, so you have to make them accessibe to stylesheets at runtime. For example, styling values that come from user settings are only available at runtime and are not known at compile time. To pass these values to the component, you can use CSS variables, built with the help of the namespacing tool's `withVariables` method. 

`withVariables` takes a single argument that consists of an object of variableName => value props that will be built as CSS variables styles.

`<div {...n('someElement').withVariables({foo: '10px', bar: '#fff'}).props}>` 
would result in:
`<div class="myComponent_someElement" style="--foo: 10px; --bar: #fff">`

In SCSS, the variables can be used like this:

```
.myComponent {
	&_someElement {
		margin-bottom: var(--foo);
		div {
			color: var(--bar, #000);
		}
	}
}
```

*We recommend that you only use CSS variables in lowercase to ensure that the tests can capture the variables. If multiple-word variable names are necessary, use kebab-case.*

### Additional classes

If it is necessary to add supplemental classes to an element outside of the BEM structure, use the `withClass` method of the naming tools, which takes an array of class names as arguments and adds them to the generated BEM class names:

`<div {...n('someElement').withClass(['foo', 'bar']).props}>` 
results in:
`<div class="myComponent_someElement foo bar">`

## Global variables and mixins

Some of the basic styles of the theme can be modified by global user settings, set through a form available in the admin interface. Therefore, these values cannot be hardcoded in the component's SCSS but come from global CSS variables injected by the system. We recommend that you always use the mixins that use these variables whenever possible in order to benefit from the user settings. Mixins are in the files located in `src/styles/definitions`.

### Text

Text dimensions and fonts are set through global settings, and you can attach their properties to an item with the appropriate mixins. For example, to make an element look like the level 1 title, you can do something like this:

```
.myComponent {
	&_title {
        @include title-1;
    }
}
```

If the user changes the text size through admin settings, this title would follow the correct user-defined styles because the mixin uses the CSS variables that contain these settings.

### Colors

The component's theme is built using a limited set of colors that are centralized in the `src/styles/definitions/_colors.scss` file. Basically, the theme consists of:

- **body color**: regular text color
- **title color**: regular title color
- **link color**: regular link color
- **primary color**: the theme's main, most prominent color
- **secondary color**: a color that complements the primary color
- **emphasis color**: a color that is applied to elements that should stand out, for example calls to action
- **emphasis color alt**: a color that is applied to elements that should stand out, but in opposition to emphasis elements

SCSS variables are set to hold these values for reuse across the component's SCSS files. These SCSS variables get their values from CSS variables, and default to hardcoded values. We recommend that you not introduce supplemental colors and that you use the ones defined in the theme to ensure consistency, but also to avoid clashes with potential user-defined colors.

Some of these colors also have variations: a lighter shade to use as hovers, and a darker shade to use for active elements. These variations are also set in variables, and are precomputed from the original color, whether the default or user-defined.

There should not be any hardcoded color values anywhere in the component's SCSS. **All color values should come from variables set in the `_colors.scss` file, or from user-defined values that come from the component's schemas.**

Some other hardcoded colors exist in the colors file that can be used in components, but are mostly functional. For example, an error color (red by default) can be used to display errors in a standard way.

## Responsive

### CSS

There are predefined breakpoints in the SCSS mixins in the `src/styles/definitions/_breakpoints.scss` file, which you should  used whenever responsive is necessary. There are breakpoints for small mobile up to large desktop displays. Generally, design is approached in a responsive way, in that the original integrations are made for desktop and then adapted for mobile.

The breakpoints available in CSS are `xxs`, `xs`, `sm`, `md`, `lg`, `xl` and `xxl`.

### JSX
Sometimes responsiveness cannot be achieved merely by CSS, such as when developing components for use in different containers whose sizes are not entirely dependent on the window size. For example, a component container might be 50% of the grid width in some cases and 100% in others. Because components are encapsulated and should rely as little as possible on their parents or context to be displayed correctly, it is sometimes necessary to respond to a component's rendered dimensions.

Several custom hooks exist to measure an element's dimensions, located in `/src/tools`. You can pass the values computed by these hooks to CSS with variables through the namespace's `withVariables` method, or use them to add BEM modifiers to elements. In other cases, it is possible to use these values to completely change a component's rendered output.

#### `useResponsive` hook

The `useResponsive` hook reproduces the behavior of the SCSS breakpoints, but in JavaScript so that the components can act according to these breakpoints. For example, a component might need to render something else entirely depending on breakpoints. 

The breakpoints used in JS should be the same ones as, or a subset of, those in CSS for the app to be consistent, and therefore they are centralised in a hook. The hook listens to changes in screen dimensions and responds with booleans for each of the set breakpoints that indicate whether they apply.

The breakpoints used in JS are `small`, `medium`, `large`, `xLarge`.

The hook outputs an object with each breakpoint, which changes whenever the screen dimensions change:

```
{
	smallDown: false,
	smallUp: true,
	mediumDown: false,
	mediumUp: true,
	largeDown: true,
	largeUp: false,
	xLargeDown: true,
	xLargeUp: false
}
```
 
You can use it in a component like this:

```
const { mediumUp } = useResponsive();
const someRender = mediumUp ? <div>The screen is larger than medium</div> : null;
```


