Skip to content

Commit 8210573

Browse files
authored
Stack: Add shrink prop to Stack.Item (#6260)
1 parent 44e80f1 commit 8210573

File tree

7 files changed

+121
-45
lines changed

7 files changed

+121
-45
lines changed

.changeset/good-bars-see.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
Stack.Item: add support for `shrink` prop

packages/react/src/Stack/Stack.docs.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
"type": "boolean | ResponsiveValue<boolean>",
5151
"description": "Allow item to keep size or expand to fill the available space."
5252
},
53+
{
54+
"name": "shrink",
55+
"type": "boolean | ResponsiveValue<boolean>",
56+
"description": "Allow item to keep size or shrink to fit the available space."
57+
},
5358
{
5459
"name": "className",
5560
"type": "string"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type {Meta} from '@storybook/react-vite'
2+
import {Stack} from '../Stack'
3+
import {ShieldLockIcon} from '@primer/octicons-react'
4+
5+
export default {
6+
title: 'Components/Stack/Features',
7+
component: Stack,
8+
} as Meta<typeof Stack>
9+
10+
export const ShrinkingStackItems = () => (
11+
<div style={{maxWidth: '200px', padding: 'var(--base-size-8)'}}>
12+
<Stack direction="horizontal" gap="condensed">
13+
<Stack.Item shrink={false}>
14+
<ShieldLockIcon size="small" />
15+
</Stack.Item>
16+
<Stack.Item>This stack has the leading icon set to prevent shrinking</Stack.Item>
17+
</Stack>
18+
<Stack direction="horizontal" gap="condensed">
19+
<Stack.Item shrink={true}>
20+
<ShieldLockIcon size="small" />
21+
</Stack.Item>
22+
<Stack.Item>This stack item does not have the icon set to prevent shrinking</Stack.Item>
23+
</Stack>
24+
</div>
25+
)

packages/react/src/Stack/Stack.module.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,11 @@
296296
flex: 0 1 auto;
297297
min-inline-size: 0;
298298

299+
&[data-shrink='false'],
300+
&[data-shrink-narrow='false'] {
301+
flex-shrink: 0;
302+
}
303+
299304
&[data-grow='true'],
300305
&[data-grow-narrow='true'] {
301306
flex-grow: 1;
@@ -309,6 +314,14 @@
309314
&[data-grow-regular='false'] {
310315
flex-grow: 0;
311316
}
317+
318+
&[data-shrink-regular='true'] {
319+
flex-shrink: 1;
320+
}
321+
322+
&[data-shrink-regular='false'] {
323+
flex-shrink: 0;
324+
}
312325
}
313326

314327
@media (--viewportRange-wide) {
@@ -319,5 +332,13 @@
319332
&[data-grow-wide='false'] {
320333
flex-grow: 0;
321334
}
335+
336+
&[data-shrink-wide='true'] {
337+
flex-shrink: 1;
338+
}
339+
340+
&[data-shrink-wide='false'] {
341+
flex-shrink: 0;
342+
}
322343
}
323344
}

packages/react/src/Stack/Stack.stories.tsx

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {Meta, StoryObj} from '@storybook/react-vite'
22
import {Stack} from '../Stack'
33
import type {ResponsiveValue} from '../hooks/useResponsiveValue'
4+
import type {InputType} from '@storybook/csf'
45

56
type Story = StoryObj<typeof Stack>
67

@@ -468,58 +469,42 @@ export const Playground: Story = {
468469
},
469470
}
470471

472+
function createArgMetaData(category: string): InputType {
473+
return {
474+
control: {
475+
type: 'boolean',
476+
},
477+
table: {
478+
category,
479+
defaultValue: {
480+
summary: 'true',
481+
},
482+
},
483+
}
484+
}
485+
471486
export const StackItemPlayground: Story = {
472487
args: {
473488
grow: true,
474489
growNarrow: true,
475490
growRegular: true,
476491
growWide: true,
492+
493+
shrink: true,
494+
shrinkNarrow: true,
495+
shrinkRegular: true,
496+
shrinkWide: true,
477497
},
478498
argTypes: {
479-
grow: {
480-
control: {
481-
type: 'boolean',
482-
},
483-
table: {
484-
category: 'Properties',
485-
defaultValue: {
486-
summary: 'true',
487-
},
488-
},
489-
},
490-
growNarrow: {
491-
control: {
492-
type: 'boolean',
493-
},
494-
table: {
495-
category: 'Narrow properties',
496-
defaultValue: {
497-
summary: 'true',
498-
},
499-
},
500-
},
501-
growRegular: {
502-
control: {
503-
type: 'boolean',
504-
},
505-
table: {
506-
category: 'Regular properties',
507-
defaultValue: {
508-
summary: 'true',
509-
},
510-
},
511-
},
512-
growWide: {
513-
control: {
514-
type: 'boolean',
515-
},
516-
table: {
517-
category: 'Wide properties',
518-
defaultValue: {
519-
summary: 'true',
520-
},
521-
},
522-
},
499+
grow: createArgMetaData('Properties'),
500+
growNarrow: createArgMetaData('Narrow properties'),
501+
growRegular: createArgMetaData('Regular properties'),
502+
growWide: createArgMetaData('Wide properties'),
503+
504+
shrink: createArgMetaData('Properties'),
505+
shrinkNarrow: createArgMetaData('Narrow properties'),
506+
shrinkRegular: createArgMetaData('Regular properties'),
507+
shrinkWide: createArgMetaData('Wide properties'),
523508
},
524509
render: args => {
525510
return (
@@ -530,6 +515,11 @@ export const StackItemPlayground: Story = {
530515
regular: args.growRegular,
531516
wide: args.growWide,
532517
})}
518+
shrink={getControlValues(args.shrink, {
519+
narrow: args.shrinkNarrow,
520+
regular: args.shrinkRegular,
521+
wide: args.shrinkWide,
522+
})}
533523
>
534524
<div
535525
style={{

packages/react/src/Stack/Stack.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,25 @@ type StackItemProps<As> = React.PropsWithChildren<{
114114
* @default false
115115
*/
116116
grow?: boolean | ResponsiveValue<boolean>
117+
118+
/**
119+
* Allow item to keep size or expand to fill the available space
120+
* @default true
121+
*/
122+
shrink?: boolean | ResponsiveValue<boolean>
123+
117124
className?: string
118125
}>
119126

120-
const StackItem = forwardRef(({as, children, grow, className, ...rest}, forwardedRef) => {
127+
const StackItem = forwardRef(({as, children, grow, shrink, className, ...rest}, forwardedRef) => {
121128
return (
122129
<BoxWithFallback
123130
as={as}
124131
ref={forwardedRef}
125132
{...rest}
126133
className={clsx(className, classes.StackItem)}
127134
{...getResponsiveAttributes('grow', grow)}
135+
{...getResponsiveAttributes('shrink', shrink)}
128136
>
129137
{children}
130138
</BoxWithFallback>

packages/react/src/Stack/__tests__/StackItem.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,28 @@ describe('StackItem', () => {
4646
expect(screen.getByTestId('responsive-grow')).toHaveAttribute('data-grow-wide', 'true')
4747
})
4848

49+
it('should support the `shrink` prop', () => {
50+
render(
51+
<Stack>
52+
<StackItem data-testid="shrink-true" shrink={true} />
53+
<StackItem data-testid="shrink-false" />
54+
</Stack>,
55+
)
56+
expect(screen.getByTestId('shrink-true')).toHaveAttribute('data-shrink', 'true')
57+
expect(screen.getByTestId('shrink-false')).not.toHaveAttribute('data-shrink', 'false')
58+
})
59+
60+
it('should support responsive `shrink` values', () => {
61+
render(
62+
<Stack>
63+
<StackItem data-testid="responsive-shrink" shrink={{narrow: true, regular: false, wide: true}} />
64+
</Stack>,
65+
)
66+
expect(screen.getByTestId('responsive-shrink')).toHaveAttribute('data-shrink-narrow', 'true')
67+
expect(screen.getByTestId('responsive-shrink')).toHaveAttribute('data-shrink-regular', 'false')
68+
expect(screen.getByTestId('responsive-shrink')).toHaveAttribute('data-shrink-wide', 'true')
69+
})
70+
4971
it('should render a custom component with the `as` prop', () => {
5072
const CustomComponent = vi.fn(({children}: React.PropsWithChildren) => {
5173
return <div data-testid="custom-stack-item">{children}</div>

0 commit comments

Comments
 (0)