Migrating Components (from ACL UI) - acl-services/paprika GitHub Wiki
- Create a new sub folder in packages for your new component.
- Copy the file/folder structure of an existing component (a simple example is the
<RawButton>). - Use
PascalCasefor your component file and its associated styles.js file (egHeading.js/Heading.styles.js). - Include a package.json (again an existing component can be used as a base, but be sure to update
name,description, andrepository.url) - The
versionfor a typical new component should bev0.1.0.
- Booleans should be prefixed with:
is(or sometimesare),has.can, orshould. - Event handlers that perform an action in a component should be prefixed with
handleand followed by the event and finally the object. (eghandleClickButton). - An event handler that is passed as a prop is distinguished by an
onprefix (egonPressEsc). -
sizeis typically handled with a custom PropType,shirtSize(see<Button>as an example). -
ariaTextorariaLabelshould typically be replaced witha11yText.
- Declare
const propTypesandconst defaultPropsat the top of the file and attach them to the component at the bottom (egMyComponent.propTypes = propTypes;). - Include
MyComponent.displayName = "My Component"; - The root node for the component likely won't need an identifying
classNameanymore withstyled-components, but instead can include an attribute to identify it (egdata-pka-anchor="my-component"). - Internal elements that also need a CSS handle, can use the same
data-pka-anchorattribute – use a.as a delimiter (egdata-pka-anchor="my-component.some-element"). - If an internal
refis only needed for focus management, it is preferred to useuseImperativeHandleto expose afocus()method instead (see<Button>as an example).
- Styles are declared and exported in a
styles.jsfile. - Define styling in template literals, but use the
styled-componentscsshelper function to improve the DX in code editors and help with static analysis tools (egconst myStyles = css`.my-selector { ... }`;). - Import the
myStylesinto yourjsxand apply to your root element with thecssprop (eg<MyComponent css={myStyles} />) - Since the styles are applied directly, there is no need for a root class name (like
aclui-button), but rather than refactor all descendent elements, it is preferred forv0.1.0to simply maintain class names (likeaclui-button--content) so the CSS can simply be copied over intact. - Class names that do remain should have the
aclui-prefix removed. - Most Sass features are supported in
styled-components, but some exceptions are@mixins+@includes(helpful ones have been converted to JS functions in thestylerspackage). - One exception is the use of the
&in the middle or end of a selector (eg.is-disabled & { ... };) which will need to be refactored. - Tokens and helper functions can be included with:
import tokens from "@paprika/tokens"; import stylers from "@paprika/stylers";
- For tokens, the JS version will be needed instead of the Sass version. Name in general can be converted by switching to
camelCasefromkebab-case, and replacing--with.(eg$color--black-lighten-10→${tokens.color.blackLighten10}). - For a spacing:
-
$space→${tokens.space} -
$space-sm→${tokens.spaceSm} -
$space-lg→${tokens.spaceLg} -
$space * 2→${stylers.spacer(2)}
-
- Some other helpful
stylersincludefontSize(),lineHeight(),zIndex(). - Component props can be accessed and used to apply styling conditionally, but it is preferred to destructure the
propsfirst (egcolor: ${({isDisabled}) => isDisabled ? 'red' : null}). - See
Button.styles.jsfor many more examples, as well as the Storybook story forStylers).
- Stories are kept in the component package, in the
storiesfolder, with astories.jssuffix that allows them to be added to the Storybook automatically. - The Design System team will be responsible for curating the Storybook. As a casual contributor, there are no other particular conventions to follow.
- You are encouraged to add as many stories as you need and be as creative as you like, but your stories will eventually end up filed away in a
devfolder in the Storybook UI. - If there are Storybook stories in
acl-ui, it makes sense to migrate them as well.
- There are three levels of test coverage that can currently be applied to components in Paprika: Screener, React Testing Library, and Cypress.
- Visual regressions can be covered first in a basic Screener story in Storybook that includes all options. If the component is not interactive, this may suffice for test coverage.
- For basic interactions, React Testing Library can run much faster, and is generally preferred (add to the package as
tests/MyComponent.spec.js). - For more complicated interactions or where RTL is not reliable enough, Cypress can be employed (another Storybook story will be needed in this case).
- The
<Popover>is a good example component as it has all three types of test.