From 140cfc2b93d100e8a149e32f4bc10ee4700dd5d2 Mon Sep 17 00:00:00 2001 From: Titani Date: Tue, 31 Mar 2026 10:27:43 -0400 Subject: [PATCH 1/2] feat(Drawer): Added support for glass --- .../src/components/Drawer/Drawer.tsx | 3 ++ .../components/Drawer/DrawerPanelContent.tsx | 17 +++++++++- .../src/components/Drawer/DrawerSection.tsx | 9 +++++- .../__tests__/DrawerPanelContent.test.tsx | 32 ++++++++++++++++++- .../Drawer/__tests__/DrawerSection.test.tsx | 15 +++++++++ .../src/components/Drawer/examples/Drawer.md | 2 +- .../PrimaryDetailContentPadding.tsx | 4 +-- 7 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx diff --git a/packages/react-core/src/components/Drawer/Drawer.tsx b/packages/react-core/src/components/Drawer/Drawer.tsx index 3470426a6b8..eaa6c58dfcd 100644 --- a/packages/react-core/src/components/Drawer/Drawer.tsx +++ b/packages/react-core/src/components/Drawer/Drawer.tsx @@ -5,6 +5,9 @@ import { css } from '@patternfly/react-styles'; export enum DrawerColorVariant { default = 'default', secondary = 'secondary', + /** + * @deprecated `DrawerColorVariant.noBackground` is deprecated. Use the `isPlain` prop on `DrawerPanelContent` and the `DrawerSection`instead. + */ noBackground = 'no-background' } diff --git a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx index 814390d3955..b1106f28c49 100644 --- a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx +++ b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx @@ -37,6 +37,12 @@ export interface DrawerPanelContentProps extends Omit void; /** The minimum size of a drawer. */ @@ -56,7 +62,10 @@ export interface DrawerPanelContentProps extends Omit { className?: string; /** Content to be rendered in the drawer section. */ children?: React.ReactNode; - /** Color variant of the background of the drawer Section */ + /** + * Color variant of the background of the drawer section. + * The `no-background` value is deprecated; use the `isPlain` prop instead. + */ colorVariant?: DrawerColorVariant | 'no-background' | 'default' | 'secondary'; + /** @beta Flag indicating that the drawer section should use plain styles. */ + isPlain?: boolean; } export const DrawerSection: React.FunctionComponent = ({ className = '', children, colorVariant = DrawerColorVariant.default, + isPlain = false, ...props }: DrawerSectionProps) => (
{ expect(screen.getByText('Drawer panel content')).toHaveClass(styles.drawerPanel, { exact: true }); }); -test(`Renders with class ${styles.modifiers.noBackground} when colorVariant="no-background"`, () => { +test(`Renders with class ${styles.modifiers.noBackground} when deprecated colorVariant="no-background" is used`, () => { render( Drawer panel content @@ -188,3 +188,33 @@ test(`Renders with class 'pf-m-no-glass' when hasNoGlass is true`, () => { expect(screen.getByText('Drawer panel content')).toHaveClass('pf-m-no-glass'); }); + +test(`Renders with class ${styles.modifiers.glass} when isGlass is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.glass); +}); + +test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.plain); +}); + +test(`Renders with class ${styles.modifiers.noPlain} when isNoPlainOnGlass is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.noPlain); +}); diff --git a/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx b/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx new file mode 100644 index 00000000000..849cf457ddf --- /dev/null +++ b/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx @@ -0,0 +1,15 @@ +import { render, screen } from '@testing-library/react'; +import { DrawerSection } from '../DrawerSection'; +import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; + +test(`Renders with only class ${styles.drawerSection} by default`, () => { + render(Section content); + + expect(screen.getByText('Section content')).toHaveClass(styles.drawerSection, { exact: true }); +}); + +test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => { + render(Section content); + + expect(screen.getByText('Section content')).toHaveClass(styles.modifiers.plain); +}); diff --git a/packages/react-core/src/components/Drawer/examples/Drawer.md b/packages/react-core/src/components/Drawer/examples/Drawer.md index 544bc08a2ba..22d79215fe6 100644 --- a/packages/react-core/src/components/Drawer/examples/Drawer.md +++ b/packages/react-core/src/components/Drawer/examples/Drawer.md @@ -13,7 +13,7 @@ propComponents: DrawerCloseButton, DrawerPanelDescription, DrawerPanelBody, - DrawerPanelFocusTrapObject + DrawerPanelFocusTrapObject, ] section: components --- diff --git a/packages/react-core/src/demos/examples/PrimaryDetail/PrimaryDetailContentPadding.tsx b/packages/react-core/src/demos/examples/PrimaryDetail/PrimaryDetailContentPadding.tsx index c19ed8ca8ca..cd5f84f2bae 100644 --- a/packages/react-core/src/demos/examples/PrimaryDetail/PrimaryDetailContentPadding.tsx +++ b/packages/react-core/src/demos/examples/PrimaryDetail/PrimaryDetailContentPadding.tsx @@ -178,7 +178,7 @@ export const PrimaryDetailContentPadding: React.FunctionComponent = () => { ); const panelContent = ( - + node-{drawerPanelBodyContent} @@ -429,7 +429,7 @@ export const PrimaryDetailContentPadding: React.FunctionComponent = () => { <Divider component="div" /> <PageSection padding={{ default: 'noPadding' }} aria-label="Drawer content section"> <Drawer isExpanded={isDrawerExpanded}> - <DrawerContent panelContent={panelContent} colorVariant="no-background"> + <DrawerContent panelContent={panelContent}> <DrawerContentBody hasPadding>{drawerContent}</DrawerContentBody> </DrawerContent> </Drawer> From 9b1b64dcf90f0ba18339e35d5d38a8e642abeb2b Mon Sep 17 00:00:00 2001 From: Titani <tlabaj@redhat.com> Date: Mon, 6 Apr 2026 16:22:56 -0400 Subject: [PATCH 2/2] update test and logic --- .../components/Drawer/DrawerPanelContent.tsx | 2 +- .../__tests__/DrawerPanelContent.test.tsx | 4 +- .../cypress/integration/drawer.spec.ts | 55 +++++++++++++++++++ .../demos/DrawerDemo/DrawerDemo.tsx | 19 +++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx index b1106f28c49..83e03eddc54 100644 --- a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx +++ b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx @@ -382,7 +382,7 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps hasNoGlass && 'pf-m-no-glass', isGlass && styles.modifiers.glass, isPlain && styles.modifiers.plain, - isNoPlainOnGlass && styles.modifiers.noPlain, + isNoPlainOnGlass && styles.modifiers.noPlainOnGlass, hasNoBorder && styles.modifiers.noBorder, formatBreakpointMods(widths, styles), colorVariant === DrawerColorVariant.noBackground && styles.modifiers.noBackground, diff --git a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx index b244cd7bb7e..ba0b0cec4c4 100644 --- a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx +++ b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx @@ -209,12 +209,12 @@ test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.plain); }); -test(`Renders with class ${styles.modifiers.noPlain} when isNoPlainOnGlass is true`, () => { +test(`Renders with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is true`, () => { render( <Drawer isExpanded> <DrawerPanelContent isNoPlainOnGlass>Drawer panel content</DrawerPanelContent> </Drawer> ); - expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.noPlain); + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.noPlainOnGlass); }); diff --git a/packages/react-integration/cypress/integration/drawer.spec.ts b/packages/react-integration/cypress/integration/drawer.spec.ts index 02a06d3fb9d..0a4bd2328ca 100644 --- a/packages/react-integration/cypress/integration/drawer.spec.ts +++ b/packages/react-integration/cypress/integration/drawer.spec.ts @@ -1,8 +1,63 @@ describe('Drawer Demo Test', () => { + afterEach(() => { + cy.document().then((doc) => { + doc.documentElement.classList.remove('pf-v6-theme-glass'); + }); + }); + it('Navigate to the drawer demo', () => { cy.visit('http://localhost:3000/drawer-demo-nav-link'); }); + // Known PatternFly CSS bug: when `pf-v6-theme-glass`, `pf-m-glass` (isGlass), and `pf-m-plain` are all active, + // `pf-m-no-plain-on-glass` does not take effect — plain-under-glass wins and no-plain-on-glass cannot restore + // the intended glass panel treatment. This test asserts the corrected outcome (semi-transparent background) + // and fails until Core CSS fixes selector/specificity for that combination. + it('glass theme + plain + glass: no-plain-on-glass should yield semi-transparent panel background (fails until CSS fix)', () => { + cy.document().then((doc) => { + doc.documentElement.classList.add('pf-v6-theme-glass'); + }); + cy.get('html').should('have.class', 'pf-v6-theme-glass'); + + cy.get('#drawer-panel-glass-plain-combo.pf-v6-c-drawer__panel') + .should('be.visible') + .should('have.class', 'pf-m-glass') + .and('have.class', 'pf-m-plain') + .and('have.class', 'pf-m-no-plain-on-glass'); + + cy.get('#drawer-panel-glass-plain-combo').within(() => { + cy.contains('Glass theme plain / no-plain-on-glass combo'); + }); + + // When the bug is fixed, no-plain-on-glass should override plain-under-glass and surface a non-opaque background. + cy.get('#drawer-panel-glass-plain-combo').should(($el) => { + const bg = window.getComputedStyle($el[0]).backgroundColor; + + const rgbaAlpha = (color: string): number | undefined => { + if (color === 'transparent') { + return 0; + } + if (!color.startsWith('rgba(') || !color.endsWith(')')) { + return undefined; + } + const inner = color.slice('rgba('.length, -1); + const parts = inner.split(',').map((p) => p.trim()); + if (parts.length !== 4) { + return undefined; + } + return parseFloat(parts[3]); + }; + + const alpha = rgbaAlpha(bg); + const hasSemiTransparentBackground = alpha !== undefined && alpha < 1; + if (!hasSemiTransparentBackground) { + throw new Error( + `expected no-plain-on-glass to win over plain+glass under theme (semi-transparent background, alpha < 1); got backgroundColor=${bg}` + ); + } + }); + }); + it('Verify focus is automatically handled with focus trap enabled', () => { cy.get('#toggleFocusTrapButton').click(); cy.get('#focusTrap-panelContent .pf-v6-c-button.pf-m-plain').should('have.focus'); diff --git a/packages/react-integration/demo-app-ts/src/components/demos/DrawerDemo/DrawerDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/DrawerDemo/DrawerDemo.tsx index 6286a8a2330..5d85bc91118 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/DrawerDemo/DrawerDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/DrawerDemo/DrawerDemo.tsx @@ -118,6 +118,18 @@ export class DrawerDemo extends Component<DrawerProps, DrawerDemoState> { const drawerContent = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; + /** + * Repro for Core CSS: with glass theme (`pf-v6-theme-glass`, applied in Cypress on `html`), `isGlass` (pf-m-glass), + * and `isPlain` (pf-m-plain), `pf-m-no-plain-on-glass` may not apply — see drawer Cypress test. + */ + const glassThemePlainComboPanelContent = ( + <DrawerPanelContent id="drawer-panel-glass-plain-combo" isPlain isNoPlainOnGlass isGlass> + <DrawerHead> + <span>Glass theme plain / no-plain-on-glass combo</span> + </DrawerHead> + </DrawerPanelContent> + ); + return ( <> <Button id="toggleButton" onClick={this.onClick}> @@ -151,6 +163,13 @@ export class DrawerDemo extends Component<DrawerProps, DrawerDemoState> { <DrawerContentBody>{drawerContent}</DrawerContentBody> </DrawerContent> </Drawer> + <div id="drawer-glass-plain-combo-container"> + <Drawer id="drawer-glass-plain-combo" isExpanded style={{ minHeight: '120px', height: '120px' }}> + <DrawerContent colorVariant={DrawerColorVariant.default} panelContent={glassThemePlainComboPanelContent}> + <DrawerContentBody>Glass theme + isPlain + isNoPlainOnGlass + isGlass demo</DrawerContentBody> + </DrawerContent> + </Drawer> + </div> </> ); }