-
Notifications
You must be signed in to change notification settings - Fork 375
feat(Compass): add compass nav components #12138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
kmcfaul
merged 19 commits into
patternfly:main
from
wise-king-sullyman:add-compass-nav-components
Nov 19, 2025
Merged
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
db5776e
feat(Compass): add compass nav components
wise-king-sullyman d02acd6
Merge branch 'main' into add-compass-nav-components
wise-king-sullyman c55a7a2
refactor to bundle children into CompassNavSearch/Home components
wise-king-sullyman 4b5f5eb
Tweak interfaces to not duplicate props from HTMLDivElement
wise-king-sullyman 40d34e7
update tests
wise-king-sullyman b8e3088
Add padding to compass demo nav
wise-king-sullyman 90e6e2b
Update icons
wise-king-sullyman 2b0d6fa
Core bump
wise-king-sullyman ba27a3f
Merge branch 'main' into add-compass-nav-components
wise-king-sullyman 36e2458
Update lockfile
wise-king-sullyman 99d749b
Update packages/react-core/src/components/Compass/CompassNavContent.tsx
wise-king-sullyman f7c0e43
Update packages/react-core/src/components/Compass/CompassNavHome.tsx
wise-king-sullyman e9539a1
Update packages/react-core/src/components/Compass/CompassNavMain.tsx
wise-king-sullyman 54ed2b9
Update packages/react-core/src/components/Compass/CompassNavSearch.tsx
wise-king-sullyman d454281
format
wise-king-sullyman edc6b88
Fix dep issue introduced during merge conflict resolution
wise-king-sullyman d5665b5
Add trigger ref to tooltips
wise-king-sullyman b44d841
Address interface/a11y feedback
wise-king-sullyman 4c8852d
Update packages/react-core/src/components/Compass/CompassNavContent.tsx
wise-king-sullyman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
packages/react-core/src/components/Compass/CompassNavContent.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<HTMLDivElement> { | ||
| /** Content of the nav content wrapper. */ | ||
| children: React.ReactNode; | ||
| } | ||
|
|
||
| export const CompassNavContent: React.FunctionComponent<CompassNavContentProps> = ({ | ||
| children, | ||
| className, | ||
| ...props | ||
| }) => ( | ||
wise-king-sullyman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <div className={css(styles.compassNavContent, className)} {...props}> | ||
| {children} | ||
| </div> | ||
| ); | ||
|
|
||
| CompassNavContent.displayName = 'CompassNavContent'; | ||
61 changes: 61 additions & 0 deletions
61
packages/react-core/src/components/Compass/CompassNavHome.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 = () => ( | ||
| <svg | ||
| width="1em" | ||
| height="1em" | ||
| className="pf-v6-svg" | ||
| viewBox="0 0 20 20" | ||
| fill="none" | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| aria-hidden="true" | ||
| > | ||
| <path | ||
| d="M8.33268 13.334H11.666" | ||
| stroke="currentcolor" | ||
| strokeWidth="1.5" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| /> | ||
| <path | ||
| d="M1.66602 6.66602L9.73102 2.63351C9.89994 2.54905 10.0988 2.54905 10.2677 2.63351L18.3327 6.66602" | ||
| stroke="currentcolor" | ||
| strokeWidth="1.5" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| /> | ||
| <path | ||
| d="M16.6673 9.16602V15.4993C16.6673 16.6039 15.7719 17.4993 14.6673 17.4993H5.33398C4.22941 17.4993 3.33398 16.6039 3.33398 15.4993V9.16602" | ||
| stroke="currentcolor" | ||
| strokeWidth="1.5" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| /> | ||
| </svg> | ||
| ); | ||
|
|
||
| export interface CompassNavHomeProps extends Omit<React.HTMLProps<HTMLDivElement>, 'onClick'> { | ||
| /** Content to display in the tooltip. Defaults to "Home". */ | ||
| tooltipContent?: React.ReactNode; | ||
| /** Click handler for the home button. */ | ||
| onClick?: React.MouseEventHandler<HTMLButtonElement>; | ||
| } | ||
|
|
||
| export const CompassNavHome: React.FunctionComponent<CompassNavHomeProps> = ({ | ||
| 'aria-label': ariaLabel = 'Home', | ||
| tooltipContent = 'Home', | ||
| className, | ||
thatblindgeye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| onClick, | ||
| ...props | ||
| }) => ( | ||
wise-king-sullyman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <div className={css(styles.compassNav + '-home', className)} {...props}> | ||
| <Tooltip content={tooltipContent}> | ||
| <Button isCircle variant="plain" icon={<CompassHomeIcon />} aria-label={ariaLabel} onClick={onClick} /> | ||
| </Tooltip> | ||
| </div> | ||
| ); | ||
|
|
||
| CompassNavHome.displayName = 'CompassNavHome'; | ||
15 changes: 15 additions & 0 deletions
15
packages/react-core/src/components/Compass/CompassNavMain.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<HTMLDivElement> { | ||
| /** Content of the nav main section (typically tabs). */ | ||
| children: React.ReactNode; | ||
| } | ||
|
|
||
| export const CompassNavMain: React.FunctionComponent<CompassNavMainProps> = ({ children, className, ...props }) => ( | ||
wise-king-sullyman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <div className={css(styles.compassNavMain, className)} {...props}> | ||
| {children} | ||
| </div> | ||
| ); | ||
|
|
||
| CompassNavMain.displayName = 'CompassNavMain'; | ||
54 changes: 54 additions & 0 deletions
54
packages/react-core/src/components/Compass/CompassNavSearch.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 = () => ( | ||
| <svg | ||
| width="1em" | ||
| height="1em" | ||
| className="pf-v6-svg" | ||
| viewBox="0 0 20 20" | ||
| fill="none" | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| aria-hidden="true" | ||
| > | ||
| <path | ||
| d="M14.166 14.166L17.4993 17.4993" | ||
| stroke="currentcolor" | ||
| strokeWidth="1.5" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| /> | ||
| <path | ||
| d="M2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333C11.0108 15.8333 12.6801 15.0846 13.887 13.8744C15.0897 12.6685 15.8333 11.0044 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667Z" | ||
| stroke="currentcolor" | ||
| strokeWidth="1.5" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| /> | ||
| </svg> | ||
| ); | ||
|
|
||
| export interface CompassNavSearchProps extends Omit<React.HTMLProps<HTMLDivElement>, 'onClick'> { | ||
| /** Content to display in the tooltip. Defaults to "Search". */ | ||
| tooltipContent?: React.ReactNode; | ||
| /** Click handler for the search button. */ | ||
| onClick?: React.MouseEventHandler<HTMLButtonElement>; | ||
| } | ||
|
|
||
| export const CompassNavSearch: React.FunctionComponent<CompassNavSearchProps> = ({ | ||
| 'aria-label': ariaLabel = 'Search', | ||
| tooltipContent = 'Search', | ||
| className, | ||
thatblindgeye marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| onClick, | ||
| ...props | ||
| }) => ( | ||
wise-king-sullyman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <div className={css(styles.compassNav + '-search', className)} {...props}> | ||
| <Tooltip content={tooltipContent}> | ||
| <Button isCircle variant="plain" icon={<CompassSearchIcon />} aria-label={ariaLabel} onClick={onClick} /> | ||
| </Tooltip> | ||
| </div> | ||
| ); | ||
|
|
||
| CompassNavSearch.displayName = 'CompassNavSearch'; | ||
37 changes: 37 additions & 0 deletions
37
packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(<CompassNavContent>Test content</CompassNavContent>); | ||
|
|
||
| expect(screen.getByText('Test content')).toBeVisible(); | ||
| }); | ||
|
|
||
| test('Renders with custom class name when className prop is provided', () => { | ||
| render(<CompassNavContent className="custom-class">Test</CompassNavContent>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveClass('custom-class'); | ||
| }); | ||
|
|
||
| test(`Renders with default ${styles.compassNavContent} class`, () => { | ||
| render(<CompassNavContent>Test</CompassNavContent>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveClass(styles.compassNavContent, { exact: true }); | ||
| }); | ||
|
|
||
| test('Renders with additional props spread to the component', () => { | ||
| render(<CompassNavContent aria-label="Test label">Test</CompassNavContent>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); | ||
| }); | ||
|
|
||
| test('Matches the snapshot', () => { | ||
| const { asFragment } = render( | ||
| <CompassNavContent> | ||
| <div>Nav content wrapper</div> | ||
| </CompassNavContent> | ||
| ); | ||
|
|
||
| expect(asFragment()).toMatchSnapshot(); | ||
| }); |
89 changes: 89 additions & 0 deletions
89
packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(<CompassNavHome />); | ||
|
|
||
| expect(screen.getByRole('button', { name: 'Home' })).toBeVisible(); | ||
| }); | ||
|
|
||
| test('Renders with custom aria-label when provided', () => { | ||
| render(<CompassNavHome aria-label="Custom home" />); | ||
|
|
||
| expect(screen.getByRole('button', { name: 'Custom home' })).toBeVisible(); | ||
| }); | ||
|
|
||
| test('Renders with default tooltip content', async () => { | ||
| const user = userEvent.setup(); | ||
|
|
||
| render(<CompassNavHome />); | ||
|
|
||
| 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(<CompassNavHome tooltipContent="Custom tooltip" />); | ||
|
|
||
| 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(<CompassNavHome className="custom-class" />); | ||
|
|
||
| expect(container.firstChild).toHaveClass('custom-class'); | ||
| }); | ||
|
|
||
| test(`Renders with default class`, () => { | ||
| const { container } = render(<CompassNavHome />); | ||
|
|
||
| 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(<CompassNavHome onClick={onClick} />); | ||
|
|
||
| await user.click(screen.getByRole('button', { name: 'Home' })); | ||
|
|
||
| expect(onClick).toHaveBeenCalledTimes(1); | ||
| }); | ||
|
|
||
| test('Renders button with plain variant and circle shape', () => { | ||
| render(<CompassNavHome />); | ||
|
|
||
| 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(<CompassNavHome />); | ||
|
|
||
| expect(asFragment()).toMatchSnapshot(); | ||
| }); | ||
|
|
||
| test('Matches the snapshot with custom props', () => { | ||
| const { asFragment } = render( | ||
| <CompassNavHome aria-label="Custom home" tooltipContent="Go home" className="custom-class" /> | ||
| ); | ||
|
|
||
| expect(asFragment()).toMatchSnapshot(); | ||
| }); |
37 changes: 37 additions & 0 deletions
37
packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(<CompassNavMain>Test content</CompassNavMain>); | ||
|
|
||
| expect(screen.getByText('Test content')).toBeVisible(); | ||
| }); | ||
|
|
||
| test('Renders with custom class name when className prop is provided', () => { | ||
| render(<CompassNavMain className="custom-class">Test</CompassNavMain>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveClass('custom-class'); | ||
| }); | ||
|
|
||
| test(`Renders with default ${styles.compassNavMain} class`, () => { | ||
| render(<CompassNavMain>Test</CompassNavMain>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveClass(styles.compassNavMain, { exact: true }); | ||
| }); | ||
|
|
||
| test('Renders with additional props spread to the component', () => { | ||
| render(<CompassNavMain aria-label="Test label">Test</CompassNavMain>); | ||
|
|
||
| expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); | ||
| }); | ||
|
|
||
| test('Matches the snapshot', () => { | ||
| const { asFragment } = render( | ||
| <CompassNavMain> | ||
| <div>Main tabs content</div> | ||
| </CompassNavMain> | ||
| ); | ||
|
|
||
| expect(asFragment()).toMatchSnapshot(); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.