diff --git a/packages/react-core/src/components/Page/PageToggleButton.tsx b/packages/react-core/src/components/Page/PageToggleButton.tsx index de43ece168d..dce88f6f58c 100644 --- a/packages/react-core/src/components/Page/PageToggleButton.tsx +++ b/packages/react-core/src/components/Page/PageToggleButton.tsx @@ -14,6 +14,8 @@ export interface PageToggleButtonProps extends ButtonProps { 'aria-label'?: string; /** Flag indicating whether the hamburger button variation with animations should be used. */ isHamburgerButton?: boolean; + /** IsHamburgerButton must be true for hamburgerVariant to be have an effect. Adjusts and animates the hamburger icon to indicate what will happen upon clicking the button. */ + hamburgerVariant?: 'expand' | 'collapse'; } export const PageToggleButton: React.FunctionComponent = ({ @@ -23,6 +25,7 @@ export const PageToggleButton: React.FunctionComponent = id = 'nav-toggle', 'aria-label': ariaLabel = 'Side navigation toggle', isHamburgerButton, + hamburgerVariant, ...props }: PageToggleButtonProps) => ( @@ -42,6 +45,10 @@ export const PageToggleButton: React.FunctionComponent = aria-expanded={sidebarOpen ? 'true' : 'false'} variant={ButtonVariant.plain} isHamburger={isHamburgerButton} + hamburgerVariant={hamburgerVariant} + {...(isHamburgerButton && { + isExpanded: sidebarOpen + })} {...props} > {!isHamburgerButton && children} diff --git a/packages/react-core/src/components/Page/__tests__/PageToggleButton.test.tsx b/packages/react-core/src/components/Page/__tests__/PageToggleButton.test.tsx new file mode 100644 index 00000000000..8fa14c82710 --- /dev/null +++ b/packages/react-core/src/components/Page/__tests__/PageToggleButton.test.tsx @@ -0,0 +1,74 @@ +import { render, screen } from '@testing-library/react'; +import { PageToggleButton } from '../PageToggleButton'; +import { PageContextProvider } from '../PageContext'; + +test('Renders without children', () => { + render( +
+ +
+ ); + + expect(screen.getByTestId('container').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Test); + + expect(screen.getByText('Test')).toBeVisible(); +}); + +test('Throws console error when isHamburger is true and isSidebarOpen is not passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(); + + expect(consoleError).toHaveBeenCalledWith( + 'Button: when the isHamburger property is passed in, you must also pass in a boolean value to the isExpanded property. It is expected that a hamburger button controls the expansion of other content.' + ); +}); + +test('Does not throw console error when isHamburger is true and isSidebarOpen is false', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: when the isHamburger property is passed in, you must also pass in a boolean value to the isExpanded property. It is expected that a hamburger button controls the expansion of other content..' + ); +}); + +test('Does not throw console error when isHamburger is true and isSidebarOpen is true', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: when the isHamburger property is passed in, you must also pass in a boolean value to the isExpanded property. It is expected that a hamburger button controls the expansion of other content..' + ); +}); + +// assisted by AI/Cursor +test('Does not throw console error when isHamburger is true, isSidebarOpen is not passed, but managedIsSidebarOpen is true', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + const mockPageContext = { + isManagedSidebar: true, + onSidebarToggle: () => null, + isSidebarOpen: true, // managedIsSidebarOpen is true + width: 1024, + height: 768, + getBreakpoint: () => 'lg' as const, + getVerticalBreakpoint: () => 'lg' as const + }; + + render( + + + + ); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: when the isHamburger property is passed in, you must also pass in a boolean value to the isExpanded property. It is expected that a hamburger button controls the expansion of other content..' + ); +});