Skip to content

Commit

Permalink
docs(react-motions): rework docs (#29860)
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter authored Nov 22, 2023
1 parent 81bc562 commit 4c1cd4b
Show file tree
Hide file tree
Showing 15 changed files with 422 additions and 22 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
By default, the child component will be animated when it first mounts. A motion can be paused by setting the `playState` prop to `"paused"`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { makeStyles, shorthands, tokens, Label, Slider, useId, Checkbox } from '@fluentui/react-components';
import { atoms, createAtom } from '@fluentui/react-motions-preview';
import * as React from 'react';

import description from './TransitionUnmountOnExit.stories.md';

const useClasses = makeStyles({
container: {
display: 'grid',
gridTemplateColumns: '1fr',
...shorthands.gap('10px'),
},
card: {
display: 'flex',
flexDirection: 'column',

...shorthands.border('3px', 'solid', tokens.colorNeutralForeground3),
...shorthands.borderRadius(tokens.borderRadiusMedium),
...shorthands.padding('10px'),

alignItems: 'center',
},
item: {
backgroundColor: tokens.colorBrandBackground,
...shorthands.borderRadius('50%'),

width: '100px',
height: '100px',
},
description: {
...shorthands.margin('5px'),
},
controls: {
display: 'flex',
flexDirection: 'column',

marginTop: '20px',

...shorthands.border('3px', 'solid', tokens.colorNeutralForeground3),
...shorthands.borderRadius(tokens.borderRadiusMedium),
...shorthands.padding('10px'),
},
});

const FadeEnter = createAtom(atoms.fade.enterUltraSlow());

export const AtomPlayState = () => {
const classes = useClasses();
const sliderId = useId();

const elementRef = React.useRef<HTMLDivElement>(null);
const [playbackRate, setPlaybackRate] = React.useState<number>(30);
const [isRunning, setIsRunning] = React.useState<boolean>(false);

React.useEffect(() => {
elementRef.current?.getAnimations().forEach(animation => {
animation.playbackRate = playbackRate / 100;
});
}, [playbackRate, isRunning]);

return (
<>
<div className={classes.container}>
<div className={classes.card}>
<FadeEnter playState={isRunning ? 'running' : 'paused'} iterations={Infinity}>
<div className={classes.item} ref={elementRef} />
</FadeEnter>

<code className={classes.description}>fadeEnterSlow</code>
</div>
</div>

<div className={classes.controls}>
<div>
<Checkbox
label={isRunning ? '⏸️ Pause' : '▶️ Play'}
checked={isRunning}
onChange={() => setIsRunning(v => !v)}
/>
</div>
<div>
<Label htmlFor={sliderId}>
<code>playbackRate</code>: {playbackRate}%
</Label>
<Slider
aria-valuetext={`Value is ${playbackRate}%`}
value={playbackRate}
onChange={(ev, data) => setPlaybackRate(data.value)}
min={0}
id={sliderId}
max={100}
step={10}
/>
</div>
</div>
</>
);
};

AtomPlayState.parameters = {
docs: {
description: {
story: description,
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`createAtom()` is a factory function that creates a React component based on the provided atom definition. This component can be used to animate any element.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { makeStyles, shorthands, tokens, Label, Slider, useId } from '@fluentui/
import { atoms, createAtom } from '@fluentui/react-motions-preview';
import * as React from 'react';

import description from './CreateAtom.stories.md';

const useClasses = makeStyles({
container: {
display: 'grid',
Expand Down Expand Up @@ -57,17 +59,18 @@ export const CreateAtom = () => {
const classes = useClasses();
const sliderId = useId();

const containerRef = React.useRef<HTMLDivElement>(null);
const [playbackRate, setPlaybackRate] = React.useState<number>(30);

React.useEffect(() => {
document.getAnimations().forEach(animation => {
containerRef.current?.getAnimations({ subtree: true }).forEach(animation => {
animation.playbackRate = playbackRate / 100;
});
}, [playbackRate]);

return (
<>
<div className={classes.container}>
<div className={classes.container} ref={containerRef}>
<div className={classes.card}>
<FadeEnter iterations={Infinity}>
<div className={classes.item} />
Expand Down Expand Up @@ -103,3 +106,11 @@ export const CreateAtom = () => {
</>
);
};

CreateAtom.parameters = {
docs: {
description: {
story: description,
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`createTransition()` is a factory function that creates a React component based on the provided transition definition. This component can be used to animate any element and intended to have a state via the `visible` prop.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { makeStyles, shorthands, tokens, Label, Slider, useId, Checkbox } from '
import { createTransition, transitions } from '@fluentui/react-motions-preview';
import * as React from 'react';

import description from './CreateTransition.stories.md';

const useClasses = makeStyles({
container: {
display: 'grid',
Expand Down Expand Up @@ -46,11 +48,12 @@ export const CreateTransition = () => {
const classes = useClasses();
const sliderId = useId();

const elementRef = React.useRef<HTMLDivElement>(null);
const [playbackRate, setPlaybackRate] = React.useState<number>(30);
const [visible, setVisible] = React.useState<boolean>(false);

React.useEffect(() => {
document.getAnimations().forEach(animation => {
elementRef.current?.getAnimations().forEach(animation => {
animation.playbackRate = playbackRate / 100;
});
}, [playbackRate, visible]);
Expand All @@ -60,7 +63,7 @@ export const CreateTransition = () => {
<div className={classes.container}>
<div className={classes.card}>
<Fade visible={visible}>
<div className={classes.item} />
<div className={classes.item} ref={elementRef} />
</Fade>

<code className={classes.description}>fadeSlow</code>
Expand Down Expand Up @@ -89,3 +92,11 @@ export const CreateTransition = () => {
</>
);
};

CreateTransition.parameters = {
docs: {
description: {
story: description,
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { makeStyles, shorthands, tokens } from '@fluentui/react-components';
import { atoms, createAtom } from '@fluentui/react-motions-preview';
import * as React from 'react';

const useClasses = makeStyles({
container: {
display: 'flex',
},
card: {
...shorthands.border('3px', 'solid', tokens.colorNeutralForeground3),
...shorthands.borderRadius(tokens.borderRadiusMedium),

...shorthands.padding('20px'),
...shorthands.margin('20px'),
},
item: {
backgroundColor: tokens.colorBrandBackground,
...shorthands.borderRadius('50%'),

width: '100px',
height: '100px',
},
});

const motionAtom = atoms.fade.enterUltraSlow();
const FadeEnter = createAtom({
keyframes: motionAtom.keyframes,
options: { ...motionAtom.options, duration: 2000 },
});

export const MotionDefault = () => {
const classes = useClasses();

return (
<div className={classes.container}>
<div className={classes.card}>
<FadeEnter iterations={Infinity}>
<div className={classes.item} />
</FadeEnter>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
`@fluentui/react-motions` implements definitions for motion animations that can be used in Fluent UI components. These animations are used to provide visual feedback to users when they interact with components.

This implementation is based on [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API) and defines atoms & transitions that can be used to create animation components.

- Atoms are the smallest building blocks of animations
- Transitions are the combination of atoms that define the in/out animation
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
By default, the child component does not perform the enter transition when it first mounts, regardless of the value of `visible`. If you want this behavior, set both `appear` and `visible` props to be true.
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { makeStyles, shorthands, tokens, Label, Slider, useId, Checkbox } from '@fluentui/react-components';
import { createTransition, transitions } from '@fluentui/react-motions-preview';
import * as React from 'react';

import description from './TransitionUnmountOnExit.stories.md';

const useClasses = makeStyles({
container: {
display: 'grid',
gridTemplateColumns: '1fr',
...shorthands.gap('10px'),
},
card: {
display: 'flex',
flexDirection: 'column',

...shorthands.border('3px', 'solid', tokens.colorNeutralForeground3),
...shorthands.borderRadius(tokens.borderRadiusMedium),
...shorthands.padding('10px'),

alignItems: 'center',
},
item: {
backgroundColor: tokens.colorBrandBackground,
...shorthands.borderRadius('50%'),

width: '100px',
height: '100px',
},
description: {
...shorthands.margin('5px'),
},
controls: {
display: 'flex',
flexDirection: 'column',

marginTop: '20px',

...shorthands.border('3px', 'solid', tokens.colorNeutralForeground3),
...shorthands.borderRadius(tokens.borderRadiusMedium),
...shorthands.padding('10px'),
},
});

const Fade = createTransition(transitions.fade.slow());

export const TransitionAppear = () => {
const classes = useClasses();
const sliderId = useId();

const elementRef = React.useRef<HTMLDivElement>(null);
const [playbackRate, setPlaybackRate] = React.useState<number>(30);
const [isMounted, setIsMounted] = React.useState<boolean>(false);

React.useEffect(() => {
elementRef.current?.getAnimations().forEach(animation => {
animation.playbackRate = playbackRate / 100;
});
}, [playbackRate, isMounted]);

return (
<>
<div className={classes.container}>
<div className={classes.card}>
{isMounted && (
<Fade appear visible>
<div className={classes.item} ref={elementRef} />
</Fade>
)}

<code className={classes.description}>fadeSlow</code>
</div>
</div>

<div className={classes.controls}>
<div>
<Checkbox label="Mount an element?" checked={isMounted} onChange={() => setIsMounted(v => !v)} />
</div>
<div>
<Label htmlFor={sliderId}>
<code>playbackRate</code>: {playbackRate}%
</Label>
<Slider
aria-valuetext={`Value is ${playbackRate}%`}
value={playbackRate}
onChange={(ev, data) => setPlaybackRate(data.value)}
min={0}
id={sliderId}
max={100}
step={10}
/>
</div>
</div>
</>
);
};

TransitionAppear.parameters = {
docs: {
description: {
story: description,
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
By default, the child component stays mounted after the animation reaches the `"finished"` state. Set `unmountOnExit` if you'd prefer to unmount the component after it finishes the animation.
Loading

0 comments on commit 4c1cd4b

Please sign in to comment.