Skip to content

Commit eab34e2

Browse files
docs(motion): motion component Storybook improvements (#35866)
Co-authored-by: Oleksandr Fediashov <olfedias@microsoft.com>
1 parent 11229e4 commit eab34e2

31 files changed

Lines changed: 600 additions & 216 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from 'react';
2+
import type { JSXElement } from '@fluentui/react-components';
3+
import { makeStyles, tokens, type PresenceComponentProps } from '@fluentui/react-components';
4+
import { Blur, type BlurParams } from '@fluentui/react-motion-components-preview';
5+
6+
const useClasses = makeStyles({
7+
wrapper: {
8+
padding: tokens.spacingVerticalXL,
9+
},
10+
});
11+
12+
const LoremIpsum = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>((props, ref) => (
13+
<div ref={ref} {...props}>
14+
{'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. '.repeat(
15+
10,
16+
)}
17+
</div>
18+
));
19+
20+
export const DefaultBlur = (props: PresenceComponentProps & BlurParams): JSXElement => {
21+
const classes = useClasses();
22+
return (
23+
<div className={classes.wrapper}>
24+
<Blur {...props}>
25+
<LoremIpsum />
26+
</Blur>
27+
</div>
28+
);
29+
};
Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,36 @@
11
import * as React from 'react';
22
import type { JSXElement } from '@fluentui/react-components';
3-
import { Field, makeStyles, tokens, Switch } from '@fluentui/react-components';
3+
import { Card, CardHeader, Field, makeStyles, tokens, Switch, Text } from '@fluentui/react-components';
44
import { Blur } from '@fluentui/react-motion-components-preview';
55

66
const useClasses = makeStyles({
77
container: {
88
display: 'grid',
9-
gridTemplateColumns: 'minmax(200px, 1fr) 2fr',
10-
gridTemplateAreas: '"controls content"',
11-
gap: '20px',
12-
padding: '20px',
13-
},
14-
content: {
15-
gridArea: 'content',
16-
display: 'flex',
17-
alignItems: 'center',
18-
justifyContent: 'center',
9+
gridTemplate: `"controls ." "card card" / 1fr 1fr`,
10+
gap: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalMNudge}`,
1911
},
2012
card: {
21-
padding: '20px',
22-
border: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStroke1}`,
23-
borderRadius: tokens.borderRadiusMedium,
24-
backgroundColor: tokens.colorNeutralBackground1,
25-
maxWidth: '400px',
13+
gridArea: 'card',
14+
padding: tokens.spacingVerticalXL,
15+
maxHeight: '300px',
16+
overflow: 'hidden',
2617
},
2718
controls: {
28-
gridArea: 'controls',
2919
display: 'flex',
3020
flexDirection: 'column',
21+
gridArea: 'controls',
22+
23+
border: `${tokens.strokeWidthThicker} solid ${tokens.colorNeutralForeground3}`,
3124
borderRadius: tokens.borderRadiusMedium,
3225
boxShadow: tokens.shadow16,
33-
padding: '20px',
26+
padding: tokens.spacingVerticalMNudge,
3427
},
3528
field: {
3629
flex: 1,
3730
},
31+
cardHeaderText: {
32+
margin: 0,
33+
},
3834
});
3935

4036
const LoremIpsum = () => (
@@ -57,13 +53,18 @@ export const Default = (): JSXElement => {
5753
</Field>
5854
</div>
5955

60-
<div className={classes.content}>
61-
<Blur visible={visible}>
62-
<div className={classes.card}>
63-
<LoremIpsum />
64-
</div>
65-
</Blur>
66-
</div>
56+
<Blur visible={visible}>
57+
<Card className={classes.card}>
58+
<CardHeader
59+
header={
60+
<Text as="h3" className={classes.cardHeaderText} weight="semibold">
61+
Lorem Ipsum
62+
</Text>
63+
}
64+
/>
65+
<LoremIpsum />
66+
</Card>
67+
</Blur>
6768
</div>
6869
);
6970
};
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
Compare different `outRadius` values to control the spread of the blur effect.
1+
The `Blur` component accepts two radius props:
2+
3+
- **`outRadius`** — blur amount when the element is hidden
4+
- **`inRadius`** — blur amount when the element is visible (defaults to `0px`)
5+
6+
Each card shows a different combination. The active radius value is **bolded** in the header. `animateOpacity` is disabled to isolate the blur effect.

packages/react-components/react-motion-components-preview/stories/src/Blur/BlurRadius.stories.tsx

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,61 @@
11
import * as React from 'react';
22
import type { JSXElement } from '@fluentui/react-components';
3-
import { makeStyles, tokens, Button } from '@fluentui/react-components';
3+
import {
4+
Button,
5+
Card,
6+
CardFooter,
7+
Table,
8+
TableBody,
9+
TableCell,
10+
TableHeader,
11+
TableHeaderCell,
12+
TableRow,
13+
makeStyles,
14+
tokens,
15+
} from '@fluentui/react-components';
416
import { Blur } from '@fluentui/react-motion-components-preview';
517
import BlurRadiusDescription from './BlurRadius.stories.md';
618

719
const useClasses = makeStyles({
820
container: {
921
display: 'grid',
10-
gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
11-
gap: '20px',
12-
padding: '20px',
22+
gridTemplateColumns: '1fr 1fr',
23+
gap: tokens.spacingVerticalXXXL,
24+
padding: tokens.spacingVerticalMNudge,
1325
},
14-
example: {
26+
card: {
1527
display: 'flex',
1628
flexDirection: 'column',
29+
justifyContent: 'center',
1730
alignItems: 'center',
18-
gap: '10px',
31+
padding: tokens.spacingVerticalXL,
32+
gap: tokens.spacingVerticalM,
1933
},
20-
card: {
21-
width: '200px',
22-
height: '150px',
23-
padding: '20px',
24-
border: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStroke1}`,
25-
borderRadius: tokens.borderRadiusMedium,
26-
backgroundColor: tokens.colorNeutralBackground1,
27-
display: 'flex',
28-
alignItems: 'center',
29-
justifyContent: 'center',
30-
fontSize: tokens.fontSizeBase300,
31-
textAlign: 'center',
34+
cellNormal: {
35+
fontWeight: tokens.fontWeightRegular,
36+
},
37+
cellBold: {
38+
fontWeight: tokens.fontWeightBold,
3239
},
3340
controls: {
3441
display: 'flex',
35-
gap: '10px',
36-
marginBottom: '20px',
42+
justifyContent: 'center',
43+
marginTop: tokens.spacingVerticalXL,
3744
},
3845
});
3946

40-
const blurRadiusOptions = [
41-
{ label: 'Small (5px)', value: '5px' },
42-
{ label: 'Medium (20px)', value: '20px' },
43-
{ label: 'Large (50px)', value: '50px' },
44-
{ label: 'Extra Large (100px)', value: '100px' },
47+
const blurRadiusCombinations = [
48+
// Top row: outRadius 5px, inRadius 0px (default)
49+
{ outRadius: '5px', inRadius: '0px' },
50+
{ outRadius: '10px', inRadius: '0px' },
51+
// Bottom row: outRadius 20px, with inRadius values
52+
{ outRadius: '10px', inRadius: '1px' },
53+
{ outRadius: '10px', inRadius: '2px' },
4554
];
4655

4756
export const Radius = (): JSXElement => {
4857
const classes = useClasses();
49-
const [visibleStates, setVisibleStates] = React.useState<boolean[]>(blurRadiusOptions.map(() => true));
58+
const [visibleStates, setVisibleStates] = React.useState<boolean[]>(() => blurRadiusCombinations.map(() => true));
5059

5160
const toggleAll = () => {
5261
setVisibleStates(prev => prev.map(state => !state));
@@ -58,26 +67,46 @@ export const Radius = (): JSXElement => {
5867

5968
return (
6069
<>
61-
<div className={classes.controls}>
62-
<Button onClick={toggleAll}>Toggle All</Button>
70+
<div className={classes.container}>
71+
{blurRadiusCombinations.map((option, index) => {
72+
const isVisible = visibleStates[index];
73+
return (
74+
<Card key={index} className={classes.card}>
75+
<Table size="small" noNativeElements aria-label="Blur radius values">
76+
<TableHeader>
77+
<TableRow>
78+
<TableHeaderCell>outRadius</TableHeaderCell>
79+
<TableHeaderCell>inRadius</TableHeaderCell>
80+
</TableRow>
81+
</TableHeader>
82+
<TableBody>
83+
<TableRow>
84+
<TableCell className={isVisible ? classes.cellNormal : classes.cellBold}>
85+
{option.outRadius}
86+
</TableCell>
87+
<TableCell className={isVisible ? classes.cellBold : classes.cellNormal}>
88+
{option.inRadius}
89+
</TableCell>
90+
</TableRow>
91+
</TableBody>
92+
</Table>
93+
<Blur visible={isVisible} outRadius={option.outRadius} inRadius={option.inRadius} animateOpacity={false}>
94+
<div>Lorem ipsum dolor sit amet</div>
95+
</Blur>
96+
<CardFooter>
97+
<Button appearance="primary" onClick={() => toggleSingle(index)}>
98+
{isVisible ? 'Hide' : 'Show'}
99+
</Button>
100+
</CardFooter>
101+
</Card>
102+
);
103+
})}
63104
</div>
64105

65-
<div className={classes.container}>
66-
{blurRadiusOptions.map((option, index) => (
67-
<div key={option.value} className={classes.example}>
68-
<h4>{option.label}</h4>
69-
<Button onClick={() => toggleSingle(index)}>{visibleStates[index] ? 'Hide' : 'Show'}</Button>
70-
<Blur visible={visibleStates[index]} outRadius={option.value}>
71-
<div className={classes.card}>
72-
<div>
73-
Blur radius: {option.value}
74-
<br />
75-
Sample content with various text and elements.
76-
</div>
77-
</div>
78-
</Blur>
79-
</div>
80-
))}
106+
<div className={classes.controls}>
107+
<Button appearance="secondary" onClick={toggleAll}>
108+
Toggle All
109+
</Button>
81110
</div>
82111
</>
83112
);

packages/react-components/react-motion-components-preview/stories/src/Blur/index.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Blur } from '@fluentui/react-motion-components-preview';
1+
import { DefaultBlur as Blur } from './Blur.stories';
22
import BlurDescription from './BlurDescription.md';
33

44
export { Default } from './BlurDefault.stories';
Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import * as React from 'react';
22
import type { JSXElement } from '@fluentui/react-components';
3-
import type { PresenceComponentProps } from '@fluentui/react-components';
4-
import { Collapse } from '@fluentui/react-motion-components-preview';
3+
import { makeStyles, tokens, type PresenceComponentProps } from '@fluentui/react-components';
4+
import { Collapse, type CollapseParams } from '@fluentui/react-motion-components-preview';
5+
6+
const useClasses = makeStyles({
7+
wrapper: {
8+
padding: tokens.spacingVerticalXL,
9+
},
10+
});
511

612
const LoremIpsum = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>((props, ref) => (
713
<div ref={ref} {...props}>
@@ -11,10 +17,13 @@ const LoremIpsum = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivEleme
1117
</div>
1218
));
1319

14-
export const DefaultCollapse = (props: PresenceComponentProps): JSXElement => {
20+
export const DefaultCollapse = (props: PresenceComponentProps & CollapseParams): JSXElement => {
21+
const classes = useClasses();
1522
return (
16-
<Collapse {...props}>
17-
<LoremIpsum />
18-
</Collapse>
23+
<div className={classes.wrapper}>
24+
<Collapse {...props}>
25+
<LoremIpsum />
26+
</Collapse>
27+
</div>
1928
);
2029
};

packages/react-components/react-motion-components-preview/stories/src/Collapse/CollapseCustomization.stories.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import * as React from 'react';
22
import type { JSXElement } from '@fluentui/react-components';
33
import {
4+
Card,
5+
CardHeader,
46
createPresenceComponentVariant,
57
Field,
68
makeStyles,
@@ -9,6 +11,7 @@ import {
911
motionTokens,
1012
Slider,
1113
Switch,
14+
Text,
1215
tokens,
1316
} from '@fluentui/react-components';
1417
import { Collapse } from '@fluentui/react-motion-components-preview';
@@ -19,11 +22,18 @@ const useClasses = makeStyles({
1922
container: {
2023
display: 'grid',
2124
gridTemplate: `"controls ." "card card" / 1fr 1fr`,
22-
gap: '20px 10px',
25+
gap: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalMNudge}`,
2326
},
2427
card: {
2528
gridArea: 'card',
26-
padding: '10px',
29+
padding: tokens.spacingVerticalXL,
30+
},
31+
cardContent: {
32+
maxHeight: '300px',
33+
overflow: 'hidden',
34+
},
35+
cardHeaderText: {
36+
margin: 0,
2737
},
2838
controls: {
2939
display: 'flex',
@@ -33,7 +43,7 @@ const useClasses = makeStyles({
3343
border: `${tokens.strokeWidthThicker} solid ${tokens.colorNeutralForeground3}`,
3444
borderRadius: tokens.borderRadiusMedium,
3545
boxShadow: tokens.shadow16,
36-
padding: '10px',
46+
padding: tokens.spacingVerticalMNudge,
3747
},
3848
field: {
3949
flex: 1,
@@ -135,9 +145,19 @@ export const Customization = (): JSXElement => {
135145
visible={visible}
136146
unmountOnExit={unmountOnExit}
137147
>
138-
<div className={classes.card}>
139-
<LoremIpsum />
140-
</div>
148+
<Card className={classes.card}>
149+
<CardHeader
150+
header={
151+
<Text as="h3" className={classes.cardHeaderText} weight="semibold">
152+
Lorem Ipsum
153+
</Text>
154+
}
155+
/>
156+
{/* Wrapper div needed because Collapse controls maxHeight on its child to animate height */}
157+
<div className={classes.cardContent}>
158+
<LoremIpsum />
159+
</div>
160+
</Card>
141161
</CustomCollapseVariant>
142162
</div>
143163
);

0 commit comments

Comments
 (0)