Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/react-core/src/components/Drawer/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down
17 changes: 16 additions & 1 deletion packages/react-core/src/components/Drawer/DrawerPanelContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export interface DrawerPanelContentProps extends Omit<React.HTMLProps<HTMLDivEle
isResizable?: boolean;
/** @beta Flag indicating that the drawer panel should disable glass styles. This prop is intended to work with isPill drawers. */
hasNoGlass?: boolean;
/** @beta Flag indicating that the drawer panel should use glass styles. */
isGlass?: boolean;
/** @beta Flag indicating that the drawer panel should use plain styles. */
isPlain?: boolean;
/** @beta Flag indicating that plain styles should be disabled when glass styles are used. */
isNoPlainOnGlass?: boolean;
/** Callback for resize end. */
onResize?: (event: MouseEvent | TouchEvent | React.KeyboardEvent, width: number, id: string) => void;
/** The minimum size of a drawer. */
Expand All @@ -56,7 +62,10 @@ export interface DrawerPanelContentProps extends Omit<React.HTMLProps<HTMLDivEle
xl?: 'width_25' | 'width_33' | 'width_50' | 'width_66' | 'width_75' | 'width_100';
'2xl'?: 'width_25' | 'width_33' | 'width_50' | 'width_66' | 'width_75' | 'width_100';
};
/** Color variant of the background of the drawer panel */
/**
* Color variant of the background of the drawer panel.
* The `no-background`is deprecated; use the `isPlain` prop instead.
*/
colorVariant?: DrawerColorVariant | 'no-background' | 'default' | 'secondary';
/** Adds and customizes a focus trap on the drawer panel content. */
focusTrap?: DrawerPanelFocusTrapObject;
Expand All @@ -71,6 +80,9 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
hasNoBorder = false,
isResizable = false,
hasNoGlass = false,
isGlass = false,
isPlain = false,
isNoPlainOnGlass = false,
onResize,
minSize,
defaultSize,
Expand Down Expand Up @@ -368,6 +380,9 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
styles.drawerPanel,
isResizable && styles.modifiers.resizable,
hasNoGlass && 'pf-m-no-glass',
isGlass && styles.modifiers.glass,
isPlain && styles.modifiers.plain,
isNoPlainOnGlass && styles.modifiers.noPlainOnGlass,
hasNoBorder && styles.modifiers.noBorder,
formatBreakpointMods(widths, styles),
colorVariant === DrawerColorVariant.noBackground && styles.modifiers.noBackground,
Expand Down
9 changes: 8 additions & 1 deletion packages/react-core/src/components/Drawer/DrawerSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@ export interface DrawerSectionProps extends React.HTMLProps<HTMLDivElement> {
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<DrawerSectionProps> = ({
className = '',
children,
colorVariant = DrawerColorVariant.default,
isPlain = false,
...props
}: DrawerSectionProps) => (
<div
className={css(
styles.drawerSection,
isPlain && styles.modifiers.plain,
colorVariant === DrawerColorVariant.noBackground && styles.modifiers.noBackground,
colorVariant === DrawerColorVariant.secondary && styles.modifiers.secondary,
className
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ test(`Renders with only class ${styles.drawerPanel} by default`, () => {
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 isExpanded>
<DrawerPanelContent colorVariant="no-background">Drawer panel content</DrawerPanelContent>
Expand Down Expand Up @@ -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 isExpanded>
<DrawerPanelContent isGlass>Drawer panel content</DrawerPanelContent>
</Drawer>
);

expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.glass);
});

test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => {
render(
<Drawer isExpanded>
<DrawerPanelContent isPlain>Drawer panel content</DrawerPanelContent>
</Drawer>
);

expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.plain);
});

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.noPlainOnGlass);
});
Original file line number Diff line number Diff line change
@@ -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(<DrawerSection>Section content</DrawerSection>);

expect(screen.getByText('Section content')).toHaveClass(styles.drawerSection, { exact: true });
});

test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => {
render(<DrawerSection isPlain>Section content</DrawerSection>);

expect(screen.getByText('Section content')).toHaveClass(styles.modifiers.plain);
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ propComponents:
DrawerCloseButton,
DrawerPanelDescription,
DrawerPanelBody,
DrawerPanelFocusTrapObject
DrawerPanelFocusTrapObject,
]
section: components
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export const PrimaryDetailContentPadding: React.FunctionComponent = () => {
);

const panelContent = (
<DrawerPanelContent>
<DrawerPanelContent isPlain>
<DrawerHead>
<Title headingLevel="h2" size="xl">
node-{drawerPanelBodyContent}
Expand Down Expand Up @@ -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>
Expand Down
55 changes: 55 additions & 0 deletions packages/react-integration/cypress/integration/drawer.spec.ts
Original file line number Diff line number Diff line change
@@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}>
Expand Down Expand Up @@ -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>
</>
);
}
Expand Down
Loading