Overview
Thanks for getting involved with Abyss! If you've made it here we'll assume you've reviewed the Abyss Contributors page. To make the contribution process go as smooth as possible, we've laid out our code standards and development steps for you below.
As a reminder the component you are developing should already be approved by product, design, and accessibility.
Code Standards
While components may differ, most Abyss Mobile UI components have the following...
The outermost styled element will be named ComponentNameRoot. The rest of the names should describe what they contain.
Below is a simplified example from Modal
<ModalRoot> <Header> <ActionButton> </ActionButton> <TitleContainer> <Title> </Title> </TitleContainer> </Header>
// code
</ModalRoot>The useAbyssProps hook must be imported in each component. This allows consuming teams to customize the style of the component and gives the ability to assign unique test-ids.
const abyssProps = useAbyssProps(props);abyssProps are spread into each element that will allow for customization and testing. The class names start with the component name followed by a dash and then the element name. These names should be simple and self-explanatory. For example, button-root describes the root element and button-label describes the label element.
<ButtonRoot {...abyssProps('button-root')} ><Label {...abyssProps('button-label')} >{label}</Label></ButtonRoot>Add accessibility props when applicable.
<ButtonRoot accessible accessibilityRole="button" accessibilityState={{ disabled: isDisabled }} ></ButtonRoot>Don't forget the display name.
Button.displayName = '@uhg-abyss/mobile/ui/Button';Types, Props, and Classes
All the types, props, and classes used in the component must be defined in a ComponentName.types.ts file. This file should export a TypeScript interface for the component's props, classes, and any reused types.
Below is a simplified example of Button:
export type ButtonClasses = { 'button-root': Abyss.Class<'Animated.Pressable'>; 'button-label': Abyss.Class<'Animated.Text'>;};Unless a prop is marked as required in the TypeScript interface, be sure to add a default value where applicable (and within the component itself).
export interface ButtonProps extends Abyss.BaseProps<ButtonClasses, 'Animated.Pressable'> { /** * The contents of the button component */ children?: | React.ReactNode | ((state: PressableStateCallbackType) => React.ReactNode); /** * Defines the button type (style) * @default 'filled' */ type?: 'filled' | 'outline' | 'text'; /** * Defines the button size * @default 'large' */ size?: 'large' | 'small'; /** * Disables the button * @default false */ isDisabled?: boolean; /** * Callback fired when the Button is pressed */ onPress?: Abyss.GestureResponderEventHandler;}export interface ButtonRef extends Abyss.PressableRef {}Once the ComponentName.types.ts file is complete import the necessary elements into the ComponentName.tsx file.
import type { ButtonProps, ButtonRef } from './Button.types';The full props spread may look something like the example below.
ButtonRoot is the outermost Pressable component, so size and type are passed in for styling, as well as all the props pertaining to press interactions: onPress, onPressIn, onPressOut, and disabled. {...abyssProps('button-root')} is added, and for the Button component specifically, accessibility props are only within the ButtonRoot element.
<ButtonRoot onPress={onPress} accessible accessibilityRole="button" accessibilityState={{ disabled: isDisabled }} size={size} type={type} {...props} {...abyssProps('button-root')} onPressIn={handlePressIn} onPressOut={handlePressOut} disabled={isDisabled}> <Label {...abyssProps('button-label')}>{children}</Label></ButtonRoot>Development Workflow
1. Developer Refinement
Before starting development, you are required to attend our Mobile Developer refinement session. Here we will discuss the development plan for the component you are contributing. This includes outlining code already available to be used within your component, as well as what we expect to be reusable from your component.
2. Development
Please review our Code Standards before you get started, and remember we're here to help! Feel free to reach out an Abyss Mobile developer and attend office hours for anything that comes up during development.
3. Documentation
A component is not complete without proper documentation. Please see our Documentation Guide for more details and examples. Be sure to continue to update documentation with any changes from the Peer, QE, and A11y reviews.
4. Peer Review
After you've completed development, make a pull request and reach out to the Abyss Mobile developer that has been assigned to review your component. They will do an initial review, as well as check any code changes after QE and Accessibility testing. Any changes requested bring you back to development.
5. Quality Engineering Review
Once the PR is complete, your component will be sent to our quality engineer for testing. Any changes requested bring you back to development.
6. Accessibility Review
After your component has been approved by QE, it will be passed on to our accessibility engineer for testing. You are responsible for adding accessibility elements within your component. Check out our Accessibility Testing page and the React Native documentation for further guidance. Any changes requested bring you back to development. If the changes made only pertain to accessibility, the component does not need to be reviewed again by QE.
Definition of Done
By contributing to Abyss, you are committing to the full development cycle. A component is complete when all changes have been made and accepted by the Peer, QE, and Accessibility reviews, and is thoroughly documented.