diff --git a/packages/react-core/src/components/Toolbar/ToolbarContent.tsx b/packages/react-core/src/components/Toolbar/ToolbarContent.tsx index 6689cfa5056..09b2770008e 100644 --- a/packages/react-core/src/components/Toolbar/ToolbarContent.tsx +++ b/packages/react-core/src/components/Toolbar/ToolbarContent.tsx @@ -3,7 +3,6 @@ import styles from '@patternfly/react-styles/css/components/Toolbar/toolbar'; import { css } from '@patternfly/react-styles'; import { ToolbarContentContext, ToolbarContext } from './ToolbarUtils'; import { formatBreakpointMods } from '../../helpers/util'; -import { ToolbarExpandableContent } from './ToolbarExpandableContent'; import { PageContext } from '../Page/PageContext'; export interface ToolbarContentProps extends React.HTMLProps { @@ -33,8 +32,6 @@ export interface ToolbarContentProps extends React.HTMLProps { clearFiltersButtonText?: string; /** Id of the parent Toolbar component */ toolbarId?: string; - /** Custom expandable content for the toolbar, for non-managed multiple toolbar toggle groups. */ - expandableContent?: React.ReactNode; } export class ToolbarContent extends React.Component { @@ -60,7 +57,6 @@ export class ToolbarContent extends React.Component { showClearFiltersButton, clearFiltersButtonText, alignSelf, - expandableContent, ...props } = this.props; @@ -73,6 +69,7 @@ export class ToolbarContent extends React.Component { formatBreakpointMods(visibility, styles, '', getBreakpoint(width)), className )} + ref={this.expandableContentRef} {...props} > @@ -80,6 +77,7 @@ export class ToolbarContent extends React.Component { clearAllFilters: clearAllFiltersContext, clearFiltersButtonText: clearFiltersButtonContext, showClearFiltersButton: showClearFiltersButtonContext, + isExpanded: isExpandedContext, toolbarId: toolbarIdContext }) => { const expandableContentId = `${ @@ -90,7 +88,11 @@ export class ToolbarContent extends React.Component { value={{ expandableContentRef: this.expandableContentRef, expandableContentId, - chipContainerRef: this.chipContainerRef + chipContainerRef: this.chipContainerRef, + isExpanded: isExpanded || isExpandedContext, + clearAllFilters: clearAllFilters || clearAllFiltersContext, + clearFiltersButtonText: clearFiltersButtonText || clearFiltersButtonContext, + showClearFiltersButton: showClearFiltersButton || showClearFiltersButtonContext }} >
{ > {children}
- {expandableContent ? ( - expandableContent - ) : ( - - )} ); }} diff --git a/packages/react-core/src/components/Toolbar/ToolbarExpandableContent.tsx b/packages/react-core/src/components/Toolbar/ToolbarExpandableContent.tsx index 3797d42e518..b76d02e494f 100644 --- a/packages/react-core/src/components/Toolbar/ToolbarExpandableContent.tsx +++ b/packages/react-core/src/components/Toolbar/ToolbarExpandableContent.tsx @@ -37,6 +37,7 @@ export class ToolbarExpandableContent extends React.Component - + {children} {numberOfFilters > 0 && ( diff --git a/packages/react-core/src/components/Toolbar/ToolbarToggleGroup.tsx b/packages/react-core/src/components/Toolbar/ToolbarToggleGroup.tsx index 9d2d5363f0e..74f9af0371b 100644 --- a/packages/react-core/src/components/Toolbar/ToolbarToggleGroup.tsx +++ b/packages/react-core/src/components/Toolbar/ToolbarToggleGroup.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import * as ReactDOM from 'react-dom'; import styles from '@patternfly/react-styles/css/components/Toolbar/toolbar'; import { css } from '@patternfly/react-styles'; import { ToolbarGroupProps } from './ToolbarGroup'; @@ -8,6 +7,8 @@ import { Button } from '../Button'; import globalBreakpointLg from '@patternfly/react-tokens/dist/esm/global_breakpoint_lg'; import { formatBreakpointMods, toCamel, canUseDOM } from '../../helpers/util'; import { PageContext } from '../Page/PageContext'; +import { ToolbarExpandableContent } from './ToolbarExpandableContent'; +import { Popper } from '../../helpers'; export interface ToolbarToggleGroupProps extends ToolbarGroupProps { /** Flag indicating when toggle group is expanded for non-managed toolbar toggle groups. */ @@ -50,12 +51,19 @@ export interface ToolbarToggleGroupProps extends ToolbarGroupProps { xl?: 'spaceItemsNone' | 'spaceItemsSm' | 'spaceItemsMd' | 'spaceItemsLg'; '2xl'?: 'spaceItemsNone' | 'spaceItemsSm' | 'spaceItemsMd' | 'spaceItemsLg'; }; - /** Reference to a custom expandable content group, for non-managed multiple toolbar toggle groups. */ - expandableContentRef?: React.RefObject; + /** Reference to a chip container group for filters inside the toolbar toggle group */ + chipContainerRef?: React.RefObject; + /** Optional callback for clearing all filters in the toolbar toggle group */ + clearAllFilters?: () => void; + /** Flag indicating that the clear all filters button should be visible in the toolbar toggle group */ + showClearFiltersButton?: boolean; + /** Text to display in the clear all filters button of the toolbar toggle group */ + clearFiltersButtonText?: string; } - export class ToolbarToggleGroup extends React.Component { static displayName = 'ToolbarToggleGroup'; + toggleRef = React.createRef(); + expandableContentRef = React.createRef(); isContentPopup = () => { const viewportSize = canUseDOM ? window.innerWidth : 1200; @@ -75,8 +83,11 @@ export class ToolbarToggleGroup extends React.Component className, children, isExpanded, - expandableContentRef, onToggle, + chipContainerRef, + clearAllFilters, + showClearFiltersButton, + clearFiltersButtonText, ...props } = this.props; @@ -89,27 +100,23 @@ export class ToolbarToggleGroup extends React.Component {({ width, getBreakpoint }) => ( - {({ isExpanded: managedIsExpanded, toggleIsExpanded: managedOnToggle }) => { - const _isExpanded = isExpanded !== undefined ? isExpanded : managedIsExpanded; + {({ toggleIsExpanded: managedOnToggle }) => { const _onToggle = onToggle !== undefined ? onToggle : managedOnToggle; return ( - {({ expandableContentRef: managedExpandableContentRef, expandableContentId }) => { - const _contentRef = - expandableContentRef !== undefined ? expandableContentRef : managedExpandableContentRef; - - if ( - isExpanded === undefined && - managedExpandableContentRef.current && - managedExpandableContentRef.current.classList - ) { - if (_isExpanded) { - managedExpandableContentRef.current.classList.add(styles.modifiers.expanded); - } else { - managedExpandableContentRef.current.classList.remove(styles.modifiers.expanded); - } - } + {({ + expandableContentRef, + expandableContentId, + chipContainerRef: managedChipContainerRef, + isExpanded: managedIsExpanded, + clearAllFilters: clearAllFiltersContext, + clearFiltersButtonText: clearFiltersButtonContext, + showClearFiltersButton: showClearFiltersButtonContext + }) => { + const _isExpanded = isExpanded !== undefined ? isExpanded : managedIsExpanded; + const _chipContainerRef = + chipContainerRef !== undefined ? chipContainerRef : managedChipContainerRef; const breakpointMod: { md?: 'show'; @@ -119,6 +126,36 @@ export class ToolbarToggleGroup extends React.Component } = {}; breakpointMod[breakpoint] = 'show'; + const expandableContent = ( + + {children} + + ); + + const toggleButton = ( +
+ +
+ ); + return (
)} {...props} > -
- -
- {_isExpanded - ? (ReactDOM.createPortal( - children, - _contentRef.current.firstElementChild - ) as React.ReactElement) - : children} + + {!_isExpanded && children}
); }} diff --git a/packages/react-core/src/components/Toolbar/ToolbarUtils.tsx b/packages/react-core/src/components/Toolbar/ToolbarUtils.tsx index 9ee37c99f85..6aec87bf74b 100644 --- a/packages/react-core/src/components/Toolbar/ToolbarUtils.tsx +++ b/packages/react-core/src/components/Toolbar/ToolbarUtils.tsx @@ -31,12 +31,17 @@ interface ToolbarContentContextProps { expandableContentRef: RefObject; expandableContentId: string; chipContainerRef: RefObject; + isExpanded?: boolean; + clearAllFilters?: () => void; + clearFiltersButtonText?: string; + showClearFiltersButton?: boolean; } export const ToolbarContentContext = React.createContext({ expandableContentRef: null, expandableContentId: '', - chipContainerRef: null + chipContainerRef: null, + clearAllFilters: () => {} }); export const globalBreakpoints = { diff --git a/packages/react-core/src/components/Toolbar/__tests__/Generated/__snapshots__/ToolbarContent.test.tsx.snap b/packages/react-core/src/components/Toolbar/__tests__/Generated/__snapshots__/ToolbarContent.test.tsx.snap index 044e3353e87..a6d292adf1f 100644 --- a/packages/react-core/src/components/Toolbar/__tests__/Generated/__snapshots__/ToolbarContent.test.tsx.snap +++ b/packages/react-core/src/components/Toolbar/__tests__/Generated/__snapshots__/ToolbarContent.test.tsx.snap @@ -12,14 +12,6 @@ exports[`ToolbarContent should match snapshot (auto-generated) 1`] = ` ReactNode -
-
-
`; diff --git a/packages/react-core/src/components/Toolbar/__tests__/Toolbar.test.tsx b/packages/react-core/src/components/Toolbar/__tests__/Toolbar.test.tsx index 582485299aa..57c83cdce8a 100644 --- a/packages/react-core/src/components/Toolbar/__tests__/Toolbar.test.tsx +++ b/packages/react-core/src/components/Toolbar/__tests__/Toolbar.test.tsx @@ -65,7 +65,7 @@ describe('Toolbar', () => { {}} - deleteChipGroup={category => {}} + deleteChipGroup={(category) => {}} categoryName="Status" > test content @@ -102,8 +102,7 @@ describe('Toolbar', () => { ); expect(asFragment()).toMatchSnapshot(); - // Expecting 2 matches for text because the buttons also exist in hidden expandable content for mobile view - expect(screen.getAllByRole('button', { name: 'Save filters' }).length).toBe(2); - expect(screen.getAllByRole('button', { name: 'Clear all filters' }).length).toBe(2); + expect(screen.getAllByRole('button', { name: 'Save filters' }).length).toBe(1); + expect(screen.getAllByRole('button', { name: 'Clear all filters' }).length).toBe(1); }); }); diff --git a/packages/react-core/src/components/Toolbar/__tests__/ToolbarToggleGroup.test.tsx b/packages/react-core/src/components/Toolbar/__tests__/ToolbarToggleGroup.test.tsx index a86b1da1c86..91aa6e4b217 100644 --- a/packages/react-core/src/components/Toolbar/__tests__/ToolbarToggleGroup.test.tsx +++ b/packages/react-core/src/components/Toolbar/__tests__/ToolbarToggleGroup.test.tsx @@ -1,23 +1,26 @@ import React from 'react'; import { render } from '@testing-library/react'; import { ToolbarToggleGroup } from '../ToolbarToggleGroup'; -import { ToolbarContentContext } from '../ToolbarUtils'; +import { Toolbar } from '../Toolbar'; +import { ToolbarContent } from '../ToolbarContent'; describe('ToolbarToggleGroup', () => { it('should warn on bad props', () => { const myMock = jest.fn() as any; global.console = { error: myMock } as any; + const items = ( + + + test + + + ); + render( - - - + + {items} + ); expect(myMock).toHaveBeenCalled(); diff --git a/packages/react-core/src/components/Toolbar/__tests__/__snapshots__/Toolbar.test.tsx.snap b/packages/react-core/src/components/Toolbar/__tests__/__snapshots__/Toolbar.test.tsx.snap index 31e809b78b6..13b971baed6 100644 --- a/packages/react-core/src/components/Toolbar/__tests__/__snapshots__/Toolbar.test.tsx.snap +++ b/packages/react-core/src/components/Toolbar/__tests__/__snapshots__/Toolbar.test.tsx.snap @@ -34,14 +34,6 @@ exports[`Toolbar should render inset 1`] = ` Test 3 -
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
{ - const statusExpandableContentRef = React.useRef(); const statusChipContainerRef = React.useRef(); - const riskExpandableContentRef = React.useRef(); const riskChipContainerRef = React.useRef(); const [isStatusGroupExpanded, setIsStatusGroupExpanded] = React.useState(false); @@ -222,43 +219,21 @@ export const Test: React.FunctionComponent = () => { ); - const toggleExpandGroups = ( - <> - onDeleteGroup('Status')} - clearFiltersButtonText="Clear status filter" - /> - onDeleteGroup('Risk')} - clearFiltersButtonText="Clear risk filter" - /> - - ); - return ( - + { setIsStatusGroupExpanded(!isStatusGroupExpanded); setIsRiskGroupExpanded(false); }} // Required to control expanded state - expandableContentRef={statusExpandableContentRef} // Required to link the toggle group to a specific expandable content group toggleIcon={} breakpoint="md" + chipContainerRef={statusChipContainerRef} + showClearFiltersButton + clearAllFilters={() => onDeleteGroup('Status')} + clearFiltersButtonText="Clear status filter" > {statusToggleGroupItems} @@ -268,9 +243,12 @@ export const Test: React.FunctionComponent = () => { setIsRiskGroupExpanded(!isRiskGroupExpanded); setIsStatusGroupExpanded(false); }} // Required to control expanded state - expandableContentRef={riskExpandableContentRef} // Required to link the toggle group to a specific expandable content group toggleIcon={} breakpoint="xl" + chipContainerRef={riskChipContainerRef} + showClearFiltersButton + clearAllFilters={() => onDeleteGroup('Risk')} + clearFiltersButtonText={'Clear risk filter'} > {riskToggleGroupItems}