diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 9c82ded3770..73d260a2dce 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -54,7 +54,7 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.21", + "@patternfly/patternfly": "6.5.0-prerelease.22", "case-anything": "^3.1.2", "css": "^3.0.0", "fs-extra": "^11.3.0" diff --git a/packages/react-core/src/components/Compass/CompassMainHeader.tsx b/packages/react-core/src/components/Compass/CompassMainHeader.tsx index cb3b6528d1d..f62d0d0be6f 100644 --- a/packages/react-core/src/components/Compass/CompassMainHeader.tsx +++ b/packages/react-core/src/components/Compass/CompassMainHeader.tsx @@ -1,17 +1,27 @@ -import { Flex, FlexItem } from '../../layouts/Flex'; -import { CompassPanel } from './CompassPanel'; +import { CompassPanel, CompassPanelProps } from './CompassPanel'; +import { CompassMainHeaderContent } from './CompassMainHeaderContent'; +import { CompassMainHeaderTitle } from './CompassMainHeaderTitle'; +import { CompassMainHeaderToolbar } from './CompassMainHeaderToolbar'; import styles from '@patternfly/react-styles/css/components/Compass/compass'; import { css } from '@patternfly/react-styles'; +/** The wrapper component for header content in the main compass area. When building out a custom implementation, + * you should ensure any content within the main header is rendered inside a compass panel and main header content wrappers. + */ + export interface CompassMainHeaderProps extends Omit, 'title'> { + /** Custom main header content. To opt into a default styling, use the title and toolbar props instead. */ + children?: React.ReactNode; /** Additional classes added to the main header */ className?: string; /** Styled title. If title or toolbar is provided, the children will be ignored. */ title?: React.ReactNode; /** Styled toolbar. If title or toolbar is provided, the children will be ignored. */ toolbar?: React.ReactNode; - /** Custom main header content. To opt into a default styling, use the title and toolbar props instead. */ - children?: React.ReactNode; + /** Additional props passed to the compass panel that wraps the main header content when using the title or toolbar props. When using the + * children prop, you should pass your own compass panel. + */ + compassPanelProps?: Omit; } export const CompassMainHeader: React.FunctionComponent = ({ @@ -19,15 +29,16 @@ export const CompassMainHeader: React.FunctionComponent title, toolbar, children, + compassPanelProps, ...props }) => { const _content = title !== undefined || toolbar !== undefined ? ( - - - {title} - {toolbar && {toolbar}} - + + + {title && {title}} + {toolbar && {toolbar}} + ) : ( children diff --git a/packages/react-core/src/components/Compass/CompassMainHeaderContent.tsx b/packages/react-core/src/components/Compass/CompassMainHeaderContent.tsx new file mode 100644 index 00000000000..cebe3baba23 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassMainHeaderContent.tsx @@ -0,0 +1,25 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; + +/** A wrapper component to be passed as custom content for the compass main header. This should also be wrapped + * in a compass panel component. + */ + +export interface CompassMainHeaderContentProps extends React.HTMLProps { + /** Content of the main header content. */ + children: React.ReactNode; + /** Additional classes added to the main header content. */ + className?: string; +} + +export const CompassMainHeaderContent: React.FunctionComponent = ({ + children, + className, + ...props +}) => ( +
+ {children} +
+); + +CompassMainHeaderContent.displayName = 'CompassMainHeaderContent'; diff --git a/packages/react-core/src/components/Compass/CompassMainHeaderTitle.tsx b/packages/react-core/src/components/Compass/CompassMainHeaderTitle.tsx new file mode 100644 index 00000000000..f1a628c0ae7 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassMainHeaderTitle.tsx @@ -0,0 +1,25 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; + +/** A wrapper component for custom title content to be passed into a compass main header. This should also be wrapped + * by a compass main header content component. + */ + +export interface CompassMainHeaderTitleProps extends React.HTMLProps { + /** Content of the main header title. */ + children: React.ReactNode; + /** Additional classes added to the main header title. */ + className?: string; +} + +export const CompassMainHeaderTitle: React.FunctionComponent = ({ + children, + className, + ...props +}) => ( +
+ {children} +
+); + +CompassMainHeaderTitle.displayName = 'CompassMainHeaderTitle'; diff --git a/packages/react-core/src/components/Compass/CompassMainHeaderToolbar.tsx b/packages/react-core/src/components/Compass/CompassMainHeaderToolbar.tsx new file mode 100644 index 00000000000..9dd986ef159 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassMainHeaderToolbar.tsx @@ -0,0 +1,25 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; + +/** A wrapper component for custom toolbar content to be passed into a compass main header. This should also be wrapped + * by a compass main header content component. + */ + +export interface CompassMainHeaderToolbarProps extends React.HTMLProps { + /** Content of the main header toolbar. */ + children: React.ReactNode; + /** Additional classes added to the main header toolbar. */ + className?: string; +} + +export const CompassMainHeaderToolbar: React.FunctionComponent = ({ + children, + className, + ...props +}) => ( +
+ {children} +
+); + +CompassMainHeaderToolbar.displayName = 'CompassMainHeaderToolbar'; diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx index ef13deb96ef..1ef47f8c7bc 100644 --- a/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx @@ -74,9 +74,52 @@ test('Renders children when neither title nor toolbar are provided', () => { expect(screen.getByText('Custom children content')).toBeVisible(); }); +test('Renders CompassPanel when title is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass(styles.compassPanel); +}); + +test('Renders CompassPanel when toolbar is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass(styles.compassPanel); +}); + +test('Does not render CompassPanel when children are passed', () => { + render( + +
Children content
+
+ ); + + const content = screen.getByTestId('test-id').firstChild; + expect(content).not.toHaveClass(styles.compassPanel); +}); + +test('Passes props to CompassPanel when title and compassPanelProps is passed', () => { + render( + + ); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass('panel-class'); +}); + +test('Passes props to CompassPanel when toolbar and compassPanelProps is passed', () => { + render( + + ); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass('panel-class'); +}); + test('Renders with additional props spread to the component', () => { - render(Test); - expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); }); test('Matches the snapshot with both title and toolbar', () => { diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx new file mode 100644 index 00000000000..44475ae7dca --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderContent } from '../CompassMainHeaderContent'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-content class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-content`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx new file mode 100644 index 00000000000..9bc10b59b45 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderTitle } from '../CompassMainHeaderTitle'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-title class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-title`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx new file mode 100644 index 00000000000..62ab818f602 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderToolbar } from '../CompassMainHeaderToolbar'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-toolbar class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-toolbar`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap index a64dcc96592..fe09fdd8fee 100644 --- a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap @@ -9,17 +9,17 @@ exports[`Matches the snapshot with both title and toolbar 1`] = ` class="pf-v6-c-compass__panel" >
Title
Toolbar diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap new file mode 100644 index 00000000000..c49e1a1d468 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap new file mode 100644 index 00000000000..15ac7ab71eb --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap new file mode 100644 index 00000000000..79550ac0b48 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/examples/Compass.md b/packages/react-core/src/components/Compass/examples/Compass.md index fbfe53abcc5..94a217dd823 100644 --- a/packages/react-core/src/components/Compass/examples/Compass.md +++ b/packages/react-core/src/components/Compass/examples/Compass.md @@ -46,3 +46,21 @@ The background image of the `Compass` and `CompassHero` may be customized by usi ```ts isFullscreen file="CompassDemo.tsx" ``` + +## Composable structure + +When building a more custom implementation using Compass components, there are some intended or expected structures that must be present. + +### CompassMainHeader structure + +When using the `children` property in the `` component, you should ensure that the expected sub-components are used. The following code block shows a general structure to follow. + +```noLive + + + + {Your custom content goes here, which can include the CompassMainHeaderTitle and/or CompassMainHeaderToolbar sub-components} + + + +``` diff --git a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx index f43c55b79bb..c00a2302414 100644 --- a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx +++ b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx @@ -1,4 +1,12 @@ -import { Compass, CompassHeader, CompassHero, CompassContent, CompassMainHeader } from '@patternfly/react-core'; +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + CompassPanel, + CompassMainHeaderContent +} from '@patternfly/react-core'; import './compass.css'; export const CompassBasic: React.FunctionComponent = () => { @@ -12,7 +20,11 @@ export const CompassBasic: React.FunctionComponent = () => { -
Content title
+ + +
Content title
+
+
Content
diff --git a/packages/react-core/src/components/Compass/index.ts b/packages/react-core/src/components/Compass/index.ts index c27bc7678f1..aabf250facb 100644 --- a/packages/react-core/src/components/Compass/index.ts +++ b/packages/react-core/src/components/Compass/index.ts @@ -3,5 +3,8 @@ export * from './CompassContent'; export * from './CompassHeader'; export * from './CompassHero'; export * from './CompassMainHeader'; +export * from './CompassMainHeaderContent'; +export * from './CompassMainHeaderTitle'; +export * from './CompassMainHeaderToolbar'; export * from './CompassMessageBar'; export * from './CompassPanel'; diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 4df6169715f..e49b34ac563 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -23,7 +23,7 @@ "test:a11y": "patternfly-a11y --config patternfly-a11y.config" }, "dependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.21", + "@patternfly/patternfly": "6.5.0-prerelease.22", "@patternfly/react-charts": "workspace:^", "@patternfly/react-code-editor": "workspace:^", "@patternfly/react-core": "workspace:^", diff --git a/packages/react-icons/package.json b/packages/react-icons/package.json index f6edeb4ccdb..bc0e59a82bc 100644 --- a/packages/react-icons/package.json +++ b/packages/react-icons/package.json @@ -33,7 +33,7 @@ "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4", - "@patternfly/patternfly": "6.5.0-prerelease.21", + "@patternfly/patternfly": "6.5.0-prerelease.22", "fs-extra": "^11.3.0", "tslib": "^2.8.1" }, diff --git a/packages/react-styles/package.json b/packages/react-styles/package.json index c21a255c304..fdc7478819c 100644 --- a/packages/react-styles/package.json +++ b/packages/react-styles/package.json @@ -19,7 +19,7 @@ "clean": "rimraf dist css" }, "devDependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.21", + "@patternfly/patternfly": "6.5.0-prerelease.22", "change-case": "^5.4.4", "fs-extra": "^11.3.0" }, diff --git a/packages/react-tokens/package.json b/packages/react-tokens/package.json index 0841e4fc964..66f718d466f 100644 --- a/packages/react-tokens/package.json +++ b/packages/react-tokens/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@adobe/css-tools": "^4.4.4", - "@patternfly/patternfly": "6.5.0-prerelease.21", + "@patternfly/patternfly": "6.5.0-prerelease.22", "fs-extra": "^11.3.0" } } diff --git a/yarn.lock b/yarn.lock index abeb14925ba..56d41d9096e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4516,10 +4516,10 @@ __metadata: languageName: node linkType: hard -"@patternfly/patternfly@npm:6.5.0-prerelease.21": - version: 6.5.0-prerelease.21 - resolution: "@patternfly/patternfly@npm:6.5.0-prerelease.21" - checksum: 10c0/2de6f81ae974c005d9d38041f1bb93732567aa37fdb5e56e8547a117b126c3649e2c5133d64eb956964cb19ccb28f39f881de41b98232dc2ee83f8f5e125bfaf +"@patternfly/patternfly@npm:6.5.0-prerelease.22": + version: 6.5.0-prerelease.22 + resolution: "@patternfly/patternfly@npm:6.5.0-prerelease.22" + checksum: 10c0/664920b21d28e25a57ac45f21896db5077d065138273bed146bde22b8925091984401575579b679f7ec66fa660d2d913119d913a9daefeec41cbb15624d10140 languageName: node linkType: hard @@ -4617,7 +4617,7 @@ __metadata: version: 0.0.0-use.local resolution: "@patternfly/react-core@workspace:packages/react-core" dependencies: - "@patternfly/patternfly": "npm:6.5.0-prerelease.21" + "@patternfly/patternfly": "npm:6.5.0-prerelease.22" "@patternfly/react-icons": "workspace:^" "@patternfly/react-styles": "workspace:^" "@patternfly/react-tokens": "workspace:^" @@ -4638,7 +4638,7 @@ __metadata: resolution: "@patternfly/react-docs@workspace:packages/react-docs" dependencies: "@patternfly/documentation-framework": "npm:^6.28.9" - "@patternfly/patternfly": "npm:6.5.0-prerelease.21" + "@patternfly/patternfly": "npm:6.5.0-prerelease.22" "@patternfly/patternfly-a11y": "npm:5.1.0" "@patternfly/react-charts": "workspace:^" "@patternfly/react-code-editor": "workspace:^" @@ -4678,7 +4678,7 @@ __metadata: "@fortawesome/free-brands-svg-icons": "npm:^5.15.4" "@fortawesome/free-regular-svg-icons": "npm:^5.15.4" "@fortawesome/free-solid-svg-icons": "npm:^5.15.4" - "@patternfly/patternfly": "npm:6.5.0-prerelease.21" + "@patternfly/patternfly": "npm:6.5.0-prerelease.22" fs-extra: "npm:^11.3.0" tslib: "npm:^2.8.1" peerDependencies: @@ -4763,7 +4763,7 @@ __metadata: version: 0.0.0-use.local resolution: "@patternfly/react-styles@workspace:packages/react-styles" dependencies: - "@patternfly/patternfly": "npm:6.5.0-prerelease.21" + "@patternfly/patternfly": "npm:6.5.0-prerelease.22" change-case: "npm:^5.4.4" fs-extra: "npm:^11.3.0" languageName: unknown @@ -4805,7 +4805,7 @@ __metadata: resolution: "@patternfly/react-tokens@workspace:packages/react-tokens" dependencies: "@adobe/css-tools": "npm:^4.4.4" - "@patternfly/patternfly": "npm:6.5.0-prerelease.21" + "@patternfly/patternfly": "npm:6.5.0-prerelease.22" fs-extra: "npm:^11.3.0" languageName: unknown linkType: soft