Migrating Components (from ACL UI) - acl-services/paprika GitHub Wiki

Migrating Components from ACL UI to Paprika

Create a New Component

  • 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 PascalCase for your component file and its associated styles.js file (eg Heading.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, and repository.url)
  • The version for a typical new component should be v0.1.0.

Prop Naming Conventions

  • Booleans should be prefixed with: is (or sometimes are), has. can, or should.
  • Event handlers that perform an action in a component should be prefixed with handle and followed by the event and finally the object. (eg handleClickButton).
  • An event handler that is passed as a prop is distinguished by an onprefix (eg onPressEsc).
  • size is typically handled with a custom PropType, shirtSize (see <Button> as an example).
  • ariaText or ariaLabel should typically be replaced with a11yText.

Component Implementation Conventions

  • Declare const propTypes and const defaultProps at the top of the file and attach them to the component at the bottom (eg MyComponent.propTypes = propTypes;).
  • Include MyComponent.displayName = "My Component";
  • The root node for the component likely won't need an identifying className anymore with styled-components, but instead can include an attribute to identify it (eg data-pka-anchor="my-component").
  • Internal elements that also need a CSS handle, can use the same data-pka-anchor attribute – use a . as a delimiter (eg data-pka-anchor="my-component.some-element").
  • If an internal ref is only needed for focus management, it is preferred to use useImperativeHandle to expose a focus() method instead (see <Button> as an example).

Styling with styled-components

  • Styles are declared and exported in a styles.js file.
  • Define styling in template literals, but use the styled-components css helper function to improve the DX in code editors and help with static analysis tools (eg const myStyles = css`.my-selector { ... }`;).
  • Import the myStyles into your jsx and apply to your root element with the css prop (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 for v0.1.0 to simply maintain class names (like aclui-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 the stylers package).
  • 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 camelCase from kebab-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 stylers include fontSize(), lineHeight(), zIndex().
  • Component props can be accessed and used to apply styling conditionally, but it is preferred to destructure the props first (eg color: ${({isDisabled}) => isDisabled ? 'red' : null}).
  • See Button.styles.js for many more examples, as well as the Storybook story for Stylers).

Storybook

  • Stories are kept in the component package, in the stories folder, with a stories.js suffix 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 dev folder in the Storybook UI.
  • If there are Storybook stories in acl-ui, it makes sense to migrate them as well.

Testing

  • 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.
⚠️ **GitHub.com Fallback** ⚠️