Skip to content

Commit bec72b4

Browse files
committed
chore(React19): Enable React19
1 parent 79a8b98 commit bec72b4

File tree

162 files changed

+1457
-1145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

162 files changed

+1457
-1145
lines changed

.eslintrc.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"plugin:react/recommended",
1010
"plugin:react-hooks/recommended",
1111
"plugin:@typescript-eslint/recommended",
12+
"plugin:react/jsx-runtime",
1213
"prettier"
1314
],
1415
"overrides": [
@@ -95,6 +96,7 @@
9596
"react-hooks/exhaustive-deps": "warn",
9697
"react/no-unescaped-entities": ["error", { "forbid": [">", "}"] }],
9798
"spaced-comment": "error",
98-
"use-isnan": "error"
99+
"use-isnan": "error",
100+
"react/react-in-jsx-scope": "off"
99101
}
100102
}

README.md

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
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.
44

55
### Branches
6+
67
`main` - PatternFly 6 implementation
78

89
`v5` - PatternFly 5 implementation
@@ -14,22 +15,27 @@ This repo contains a set of opinionated react component groups used to standardi
1415
---
1516

1617
### Migration from [RedHatInsights/frontend-components](https://github.com/RedHatInsights/frontend-components) to [patternfly/react-component-groups](https://github.com/patternfly/react-component-groups)
18+
1719
Please see the [migration guide](./migration.md)
1820

1921
---
22+
2023
## Contribution guide
2124

2225
### Before adding a new component:
26+
2327
- make sure your use case is new/complex enough to be added to this extension
2428
- the component should bring a value value above and beyond existing PatternFly components
2529

2630
### To add a new component:
31+
2732
1. create a folder in `src/` matching its name (for example `src/MyComponent`)
2833
2. to the new folder add a new `.tsx` file named after the component (for example `src/MyComponent/MyComponent.tsx`)
2934
3. to the same folder include an `index.ts` which will export the component as a default and then all necessary interfaces
3035
4. if this file structure is not met, your component won't be exposed correctly
3136

3237
#### Example component:
38+
3339
```
3440
import * as React from 'react';
3541
import { Content } from '@patternfly/react-core';
@@ -49,7 +55,8 @@ const useStyles = createUseStyles({
4955
})
5056
5157
// do not use the named export of your component, just a default one
52-
const MyComponent: React.FunctionComponent<MyComponentProps> = () => {
58+
import { FunctionComponent } from 'react';
59+
const MyComponent: FunctionComponent<MyComponentProps> = () => {
5360
const classes = useStyles();
5461
5562
return (
@@ -60,42 +67,49 @@ const MyComponent: React.FunctionComponent<MyComponentProps> = () => {
6067
};
6168
6269
export default MyComponent;
63-
```
70+
```
6471

6572
#### Index file example:
73+
6674
```
6775
export { default } from './MyComponent';
6876
export * from './MyComponent';
69-
```
77+
```
7078

7179
#### Component directory structure example:
80+
7281
```
7382
src
7483
|- MyComponent
7584
|- index.ts
7685
|- MyComponent.tsx
77-
```
86+
```
7887

7988
### Component's API rules:
89+
8090
- prop names comply with PatternFly components naming standards (`variant`, `onClick`, `position`, etc.)
8191
- the API is maximally simplified and all props are provided with a description
8292
- it is built on top of existing PatternFly types without prop omitting
8393
- 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`)
8494
- do not unnecessarily use external libraries in your component - rather, delegate the necessary logic to the component's user using the component's API
8595

8696
#### Component API definition example:
97+
8798
```
99+
100+
import { FunctionComponent } from 'react';
101+
88102
// when possible, extend available PatternFly types
89103
export interface MyComponentProps extends ButtonProps {
90104
customLabel: Boolean
91105
};
92106
93-
export const MyComponent: React.FunctionComponent<MyComponentProps> = ({ customLabel, ...props }) => ( ... );
107+
export const MyComponent: FunctionComponent<MyComponentProps> = ({ customLabel, ...props }) => ( ... );
94108
```
95109

96-
97110
#### Markdown file example:
98-
```
111+
112+
````
99113
---
100114
section: Component groups
101115
subsection: My component's category
@@ -113,36 +127,42 @@ MyComponent has been created to demo contributing to this repository.
113127
114128
```js file="./MyComponentExample.tsx"```
115129
116-
```
130+
````
117131

118132
#### Component usage file example: (`MyComponentExample.tsx`)
133+
119134
```
120-
import React from 'react';
135+
import { FunctionComponent } from 'react';
121136
122-
const MyComponentExample: React.FunctionComponent = () => (
137+
const MyComponentExample: FunctionComponent = () => (
123138
<MyComponent customLabel="My label">
124139
);
125140
126141
export default MyComponentExample;
127142
```
128143

129144
### Sub-components:
130-
When adding a component for which it is advantageous to divide it into several sub-components make sure:
145+
146+
When adding a component for which it is advantageous to divide it into several sub-components make sure:
147+
131148
- component and all its sub-components are located in separate files and directories straight under the `src/` folder
132149
- sub-components are exported and documented separately from their parent
133150
- parent component should provide a way to pass props to all its sub-components
134151

135152
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.
136153

137154
### Testing:
155+
138156
When adding/making changes to a component, always make sure your code is tested:
139-
- use React Testing Library for unit testing
157+
158+
- use React Testing Library for unit testing
140159
- add unit tests to a `[ComponentName].test.tsx` file to your component's directory
141160
- make sure all the core functionality is covered using Cypress component or E2E tests
142161
- add component tests to `cypress/component/[ComponentName].cy.tsx` file and E2E tests to `cypress/e2e/[ComponentName].spec.cy.ts`
143162
- 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"`)
144163

145164
### Styling:
165+
146166
- for styling always use JSS
147167
- 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.)
148168
- 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)
@@ -153,10 +173,12 @@ When adding/making changes to a component, always make sure your code is tested:
153173
- run `npm run build`
154174

155175
## Development
176+
156177
- run `npm install`
157178
- run `npm run start` to build and start the development server
158179

159180
## Testing and Linting
181+
160182
- run `npm run test` to run the unit tests
161183
- run `npm run cypress:run:cp` to run Cypress component tests
162184
- run `npm run cypress:run:e2e` to run Cypress E2E tests
@@ -165,4 +187,3 @@ When adding/making changes to a component, always make sure your code is tested:
165187
## A11y testing
166188

167189
- 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.
168-

cypress/component/Ansible.cy.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import React from 'react';
21
import { Ansible } from '@patternfly/react-component-groups/dist/dynamic/Ansible';
32

43
describe('Ansible', () => {
54
it('renders supported Ansible', () => {
6-
cy.mount(<Ansible />)
5+
cy.mount(<Ansible />);
76
cy.get('i').should('have.class', 'ansibleSupported-0-2-2');
87
});
98
it('renders unsupported Ansible', () => {
10-
cy.mount(<Ansible isSupported={false}/>)
9+
cy.mount(<Ansible isSupported={false} />);
1110
cy.get('i').should('have.class', 'ansibleUnsupported-0-2-3');
1211
});
13-
});
12+
});
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
import React from 'react';
21
import CloseButton from '../../packages/module/dist/dynamic/CloseButton';
32

43
describe('CloseButton', () => {
54
/* eslint-disable no-console */
65
it('renders the Close button', () => {
7-
cy.mount(<CloseButton dataTestID="close-button-example" onClick={()=>{console.log('Close button clicked')}} style={{ float: 'none' }}/>)
6+
cy.mount(
7+
<CloseButton
8+
dataTestID="close-button-example"
9+
onClick={() => {
10+
console.log('Close button clicked');
11+
}}
12+
style={{ float: 'none' }}
13+
/>
14+
);
815
cy.get('[data-test-id="close-button-example"]').should('exist');
916
});
1017
it('should call callback on click', () => {
1118
const onClickSpy = cy.spy().as('onClickSpy');
12-
cy.mount(<CloseButton dataTestID="close-button-example" onClick={onClickSpy}/>);
19+
cy.mount(<CloseButton dataTestID="close-button-example" onClick={onClickSpy} />);
1320
cy.get('[data-test-id="close-button-example"]').click();
1421
cy.get('@onClickSpy').should('have.been.called');
1522
});
16-
})
23+
});
Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1-
import React from 'react';
21
import ErrorBoundary from '../../packages/module/dist/dynamic/ErrorBoundary';
32

43
describe('ErrorBoundary', () => {
54
it('renders the ErrorBoundary ', () => {
6-
cy.mount(<ErrorBoundary headerTitle="My app header" errorTitle="Something wrong happened"><div data-ouia-component-id="test">Test</div></ErrorBoundary>)
5+
cy.mount(
6+
<ErrorBoundary headerTitle="My app header" errorTitle="Something wrong happened">
7+
<div data-ouia-component-id="test">Test</div>
8+
</ErrorBoundary>
9+
);
710
cy.get('[data-ouia-component-id="test"]').should('have.text', 'Test');
811
});
912

1013
it('should expand the details section', () => {
1114
const Surprise = () => {
1215
throw new Error('but a welcome one');
1316
};
14-
cy.mount(<ErrorBoundary headerTitle="My app header" errorTitle="Something wrong happened">
15-
<Surprise />
16-
</ErrorBoundary>)
17+
cy.mount(
18+
<ErrorBoundary headerTitle="My app header" errorTitle="Something wrong happened">
19+
<Surprise />
20+
</ErrorBoundary>
21+
);
1722

1823
cy.get('[data-ouia-component-id="ErrorBoundary-toggle"').click();
1924
cy.get('[class="pf-v5-c-expandable-section__content"]').should('contain.text', 'Error: but a welcome one');
20-
})
21-
})
25+
});
26+
});
Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1-
import React from 'react';
21
import ErrorState from '../../packages/module/dist/dynamic/ErrorState';
3-
import { ActionButton } from '../../packages/module/dist/dynamic/ActionButton'
2+
import { ActionButton } from '../../packages/module/dist/dynamic/ActionButton';
43

54
describe('ErrorState', () => {
65
it('renders the Close button', () => {
7-
cy.mount(<ErrorState titleText='Sample error title' bodyText='Sample error description' />);
6+
cy.mount(<ErrorState titleText="Sample error title" bodyText="Sample error description" />);
87
cy.get('[data-ouia-component-id="ErrorState"]').contains('Sample error title');
98
cy.get('[data-ouia-component-id="ErrorState-body"]').should('have.text', 'Sample error description');
109
});
1110

1211
it('render with a custom footer', () => {
1312
const onClickSpy = cy.spy().as('onClickSpy');
14-
cy.mount(<ErrorState titleText='Sample error title' bodyText='Sample error description' customFooter={<ActionButton variant="secondary" onClick={onClickSpy}>
15-
Custom action
16-
</ActionButton>}/>);
17-
cy.get('button').should('have.text', "Custom action");
13+
cy.mount(
14+
<ErrorState
15+
titleText="Sample error title"
16+
bodyText="Sample error description"
17+
customFooter={
18+
<ActionButton variant="secondary" onClick={onClickSpy}>
19+
Custom action
20+
</ActionButton>
21+
}
22+
/>
23+
);
24+
cy.get('button').should('have.text', 'Custom action');
1825
cy.get('button').click();
1926
cy.get('@onClickSpy').should('have.been.called');
20-
})
21-
})
27+
});
28+
});
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import React from 'react';
21
import LogSnippet from '../../packages/module/dist/dynamic/LogSnippet';
32

43
describe('LogSnippet', () => {
54
it('renders LogSnippet', () => {
6-
cy.mount(<LogSnippet logSnippet='test test code' message='A test message'/>)
5+
cy.mount(<LogSnippet logSnippet="test test code" message="A test message" />);
76
cy.get('[data-ouia-component-id="LogSnippet-message"]').contains('A test message');
87
cy.get('[data-ouia-component-id="LogSnippet-code-content"]').contains('test code');
98
});
10-
});
9+
});
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import React from 'react';
21
import Maintenance from '@patternfly/react-component-groups/dist/dynamic/Maintenance';
32

43
describe('Maintenance', () => {
54
it('renders Maintenance', () => {
6-
cy.mount(<Maintenance />)
5+
cy.mount(<Maintenance />);
76
cy.get('[data-ouia-component-id="Maintenance"]').should('exist');
87
cy.get('[data-ouia-component-id="Maintenance"]').contains('Maintenance in progress');
9-
cy.get('[data-ouia-component-id="Maintenance-body"]').contains('We are currently undergoing scheduled maintenance and will be unavailable from 6am to 8am UTC. For more information please visit status.redhat.com.');
8+
cy.get('[data-ouia-component-id="Maintenance-body"]').contains(
9+
'We are currently undergoing scheduled maintenance and will be unavailable from 6am to 8am UTC. For more information please visit status.redhat.com.'
10+
);
1011
});
11-
});
12+
});
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import React from 'react';
21
import MissingPage from '@patternfly/react-component-groups/dist/dynamic/MissingPage';
32

43
describe('MissingPage', () => {
54
it('renders MissingPage', () => {
6-
cy.mount(<MissingPage />)
7-
cy.get('[data-ouia-component-id="MissingPage"]').should('exist')
5+
cy.mount(<MissingPage />);
6+
cy.get('[data-ouia-component-id="MissingPage"]').should('exist');
87
cy.get('[data-ouia-component-id="MissingPage"]').contains('We lost that page');
9-
cy.get('[data-ouia-component-id="MissingPage-body"]').contains("Let's find you a new one. Try a new search or return home.");
8+
cy.get('[data-ouia-component-id="MissingPage-body"]').contains(
9+
"Let's find you a new one. Try a new search or return home."
10+
);
1011
cy.get('[data-ouia-component-id="MissingPage-home-button"]').contains('Return to homepage');
1112
});
12-
})
13+
});

0 commit comments

Comments
 (0)