@appdirect/sfb-theme-components

Components used by storefront builder to build themes

Usage no npm install needed!

<script type="module">
  import appdirectSfbThemeComponents from 'https://cdn.skypack.dev/@appdirect/sfb-theme-components';
</script>

README

sfb-theme-components

Components used by storefront builder to build themes

Local development

  • Run npm run start
  • You can do resource override for the js and css from:
    • http://localhost:3444/sfb-components.js
    • 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

To deploy a Storybook PR version, please read this wiki: https://appdirect.jira.com/wiki/spaces/MP/pages/981532752/How+to+deploy+sfb-theme-components+storybook+s+PR+version+on+Orchard

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:

// just an element, nothing to see
<div class="blockName_elementName"></div>
// 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

Proptypes and functional components are inforced

CSS - Naming Tool

There has been implemented namingTool to help out follow above CSS naming structure:

Every component should contain:

import { createNamespace } from './tools/namingTools';
const n = createNamespace('MyComponentName');

Simple usage:

<div {...n(element[, [modifiers]]).props}></div>
  • modifier is optional and can be either string or array of strings

Examples

Element with modifier:
<div {...n('elementName', 'myModifier').props}></div> 
// translates to
<div 
    class="myComponentName_elementName 
           myComponentName_elementName--myModifier">
</div> 
Element with list of modifiers:
<div {...n('elementName', ['myModifier1', 'myModifier2']).props}></div> 
// translates to
<div 
    class="myComponentName_elementName 
           myComponentName_elementName--myModifier1 
           myComponentName_elementName--myModifier2">
</div> 
Element with testId: .withTestId()
<div {...n('elementName').withTestId().props}></div> 
// translates to
<div class="myComponentName_elementName" data-testid="myComponentName:elementName"></div> 
Element with custom testId: .withTestId(*)
<div {...n('elementName').withTestId('myTestId').props}></div> 
// translates to
<div class="myComponentName_elementName" data-testid="myComponentName:myTestId"></div> 
Element with testId only: .withTestId()
<div {...n().withTestId('myTestId').props}></div> 
// translates to
<div data-testid="myComponentName:myTestId"></div> 
Element with extra class .withClass(*)
<div {...n('elementName').withClass('myExtraClass').props}></div> 
// translates to
<div class="myComponentName_elementName myExtraClass"></div> 
Element with extra classes .withClass(*)
<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
<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 corrently in VS Code when using the above configurations.