Coding Conventions - acl-services/paprika GitHub Wiki

The Paprika code base consists primarily of JavaScript — some vanilla JS, but mainly JSX with styling supported by the styled-components library. We rely on Babel to transpile our code with preset-env to support all stable language features, which we encourage the use of, as well as select proposals (such as class properties, supported by @babel/plugin-proposal-class-properties).

Sections —


Additionally...

Linting

ESLint is integrated into our build, and even the git commit and git push commands via Husky hooks. We have integrated Airbnb's linter rules, as well as several other targeted eslint plugins. We strongly recommend integrating a linter plugin into your IDE.

Formatting

We use Prettier with the following configuration.


Naming

Naming is hard. To make it easier, please adhere to the naming standards established in Paprika.

Please note that these rules are not comprehensive, and continue to evolve.

File Names

Components should be given clear PascalCase names. The main JSX file name should match the package folder name, should be kept in a src folder, and should have a .js extension.

For simpler consumption, an index.js file is included with each component.

Sub components should be placed in a separate sub folder (ex packages/MyComponent/src/components/SubComponent/SubComponent.js).

Styling is separated into a file with a .styles.js extension and kept alongside the JSX file.

Tests are included with the component, in a tests folder, and should have the same file name as the component, but with a .spec.js extension for React Testing Library tests, or .cypress.js for Cypress tests.

Storybook stories, and supporting components/styling are kept in the stories folder, also within the same folder as src and tests. There should be one file with a .stories.js extension that will be automatically added to Storybook. This file should have the same name as the main component file and be a minimal, manifest file for all of the component's stories. Each specific story can be written as a component and kept in the stories/examples folder.

The Popover illustrates the desired file naming / folder structure.

Prop Names

Booleans are very common props — to quickly identify and group them they should be consistently named with an is, are, has, can, or should prefix.

Some examples of common state props include: isOpen, isDisabled, isCollapsed, isSelected, isPending, isLoaded.

Size (or sometimes width) props with a few limited choices is also common. A custom propType has been implemented for this purpose called ShirtSizes. Example:

import { ShirtSizes } from "@paprika/helpers/lib/customPropTypes";

And then in the propTypes as:

size: PropTypes.oneOf(ShirtSizes.DEFAULT),

In most cases, it is very convenient to be able to provide a className or other attributes (like zIndex, onMouseOver, etc) to a component and have it applied to the rendered DOM element. For this purpose, the deconstruction of props can be utilized:

const { children, className, isDisabled, size, ...moreProps } = props;
...
<MyComponent {...moreProps} />

It is also strongly encouraged that you document a component's props directly above their propType declaration in a format that react-docgen can parse (example: /** comment */).

It is required that default props are specified for all props that are not isRequired. If an empty value is desired when not provided, typically null will suffice.

Function Names

Event handlers that perform an action in a component should be prefixed with handle and followed by the event and finally the object. An event handler that is passed as a prop is distinguished by an on prefix. For example, compliant prop names for a callback may include onClickButton or onPressEsc, whereas the functions that actually implement the work for these callbacks would be named handleClickButton and handlePressEsc.


Markup

Semantic markup should be used as much as possible. This helps with a11y, and can serve to better self-document the code.

For more information about best practices for coding with a11y in mind, it is highly recommended that you review the Accessibility Guidelines for Developers from the Starling Design System.

Some components employ a non-semantic strategy as a way of being more resilient to global CSS that would otherwise apply to semantic elements. <Button> is an example of this, where we use a <div> instead of a <button> (by using <RawButton>). Consequently we must implement a lot of the native functionality of a <button> ourselves to ensure full keyboard support and a11y.

Anchors

Since styling is implemented with the styled-components library, classes are typically not needed and best avoided. However, it is important to be able to target specific DOM elements for testing or styling overrides (by consumers of Paprika). We solve this with custom data-pka-anchor attributes. The value for the attribute should be the kebab-case version of the component's displayName.

For example, the ProgressAccordion component has a data-pka-anchor='progress-accordion' attribute, and its 'Item' subcomponent (which has a displayName property of 'ProgressAccordion.Item') will have a data-pka-anchor='progress-accordion.item' attribute.


Styling

Tokens

Use Design Tokens wherever possible, namely for colours and spacing, but there are many other uses as well. These tokens are for internal use, developing Paprika components, but also provided as a package for consumers (application developers) to implement features. Typically, consumers will use the Sass version of the tokens, while Paprika developers, using styled-components, will use the JS versions.

There is a colour scale, so you will have access to colours like color.blackLighten30 and color.blueDarken10, but there are also more semantic colour tokens for specific use cases that are preferred, if available (example, border.color).

Designs will typically adhere to consistent spacing constraints where one space = 8px. There are also variations for common use cases: spaceSm = 4px + spaceLg = 12px. For multiples of 8px, it is acceptable (in Sass) to use $space * n where n is not greater than 5. In styled-components, this is more cumbersome, and a Styler function is provided to help with this common use case (see below). Situations where greater or in-between values are needed are considered special cases and a literal value is more appropriate than a token.

To consume the tokens in Paprika with styled-components, simply import them with import tokens from "@paprika/tokens";. To consume in a Sass file (as a Paprika consumer) you can import with @import '@paprika/tokens/lib/tokens.scss';.

Stylers

There are a number of generic helpers provided for helping with writing styled-components, most of which also have a Sass version provided for the convenience of Paprika consumers.

For scalability, in the package they are split into includes, for bundles of styling rules that can be inserted where needed, and helpers, which are functions that take an input and generate a value or styling rule/rules. They can all be consumed together though in the same import, typically import stylers from "@paprika/stylers"; for styled-components and @import '@paprika/stylers/lib/helpers.scss'; in a Sass context (usually for app developers).

⚠️ **GitHub.com Fallback** ⚠️