Skip to content

Commit 0fec3f9

Browse files
committed
feat(Compass): updated mainheader structure to be composable
1 parent 7f37467 commit 0fec3f9

23 files changed

+267
-80
lines changed

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.19",
57+
"@patternfly/patternfly": "6.5.0-prerelease.22",
5858
"case-anything": "^3.1.2",
5959
"css": "^3.0.0",
6060
"fs-extra": "^11.3.0"

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

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
import styles from '@patternfly/react-styles/css/components/Compass/compass';
22
import { css } from '@patternfly/react-styles';
33

4-
import compassHeroBackgroundImageLight from '@patternfly/react-tokens/dist/esm/c_compass__hero_BackgroundImage_light';
5-
import compassHeroBackgroundImageDark from '@patternfly/react-tokens/dist/esm/c_compass__hero_BackgroundImage_dark';
6-
import compassHeroGradientStop1Light from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_1_light';
7-
import compassHeroGradientStop2Light from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_2_light';
8-
import compassHeroGradientStop3Light from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_3_light';
9-
import compassHeroGradientStop1Dark from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_1_dark';
10-
import compassHeroGradientStop2Dark from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_2_dark';
11-
import compassHeroGradientStop3Dark from '@patternfly/react-tokens/dist/esm/c_compass__hero_gradient_stop_3_dark';
12-
134
interface CompassHeroProps extends Omit<React.HTMLProps<HTMLDivElement>, 'content'> {
145
/** Content of the hero */
156
children?: React.ReactNode;
@@ -33,53 +24,16 @@ interface CompassHeroProps extends Omit<React.HTMLProps<HTMLDivElement>, 'conten
3324
};
3425
}
3526

36-
export const CompassHero: React.FunctionComponent<CompassHeroProps> = ({
37-
className,
38-
children,
39-
backgroundSrcLight,
40-
backgroundSrcDark,
41-
gradientLight,
42-
gradientDark,
43-
...props
44-
}) => {
27+
export const CompassHero: React.FunctionComponent<CompassHeroProps> = ({ className, children, ...props }) => {
4528
const backgroundImageStyles: { [key: string]: string } = {};
46-
if (backgroundSrcLight) {
47-
backgroundImageStyles[compassHeroBackgroundImageLight.name] = `url(${backgroundSrcLight})`;
48-
}
49-
if (backgroundSrcDark) {
50-
backgroundImageStyles[compassHeroBackgroundImageDark.name] = `url(${backgroundSrcDark})`;
51-
}
52-
53-
if (gradientLight) {
54-
if (gradientLight.stop1) {
55-
backgroundImageStyles[compassHeroGradientStop1Light.name] = gradientLight.stop1;
56-
}
57-
if (gradientLight.stop2) {
58-
backgroundImageStyles[compassHeroGradientStop2Light.name] = gradientLight.stop2;
59-
}
60-
if (gradientLight.stop3) {
61-
backgroundImageStyles[compassHeroGradientStop3Light.name] = gradientLight.stop3;
62-
}
63-
}
64-
if (gradientDark) {
65-
if (gradientDark.stop1) {
66-
backgroundImageStyles[compassHeroGradientStop1Dark.name] = gradientDark.stop1;
67-
}
68-
if (gradientDark.stop2) {
69-
backgroundImageStyles[compassHeroGradientStop2Dark.name] = gradientDark.stop2;
70-
}
71-
if (gradientDark.stop3) {
72-
backgroundImageStyles[compassHeroGradientStop3Dark.name] = gradientDark.stop3;
73-
}
74-
}
7529

7630
return (
7731
<div
78-
className={css(styles.compassPanel, styles.compassHero, className)}
32+
className={css(styles.compassPanel, className)}
7933
style={{ ...props.style, ...backgroundImageStyles }}
8034
{...props}
8135
>
82-
<div className={css(styles.compassHeroBody)}>{children}</div>
36+
<div className={css()}>{children}</div>
8337
</div>
8438
);
8539
};

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
1-
import { Flex, FlexItem } from '../../layouts/Flex';
2-
import { CompassPanel } from './CompassPanel';
1+
import { CompassPanel, CompassPanelProps } from './CompassPanel';
32
import styles from '@patternfly/react-styles/css/components/Compass/compass';
43
import { css } from '@patternfly/react-styles';
54

5+
/** The wrapper component for header content in the main compass area. When building out a custom implementation,
6+
* you should ensure any content within the main header is rendered inside a compass panel and main header content wrappers.
7+
*/
8+
69
interface CompassMainHeaderProps extends Omit<React.HTMLProps<HTMLDivElement>, 'title'> {
10+
/** Custom main header content. To opt into a default styling, use the title and toolbar props instead. */
11+
children?: React.ReactNode;
712
/** Additional classes added to the main header */
813
className?: string;
914
/** Styled title. If title or toolbar is provided, the children will be ignored. */
1015
title?: React.ReactNode;
1116
/** Styled toolbar. If title or toolbar is provided, the children will be ignored. */
1217
toolbar?: React.ReactNode;
13-
/** Custom main header content. To opt into a default styling, use the title and toolbar props instead. */
14-
children?: React.ReactNode;
18+
/** Additional props passed to the compass panel that wraps the main header content when using the title or toolbar props. When using the
19+
* children prop, you should pass your own compass panel.
20+
*/
21+
compassPanelProps?: Omit<CompassPanelProps, 'children'>;
1522
}
1623

1724
export const CompassMainHeader: React.FunctionComponent<CompassMainHeaderProps> = ({
1825
className,
1926
title,
2027
toolbar,
2128
children,
29+
compassPanelProps,
2230
...props
2331
}) => {
2432
const _content =
2533
title !== undefined || toolbar !== undefined ? (
26-
<CompassPanel>
27-
<Flex alignItems={{ default: 'alignItemsCenter' }}>
28-
<FlexItem grow={{ default: 'grow' }}>{title}</FlexItem>
29-
{toolbar && <FlexItem>{toolbar}</FlexItem>}
30-
</Flex>
34+
<CompassPanel {...compassPanelProps}>
35+
<div className={css(`${styles.compass}__main-header-content`)}>
36+
{title && <div className={css(`${styles.compass}__main-header-title`)}>{title}</div>}
37+
{toolbar && <div className={css(`${styles.compass}__main-header-toolbar`)}>{toolbar}</div>}
38+
</div>
3139
</CompassPanel>
3240
) : (
3341
children
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
2+
import { css } from '@patternfly/react-styles';
3+
4+
/** A wrapper component to be passed as custom content for the compass main header. This should also be wrapped
5+
* in a compass panel component.
6+
*/
7+
8+
export interface CompassMainHeaderContentProps extends React.HTMLProps<HTMLDivElement> {
9+
/** Content of the main header content. */
10+
children: React.ReactNode;
11+
/** Additional classes added to the main header content. */
12+
className?: string;
13+
}
14+
15+
export const CompassMainHeaderContent: React.FunctionComponent<CompassMainHeaderContentProps> = ({
16+
children,
17+
className,
18+
...props
19+
}) => (
20+
<div className={css(styles.compassMainHeaderContent, className)} {...props}>
21+
{children}
22+
</div>
23+
);
24+
25+
CompassMainHeaderContent.displayName = 'CompassMainHeaderContent';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
2+
import { css } from '@patternfly/react-styles';
3+
4+
/** A wrapper component for custom title content to be passed into a compass main header. This should also be wrapped
5+
* by a compass main header content component.
6+
*/
7+
8+
export interface CompassMainHeaderTitleProps extends React.HTMLProps<HTMLDivElement> {
9+
/** Content of the main header title. */
10+
children: React.ReactNode;
11+
/** Additional classes added to the main header title. */
12+
className?: string;
13+
}
14+
15+
export const CompassMainHeaderTitle: React.FunctionComponent<CompassMainHeaderTitleProps> = ({
16+
children,
17+
className,
18+
...props
19+
}) => (
20+
<div className={css(`${styles.compass}__main-header-title`, className)} {...props}>
21+
{children}
22+
</div>
23+
);
24+
25+
CompassMainHeaderTitle.displayName = 'CompassMainHeaderTitle';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
2+
import { css } from '@patternfly/react-styles';
3+
4+
/** A wrapper component for custom toolbar content to be passed into a compass main header. This should also be wrapped
5+
* by a compass main header content component.
6+
*/
7+
8+
export interface CompassMainHeaderToolbarProps extends React.HTMLProps<HTMLDivElement> {
9+
/** Content of the main header toolbar. */
10+
children: React.ReactNode;
11+
/** Additional classes added to the main header toolbar. */
12+
className?: string;
13+
}
14+
15+
export const CompassMainHeaderToolbar: React.FunctionComponent<CompassMainHeaderToolbarProps> = ({
16+
children,
17+
className,
18+
...props
19+
}) => (
20+
<div className={css(`${styles.compass}__main-header-toolbar`, className)} {...props}>
21+
{children}
22+
</div>
23+
);
24+
25+
CompassMainHeaderToolbar.displayName = 'CompassMainHeaderToolbar';

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import styles from '@patternfly/react-styles/css/components/Compass/compass';
22
import { css } from '@patternfly/react-styles';
33

4-
interface CompassPanelProps extends React.HTMLProps<HTMLDivElement> {
4+
export interface CompassPanelProps extends React.HTMLProps<HTMLDivElement> {
55
/** Content of the panel. */
66
children: React.ReactNode;
77
/** Additional classes added to the panel. */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ test('Renders children when neither title nor toolbar are provided', () => {
7575
});
7676

7777
test('Renders with additional props spread to the component', () => {
78-
render(<CompassMainHeader aria-label="Test label">Test</CompassMainHeader>);
79-
expect(screen.getByText('Test')).toHaveAccessibleName('Test label');
78+
render(<CompassMainHeader id="custom-id">Test</CompassMainHeader>);
79+
expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id');
8080
});
8181

8282
test('Matches the snapshot with both title and toolbar', () => {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { CompassMainHeaderContent } from '../CompassMainHeaderContent';
3+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
4+
5+
test('Renders with children', () => {
6+
render(<CompassMainHeaderContent>Custom content</CompassMainHeaderContent>);
7+
expect(screen.getByText('Custom content')).toBeVisible();
8+
});
9+
10+
test(`Renders with default ${styles.compass}__main-header-content class`, () => {
11+
render(<CompassMainHeaderContent>Test</CompassMainHeaderContent>);
12+
expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-content`);
13+
});
14+
15+
test('Renders with custom class name when className prop is provided', () => {
16+
render(<CompassMainHeaderContent className="custom-class">Test</CompassMainHeaderContent>);
17+
expect(screen.getByText('Test')).toHaveClass('custom-class');
18+
});
19+
20+
test('Renders with additional props spread to the component', () => {
21+
render(<CompassMainHeaderContent id="custom-id">Test</CompassMainHeaderContent>);
22+
expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id');
23+
});
24+
25+
test('Matches the snapshot', () => {
26+
const { asFragment } = render(<CompassMainHeaderContent>Content</CompassMainHeaderContent>);
27+
expect(asFragment()).toMatchSnapshot();
28+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { CompassMainHeaderTitle } from '../CompassMainHeaderTitle';
3+
import styles from '@patternfly/react-styles/css/components/Compass/compass';
4+
5+
test('Renders with children', () => {
6+
render(<CompassMainHeaderTitle>Custom content</CompassMainHeaderTitle>);
7+
expect(screen.getByText('Custom content')).toBeVisible();
8+
});
9+
10+
test(`Renders with default ${styles.compass}__main-header-title class`, () => {
11+
render(<CompassMainHeaderTitle>Test</CompassMainHeaderTitle>);
12+
expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-title`);
13+
});
14+
15+
test('Renders with custom class name when className prop is provided', () => {
16+
render(<CompassMainHeaderTitle className="custom-class">Test</CompassMainHeaderTitle>);
17+
expect(screen.getByText('Test')).toHaveClass('custom-class');
18+
});
19+
20+
test('Renders with additional props spread to the component', () => {
21+
render(<CompassMainHeaderTitle id="custom-id">Test</CompassMainHeaderTitle>);
22+
expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id');
23+
});
24+
25+
test('Matches the snapshot', () => {
26+
const { asFragment } = render(<CompassMainHeaderTitle>Content</CompassMainHeaderTitle>);
27+
expect(asFragment()).toMatchSnapshot();
28+
});

0 commit comments

Comments
 (0)