Skip to content

Commit ccad519

Browse files
feat(Compass): added responsive docked compass (#12382)
* feat(Compass): added responsive docked compass * Updated docs and toggle logic * Added inert to mobile items when collapsed
1 parent 3392662 commit ccad519

17 files changed

Lines changed: 496 additions & 161 deletions

File tree

packages/react-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"tslib": "^2.8.1"
5555
},
5656
"devDependencies": {
57-
"@patternfly/patternfly": "6.5.0-prerelease.75",
57+
"@patternfly/patternfly": "6.5.0-prerelease.78",
5858
"case-anything": "^3.1.2",
5959
"css": "^3.0.0",
6060
"fs-extra": "^11.3.3"

packages/react-core/src/components/Compass/Compass.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@ import compassBackgroundImageDark from '@patternfly/react-tokens/dist/esm/c_comp
88
export interface CompassProps extends React.HTMLProps<HTMLDivElement> {
99
/** Additional classes added to the Compass. */
1010
className?: string;
11+
/** The horizontal masthead content (e.g. <Masthead />). This masthead will only render when dock content is passed and only at mobile viewports. */
12+
masthead?: React.ReactNode;
1113
/** Content of the docked navigation area of the layout */
1214
dock?: React.ReactNode;
13-
/** Content placed at the top of the layout */
15+
/** @beta Flag indicating the docked nav is expanded on mobile. Only applies when dock content is passed. */
16+
isDockExpanded?: boolean;
17+
/** @beta Flag indicating the docked nav should display text on desktop. Only applies when dock content is passed, and
18+
* will handle toggling the visibility of the text in individual isDocked components.
19+
*/
20+
isDockTextExpanded?: boolean;
21+
/** Content placed at the top of the compass layout */
1422
header?: React.ReactNode;
1523
/** Flag indicating if the header is expanded */
1624
isHeaderExpanded?: boolean;
@@ -40,7 +48,10 @@ export interface CompassProps extends React.HTMLProps<HTMLDivElement> {
4048

4149
export const Compass: React.FunctionComponent<CompassProps> = ({
4250
className,
51+
masthead,
4352
dock,
53+
isDockExpanded,
54+
isDockTextExpanded,
4455
header,
4556
isHeaderExpanded = true,
4657
sidebarStart,
@@ -72,7 +83,18 @@ export const Compass: React.FunctionComponent<CompassProps> = ({
7283
{...props}
7384
style={{ ...props.style, ...backgroundImageStyles }}
7485
>
75-
{dock && <div className={css(`${styles.compass}__dock`)}>{dock}</div>}
86+
{dock && masthead}
87+
{dock && (
88+
<div
89+
className={css(
90+
`${styles.compass}__dock`,
91+
isDockExpanded && styles.modifiers.expanded,
92+
isDockTextExpanded && styles.modifiers.textExpanded
93+
)}
94+
>
95+
{dock}
96+
</div>
97+
)}
7698
{header && (
7799
<div
78100
className={css(styles.compassHeader, isHeaderExpanded && 'pf-m-expanded')}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
2+
import { css } from '@patternfly/react-styles';
3+
4+
export interface CompassDockMainProps extends React.HTMLProps<HTMLDivElement> {
5+
/** Additional classes added to the compass dock main container. */
6+
className?: string;
7+
/** Content of the compass dock main container. */
8+
children?: React.ReactNode;
9+
}
10+
11+
export const CompassDockMain: React.FunctionComponent<CompassDockMainProps> = ({
12+
className,
13+
children,
14+
...props
15+
}: CompassDockMainProps) => (
16+
<div className={css(styles.compassDockMain, className)} {...props}>
17+
{children}
18+
</div>
19+
);
20+
21+
CompassDockMain.displayName = 'CompassDockMain';

packages/react-core/src/components/Compass/__tests__/Compass.test.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,33 @@ test(`Does not render with ${styles.modifiers.docked} class when dock is not pas
180180
render(<Compass data-testid="compass" />);
181181
expect(screen.getByTestId('compass')).not.toHaveClass(styles.modifiers.docked);
182182
});
183+
184+
test('Does not render masthead content when dock is not passed', () => {
185+
render(<Compass masthead="Masthead content" />);
186+
expect(screen.queryByText('Masthead content')).not.toBeInTheDocument();
187+
});
188+
189+
test('Renders masthead content when dock is passed', () => {
190+
render(<Compass masthead={<div>Masthead content</div>} dock={<div>Dock content</div>} />);
191+
expect(screen.getByText('Masthead content')).toBeVisible();
192+
});
193+
194+
test(`Renders dock with ${styles.modifiers.expanded} class when isDockExpanded is true`, () => {
195+
render(<Compass dock="Dock content" isDockExpanded />);
196+
expect(screen.getByText('Dock content')).toHaveClass(styles.modifiers.expanded);
197+
});
198+
199+
test(`Renders dock without ${styles.modifiers.expanded} class when isDockExpanded is false`, () => {
200+
render(<Compass dock="Dock content" isDockExpanded={false} />);
201+
expect(screen.getByText('Dock content')).not.toHaveClass(styles.modifiers.expanded);
202+
});
203+
204+
test(`Renders dock with ${styles.modifiers.textExpanded} class when isDockTextExpanded is true`, () => {
205+
render(<Compass dock="Dock content" isDockTextExpanded />);
206+
expect(screen.getByText('Dock content')).toHaveClass(styles.modifiers.textExpanded);
207+
});
208+
209+
test(`Renders dock without ${styles.modifiers.textExpanded} class when isDockTextExpanded is false`, () => {
210+
render(<Compass dock="Dock content" isDockTextExpanded={false} />);
211+
expect(screen.getByText('Dock content')).not.toHaveClass(styles.modifiers.textExpanded);
212+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { CompassDockMain } from '../CompassDockMain';
3+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
4+
5+
test('Renders without children', () => {
6+
render(
7+
<div data-testid="test-compass-dock-main">
8+
<CompassDockMain />
9+
</div>
10+
);
11+
expect(screen.getByTestId('test-compass-dock-main').firstChild).toBeVisible();
12+
});
13+
14+
test('Renders with children', () => {
15+
render(<CompassDockMain>Test content</CompassDockMain>);
16+
expect(screen.getByText('Test content')).toBeVisible();
17+
});
18+
19+
test('Renders with custom class name when className prop is provided', () => {
20+
render(<CompassDockMain className="custom-class">Test</CompassDockMain>);
21+
expect(screen.getByText('Test')).toHaveClass('custom-class');
22+
});
23+
24+
test(`Renders with default ${styles.compassDockMain} class`, () => {
25+
render(<CompassDockMain>Test</CompassDockMain>);
26+
expect(screen.getByText('Test')).toHaveClass(styles.compassDockMain, { exact: true });
27+
});
28+
29+
test('Renders with additional props spread to the component', () => {
30+
render(<CompassDockMain id="custom-id">Test</CompassDockMain>);
31+
expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id');
32+
});
33+
34+
test('Matches the snapshot', () => {
35+
const { asFragment } = render(
36+
<CompassDockMain>
37+
<div>Test content</div>
38+
</CompassDockMain>
39+
);
40+
expect(asFragment()).toMatchSnapshot();
41+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Matches the snapshot 1`] = `
4+
<DocumentFragment>
5+
<div
6+
class="pf-v6-c-compass__dock-main"
7+
>
8+
<div>
9+
Test content
10+
</div>
11+
</div>
12+
</DocumentFragment>
13+
`;

packages/react-core/src/components/Compass/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './Compass';
22
export * from './CompassContent';
3+
export * from './CompassDockMain';
34
export * from './CompassHeader';
45
export * from './CompassHero';
56
export * from './CompassMainHeader';

packages/react-core/src/components/Page/Page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ export interface PageProps extends React.HTMLProps<HTMLDivElement> {
2424
variant?: 'default' | 'docked';
2525
/** @beta Flag indicating the docked nav is expanded on mobile. Only applies when variant is docked. */
2626
isDockExpanded?: boolean;
27-
/** @beta Flag indicating the docked nav should display text on desktop. Only applies when variant is docked, and will handle
28-
* setting isTextExpanded on individual isDocked components.
29-
* */
27+
/** @beta Flag indicating the docked nav should display text on desktop. Only applies when variant is docked, and
28+
* will handle toggling the visibility of the text in individual isDocked components.
29+
*/
3030
isDockTextExpanded?: boolean;
3131
/** The horizontal masthead content (e.g. <Masthead />). When using the docked variant, this content will only render at mobile viewports. */
3232
masthead?: React.ReactNode;

packages/react-core/src/demos/Compass/Compass.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ section: AI
44
subsection: Generative UIs
55
---
66

7-
import { useRef, useState } from 'react';
7+
import { useRef, useState, useEffect } from 'react';
88
import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon';
99
import OutlinedPlusSquare from '@patternfly/react-icons/dist/esm/icons/outlined-plus-square-icon';
1010
import OutlinedCopy from '@patternfly/react-icons/dist/esm/icons/outlined-copy-icon';
@@ -14,8 +14,11 @@ import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon';
1414
import RhUiQuestionMarkCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-question-mark-circle-fill-icon';
1515
import CloudIcon from '@patternfly/react-icons/dist/esm/icons/cloud-icon';
1616
import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
17+
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
1718
import imgAvatar from '../assets/avatarImg.svg';
19+
import ThIcon from '@patternfly/react-icons/dist/esm/icons/th-icon';
1820
import pfLogo from '../assets/PF-IconLogo-color.svg';
21+
import globalBreakpointLg from '@patternfly/react-tokens/dist/esm/t_global_breakpoint_lg';
1922

2023
## Demos
2124

0 commit comments

Comments
 (0)