Skip to content

Commit 6b1646f

Browse files
authored
feat(Toolbar): Add row wrap prop to ToolbarGroup and ToolbarItem (#11559)
* feat(Toolbar): Add row wrap prop to ToolbarGroup and ToolbarItem * rm unsupported wrap reverse * add wrap to toolbar content * test rowWrap for all breakpoints * fixed test after bad merge
1 parent dd8e4d8 commit 6b1646f

File tree

10 files changed

+168
-10
lines changed

10 files changed

+168
-10
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ export interface ToolbarContentProps extends React.HTMLProps<HTMLDivElement> {
1616
xl?: 'hidden' | 'visible';
1717
'2xl'?: 'hidden' | 'visible';
1818
};
19+
/** Value to set for content wrapping at various breakpoints */
20+
rowWrap?: {
21+
default?: 'wrap' | 'nowrap';
22+
sm?: 'wrap' | 'nowrap';
23+
md?: 'wrap' | 'nowrap';
24+
lg?: 'wrap' | 'nowrap';
25+
xl?: 'wrap' | 'nowrap';
26+
'2xl'?: 'wrap' | 'nowrap';
27+
};
1928
/** Vertical alignment of children */
2029
alignItems?: 'start' | 'center' | 'baseline' | 'default';
2130
/** Content to be rendered as children of the content row */
@@ -50,6 +59,7 @@ class ToolbarContent extends Component<ToolbarContentProps> {
5059
isExpanded,
5160
toolbarId,
5261
visibility,
62+
rowWrap,
5363
alignItems,
5464
clearAllFilters,
5565
showClearFiltersButton,
@@ -95,6 +105,7 @@ class ToolbarContent extends Component<ToolbarContentProps> {
95105
<div
96106
className={css(
97107
styles.toolbarContentSection,
108+
formatBreakpointMods(rowWrap, styles, '', getBreakpoint(width)),
98109
alignItems === 'center' && styles.modifiers.alignItemsCenter,
99110
alignItems === 'start' && styles.modifiers.alignItemsStart,
100111
alignItems === 'baseline' && styles.modifiers.alignItemsBaseline

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ export interface ToolbarGroupProps extends Omit<React.HTMLProps<HTMLDivElement>,
157157
| 'rowGap_3xl'
158158
| 'rowGap_4xl';
159159
};
160+
/** Value to set for row wrapping at various breakpoints */
161+
rowWrap?: {
162+
default?: 'wrap' | 'nowrap';
163+
sm?: 'wrap' | 'nowrap';
164+
md?: 'wrap' | 'nowrap';
165+
lg?: 'wrap' | 'nowrap';
166+
xl?: 'wrap' | 'nowrap';
167+
'2xl'?: 'wrap' | 'nowrap';
168+
};
160169
/** Content to be rendered inside the data toolbar group */
161170
children?: React.ReactNode;
162171
/** Flag that modifies the toolbar group to hide overflow and respond to available space. Used for horizontal navigation. */
@@ -175,6 +184,7 @@ class ToolbarGroupWithRef extends Component<ToolbarGroupProps> {
175184
gap,
176185
columnGap,
177186
rowGap,
187+
rowWrap,
178188
className,
179189
variant,
180190
children,
@@ -203,6 +213,7 @@ class ToolbarGroupWithRef extends Component<ToolbarGroupProps> {
203213
formatBreakpointMods(gap, styles, '', getBreakpoint(width)),
204214
formatBreakpointMods(columnGap, styles, '', getBreakpoint(width)),
205215
formatBreakpointMods(rowGap, styles, '', getBreakpoint(width)),
216+
formatBreakpointMods(rowWrap, styles, '', getBreakpoint(width)),
206217
alignItems === 'start' && styles.modifiers.alignItemsStart,
207218
alignItems === 'center' && styles.modifiers.alignItemsCenter,
208219
alignItems === 'baseline' && styles.modifiers.alignItemsBaseline,

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,15 @@ export interface ToolbarItemProps extends React.HTMLProps<HTMLDivElement> {
151151
| 'rowGap_3xl'
152152
| 'rowGap_4xl';
153153
};
154+
/** Value to set for row wrapping at various breakpoints */
155+
rowWrap?: {
156+
default?: 'wrap' | 'nowrap';
157+
sm?: 'wrap' | 'nowrap';
158+
md?: 'wrap' | 'nowrap';
159+
lg?: 'wrap' | 'nowrap';
160+
xl?: 'wrap' | 'nowrap';
161+
'2xl'?: 'wrap' | 'nowrap';
162+
};
154163
/** id for this data toolbar item */
155164
id?: string;
156165
/** Flag indicating if the expand-all variant is expanded or not */
@@ -168,6 +177,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
168177
gap,
169178
columnGap,
170179
rowGap,
180+
rowWrap,
171181
align,
172182
alignSelf,
173183
alignItems,
@@ -196,6 +206,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
196206
formatBreakpointMods(gap, styles, '', getBreakpoint(width)),
197207
formatBreakpointMods(columnGap, styles, '', getBreakpoint(width)),
198208
formatBreakpointMods(rowGap, styles, '', getBreakpoint(width)),
209+
formatBreakpointMods(rowWrap, styles, '', getBreakpoint(width)),
199210
alignItems === 'start' && styles.modifiers.alignItemsStart,
200211
alignItems === 'center' && styles.modifiers.alignItemsCenter,
201212
alignItems === 'baseline' && styles.modifiers.alignItemsBaseline,

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,33 @@ describe('Toolbar', () => {
147147

148148
expect(screen.getByTestId('Toolbar-test-secondary-id')).toHaveClass(styles.modifiers.secondary);
149149
});
150+
151+
describe('ToobarContent rowWrap', () => {
152+
const bps = ['default', 'sm', 'md', 'lg', 'xl', '2xl'];
153+
154+
describe.each(bps)(`rowWrap at various breakpoints`, (bp) => {
155+
it(`should render with pf-m-wrap when rowWrap is set to wrap at ${bp}`, () => {
156+
render(
157+
<Toolbar>
158+
<ToolbarContent data-testid="toolbarconent" rowWrap={{ [bp]: 'wrap' }}>
159+
Test
160+
</ToolbarContent>
161+
</Toolbar>
162+
);
163+
const bpWrapClass = bp === 'default' ? 'pf-m-wrap' : `pf-m-wrap-on-${bp}`;
164+
165+
expect(screen.getByTestId('toolbarconent').querySelector('div')).toHaveClass(bpWrapClass);
166+
});
167+
168+
it(`should render with pf-m-nowrap when rowWrap is set to nowrap at ${bp}`, () => {
169+
render(
170+
<ToolbarContent data-testid="toolbarconent" rowWrap={{ [bp]: 'nowrap' }}>
171+
Test
172+
</ToolbarContent>
173+
);
174+
const bpNoWrapClass = bp === 'default' ? 'pf-m-nowrap' : `pf-m-nowrap-on-${bp}`;
175+
expect(screen.getByTestId('toolbarconent').querySelector('div')).toHaveClass(bpNoWrapClass);
176+
});
177+
});
178+
});
150179
});
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { render, screen } from '@testing-library/react';
22
import { ToolbarGroup } from '../ToolbarGroup';
33

4-
describe('ToolbarItem', () => {
4+
describe('ToolbarGroup', () => {
55
it('should render with pf-m-overflow-container when isOverflowContainer is set', () => {
66
render(
77
<ToolbarGroup data-testid="toolbargroup" isOverflowContainer>
@@ -10,4 +10,31 @@ describe('ToolbarItem', () => {
1010
);
1111
expect(screen.getByTestId('toolbargroup')).toHaveClass('pf-m-overflow-container');
1212
});
13+
14+
describe('ToobarGroup rowWrap', () => {
15+
const bps = ['default', 'sm', 'md', 'lg', 'xl', '2xl'];
16+
17+
describe.each(bps)(`rowWrap at various breakpoints`, (bp) => {
18+
it(`should render with pf-m-wrap when rowWrap is set to wrap at ${bp}`, () => {
19+
render(
20+
<ToolbarGroup data-testid="toolbargroup" rowWrap={{ [bp]: 'wrap' }}>
21+
Test
22+
</ToolbarGroup>
23+
);
24+
const bpWrapClass = bp === 'default' ? 'pf-m-wrap' : `pf-m-wrap-on-${bp}`;
25+
26+
expect(screen.getByTestId('toolbargroup')).toHaveClass(bpWrapClass);
27+
});
28+
29+
it(`should render with pf-m-nowrap when rowWrap is set to nowrap at ${bp}`, () => {
30+
render(
31+
<ToolbarGroup data-testid="toolbargroup" rowWrap={{ [bp]: 'nowrap' }}>
32+
Test
33+
</ToolbarGroup>
34+
);
35+
const bpNoWrapClass = bp === 'default' ? 'pf-m-nowrap' : `pf-m-nowrap-on-${bp}`;
36+
expect(screen.getByTestId('toolbargroup')).toHaveClass(bpNoWrapClass);
37+
});
38+
});
39+
});
1340
});

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,31 @@ describe('ToolbarItem', () => {
1010
);
1111
expect(screen.getByTestId('toolbaritem')).toHaveClass('pf-m-overflow-container');
1212
});
13+
14+
describe('ToobarItem rowWrap', () => {
15+
const bps = ['default', 'sm', 'md', 'lg', 'xl', '2xl'];
16+
17+
describe.each(bps)(`rowWrap at various breakpoints`, (bp) => {
18+
it(`should render with pf-m-wrap when rowWrap is set to wrap at ${bp}`, () => {
19+
render(
20+
<ToolbarItem data-testid="toolbaritem" rowWrap={{ [bp]: 'wrap' }}>
21+
Test
22+
</ToolbarItem>
23+
);
24+
const bpWrapClass = bp === 'default' ? 'pf-m-wrap' : `pf-m-wrap-on-${bp}`;
25+
26+
expect(screen.getByTestId('toolbaritem')).toHaveClass(bpWrapClass);
27+
});
28+
29+
it(`should render with pf-m-nowrap when rowWrap is set to nowrap at ${bp}`, () => {
30+
render(
31+
<ToolbarItem data-testid="toolbaritem" rowWrap={{ [bp]: 'nowrap' }}>
32+
Test
33+
</ToolbarItem>
34+
);
35+
const bpNoWrapClass = bp === 'default' ? 'pf-m-nowrap' : `pf-m-nowrap-on-${bp}`;
36+
expect(screen.getByTestId('toolbaritem')).toHaveClass(bpNoWrapClass);
37+
});
38+
});
39+
});
1340
});

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,18 @@ When all of a toolbar's required elements cannot fit in a single line, you can s
113113

114114
```
115115

116-
## Examples with toolbar spacers
116+
## Examples with spacers and wrapping
117117
You may adjust the space between toolbar items to arrange them into groups. Read our spacers documentation to learn more about using spacers.
118118

119119
Items are spaced “16px” apart by default and can be modified by changing their or their parents' `gap`, `columnGap`, and `rowGap` properties. You can set the property values at multiple breakpoints, including "default", "md", "lg", "xl", and "2xl".
120120

121+
### Toolbar content wrapping
122+
The toolbar content section will wrap by default, but you can set the `rowRap` property to `noWrap` to make it not wrap.
123+
124+
```ts file="./ToolbarContentWrap.tsx"
125+
126+
```
127+
121128
### Toolbar group spacers
122129

123130
```ts file="./ToolbarGroupSpacers.tsx"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Fragment } from 'react';
2+
import { Toolbar, ToolbarItem, ToolbarContent } from '@patternfly/react-core';
3+
import { Button, SearchInput } from '@patternfly/react-core';
4+
5+
export const ToolbarItems: React.FunctionComponent = () => {
6+
const items = (
7+
<Fragment>
8+
<ToolbarItem>
9+
<SearchInput aria-label="Items example search input" />
10+
</ToolbarItem>
11+
<ToolbarItem>
12+
<Button variant="secondary">Action</Button>
13+
</ToolbarItem>
14+
<ToolbarItem>
15+
<Button variant="secondary">Action</Button>
16+
</ToolbarItem>
17+
<ToolbarItem>
18+
<Button variant="secondary">Action</Button>
19+
</ToolbarItem>
20+
<ToolbarItem>
21+
<Button variant="secondary">Action</Button>
22+
</ToolbarItem>
23+
<ToolbarItem variant="separator" />
24+
<ToolbarItem>
25+
<Button variant="primary">Action</Button>
26+
</ToolbarItem>
27+
</Fragment>
28+
);
29+
30+
return (
31+
<Toolbar id="toolbar-items-example">
32+
<ToolbarContent rowWrap={{ default: 'nowrap' }}>{items}</ToolbarContent>
33+
</Toolbar>
34+
);
35+
};

packages/react-core/src/components/Toolbar/examples/ToolbarGroupSpacers.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const ToolbarGroupSpacers: React.FunctionComponent = () => {
7676

7777
const groupRowGapItems = (
7878
<Fragment>
79-
<ToolbarGroup className="pf-m-wrap" rowGap={{ default: 'rowGapNone' }}>
79+
<ToolbarGroup rowGap={{ default: 'rowGapNone' }} rowWrap={{ default: 'wrap' }}>
8080
<ToolbarItem>
8181
<Button variant="secondary">No Row Gap</Button>
8282
</ToolbarItem>
@@ -103,7 +103,7 @@ export const ToolbarGroupSpacers: React.FunctionComponent = () => {
103103
</ToolbarItem>
104104
<ToolbarItem variant="separator"></ToolbarItem>
105105
</ToolbarGroup>
106-
<ToolbarGroup className="pf-m-wrap" rowGap={{ default: 'rowGapSm' }}>
106+
<ToolbarGroup rowGap={{ default: 'rowGapSm' }} rowWrap={{ default: 'wrap' }}>
107107
<ToolbarItem>
108108
<Button variant="secondary">Small Row Gap</Button>
109109
</ToolbarItem>
@@ -130,7 +130,7 @@ export const ToolbarGroupSpacers: React.FunctionComponent = () => {
130130
</ToolbarItem>
131131
<ToolbarItem variant="separator"></ToolbarItem>
132132
</ToolbarGroup>
133-
<ToolbarGroup className="pf-m-wrap" rowGap={{ default: 'rowGapXl' }}>
133+
<ToolbarGroup rowGap={{ default: 'rowGapXl' }} rowWrap={{ default: 'wrap' }}>
134134
<ToolbarItem>
135135
<Button variant="secondary">Extra Large Row Gap</Button>
136136
</ToolbarItem>

packages/react-core/src/components/Toolbar/examples/ToolbarItemSpacers.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Button } from '@patternfly/react-core';
55
export const ToolbarItemSpacers: React.FunctionComponent = () => {
66
const itemGapItems = (
77
<Fragment>
8-
<ToolbarGroup className="pf-m-wrap">
8+
<ToolbarGroup rowWrap={{ default: 'wrap' }}>
99
<ToolbarItem gap={{ default: 'gapNone' }}>
1010
<Button variant="secondary">No Gap</Button>
1111
<Button variant="secondary">No Gap</Button>
@@ -26,7 +26,7 @@ export const ToolbarItemSpacers: React.FunctionComponent = () => {
2626

2727
const itemColumnGapItems = (
2828
<Fragment>
29-
<ToolbarGroup className="pf-m-wrap">
29+
<ToolbarGroup rowWrap={{ default: 'wrap' }}>
3030
<ToolbarItem columnGap={{ default: 'columnGapNone' }}>
3131
<Button variant="secondary">No Column Gap</Button>
3232
<Button variant="secondary">No Column Gap</Button>
@@ -48,17 +48,17 @@ export const ToolbarItemSpacers: React.FunctionComponent = () => {
4848
const itemRowGapItems = (
4949
<Fragment>
5050
<ToolbarGroup>
51-
<ToolbarItem className="pf-m-wrap" rowGap={{ default: 'rowGapNone' }}>
51+
<ToolbarItem rowGap={{ default: 'rowGapNone' }} rowWrap={{ default: 'wrap' }}>
5252
<Button variant="secondary">No Row Gap</Button>
5353
<Button variant="secondary">No Row Gap</Button>
5454
</ToolbarItem>
5555
<ToolbarItem variant="separator"></ToolbarItem>
56-
<ToolbarItem className="pf-m-wrap" rowGap={{ default: 'rowGapSm' }}>
56+
<ToolbarItem rowGap={{ default: 'rowGapSm' }} rowWrap={{ default: 'wrap' }}>
5757
<Button variant="secondary">Small Row Gap</Button>
5858
<Button variant="secondary">Small Row Gap</Button>
5959
</ToolbarItem>
6060
<ToolbarItem variant="separator"></ToolbarItem>
61-
<ToolbarItem className="pf-m-wrap" rowGap={{ default: 'rowGapXl' }}>
61+
<ToolbarItem rowGap={{ default: 'rowGapXl' }} rowWrap={{ default: 'wrap' }}>
6262
<Button variant="secondary">Extra Large Row Gap</Button>
6363
<Button variant="secondary">Extra Large Row Gap</Button>
6464
</ToolbarItem>

0 commit comments

Comments
 (0)