From 818a0c8a7fa8a92ef0fd3d1d2319589f0328e90b Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Thu, 23 Oct 2025 13:50:43 -0400 Subject: [PATCH 01/21] feat(Compass): add Compass components --- .../src/components/Compass/Compass.tsx | 89 ++++++++++++++++++ .../src/components/Compass/CompassContent.tsx | 41 ++++++++ .../src/components/Compass/CompassGlass.tsx | 14 +++ .../src/components/Compass/CompassHeader.tsx | 20 ++++ .../src/components/Compass/CompassHero.tsx | 33 +++++++ .../components/Compass/CompassMainHeader.tsx | 40 ++++++++ .../src/components/Compass/CompassSection.tsx | 16 ++++ .../components/Compass/examples/Compass.md | 26 ++++++ .../Compass/examples/CompassBasic.tsx | 36 +++++++ .../Compass/examples/CompassDemo.tsx | 93 +++++++++++++++++++ .../components/Compass/examples/compass.css | 0 .../src/components/Compass/index.ts | 6 ++ packages/react-core/src/components/index.ts | 1 + 13 files changed, 415 insertions(+) create mode 100644 packages/react-core/src/components/Compass/Compass.tsx create mode 100644 packages/react-core/src/components/Compass/CompassContent.tsx create mode 100644 packages/react-core/src/components/Compass/CompassGlass.tsx create mode 100644 packages/react-core/src/components/Compass/CompassHeader.tsx create mode 100644 packages/react-core/src/components/Compass/CompassHero.tsx create mode 100644 packages/react-core/src/components/Compass/CompassMainHeader.tsx create mode 100644 packages/react-core/src/components/Compass/CompassSection.tsx create mode 100644 packages/react-core/src/components/Compass/examples/Compass.md create mode 100644 packages/react-core/src/components/Compass/examples/CompassBasic.tsx create mode 100644 packages/react-core/src/components/Compass/examples/CompassDemo.tsx create mode 100644 packages/react-core/src/components/Compass/examples/compass.css create mode 100644 packages/react-core/src/components/Compass/index.ts diff --git a/packages/react-core/src/components/Compass/Compass.tsx b/packages/react-core/src/components/Compass/Compass.tsx new file mode 100644 index 00000000000..bd7408d101e --- /dev/null +++ b/packages/react-core/src/components/Compass/Compass.tsx @@ -0,0 +1,89 @@ +import { Drawer, DrawerContent, DrawerProps } from '../Drawer'; +import { css } from '@patternfly/react-styles'; + +export interface CompassProps extends React.HTMLProps { + /** Additional classes added to the compass. */ + className?: string; + /** Content placed at the top of the layout */ + header?: React.ReactNode; + /** Flag indicating if the header is expanded */ + isHeaderExpanded?: boolean; + /** Content placed at the start of the layout */ + panelStart?: React.ReactNode; + /** Flag indicating if the start panel is expanded */ + isPanelStartExpanded?: boolean; + /** Content placed at the center of the layout */ + main?: React.ReactNode; + /** Content placed at the end of the layout */ + panelEnd?: React.ReactNode; + /** Flag indicating if the end panel is expanded */ + isPanelEndExpanded?: boolean; + /** Content placed at the bottom of the layout */ + footer?: React.ReactNode; + /** Flag indicating if the footer is expanded */ + isFooterExpanded?: boolean; + /** Content rendered in the drawer panel */ + drawerContent?: React.ReactNode; + /** Props for the drawer */ + drawerProps?: DrawerProps; +} + +export const Compass: React.FunctionComponent = ({ + className, + header, + isHeaderExpanded = true, + panelStart, + isPanelStartExpanded = true, + main, + panelEnd, + isPanelEndExpanded = true, + footer, + isFooterExpanded = true, + drawerContent, + drawerProps, + ...props +}) => { + const hasDrawer = drawerContent !== undefined; + + const compassContent = ( +
+
+ {header} +
+
+ {panelStart} +
+
{main}
+
+ {panelEnd} +
+
+ {footer} +
+
+ ); + + if (hasDrawer) { + return ( + + {compassContent} + + ); + } + + return compassContent; +}; + +Compass.displayName = 'Compass'; diff --git a/packages/react-core/src/components/Compass/CompassContent.tsx b/packages/react-core/src/components/Compass/CompassContent.tsx new file mode 100644 index 00000000000..6ea577ee595 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassContent.tsx @@ -0,0 +1,41 @@ +import { Drawer, DrawerContent, DrawerProps } from '../Drawer'; +import { css } from '@patternfly/react-styles'; + +interface CompassContentProps extends React.HTMLProps { + /** Content. Typically CompassSection components. */ + children: React.ReactNode; + /** Additional classes added to the component */ + className?: string; + /** Content of the drawer */ + drawerContent?: React.ReactNode; + /** Additional props passed to the drawer */ + drawerProps?: DrawerProps; +} + +export const CompassContent: React.FunctionComponent = ({ + children, + className, + drawerProps, + drawerContent, + ...props +}) => { + const hasDrawer = drawerContent !== undefined; + + const compassContent = ( +
+ {children} +
+ ); + + if (hasDrawer) { + return ( + + {compassContent} + + ); + } + + return compassContent; +}; + +CompassContent.displayName = 'CompassContent'; diff --git a/packages/react-core/src/components/Compass/CompassGlass.tsx b/packages/react-core/src/components/Compass/CompassGlass.tsx new file mode 100644 index 00000000000..2f0361ea14e --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassGlass.tsx @@ -0,0 +1,14 @@ +import { css } from '@patternfly/react-styles'; + +interface CompassGlassProps { + /** Content that should have a glass effect */ + children: React.ReactNode; + /** Additional classes added to the container */ + className?: string; +} + +export const CompassGlass: React.FunctionComponent = ({ children, className }) => ( +
{children}
+); + +CompassGlass.displayName = 'CompassGlass'; diff --git a/packages/react-core/src/components/Compass/CompassHeader.tsx b/packages/react-core/src/components/Compass/CompassHeader.tsx new file mode 100644 index 00000000000..88f69cfda44 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassHeader.tsx @@ -0,0 +1,20 @@ +import { css } from '@patternfly/react-styles'; + +interface CompassHeaderProps { + /** Content for the logo area */ + logo?: React.ReactNode; + /** Content for the navigation area */ + nav?: React.ReactNode; + /** Content for the profile area */ + profile?: React.ReactNode; +} + +export const CompassHeader: React.FunctionComponent = ({ logo, nav, profile }) => ( + <> +
{logo}
+
{nav}
+
{profile}
+ +); + +CompassHeader.displayName = 'CompassHeader'; diff --git a/packages/react-core/src/components/Compass/CompassHero.tsx b/packages/react-core/src/components/Compass/CompassHero.tsx new file mode 100644 index 00000000000..2f4762b1c39 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassHero.tsx @@ -0,0 +1,33 @@ +import { Flex, FlexItem } from '../../layouts/Flex'; +import { css } from '@patternfly/react-styles'; + +interface CompassHeroProps extends Omit, 'content'> { + /** Additional classes added to the hero. */ + className?: string; + /** Styled hero content. If provided, the children prop will be ignored. */ + content?: React.ReactNode; + /** Custom hero content. To opt into a default set of styling, use the content prop instead. */ + children?: React.ReactNode; +} + +export const CompassHero: React.FunctionComponent = ({ className, children, content, ...props }) => { + if (content !== undefined) { + return ( +
+
+ + {content} + +
+
+ ); + } + + return ( +
+
{children}
+
+ ); +}; + +CompassHero.displayName = 'CompassHero'; diff --git a/packages/react-core/src/components/Compass/CompassMainHeader.tsx b/packages/react-core/src/components/Compass/CompassMainHeader.tsx new file mode 100644 index 00000000000..a3a7c60d977 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassMainHeader.tsx @@ -0,0 +1,40 @@ +import { Flex, FlexItem } from '../../layouts/Flex'; +import { css } from '@patternfly/react-styles'; + +interface CompassMainHeaderProps extends Omit, 'title'> { + /** Additional classes added to the main header. */ + className?: string; + /** Styled title. If title or toolbar is provided, the children will be ignored. */ + title?: React.ReactNode; + /** Styled toolbar. If title or toolbar is provided, the children will be ignored. */ + toolbar?: React.ReactNode; + /** Custom main header content. To opt into a default set of styling, use the title and toolbar props instead. */ + children?: React.ReactNode; +} + +export const CompassMainHeader: React.FunctionComponent = ({ + className, + title, + toolbar, + children, + ...props +}) => { + if (title !== undefined || toolbar !== undefined) { + return ( +
+ + {title} + {toolbar} + +
+ ); + } + + return ( +
+ {children} +
+ ); +}; + +CompassMainHeader.displayName = 'CompassMainHeader'; diff --git a/packages/react-core/src/components/Compass/CompassSection.tsx b/packages/react-core/src/components/Compass/CompassSection.tsx new file mode 100644 index 00000000000..4ccf130cea6 --- /dev/null +++ b/packages/react-core/src/components/Compass/CompassSection.tsx @@ -0,0 +1,16 @@ +import { css } from '@patternfly/react-styles'; + +interface CompassSectionProps extends React.HTMLProps { + /** Additional classes added to the section. */ + className?: string; + /** Content of the section. */ + children: React.ReactNode; +} + +export const CompassSection: React.FunctionComponent = ({ children, className, ...props }) => ( +
+ {children} +
+); + +CompassSection.displayName = 'CompassSection'; diff --git a/packages/react-core/src/components/Compass/examples/Compass.md b/packages/react-core/src/components/Compass/examples/Compass.md new file mode 100644 index 00000000000..b050b1d7460 --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/Compass.md @@ -0,0 +1,26 @@ +--- +id: Compass +cssPrefix: pf-v6-c-compass +section: layouts +propComponents: ['Compass', 'CompassHeader', 'CompassContent', 'CompassHero', 'CompassMainHeader', 'CompassSection'] +--- + +import './compass.css'; +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'; + +## Examples + +### Basic + +```ts file="CompassBasic.tsx" + +``` + +### Demo + +```ts isFullscreen file="CompassDemo.tsx" + +``` diff --git a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx new file mode 100644 index 00000000000..d91691f3066 --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx @@ -0,0 +1,36 @@ +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + CompassSection +} from '@patternfly/react-core'; + +export const CompassBasic: React.FunctionComponent = () => { + const headerContent = Logo} nav={
Nav
} profile={
Profile
} />; + const panelStartContent =
Panel start
; + const mainContent = ( + <> + +
Hero
+
+ + + Content + + + ); + const panelEndContent =
Panel end
; + const footerContent =
Footer
; + + return ( + + ); +}; diff --git a/packages/react-core/src/components/Compass/examples/CompassDemo.tsx b/packages/react-core/src/components/Compass/examples/CompassDemo.tsx new file mode 100644 index 00000000000..ea5f9480981 --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassDemo.tsx @@ -0,0 +1,93 @@ +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + CompassSection, + Tabs, + TabsComponent, + Tab, + TabTitleText, + ActionList, + ActionListGroup, + ActionListItem, + Button, + Title, + SearchInput +} from '@patternfly/react-core'; +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'; + +export const CompassBasic: React.FunctionComponent = () => { + const subTabs = ( + {}}> + Subtab 1} /> + Subtab 2} /> + Disabled Subtab 3} isDisabled /> + + ); + + const navContent = ( + {}} component={TabsComponent.nav} aria-label="Compass navigation tabs"> + Tab 1}> + {subTabs} + + Tab 2} /> + Tab 3} /> + Disabled Tab 4} isDisabled /> + + ); + + const panelContent = ( + + + +