From 705bf3080af14b227d648c3d356d953360c78461 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Wed, 12 Nov 2025 13:06:18 -0500 Subject: [PATCH 1/4] feat(Compass): add CompassMainFooter --- .../components/Compass/CompassMainFooter.tsx | 21 ++++++++++ .../components/Compass/examples/Compass.md | 11 ++++- .../examples/CompassMainFooterDemo.tsx | 42 +++++++++++++++++++ .../components/Compass/examples/compass.css | 16 ++++++- .../src/components/Compass/index.ts | 1 + 5 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 packages/react-core/src/components/Compass/CompassMainFooter.tsx create mode 100644 packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx diff --git a/packages/react-core/src/components/Compass/CompassMainFooter.tsx b/packages/react-core/src/components/Compass/CompassMainFooter.tsx new file mode 100644 index 00000000000..d4828974682 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassMainFooter.tsx @@ -0,0 +1,21 @@ +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import { css } from '@patternfly/react-styles'; + +interface CompassMainFooterProps extends Omit, 'title'> { + /** Additional classes added to the main footer */ + className?: string; + /** Main footer content */ + children?: React.ReactNode; +} + +export const CompassMainFooter: React.FunctionComponent = ({ + className, + children, + ...props +}) => ( +
+ {children} +
+); + +CompassMainFooter.displayName = 'CompassMainFooter'; diff --git a/packages/react-core/src/components/Compass/examples/Compass.md b/packages/react-core/src/components/Compass/examples/Compass.md index af4df67604f..b24170a3eea 100644 --- a/packages/react-core/src/components/Compass/examples/Compass.md +++ b/packages/react-core/src/components/Compass/examples/Compass.md @@ -16,13 +16,14 @@ propComponents: ] --- -import './compass.css'; import { useRef, useState } from 'react'; import PlayIcon from '@patternfly/react-icons/dist/esm/icons/play-icon'; import OutlinedPlusSquare from '@patternfly/react-icons/dist/esm/icons/outlined-plus-square-icon'; import OutlinedCopy from '@patternfly/react-icons/dist/esm/icons/outlined-copy-icon'; import OutlinedQuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/outlined-question-circle-icon'; +import './compass.css'; + ## Examples ### Basic @@ -41,6 +42,14 @@ The background image of the `Compass` and `CompassHero` may be customized by usi ``` +### With alternate footer + +When `footer` is used, its content will take up the width of the screen. However, if content inside of the footer grows, then the two sidebars' heights and placement will adjust to allow for the change. If this is not the desired behavior, then using a `CompassMainFooter` inside of the of the `main` section provides an alterate way to render footer content without interfering with the sidebars, by rendering content at the bottom of the page between the two sidebars opposed to the whole bottom of the page. + +```ts file="CompassMainFooterDemo.tsx" + +``` + ### Demo ```ts isFullscreen file="CompassDemo.tsx" diff --git a/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx new file mode 100644 index 00000000000..9d26948051f --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx @@ -0,0 +1,42 @@ +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + CompassMainFooter +} from '@patternfly/react-core'; +import './compass.css'; + +export const CompassMainFooterDemo: React.FunctionComponent = () => { + const headerContent = Logo} nav={
Nav
} profile={
Profile
} />; + const sidebarStartContent =
Sidebar start
; + // TODO: simplify mainContent to only a div string + const mainContent = ( + <> + +
Hero
+
+ + +
Content title
+
+
Content
+
+ +
Footer
+
+ + ); + const sidebarEndContent =
Sidebar end
; + + return ( + + ); +}; diff --git a/packages/react-core/src/components/Compass/examples/compass.css b/packages/react-core/src/components/Compass/examples/compass.css index 46c3b19746b..75aef0a3a59 100644 --- a/packages/react-core/src/components/Compass/examples/compass.css +++ b/packages/react-core/src/components/Compass/examples/compass.css @@ -1,8 +1,20 @@ -#ws-react-c-compass-basic [class*="pf-v6-c-compass"] { +#ws-react-p-compass-basic [class*="pf-v6-c-compass"] { position: relative; } -#ws-react-c-compass-basic [class*="pf-v6-c-compass"]::after { +#ws-react-p-compass-basic [class*="pf-v6-c-compass"]::after { + content: ""; + position: absolute; + inset: 0; + border: var(--pf-t--global--border--width--regular) dashed var(--pf-t--global--border--color--default); + pointer-events: none; +} + +#ws-react-p-compass-with-alternate-footer [class*="pf-v6-c-compass"] { + position: relative; +} + +#ws-react-p-compass-with-alternate-footer [class*="pf-v6-c-compass"]:not([class*="footer"])::after { content: ""; position: absolute; inset: 0; diff --git a/packages/react-core/src/components/Compass/index.ts b/packages/react-core/src/components/Compass/index.ts index aabf250facb..af1b6b562dd 100644 --- a/packages/react-core/src/components/Compass/index.ts +++ b/packages/react-core/src/components/Compass/index.ts @@ -6,5 +6,6 @@ export * from './CompassMainHeader'; export * from './CompassMainHeaderContent'; export * from './CompassMainHeaderTitle'; export * from './CompassMainHeaderToolbar'; +export * from './CompassMainFooter'; export * from './CompassMessageBar'; export * from './CompassPanel'; From 33c168bf1a46c27aedf0aea67531978e1f6bb680 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Wed, 12 Nov 2025 13:15:47 -0500 Subject: [PATCH 2/4] add tests --- .../__tests__/CompassMainFooter.test.tsx | 37 +++++++++++++++++++ .../CompassMainFooter.test.tsx.snap | 11 ++++++ 2 files changed, 48 insertions(+) create mode 100644 packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx create mode 100644 packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx new file mode 100644 index 00000000000..9d3d94f3fa5 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainFooter } from '../CompassMainFooter'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-main-footer').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom 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.compassMainFooter} class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.compassMainFooter); +}); + +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(Custom children content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap new file mode 100644 index 00000000000..eef7b6fe7c1 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + + + +`; From b0076a6e19e507cdd00e52f98e43110692220265 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Wed, 12 Nov 2025 16:26:27 -0500 Subject: [PATCH 3/4] add isExpanded to CompassMainFooter --- .../src/components/Compass/CompassMainFooter.tsx | 5 ++++- .../Compass/__tests__/CompassMainFooter.test.tsx | 15 +++++++++++++++ .../__snapshots__/CompassMainFooter.test.tsx.snap | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/react-core/src/components/Compass/CompassMainFooter.tsx b/packages/react-core/src/components/Compass/CompassMainFooter.tsx index d4828974682..cbbd60f663f 100644 --- a/packages/react-core/src/components/Compass/CompassMainFooter.tsx +++ b/packages/react-core/src/components/Compass/CompassMainFooter.tsx @@ -6,14 +6,17 @@ interface CompassMainFooterProps extends Omit, ' className?: string; /** Main footer content */ children?: React.ReactNode; + /** Indicates if the main footer is expanded */ + isExpanded?: boolean; } export const CompassMainFooter: React.FunctionComponent = ({ className, children, + isExpanded = true, ...props }) => ( -
+
{children}
); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx index 9d3d94f3fa5..25b955ba77c 100644 --- a/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx @@ -26,6 +26,21 @@ test(`Renders with default ${styles.compassMainFooter} class`, () => { expect(screen.getByText('Test')).toHaveClass(styles.compassMainFooter); }); +test(`Renders with pf-m-expanded class by default`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('pf-m-expanded'); +}); + +test(`Renders with pf-m-expanded class when isExpanded is true`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('pf-m-expanded'); +}); + +test(`Renders without pf-m-expanded class when isExpanded is false`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass('pf-m-expanded'); +}); + test('Renders with additional props spread to the component', () => { render(Test); expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap index eef7b6fe7c1..160ef4650a2 100644 --- a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap @@ -3,7 +3,7 @@ exports[`Matches the snapshot 1`] = ` From e9a243c9ed260511078d64d65865d5f23d5a7717 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Wed, 12 Nov 2025 16:31:59 -0500 Subject: [PATCH 4/4] add max height to examples --- .../react-core/src/components/Compass/examples/CompassBasic.tsx | 1 + .../src/components/Compass/examples/CompassMainFooterDemo.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx index c00a2302414..fd3cd1a57cb 100644 --- a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx +++ b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx @@ -40,6 +40,7 @@ export const CompassBasic: React.FunctionComponent = () => { main={mainContent} sidebarEnd={sidebarEndContent} footer={footerContent} + style={{ height: '600px' }} /> ); }; diff --git a/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx index 9d26948051f..4846f6f07aa 100644 --- a/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx +++ b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx @@ -37,6 +37,7 @@ export const CompassMainFooterDemo: React.FunctionComponent = () => { main={mainContent} sidebarEnd={sidebarEndContent} isFooterExpanded={false} + style={{ height: '600px' }} /> ); };