diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 73d260a2dce..319018a7942 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.22", + "@patternfly/patternfly": "6.5.0-prerelease.26", "case-anything": "^3.1.2", "css": "^3.0.0", "fs-extra": "^11.3.0" diff --git a/packages/react-core/src/components/Compass/CompassNavContent.tsx b/packages/react-core/src/components/Compass/CompassNavContent.tsx new file mode 100644 index 00000000000..3d962976fff --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassNavContent.tsx @@ -0,0 +1,18 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; +export interface CompassNavContentProps extends React.HTMLProps { + /** Content of the nav content wrapper. */ + children: React.ReactNode; +} + +export const CompassNavContent: React.FunctionComponent = ({ + children, + className, + ...props +}) => ( +
+ {children} +
+); + +CompassNavContent.displayName = 'CompassNavContent'; diff --git a/packages/react-core/src/components/Compass/CompassNavHome.tsx b/packages/react-core/src/components/Compass/CompassNavHome.tsx new file mode 100644 index 00000000000..1ecd73736d4 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassNavHome.tsx @@ -0,0 +1,61 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; +import { Button } from '../Button'; +import { Tooltip } from '../Tooltip'; + +const CompassHomeIcon = () => ( + +); + +export interface CompassNavHomeProps extends Omit, 'onClick'> { + /** Content to display in the tooltip. Defaults to "Home". */ + tooltipContent?: React.ReactNode; + /** Click handler for the home button. */ + onClick?: React.MouseEventHandler; +} + +export const CompassNavHome: React.FunctionComponent = ({ + 'aria-label': ariaLabel = 'Home', + tooltipContent = 'Home', + className, + onClick, + ...props +}) => ( +
+ +
+); + +CompassNavHome.displayName = 'CompassNavHome'; diff --git a/packages/react-core/src/components/Compass/CompassNavMain.tsx b/packages/react-core/src/components/Compass/CompassNavMain.tsx new file mode 100644 index 00000000000..1dfde77e721 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassNavMain.tsx @@ -0,0 +1,15 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; + +export interface CompassNavMainProps extends React.HTMLProps { + /** Content of the nav main section (typically tabs). */ + children: React.ReactNode; +} + +export const CompassNavMain: React.FunctionComponent = ({ children, className, ...props }) => ( +
+ {children} +
+); + +CompassNavMain.displayName = 'CompassNavMain'; diff --git a/packages/react-core/src/components/Compass/CompassNavSearch.tsx b/packages/react-core/src/components/Compass/CompassNavSearch.tsx new file mode 100644 index 00000000000..8e6ad1998a6 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassNavSearch.tsx @@ -0,0 +1,54 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; +import { Button } from '../Button'; +import { Tooltip } from '../Tooltip'; + +const CompassSearchIcon = () => ( + +); + +export interface CompassNavSearchProps extends Omit, 'onClick'> { + /** Content to display in the tooltip. Defaults to "Search". */ + tooltipContent?: React.ReactNode; + /** Click handler for the search button. */ + onClick?: React.MouseEventHandler; +} + +export const CompassNavSearch: React.FunctionComponent = ({ + 'aria-label': ariaLabel = 'Search', + tooltipContent = 'Search', + className, + onClick, + ...props +}) => ( +
+ +
+); + +CompassNavSearch.displayName = 'CompassNavSearch'; diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx new file mode 100644 index 00000000000..eb176b5ccae --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { CompassNavContent } from '../CompassNavContent'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Test content); + + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassNavContent} class`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.compassNavContent, { exact: true }); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Nav content wrapper
+
+ ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx new file mode 100644 index 00000000000..020d154cfd5 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx @@ -0,0 +1,89 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { CompassNavHome } from '../CompassNavHome'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with default aria-label', () => { + render(); + + expect(screen.getByRole('button', { name: 'Home' })).toBeVisible(); +}); + +test('Renders with custom aria-label when provided', () => { + render(); + + expect(screen.getByRole('button', { name: 'Custom home' })).toBeVisible(); +}); + +test('Renders with default tooltip content', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Home'); +}); + +test('Renders with custom tooltip content when provided', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + user.hover(button); + + await screen.findByRole('tooltip'); + expect(screen.getByRole('tooltip')).toHaveTextContent('Custom tooltip'); +}); + +test('Renders with custom class name when className prop is provided', () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass('custom-class'); +}); + +test(`Renders with default class`, () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass(styles.compassNav + '-home', { exact: true }); +}); + +test('Calls onClick handler when button is clicked', async () => { + const user = userEvent.setup(); + const onClick = jest.fn(); + + render(); + + await user.click(screen.getByRole('button', { name: 'Home' })); + + expect(onClick).toHaveBeenCalledTimes(1); +}); + +test('Renders button with plain variant and circle shape', () => { + render(); + + const button = screen.getByRole('button', { name: 'Home' }); + + expect(button).toHaveClass('pf-m-plain'); + expect(button).toHaveClass('pf-m-circle'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with custom props', () => { + const { asFragment } = render( + + ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx new file mode 100644 index 00000000000..0242f9ef64c --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { CompassNavMain } from '../CompassNavMain'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Test content); + + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassNavMain} class`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.compassNavMain, { exact: true }); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Main tabs content
+
+ ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx new file mode 100644 index 00000000000..2c5432c9bb2 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx @@ -0,0 +1,87 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { CompassNavSearch } from '../CompassNavSearch'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with default aria-label', () => { + render(); + expect(screen.getByRole('button', { name: 'Search' })).toBeVisible(); +}); + +test('Renders with custom aria-label when provided', () => { + render(); + expect(screen.getByRole('button', { name: 'Custom search' })).toBeVisible(); +}); + +test('Renders with default tooltip content', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Search'); +}); + +test('Renders with custom tooltip content when provided', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Custom tooltip'); +}); + +test('Renders with custom class name when className prop is provided', () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass('custom-class'); +}); + +test(`Renders with default class`, () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass(styles.compassNav + '-search', { exact: true }); +}); + +test('Calls onClick handler when button is clicked', async () => { + const user = userEvent.setup(); + const onClick = jest.fn(); + + render(); + + await user.click(screen.getByRole('button', { name: 'Search' })); + + expect(onClick).toHaveBeenCalledTimes(1); +}); + +test('Renders button with plain variant and circle shape', () => { + render(); + + const button = screen.getByRole('button', { name: 'Search' }); + + expect(button).toHaveClass('pf-m-plain'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with custom props', () => { + const { asFragment } = render( + + ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap new file mode 100644 index 00000000000..df1e9a2ddea --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Nav content wrapper +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap new file mode 100644 index 00000000000..552af070bb2 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ +
+
+
+`; + +exports[`Matches the snapshot with custom props 1`] = ` + +
+
+ +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap new file mode 100644 index 00000000000..53987fbf559 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Main tabs content +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap new file mode 100644 index 00000000000..5a775d0967d --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + + + +`; + +exports[`Matches the snapshot with custom props 1`] = ` + + + +`; diff --git a/packages/react-core/src/components/Compass/examples/CompassDemo.tsx b/packages/react-core/src/components/Compass/examples/CompassDemo.tsx index f2c08e72180..e70a9b15873 100644 --- a/packages/react-core/src/components/Compass/examples/CompassDemo.tsx +++ b/packages/react-core/src/components/Compass/examples/CompassDemo.tsx @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + import { useRef, useState } from 'react'; import { Compass, @@ -7,6 +9,10 @@ import { CompassMainHeader, CompassPanel, CompassMessageBar, + CompassNavContent, + CompassNavHome, + CompassNavMain, + CompassNavSearch, Hero, Tabs, TabsComponent, @@ -32,49 +38,57 @@ export const CompassBasic: React.FunctionComponent = () => { const navContent = ( <> - - setActiveTab(tabIndex as number)} - component={TabsComponent.nav} - aria-label="Compass navigation tabs" - inset={{ default: 'insetXl' }} - > - Tab 1} - aria-label="Compass tab with subtabs" - /> - Tab 2} /> - Tab 3} /> - Disabled Tab 4} isDisabled /> - + + + console.log('Home')} /> + + setActiveTab(tabIndex as number)} + component={TabsComponent.nav} + aria-label="Compass navigation tabs" + > + Tab 1} + aria-label="Compass tab with subtabs" + /> + Tab 2} /> + Tab 3} /> + Disabled Tab 4} isDisabled /> + + + console.log('Search')} /> + - setActiveSubtab(tabIndex as number)} - aria-label="Compass navigation subtabs" - inset={{ default: 'insetXl' }} - > - -
Subtab 1
- - } - /> - Subtab 2} /> - Disabled Subtab 3} isDisabled /> -
+ + + setActiveSubtab(tabIndex as number)} + aria-label="Compass navigation subtabs" + > + +
Subtab 1
+ + } + /> + Subtab 2} /> + Disabled Subtab 3} isDisabled /> +
+
+
diff --git a/packages/react-core/src/components/Compass/index.ts b/packages/react-core/src/components/Compass/index.ts index aabf250facb..936b03ca5af 100644 --- a/packages/react-core/src/components/Compass/index.ts +++ b/packages/react-core/src/components/Compass/index.ts @@ -7,4 +7,8 @@ export * from './CompassMainHeaderContent'; export * from './CompassMainHeaderTitle'; export * from './CompassMainHeaderToolbar'; export * from './CompassMessageBar'; +export * from './CompassNavContent'; +export * from './CompassNavHome'; +export * from './CompassNavMain'; +export * from './CompassNavSearch'; export * from './CompassPanel'; diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index e49b34ac563..b1afc4cdd48 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.22", + "@patternfly/patternfly": "6.5.0-prerelease.26", "@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 bc0e59a82bc..d5b42ebc603 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.22", + "@patternfly/patternfly": "6.5.0-prerelease.26", "fs-extra": "^11.3.0", "tslib": "^2.8.1" }, diff --git a/packages/react-styles/package.json b/packages/react-styles/package.json index fdc7478819c..b644b8299d9 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.22", + "@patternfly/patternfly": "6.5.0-prerelease.26", "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 66f718d466f..3ae19bde72d 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.22", + "@patternfly/patternfly": "6.5.0-prerelease.26", "fs-extra": "^11.3.0" } } diff --git a/yarn.lock b/yarn.lock index 56d41d9096e..8db1106b8e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4516,10 +4516,10 @@ __metadata: languageName: node linkType: hard -"@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 +"@patternfly/patternfly@npm:6.5.0-prerelease.26": + version: 6.5.0-prerelease.26 + resolution: "@patternfly/patternfly@npm:6.5.0-prerelease.26" + checksum: 10c0/052ea96553532dae97cfc2275dc3fcc86615bf2526781300555e097574c2983d0869cf9523a9076ff8eba1c8be808525afef75d0ac99059391e82d2007aa18f1 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.22" + "@patternfly/patternfly": "npm:6.5.0-prerelease.26" "@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.22" + "@patternfly/patternfly": "npm:6.5.0-prerelease.26" "@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.22" + "@patternfly/patternfly": "npm:6.5.0-prerelease.26" 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.22" + "@patternfly/patternfly": "npm:6.5.0-prerelease.26" 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.22" + "@patternfly/patternfly": "npm:6.5.0-prerelease.26" fs-extra: "npm:^11.3.0" languageName: unknown linkType: soft