# PatternFly React Component Groups This repo contains a set of opinionated react component groups used to standardize functionality and look and feel across products. The components are based on PatternFly with some additional functionality. ### Branches `main` - PatternFly 6 implementation `v5` - PatternFly 5 implementation `do-not-delete` - do not delete > NOTE: If new features are not needed in `v5,` they should be added directly to the `main` branch. For bug fixes, it is preferred to fix the bug for both versions (fix in one branch and cherry-pick to another). Pulling new changes from 5 to 6 and vice versa is not recommended using `rebase`. Rather, always cherry-pick specific commits. --- ### Migration from [RedHatInsights/frontend-components](https://github.com/RedHatInsights/frontend-components) to [patternfly/react-component-groups](https://github.com/patternfly/react-component-groups) Please see the [migration guide](./migration.md) --- ## Contribution guide ### AI-assisted development guidelines Please reference [PatternFly's AI-assisted development guidelines](https://github.com/patternfly/.github/blob/main/CONTRIBUTING.md) if you'd like to contribute code generated using AI. ### Before adding a new component: - make sure your use case is new/complex enough to be added to this extension - the component should bring a value above and beyond existing PatternFly components ### To add a new component: 1. create a folder in `src/` matching its name (for example `src/MyComponent`) 2. to the new folder add a new `.tsx` file named after the component (for example `src/MyComponent/MyComponent.tsx`) 3. to the same folder include an `index.ts` which will export the component as a default and then all necessary interfaces 4. if this file structure is not met, your component won't be exposed correctly #### Example component: ``` TSX import * as React from 'react'; import { Content } from '@patternfly/react-core'; import { createUseStyles } from 'react-jss'; // do not forget to export your component's interface // always place the component's interface above the component itself in the code export interface MyComponentProps { text: String; } const useStyles = createUseStyles({ myText: { fontFamily: 'monospace', fontSize: 'var(--pf-v6-global--icon--FontSize--md)', }, }) // do not use the named export of your component, just a default one import { FunctionComponent } from 'react'; const MyComponent: FunctionComponent = () => { const classes = useStyles(); return ( This is my new reusable component ); }; export default MyComponent; ``` #### Index file example: ``` TSX export { default } from './MyComponent'; export * from './MyComponent'; ``` #### Component directory structure example: ``` src |- MyComponent |- index.ts |- MyComponent.tsx ``` ### Component's API rules: - prop names comply with PatternFly components naming standards (`variant`, `onClick`, `position`, etc.) - the API is maximally simplified and all props are provided with a description - it is built on top of existing PatternFly types without prop omitting - it is well documented using the PatternFly documentation (`/packages/module/patternfly-docs/content/extensions/component-groups/examples/MyComponent/MyComponent.md`) with examples of all possible use cases (`packages/module/patternfly-docs/content/extensions/component-groups/examples/MyComponent/MyComponent[...]Example.tsx`) - do not unnecessarily use external libraries in your component - rather, delegate the necessary logic to the component's user using the component's API #### Component API definition example: ``` TSX import { FunctionComponent } from 'react'; // when possible, extend available PatternFly types export interface MyComponentProps extends ButtonProps { customLabel: Boolean }; export const MyComponent: FunctionComponent = ({ customLabel, ...props }) => ( ... ); ``` #### Markdown file example: ```` MDX --- section: Component groups subsection: My component's category id: MyComponent propComponents: ['MyComponent'] --- import MyComponent from "@patternfly/react-component-groups/dist/dynamic/MyComponent"; ## Component usage MyComponent has been created to demo contributing to this repository. ### MyComponent component example label ```js file="./MyComponentExample.tsx"``` ```` #### Component usage file example: (`MyComponentExample.tsx`) ``` TSX import { FunctionComponent } from 'react'; const MyComponentExample: FunctionComponent = () => ( ); export default MyComponentExample; ``` ### Sub-components: When adding a component for which it is advantageous to divide it into several sub-components make sure: - component and all its sub-components are located in separate files and directories straight under the `src/` folder - sub-components are exported and documented separately from their parent - parent component should provide a way to pass props to all its sub-components The aim is to enable the user of our "complex" component to use either complete or take advantage of its sub-components and manage their composition independently. ### Testing: When adding/making changes to a component, always make sure your code is tested: - use React Testing Library for unit testing - add unit tests to a `[ComponentName].test.tsx` file to your component's directory - make sure all the core functionality is covered using Cypress component or E2E tests - add component tests to `cypress/component/[ComponentName].cy.tsx` file and E2E tests to `cypress/e2e/[ComponentName].spec.cy.ts` - add `ouiaId` to the component props definition with a default value of the component name (for subcomponents, let's use `ComponentName-element-specification` naming convention e.g. `ouiaId="WarningModal-confirm-button"`) ### Styling: - for styling always use JSS - new classNames should be named in camelCase starting with the name of a given component and following with more details clarifying its purpose/component's subsection to which the class is applied (`actionMenu`, `actionMenuDropdown`, `actionMenuDropdownToggle`, etc.) - do not use `pf-v6-u-XXX` classes, use CSS variables in a custom class instead (styles for the utility classes are not bundled with the standard patternfly.css - it would require the consumer to import also addons.css) ## Building for production - run `npm install` - run `npm run build` ## Development - run `npm install` - run `npm run start` to build and start the development server ## Testing and Linting - run `npm run test` to run the unit tests - run `npm run cypress:run:cp` to run Cypress component tests - run `npm run cypress:run:e2e` to run Cypress E2E tests - run `npm run lint` to run the linter ## A11y testing - run `npm run build:docs` followed by `npm run serve:docs`, then run `npm run test:a11y` in a new terminal window to run our accessibility tests for the components. Once the accessibility tests have finished running you can run `npm run serve:a11y` to locally view the generated report.