@@ -2,11 +2,12 @@ import { Component, createRef } from 'react';
22import styles from '@patternfly/react-styles/css/components/Toolbar/toolbar' ;
33import { GenerateId } from '../../helpers/GenerateId/GenerateId' ;
44import { css } from '@patternfly/react-styles' ;
5- import { ToolbarContext } from './ToolbarUtils' ;
5+ import { ToolbarContext , globalBreakpoints , containerBreakpoints } from './ToolbarUtils' ;
66import { ToolbarLabelGroupContent } from './ToolbarLabelGroupContent' ;
77import { formatBreakpointMods , canUseDOM } from '../../helpers/util' ;
88import { getDefaultOUIAId , getOUIAProps , OUIAProps } from '../../helpers' ;
99import { PageContext } from '../Page/PageContext' ;
10+ import { getResizeObserver } from '../../helpers/resizeObserver' ;
1011
1112export enum ToolbarColorVariant {
1213 default = 'default' ,
@@ -59,6 +60,10 @@ export interface ToolbarProps extends React.HTMLProps<HTMLDivElement>, OUIAProps
5960 colorVariant ?: ToolbarColorVariant | 'default' | 'no-background' | 'primary' | 'secondary' ;
6061 /** Flag indicating the toolbar padding is removed */
6162 hasNoPadding ?: boolean ;
63+ /** Use container queries instead of viewport media queries for responsive behavior */
64+ useContainerQuery ?: boolean ;
65+ /** Breakpoint for container queries. Only applies when useContainerQuery is true. */
66+ containerQueryBreakpoint ?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' ;
6267}
6368
6469export interface ToolbarState {
@@ -69,6 +74,8 @@ export interface ToolbarState {
6974 filterInfo : FilterInfo ;
7075 /** Used to keep track of window width so we can collapse expanded content when window is resizing */
7176 windowWidth : number ;
77+ /** Used to keep track of container width so we can collapse expanded content when container is resizing */
78+ containerWidth : number ;
7279 ouiaStateId : string ;
7380}
7481
@@ -79,12 +86,15 @@ interface FilterInfo {
7986class Toolbar extends Component < ToolbarProps , ToolbarState > {
8087 static displayName = 'Toolbar' ;
8188 labelGroupContentRef = createRef < HTMLDivElement > ( ) ;
89+ toolbarRef = createRef < HTMLDivElement > ( ) ;
90+ observer : any = ( ) => { } ;
8291 staticFilterInfo = { } ;
8392 hasNoPadding = false ;
8493 state = {
8594 isManagedToggleExpanded : false ,
8695 filterInfo : { } ,
8796 windowWidth : canUseDOM ? window . innerWidth : 1200 ,
97+ containerWidth : 0 ,
8898 ouiaStateId : getDefaultOUIAId ( Toolbar . displayName )
8999 } ;
90100
@@ -105,15 +115,58 @@ class Toolbar extends Component<ToolbarProps, ToolbarState> {
105115 }
106116 } ;
107117
118+ closeExpandableContentOnContainerResize = ( ) => {
119+ if ( this . toolbarRef . current && this . toolbarRef . current . clientWidth ) {
120+ const newWidth = this . toolbarRef . current . clientWidth ;
121+
122+ if ( newWidth !== this . state . containerWidth ) {
123+ // If expanded and container is wide enough for inline display at the specific breakpoint, close it
124+ const specificBreakpoint = this . props . containerQueryBreakpoint || 'lg' ;
125+
126+ // Use container breakpoints when using container queries, otherwise use global breakpoints
127+ let isWideEnoughForInline : boolean ;
128+ if ( this . props . useContainerQuery ) {
129+ // Handle 'sm' case for container breakpoints
130+ const breakpointKey = specificBreakpoint === 'sm' ? 'sm' : specificBreakpoint ;
131+ isWideEnoughForInline = newWidth >= containerBreakpoints [ breakpointKey ] ;
132+ } else {
133+ // Handle 'sm' case - map to 'md' since globalBreakpoints doesn't have 'sm'
134+ const breakpointKey = specificBreakpoint === 'sm' ? 'md' : specificBreakpoint ;
135+ isWideEnoughForInline = newWidth >= globalBreakpoints [ breakpointKey ] ;
136+ }
137+
138+ if ( this . state . isManagedToggleExpanded && isWideEnoughForInline ) {
139+ this . setState ( ( ) => ( {
140+ isManagedToggleExpanded : false ,
141+ containerWidth : newWidth
142+ } ) ) ;
143+ } else {
144+ // Just update width without closing
145+ this . setState ( ( ) => ( {
146+ containerWidth : newWidth
147+ } ) ) ;
148+ }
149+ }
150+ }
151+ } ;
152+
108153 componentDidMount ( ) {
109154 if ( this . isToggleManaged ( ) && canUseDOM ) {
110- window . addEventListener ( 'resize' , this . closeExpandableContent ) ;
155+ if ( this . props . useContainerQuery && this . toolbarRef . current ) {
156+ this . observer = getResizeObserver ( this . toolbarRef . current , this . closeExpandableContentOnContainerResize , true ) ;
157+ } else {
158+ window . addEventListener ( 'resize' , this . closeExpandableContent ) ;
159+ }
111160 }
112161 }
113162
114163 componentWillUnmount ( ) {
115164 if ( this . isToggleManaged ( ) && canUseDOM ) {
116- window . removeEventListener ( 'resize' , this . closeExpandableContent ) ;
165+ if ( this . props . useContainerQuery ) {
166+ this . observer ( ) ;
167+ } else {
168+ window . removeEventListener ( 'resize' , this . closeExpandableContent ) ;
169+ }
117170 }
118171 }
119172
@@ -147,6 +200,8 @@ class Toolbar extends Component<ToolbarProps, ToolbarState> {
147200 numberOfFiltersText,
148201 customLabelGroupContent,
149202 colorVariant = ToolbarColorVariant . default ,
203+ useContainerQuery,
204+ containerQueryBreakpoint,
150205 ...props
151206 } = this . props ;
152207
@@ -167,13 +222,27 @@ class Toolbar extends Component<ToolbarProps, ToolbarState> {
167222 isFullHeight && styles . modifiers . fullHeight ,
168223 isStatic && styles . modifiers . static ,
169224 isSticky && styles . modifiers . sticky ,
225+ useContainerQuery && ! containerQueryBreakpoint && styles . modifiers . container ,
226+ useContainerQuery &&
227+ containerQueryBreakpoint &&
228+ ( ( ) : string => {
229+ const breakpointClassMap : Record < string , string > = {
230+ '2xl' : styles . modifiers . container_2xl ,
231+ sm : styles . modifiers . containerSm ,
232+ md : styles . modifiers . containerMd ,
233+ lg : styles . modifiers . containerLg ,
234+ xl : styles . modifiers . containerXl
235+ } ;
236+ return breakpointClassMap [ containerQueryBreakpoint ] || '' ;
237+ } ) ( ) ,
170238 formatBreakpointMods ( inset , styles , '' , getBreakpoint ( width ) ) ,
171239 colorVariant === 'primary' && styles . modifiers . primary ,
172240 colorVariant === 'secondary' && styles . modifiers . secondary ,
173241 colorVariant === 'no-background' && styles . modifiers . noBackground ,
174242 className
175243 ) }
176244 id = { randomId }
245+ ref = { this . toolbarRef }
177246 { ...getOUIAProps ( Toolbar . displayName , ouiaId !== undefined ? ouiaId : this . state . ouiaStateId ) }
178247 { ...props }
179248 >
@@ -188,7 +257,8 @@ class Toolbar extends Component<ToolbarProps, ToolbarState> {
188257 clearFiltersButtonText,
189258 showClearFiltersButton,
190259 toolbarId : randomId ,
191- customLabelGroupContent
260+ customLabelGroupContent,
261+ useContainerQuery
192262 } }
193263 >
194264 { children }
0 commit comments