Skip to content
Closed
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
44 changes: 28 additions & 16 deletions packages/react-core/src/components/Toolbar/ToolbarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ToolbarContentContext, ToolbarContext } from './ToolbarUtils';
import { formatBreakpointMods } from '../../helpers/util';
import { ToolbarExpandableContent } from './ToolbarExpandableContent';
import { PageContext } from '../Page/PageContext';
import { debounce, canUseDOM } from '../../helpers/util';

export interface ToolbarContentProps extends React.HTMLProps<HTMLDivElement> {
/** Classes applied to root element of the data toolbar content row */
Expand Down Expand Up @@ -34,18 +35,41 @@ export interface ToolbarContentProps extends React.HTMLProps<HTMLDivElement> {
/** Id of the parent Toolbar component */
toolbarId?: string;
}

// TODO: do i have any toggle groups? do any of them lack a breakpoint prop? I need have ordered references to them.
// I need to know how wide the toggle groups are when they are not collapsed
// How wide are my children collectively? are they wider than me?
// Collapse toggle groups in priority order, expand toggles in reverse priority order
// ToolbarContents tells toggle groups which state they are in and toggle group needs pf-m-show if it's not collapsed.
// BONUS: ToolbarGroups with visibility breakpoint mods could also have a priority order and be hidden when running out of space
export class ToolbarContent extends React.Component<ToolbarContentProps> {
static displayName = 'ToolbarContent';
private expandableContentRef = React.createRef<HTMLDivElement>();
private chipContainerRef = React.createRef<HTMLDivElement>();
private contentRef = React.createRef<HTMLDivElement>();
private static currentId = 0;

static defaultProps: ToolbarContentProps = {
isExpanded: false,
showClearFiltersButton: false
};

componentDidMount() {
// Initial check if should be shown
this.resize();
}

resize = () => {
if (this.contentRef?.current) {
const currentWidth = this.contentRef.current.clientWidth;

if (this.state.width !== currentWidth) {
this.setState({ width: currentWidth });
}
}
};

handleResize = debounce(this.resize, 250);

render() {
const {
className,
Expand All @@ -70,13 +94,11 @@ export class ToolbarContent extends React.Component<ToolbarContentProps> {
formatBreakpointMods(visibility, styles, '', getBreakpoint(width)),
className
)}
ref={this.contentRef}
{...props}
>
<ToolbarContext.Consumer>
{({
clearAllFilters: clearAllFiltersContext,
clearFiltersButtonText: clearFiltersButtonContext,
showClearFiltersButton: showClearFiltersButtonContext,
toolbarId: toolbarIdContext
}) => {
const expandableContentId = `${
Expand All @@ -85,9 +107,8 @@ export class ToolbarContent extends React.Component<ToolbarContentProps> {
return (
<ToolbarContentContext.Provider
value={{
expandableContentRef: this.expandableContentRef,
expandableContentId,
chipContainerRef: this.chipContainerRef
chipContainerRef: this.chipContainerRef,
contentRef: this.contentRef
}}
>
<div
Expand All @@ -103,15 +124,6 @@ export class ToolbarContent extends React.Component<ToolbarContentProps> {
>
{children}
</div>
<ToolbarExpandableContent
id={expandableContentId}
isExpanded={isExpanded}
expandableContentRef={this.expandableContentRef}
chipContainerRef={this.chipContainerRef}
clearAllFilters={clearAllFilters || clearAllFiltersContext}
showClearFiltersButton={showClearFiltersButton || showClearFiltersButtonContext}
clearFiltersButtonText={clearFiltersButtonText || clearFiltersButtonContext}
/>
</ToolbarContentContext.Provider>
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { ToolbarContext } from './ToolbarUtils';
import { PickOptional } from '../../helpers/typeUtils';

export interface ToolbarExpandableContentProps extends React.HTMLProps<HTMLDivElement> {
/** Content displayed in the expandable content */
children?: React.ReactNode;
/** Classes added to the root element of the data toolbar expandable content */
className?: string;
/** Flag indicating the expandable content is expanded */
Expand Down Expand Up @@ -37,6 +39,7 @@ export class ToolbarExpandableContent extends React.Component<ToolbarExpandableC

render() {
const {
children,
className,
expandableContentRef,
chipContainerRef,
Expand All @@ -54,8 +57,8 @@ export class ToolbarExpandableContent extends React.Component<ToolbarExpandableC
};

return (
<div className={css(styles.toolbarExpandableContent, className)} ref={expandableContentRef} {...props}>
<ToolbarGroup />
<div className={css(styles.toolbarExpandableContent, styles.modifiers.expanded, className)} ref={expandableContentRef} {...props}>
<ToolbarGroup>{children}</ToolbarGroup>
{numberOfFilters > 0 && (
<ToolbarGroup className={styles.modifiers.chipContainer}>
<ToolbarGroup ref={chipContainerRef} />
Expand Down
170 changes: 88 additions & 82 deletions packages/react-core/src/components/Toolbar/ToolbarToggleGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ 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 {
export interface ToolbarToggleGroupProps extends ToolbarGroupProps{
/** An icon to be rendered when the toggle group has collapsed down */
toggleIcon: React.ReactNode;
/** Controls when filters are shown and when the toggle button is hidden. */
Expand Down Expand Up @@ -48,98 +50,102 @@ export interface ToolbarToggleGroupProps extends ToolbarGroupProps {
};
}

export class ToolbarToggleGroup extends React.Component<ToolbarToggleGroupProps> {
static displayName = 'ToolbarToggleGroup';
isContentPopup = () => {
export const ToolbarToggleGroup: React.FunctionComponent<ToolbarToggleGroupProps> = ({
toggleIcon,
variant,
visibility,
visiblity,
breakpoint,
alignment,
spacer,
spaceItems,
className,
children,
...props
}: ToolbarToggleGroupProps
) => {
const { width, getBreakpoint } = React.useContext(PageContext);
const { isExpanded, toggleIsExpanded } = React.useContext(ToolbarContext);
const { contentRef } = React.useContext(ToolbarContentContext);

const isContentPopup = () => {
const viewportSize = canUseDOM ? window.innerWidth : 1200;
const lgBreakpointValue = parseInt(globalBreakpointLg.value);
return viewportSize < lgBreakpointValue;
};

render() {
const {
toggleIcon,
variant,
visibility,
breakpoint,
alignment,
spacer,
spaceItems,
className,
children,
...props
} = this.props;

React.useEffect(() => {
if (!breakpoint && !toggleIcon) {
// eslint-disable-next-line no-console
console.error('ToolbarToggleGroup will not be visible without a breakpoint or toggleIcon.');
}

return (
<PageContext.Consumer>
{({ width, getBreakpoint }) => (
<ToolbarContext.Consumer>
{({ isExpanded, toggleIsExpanded }) => (
<ToolbarContentContext.Consumer>
{({ expandableContentRef, expandableContentId }) => {
if (expandableContentRef.current && expandableContentRef.current.classList) {
if (isExpanded) {
expandableContentRef.current.classList.add(styles.modifiers.expanded);
} else {
expandableContentRef.current.classList.remove(styles.modifiers.expanded);
}
}
if (visiblity !== undefined) {
// eslint-disable-next-line no-console
console.warn(
'The ToolbarToggleGroup visiblity prop has been deprecated. ' +
'Please use the correctly spelled visibility prop instead.'
);
}
}, [breakpoint, toggleIcon, visiblity]);

const breakpointMod: {
md?: 'show';
lg?: 'show';
xl?: 'show';
'2xl'?: 'show';
} = {};
breakpointMod[breakpoint] = 'show';
const breakpointMod: {
md?: 'show';
lg?: 'show';
xl?: 'show';
'2xl'?: 'show';
} = {};
breakpointMod[breakpoint] = 'show';

return (
<div
className={css(
styles.toolbarGroup,
styles.modifiers.toggleGroup,
variant &&
styles.modifiers[toCamel(variant) as 'filterGroup' | 'iconButtonGroup' | 'buttonGroup'],
formatBreakpointMods(breakpointMod, styles, '', getBreakpoint(width)),
formatBreakpointMods(visibility, styles, '', getBreakpoint(width)),
formatBreakpointMods(alignment, styles, '', getBreakpoint(width)),
formatBreakpointMods(spacer, styles, '', getBreakpoint(width)),
formatBreakpointMods(spaceItems, styles, '', getBreakpoint(width)),
className
)}
{...props}
>
<div className={css(styles.toolbarToggle)}>
<Button
variant="plain"
onClick={toggleIsExpanded}
aria-label="Show Filters"
{...(isExpanded && { 'aria-expanded': true })}
aria-haspopup={isExpanded && this.isContentPopup()}
aria-controls={expandableContentId}
>
{toggleIcon}
</Button>
</div>
{isExpanded
? (ReactDOM.createPortal(
children,
expandableContentRef.current.firstElementChild
) as React.ReactElement)
: children}
</div>
);
}}
</ToolbarContentContext.Consumer>
)}
</ToolbarContext.Consumer>
)}
</PageContext.Consumer>
);
const expandableContent = () => {
console.log(children);
return (
<ToolbarExpandableContent
showClearFiltersButton={false}
>
{children}
</ToolbarExpandableContent>
);
}

const popper = (
<div className={css(styles.toolbarToggle)}>
<Button
variant="plain"
onClick={toggleIsExpanded}
aria-label="Show Filters"
{...(isExpanded && { 'aria-expanded': true })}
aria-haspopup={isExpanded && isContentPopup()}
>
{toggleIcon}
</Button>
</div>
);

return (
<div
className={css(
styles.toolbarGroup,
styles.modifiers.toggleGroup,
variant &&
styles.modifiers[toCamel(variant) as 'filterGroup' | 'iconButtonGroup' | 'buttonGroup'],
formatBreakpointMods(breakpointMod, styles, '', getBreakpoint(width)),
formatBreakpointMods(visibility || visiblity, styles, '', getBreakpoint(width)),
formatBreakpointMods(alignment, styles, '', getBreakpoint(width)),
formatBreakpointMods(spacer, styles, '', getBreakpoint(width)),
formatBreakpointMods(spaceItems, styles, '', getBreakpoint(width)),
className
)}
{...props}
>
<Popper
appendTo={contentRef.current}
trigger={popper}
popper={expandableContent()}
isVisible={isExpanded}
/>
{ !isExpanded && children }
</div>
);
}
ToolbarToggleGroup.displayName = 'ToolbarToggleGroup';
8 changes: 3 additions & 5 deletions packages/react-core/src/components/Toolbar/ToolbarUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,13 @@ export const ToolbarContext = React.createContext<ToolbarContextProps>({
});

interface ToolbarContentContextProps {
expandableContentRef: RefObject<HTMLDivElement>;
expandableContentId: string;
chipContainerRef: RefObject<any>;
contentRef: RefObject<any>;
}

export const ToolbarContentContext = React.createContext<ToolbarContentContextProps>({
expandableContentRef: null,
expandableContentId: '',
chipContainerRef: null
chipContainerRef: null,
contentRef: null
});

export const globalBreakpoints = {
Expand Down