Skip to content

Commit 8e610ef

Browse files
arpanroy41cursoragentthatblindgeye
authored
feat(Toolbar): add flexGrow and widths props to ToolbarItem and Toolb… (#12237)
* feat(Toolbar): add flexGrow and widths props to ToolbarItem and ToolbarGroup - Add flexGrow prop to ToolbarItem with breakpoint support (default, sm, md, lg, xl, 2xl) - Add flexGrow prop to ToolbarGroup with breakpoint support - Add widths prop to ToolbarItem for setting custom widths at various breakpoints - Add comprehensive tests for new props - Add example documentation showing flexGrow and widths usage Fixes #11910 Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(Toolbar): consolidate imports in ToolbarFlexGrowAndWidths example * fix(ToolbarItem): add style prop to Divider component for customization * Updated snapshot --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Eric Olkowski <git.eric@thatblindgeye.dev>
1 parent 9169658 commit 8e610ef

7 files changed

Lines changed: 213 additions & 17 deletions

File tree

packages/react-core/src/components/Toolbar/ToolbarGroup.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,15 @@ export interface ToolbarGroupProps extends Omit<React.HTMLProps<HTMLDivElement>,
174174
xl?: 'wrap' | 'nowrap';
175175
'2xl'?: 'wrap' | 'nowrap';
176176
};
177+
/** Sets flex-grow at various breakpoints to allow the group to consume available main-axis space */
178+
flexGrow?: {
179+
default?: 'flexGrow';
180+
sm?: 'flexGrow';
181+
md?: 'flexGrow';
182+
lg?: 'flexGrow';
183+
xl?: 'flexGrow';
184+
'2xl'?: 'flexGrow';
185+
};
177186
/** Content to be rendered inside the data toolbar group */
178187
children?: React.ReactNode;
179188
/** Flag that modifies the toolbar group to hide overflow and respond to available space. Used for horizontal navigation. */
@@ -194,6 +203,7 @@ class ToolbarGroupWithRef extends Component<ToolbarGroupProps> {
194203
columnGap,
195204
rowGap,
196205
rowWrap,
206+
flexGrow,
197207
className,
198208
variant,
199209
children,
@@ -224,6 +234,7 @@ class ToolbarGroupWithRef extends Component<ToolbarGroupProps> {
224234
formatBreakpointMods(columnGap, styles, '', getBreakpoint(width)),
225235
formatBreakpointMods(rowGap, styles, '', getBreakpoint(width)),
226236
formatBreakpointMods(rowWrap, styles, '', getBreakpoint(width)),
237+
formatBreakpointMods(flexGrow, styles, '', getBreakpoint(width)),
227238
alignItems === 'start' && styles.modifiers.alignItemsStart,
228239
alignItems === 'center' && styles.modifiers.alignItemsCenter,
229240
alignItems === 'baseline' && styles.modifiers.alignItemsBaseline,

packages/react-core/src/components/Toolbar/ToolbarItem.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import styles from '@patternfly/react-styles/css/components/Toolbar/toolbar';
22
import { css } from '@patternfly/react-styles';
3-
import { formatBreakpointMods, toCamel } from '../../helpers/util';
3+
import { formatBreakpointMods, setBreakpointCssVars, toCamel } from '../../helpers/util';
44
import { Divider } from '../Divider';
55
import { PageContext } from '../Page/PageContext';
6+
import cssToolbarItemWidth from '@patternfly/react-tokens/dist/esm/c_toolbar__item_Width';
67

78
export enum ToolbarItemVariant {
89
separator = 'separator',
@@ -168,6 +169,24 @@ export interface ToolbarItemProps extends React.HTMLProps<HTMLDivElement> {
168169
xl?: 'wrap' | 'nowrap';
169170
'2xl'?: 'wrap' | 'nowrap';
170171
};
172+
/** Sets flex-grow at various breakpoints to allow the item to consume available main-axis space */
173+
flexGrow?: {
174+
default?: 'flexGrow';
175+
sm?: 'flexGrow';
176+
md?: 'flexGrow';
177+
lg?: 'flexGrow';
178+
xl?: 'flexGrow';
179+
'2xl'?: 'flexGrow';
180+
};
181+
/** Width at various breakpoints. */
182+
widths?: {
183+
default?: string;
184+
sm?: string;
185+
md?: string;
186+
lg?: string;
187+
xl?: string;
188+
'2xl'?: string;
189+
};
171190
/** id for this data toolbar item */
172191
id?: string;
173192
/** Flag indicating if the expand-all variant is expanded or not */
@@ -187,6 +206,8 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
187206
columnGap,
188207
rowGap,
189208
rowWrap,
209+
flexGrow,
210+
widths,
190211
align,
191212
alignSelf,
192213
alignItems,
@@ -195,6 +216,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
195216
isAllExpanded,
196217
isOverflowContainer,
197218
role,
219+
style,
198220
...props
199221
}: ToolbarItemProps) => {
200222
if (variant === ToolbarItemVariant.separator) {
@@ -203,12 +225,15 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
203225
<Divider
204226
className={css(className)}
205227
orientation={{ default: 'vertical' }}
228+
style={style}
206229
{...props}
207230
{...(isDividerRoleValid && { role: role as 'separator' | 'presentation' })}
208231
/>
209232
);
210233
}
211234

235+
const responsiveWidths = widths ? setBreakpointCssVars(widths, cssToolbarItemWidth.name) : {};
236+
212237
return (
213238
<PageContext.Consumer>
214239
{({ width, getBreakpoint, height, getVerticalBreakpoint }) => (
@@ -226,6 +251,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
226251
formatBreakpointMods(columnGap, styles, '', getBreakpoint(width)),
227252
formatBreakpointMods(rowGap, styles, '', getBreakpoint(width)),
228253
formatBreakpointMods(rowWrap, styles, '', getBreakpoint(width)),
254+
formatBreakpointMods(flexGrow, styles, '', getBreakpoint(width)),
229255
alignItems === 'start' && styles.modifiers.alignItemsStart,
230256
alignItems === 'center' && styles.modifiers.alignItemsCenter,
231257
alignItems === 'baseline' && styles.modifiers.alignItemsBaseline,
@@ -237,6 +263,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
237263
{...(variant === 'label' && { 'aria-hidden': true })}
238264
id={id}
239265
role={role}
266+
style={{ ...style, ...responsiveWidths }}
240267
{...props}
241268
>
242269
{children}

packages/react-core/src/components/Toolbar/__tests__/ToolbarGroup.test.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,20 @@ describe('ToolbarGroup', () => {
6363
expect(screen.getByTestId('toolbargroup')).toHaveClass(expectedClass);
6464
});
6565
});
66+
67+
describe('ToolbarGroup flexGrow', () => {
68+
const bps = ['default', 'sm', 'md', 'lg', 'xl', '2xl'];
69+
70+
describe.each(bps)(`flexGrow at various breakpoints`, (bp) => {
71+
it(`should render with pf-m-flex-grow when flexGrow is set at ${bp}`, () => {
72+
render(
73+
<ToolbarGroup data-testid="toolbargroup" flexGrow={{ [bp]: 'flexGrow' }}>
74+
Test
75+
</ToolbarGroup>
76+
);
77+
const bpFlexGrowClass = bp === 'default' ? 'pf-m-flex-grow' : `pf-m-flex-grow-on-${bp}`;
78+
expect(screen.getByTestId('toolbargroup')).toHaveClass(bpFlexGrowClass);
79+
});
80+
});
81+
});
6682
});

packages/react-core/src/components/Toolbar/__tests__/ToolbarItem.test.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,46 @@ describe('ToolbarItem', () => {
6363
expect(screen.getByTestId('toolbaritem')).toHaveClass(expectedClass);
6464
});
6565
});
66+
67+
describe('ToolbarItem flexGrow', () => {
68+
const bps = ['default', 'sm', 'md', 'lg', 'xl', '2xl'];
69+
70+
describe.each(bps)(`flexGrow at various breakpoints`, (bp) => {
71+
it(`should render with pf-m-flex-grow when flexGrow is set at ${bp}`, () => {
72+
render(
73+
<ToolbarItem data-testid="toolbaritem" flexGrow={{ [bp]: 'flexGrow' }}>
74+
Test
75+
</ToolbarItem>
76+
);
77+
const bpFlexGrowClass = bp === 'default' ? 'pf-m-flex-grow' : `pf-m-flex-grow-on-${bp}`;
78+
expect(screen.getByTestId('toolbaritem')).toHaveClass(bpFlexGrowClass);
79+
});
80+
});
81+
});
82+
83+
describe('ToolbarItem widths', () => {
84+
it('should apply width CSS variable when widths prop is set', () => {
85+
render(
86+
<ToolbarItem data-testid="toolbaritem" widths={{ default: '200px' }}>
87+
Test
88+
</ToolbarItem>
89+
);
90+
const item = screen.getByTestId('toolbaritem');
91+
expect(item).toHaveStyle('--pf-v6-c-toolbar__item--Width: 200px');
92+
});
93+
94+
it('should apply responsive width CSS variables when widths prop has breakpoint values', () => {
95+
render(
96+
<ToolbarItem data-testid="toolbaritem" widths={{ default: '100px', md: '200px', xl: '300px' }}>
97+
Test
98+
</ToolbarItem>
99+
);
100+
const item = screen.getByTestId('toolbaritem');
101+
expect(item).toHaveStyle({
102+
'--pf-v6-c-toolbar__item--Width': '100px',
103+
'--pf-v6-c-toolbar__item--Width-on-md': '200px',
104+
'--pf-v6-c-toolbar__item--Width-on-xl': '300px'
105+
});
106+
});
107+
});
66108
});

packages/react-core/src/components/Toolbar/examples/Toolbar.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,11 @@ The toolbar content section will wrap by default, but you can set the `rowRap` p
154154
```ts file="./ToolbarItemSpacers.tsx"
155155

156156
```
157+
158+
### FlexGrow and widths
159+
160+
You can use the `flexGrow` prop to make toolbar items or groups expand to fill available space. The `widths` prop allows you to set custom widths at various breakpoints.
161+
162+
```ts file="./ToolbarFlexGrowAndWidths.tsx"
163+
164+
```
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Fragment } from 'react';
2+
import { Toolbar, ToolbarItem, ToolbarGroup, ToolbarContent, Button, SearchInput } from '@patternfly/react-core';
3+
4+
export const ToolbarFlexGrowAndWidths: React.FunctionComponent = () => {
5+
const flexGrowItems = (
6+
<Fragment>
7+
<ToolbarItem>
8+
<Button variant="secondary">Item 1</Button>
9+
</ToolbarItem>
10+
<ToolbarItem flexGrow={{ default: 'flexGrow' }}>
11+
<SearchInput aria-label="Flex grow search input" />
12+
</ToolbarItem>
13+
<ToolbarItem>
14+
<Button variant="secondary">Item 2</Button>
15+
</ToolbarItem>
16+
</Fragment>
17+
);
18+
19+
const flexGrowGroupItems = (
20+
<Fragment>
21+
<ToolbarGroup>
22+
<ToolbarItem>
23+
<Button variant="secondary">Item 1</Button>
24+
</ToolbarItem>
25+
<ToolbarItem>
26+
<Button variant="secondary">Item 2</Button>
27+
</ToolbarItem>
28+
</ToolbarGroup>
29+
<ToolbarGroup flexGrow={{ default: 'flexGrow' }}>
30+
<ToolbarItem>
31+
<Button variant="secondary">Flex grow group item 1</Button>
32+
</ToolbarItem>
33+
<ToolbarItem>
34+
<Button variant="secondary">Flex grow group item 2</Button>
35+
</ToolbarItem>
36+
</ToolbarGroup>
37+
<ToolbarGroup>
38+
<ToolbarItem>
39+
<Button variant="secondary">Item 3</Button>
40+
</ToolbarItem>
41+
</ToolbarGroup>
42+
</Fragment>
43+
);
44+
45+
const widthItems = (
46+
<Fragment>
47+
<ToolbarItem widths={{ default: '200px' }}>
48+
<SearchInput aria-label="Search input with fixed width" />
49+
</ToolbarItem>
50+
<ToolbarItem>
51+
<Button variant="secondary">Regular item</Button>
52+
</ToolbarItem>
53+
<ToolbarItem widths={{ default: '300px' }}>
54+
<SearchInput aria-label="Search input with wider fixed width" />
55+
</ToolbarItem>
56+
</Fragment>
57+
);
58+
59+
const responsiveWidthItems = (
60+
<Fragment>
61+
<ToolbarItem widths={{ default: '100px', md: '200px', xl: '300px' }}>
62+
<SearchInput aria-label="Search input with responsive width" />
63+
</ToolbarItem>
64+
<ToolbarItem>
65+
<Button variant="secondary">Regular item</Button>
66+
</ToolbarItem>
67+
</Fragment>
68+
);
69+
70+
return (
71+
<>
72+
Using flexGrow on ToolbarItem
73+
<br />
74+
<br />
75+
<Toolbar id="toolbar-flex-grow-item">
76+
<ToolbarContent>{flexGrowItems}</ToolbarContent>
77+
</Toolbar>
78+
<br />
79+
<br />
80+
Using flexGrow on ToolbarGroup
81+
<br />
82+
<br />
83+
<Toolbar id="toolbar-flex-grow-group">
84+
<ToolbarContent>{flexGrowGroupItems}</ToolbarContent>
85+
</Toolbar>
86+
<br />
87+
<br />
88+
Using widths on ToolbarItem
89+
<br />
90+
<br />
91+
<Toolbar id="toolbar-widths">
92+
<ToolbarContent>{widthItems}</ToolbarContent>
93+
</Toolbar>
94+
<br />
95+
<br />
96+
Using responsive widths on ToolbarItem
97+
<br />
98+
<br />
99+
<Toolbar id="toolbar-responsive-widths">
100+
<ToolbarContent>{responsiveWidthItems}</ToolbarContent>
101+
</Toolbar>
102+
</>
103+
);
104+
};

packages/react-table/src/deprecated/components/Table/__tests__/__snapshots__/Table.test.tsx.snap

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2953,24 +2953,12 @@ exports[`Table Compact table with Radio select 1`] = `
29532953
fill="currentColor"
29542954
height="1em"
29552955
role="img"
2956+
viewBox="0 0 32 32"
29562957
width="1em"
29572958
>
2958-
<svg
2959-
class="pf-v6-icon-default"
2960-
viewBox="0 0 256 512"
2961-
>
2962-
<path
2963-
d="M214.059 377.941H168V134.059h46.059c21.382 0 32.09-25.851 16.971-40.971L144.971 7.029c-9.373-9.373-24.568-9.373-33.941 0L24.971 93.088c-15.119 15.119-4.411 40.971 16.971 40.971H88v243.882H41.941c-21.382 0-32.09 25.851-16.971 40.971l86.059 86.059c9.373 9.373 24.568 9.373 33.941 0l86.059-86.059c15.12-15.119 4.412-40.971-16.97-40.971z"
2964-
/>
2965-
</svg>
2966-
<svg
2967-
class="pf-v6-icon-rh-ui"
2968-
viewBox="0 0 32 32"
2969-
>
2970-
<path
2971-
d="M21.293 23.293 17 27.586V4.414l4.293 4.293a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414l-5.646-5.646a1.5 1.5 0 0 0-2.121 0L9.294 7.293a.999.999 0 1 0 1.414 1.414l4.293-4.293v23.172l-4.293-4.293a.999.999 0 1 0-1.414 1.414l5.646 5.646c.292.293.676.438 1.061.438s.768-.146 1.061-.438l5.646-5.646a.999.999 0 1 0-1.414-1.414Z"
2972-
/>
2973-
</svg>
2959+
<path
2960+
d="M21.293 23.293 17 27.586V4.414l4.293 4.293a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414l-5.646-5.646a1.5 1.5 0 0 0-2.121 0L9.294 7.293a.999.999 0 1 0 1.414 1.414l4.293-4.293v23.172l-4.293-4.293a.999.999 0 1 0-1.414 1.414l5.646 5.646c.292.293.676.438 1.061.438s.768-.146 1.061-.438l5.646-5.646a.999.999 0 1 0-1.414-1.414Z"
2961+
/>
29742962
</svg>
29752963
</span>
29762964
</div>

0 commit comments

Comments
 (0)