-
Notifications
You must be signed in to change notification settings - Fork 9
Coding Conventions
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...
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.
We use Prettier with the following configuration.
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.
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.
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.
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
.
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 anda11y
.
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.
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';
.
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).
- Coding Conventions
- Accessibility
-
Testing
WIP
- Getting Started
- Design Philosophy
- Development Workflow
-
Submitting an Issue
WIP