# sfb-theme-components

Components used by the storefront builder to build themes.

### Local development
* Install [sfb-toolkit](https://help.appdirect.com/platform/Default.htm#StorefrontBuilder/sfb-install-dev-tool.htm%3FTocPath%3DCustomize%2520the%2520storefront%7CWork%2520with%2520the%2520Storefront%2520Toolkit%7C_____1).
* Setup a theme project with a Plaza theme: `sfb-toolkit setup`.
* Start the `sfb-toolkit` local server: `sfb-toolkit start`.
* Start the `sfb-theme-components` local server to serve the bundles: `npm run start`
* You can do the [resource override](https://chrome.google.com/webstore/detail/resource-override/pkoacgokdfckfpndoffpifphamojphii?hl=en) for the js and css: 
    - From: `https://*/sfb-theme-components@0/sfb-components.js` to `http://localhost:3444/sfb-components.js`
    - From: `https://*/sfb-theme-components@0/sfb-components.css` to `http://localhost:3444/sfb-components.css`
### Storybook
To view the components, we can start the Storybook server:
* Run `npm run storybook`.
* Navigate to `http://localhost:8087/`.
* On the left hand navigation bar, selecting a Component/Atom will render the component in the main section.
* We are using [Storybook Knobs](https://storybook.js.org/addons/storybook-addon-knobs-color-options) to update the component's settings prop in Storybook.

### Creating custom components for your theme
* Start the Storybook server: `npm run storybook`
* Go to the [Custom components documentation](http://localhost:8087/?path=/story/docs-customization-custom-components--page) for more info.

### CSS - Naming convention
We're gonna follow modified version of: https://css-tricks.com/abem-useful-adaptation-bem/
* **NO** a/o/m prefixes
* Names with more then one term should use *camelCase* convention instead of `-`
* Modifiers are using `--` (double dash) and are connected with the name

Examples: 
```jsx
// just an element, nothing to see
<div class="blockName_elementName"></div>
```
```jsx
// with a modifier
<div class="blockName_elementName blockName_elementName--modifier"></div>
```
For more detailed examples please take a look in section `CSS - Naming Tool`

### Component's structure
There are two folders for components:
* `atoms/` which should include very basic, easily re-usable across different themes and styling components like *Image*, *Button*, *Header*, etc.
* `components/` should contain components that are more specific for a theme, most of the time are including one or more *atom* components


### Doing Responsive
* Flex https://markus.oberlehner.net/blog/creating-a-responsive-alternating-two-column-layout-with-flexbox/
* Hiding elements https://markus.oberlehner.net/blog/poor-mans-container-queries-hide-content-based-on-the-width-of-its-container/

* **DO NOT use media queries**

### Proptypes and functional components are inforced

* Functional component example https://reactjs.org/docs/hooks-state.html
* Follow Clean Code best practices https://github.com/ryanmcdermott/clean-code-javascript

### CSS - Naming Tool
There has been implemented namingTool to help out follow above CSS naming structure:

Every component should contain: 
```js
import { createNamespace } from './tools/namingTools';

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

#### Simple usage:
```jsx
<div {...n(element[, [modifiers]]).props}></div>
```
* `modifier` is optional and can be either `string` or `array of strings`
#### Examples
##### Element with modifier:
```jsx
<div {...n('elementName', 'myModifier').props}></div> 
// translates to
<div 
    class="myComponentName_elementName 
           myComponentName_elementName--myModifier">
</div> 
```
##### Element with list of modifiers:
```jsx
<div {...n('elementName', ['myModifier1', 'myModifier2']).props}></div> 
// translates to
<div 
    class="myComponentName_elementName 
           myComponentName_elementName--myModifier1 
           myComponentName_elementName--myModifier2">
</div> 
```
##### Element with testId: `.withTestId()`
```jsx
<div {...n('elementName').withTestId().props}></div> 
// translates to
<div class="myComponentName_elementName" data-testid="myComponentName:elementName"></div> 
```
##### Element with custom testId: `.withTestId(*)`
```jsx
<div {...n('elementName').withTestId('myTestId').props}></div> 
// translates to
<div class="myComponentName_elementName" data-testid="myComponentName:myTestId"></div> 
```
##### Element with testId *only*: `.withTestId()`
```jsx
<div {...n().withTestId('myTestId').props}></div> 
// translates to
<div data-testid="myComponentName:myTestId"></div> 
```
##### Element with extra class `.withClass(*)`
```jsx
<div {...n('elementName').withClass('myExtraClass').props}></div> 
// translates to
<div class="myComponentName_elementName myExtraClass"></div> 
```
##### Element with extra classes `.withClass(*)`
```jsx
<div {...n('elementName').withClass(['myExtraClass1', 'myExtraClass2']).props}></div> 
// or
<div {...n('elementName').withClass('myExtraClass1').withClass('myExtraClass2').props}></div> 
// translates to
<div class="myComponentName_elementName myExtraClass1 myExtraClass2"></div> 
```

`namingTool` and it's functions `.withClass()`, `.withTestId()` are **chainable** which means you can work on the results of each function until the `.props` will be called. 
##### Complex example
```jsx
<div 
     {...n('elementName', ['modifier1', modifier2'])
         .withClass(['myExtraClass1', 'myExtraClass2'])
         .withClass('testClass')
         .withTestId()
         .props
     }></div> 
// translates to
<div 
    class="myComponentName_elementName 
           myComponentName_elementName--modifier1
           myComponentName_elementName--modifier2
           myExtraClass1 
           myExtraClass2
           testClass"
    data-testid="myComponentName:elementName "
></div> 
```

### Jest - Testing & Debugging

There are five launch configurations defined that can be used to test and debug:

* `Jest run all test suites` - this configuration will go through all test suites and all test cases defined in the project.
* `Jest run selected test suite` - this configuration will run all test cases found in the file (test suite) that is currently selected in your workspace.
* `Jest run all tests matching selected text` - this configuration will run all test cases that will match the text selected/highlighted in your workspace (multiple tests can match depending on the selected text)
* `Jest run all test suites matching prompted input` - this configuration will run all test suites that contain/match the text provided in the input box that will show up once the configuration is run (multiple test suites can match)
* `Jest run all tests matching prompted input` - this configuration will run all test cases that contain/match the text provided in the input box that will show up once the configuration is run (multiple test cases can match)

`NOTE:` Breakpoints should work correctly in VS Code when using the above configurations.
