diff --git a/packages/react-core/src/components/Button/Button.tsx b/packages/react-core/src/components/Button/Button.tsx index 2c6a28da139..5b441384b54 100644 --- a/packages/react-core/src/components/Button/Button.tsx +++ b/packages/react-core/src/components/Button/Button.tsx @@ -109,6 +109,10 @@ export interface ButtonProps extends Omit, 'r hamburgerVariant?: 'expand' | 'collapse'; /** @beta Flag indicating the button is a circle button. Intended for buttons that only contain an icon.. */ isCircle?: boolean; + /** @beta Flag indicating the button is a docked variant button. For use in docked navigation. */ + isDocked?: boolean; + /** @beta Flag indicating the dock button should display text. Only applies when isDock is true. */ + isTextExpanded?: boolean; /** @hide Forwarded ref */ innerRef?: React.Ref; /** Adds count number to button */ @@ -134,6 +138,8 @@ const ButtonBase: React.FunctionComponent = ({ isHamburger, hamburgerVariant, isCircle, + isDocked = false, + isTextExpanded = false, spinnerAriaValueText, spinnerAriaLabelledBy, spinnerAriaLabel, @@ -265,6 +271,8 @@ const ButtonBase: React.FunctionComponent = ({ size === ButtonSize.sm && styles.modifiers.small, size === ButtonSize.lg && styles.modifiers.displayLg, isCircle && styles.modifiers.circle, + isDocked && styles.modifiers.dock, // Replace wwith docked class from https://github.com/patternfly/patternfly/pull/8308 + isTextExpanded && styles.modifiers.textExpanded, className )} disabled={isButtonElement ? isDisabled : null} diff --git a/packages/react-core/src/components/Button/__tests__/Button.test.tsx b/packages/react-core/src/components/Button/__tests__/Button.test.tsx index 2c6ec2bf4a6..a0835ec7e78 100644 --- a/packages/react-core/src/components/Button/__tests__/Button.test.tsx +++ b/packages/react-core/src/components/Button/__tests__/Button.test.tsx @@ -555,6 +555,39 @@ describe('Favorite button', () => { }); }); +describe('Dock variant', () => { + test(`Renders with class ${styles.modifiers.dock} when isDocked = true`, () => { + render(); + expect(screen.getByRole('button')).toHaveClass(styles.modifiers.dock); + }); + + test(`Does not render with class ${styles.modifiers.dock} when isDocked is not passed`, () => { + render(); + expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.dock); + }); + + test(`Renders with class ${styles.modifiers.textExpanded} when isTextExpanded = true`, () => { + render(); + expect(screen.getByRole('button')).toHaveClass(styles.modifiers.textExpanded); + }); + + test(`Does not render with class ${styles.modifiers.textExpanded} when isTextExpanded is not passed`, () => { + render(); + expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.textExpanded); + }); + + test(`Renders with both ${styles.modifiers.dock} and ${styles.modifiers.textExpanded} when both props are true`, () => { + render( + + ); + const button = screen.getByRole('button'); + expect(button).toHaveClass(styles.modifiers.dock); + expect(button).toHaveClass(styles.modifiers.textExpanded); + }); +}); + test(`Renders basic button`, () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap b/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap index d9ce0770e4a..93099d8a596 100644 --- a/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +++ b/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Renders basic button 1`] = ` + ) : ( + + + + )} + + + {isDockTextExpanded ? ( + } + isDocked + isTextExpanded={isDockTextExpanded} + aria-label="Help" + > + Help + + ) : ( + + } + isDocked + isTextExpanded={isDockTextExpanded} + aria-label="Help" + > + Help + + + )} + + + + + + + ); + + const mainContainerId = 'main-content-page-layout-docked-nav'; + + const handleClick = (event: React.MouseEvent) => { + event.preventDefault(); + + const mainContentElement = document.getElementById(mainContainerId); + if (mainContentElement) { + mainContentElement.focus(); + } + }; + + const pageSkipToContent = ( + + Skip to content + + ); + + return ( + <> + + +

Main title

+

This is a full page demo.

+
+ + } + > + + + {Array.from({ length: 10 }).map((_value, index) => ( + + + This is a card + + + ))} + + +
+ + ); +}; diff --git a/packages/react-core/src/demos/examples/Page/PageDockedNav.tsx b/packages/react-core/src/demos/examples/Page/PageDockedNav.tsx deleted file mode 100644 index 962c2210af3..00000000000 --- a/packages/react-core/src/demos/examples/Page/PageDockedNav.tsx +++ /dev/null @@ -1,259 +0,0 @@ -import { useRef, useState } from 'react'; -import { - Avatar, - Brand, - Breadcrumb, - BreadcrumbItem, - Button, - ButtonVariant, - Card, - CardBody, - Content, - Divider, - Dropdown, - DropdownItem, - DropdownList, - Gallery, - GalleryItem, - Masthead, - MastheadMain, - MastheadLogo, - MastheadContent, - MastheadBrand, - MenuToggle, - Nav, - NavItem, - NavList, - Page, - PageSection, - SkipToContent, - Toolbar, - ToolbarContent, - ToolbarGroup, - ToolbarItem, - Tooltip -} from '@patternfly/react-core'; -import QuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/question-circle-icon'; -import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; -import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon'; -import CloudIcon from '@patternfly/react-icons/dist/esm/icons/cloud-icon'; -import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon'; -import imgAvatar from '@patternfly/react-core/src/components/assets/avatarImg.svg'; -import pfIconLogo from '@patternfly/react-core/src/demos/assets/PF-IconLogo-color.svg'; - -interface NavOnSelectProps { - groupId: number | string; - itemId: number | string; - to: string; -} - -export const PageDockedNav: React.FunctionComponent = () => { - const [isDropdownOpen, setIsDropdownOpen] = useState(false); - const [activeItem, setActiveItem] = useState(1); - - const onNavSelect = (_event: React.FormEvent, selectedItem: NavOnSelectProps) => { - typeof selectedItem.itemId === 'number' && setActiveItem(selectedItem.itemId); - }; - - const onDropdownToggle = () => { - setIsDropdownOpen((prevIsOpen) => !prevIsOpen); - }; - - const onDropdownSelect = () => { - setIsDropdownOpen(false); - }; - - const dashboardBreadcrumb = ( - - Section home - Section title - Section title - - Section landing - - - ); - - const userDropdownItems = [ - <> - My profile - User management - Logout - - ]; - - const navItem1Ref = useRef(null); - const navItem2Ref = useRef(null); - const navItem3Ref = useRef(null); - const navItem4Ref = useRef(null); - const settingsRef = useRef(null); - const helpRef = useRef(null); - const userMenuRef = useRef(null); - - const masthead = ( - - - -
}> - - - - - - - - - - - - - - - - - - - -