Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-motion): add useMotion hook #28699

Merged
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1faa4c8
feat: implement useMotionPresence hook
marcosmoura Aug 1, 2023
230e273
docs: add missing change files
marcosmoura Aug 1, 2023
b8128e7
fix: improve performance of duration calculation
marcosmoura Aug 2, 2023
c721171
feat: implement useAnimationFrame hook to help controlling the motion…
marcosmoura Aug 3, 2023
6bbf319
fix: improve type definition to avoid typecast
marcosmoura Aug 3, 2023
44b58d5
fix: return a blank style declaration in case global "window" do not …
marcosmoura Aug 3, 2023
b3124d6
fix: regenerate API
marcosmoura Aug 3, 2023
caef0bd
fix: regenerate API
marcosmoura Aug 3, 2023
ac4e941
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 3, 2023
8fa8f4a
revert: use RefCallback instead of Ref
marcosmoura Aug 3, 2023
45ac91f
fix: regenerate API
marcosmoura Aug 3, 2023
2497b77
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 3, 2023
cceb832
fix: regenerate API
marcosmoura Aug 3, 2023
91cdd11
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 7, 2023
d3cbded
feat: simplify API by removing redundant prop
marcosmoura Aug 7, 2023
cfea341
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 17, 2023
ab9ff66
feat: implement useMotion hook instead of useMotionPresence
marcosmoura Aug 17, 2023
76d1b82
feat: remove useMotionPresence hook
marcosmoura Aug 17, 2023
7fd87f9
fix: remove old changefile
marcosmoura Aug 17, 2023
1e16743
feat: expose useAnimationFrame hook
marcosmoura Aug 17, 2023
41e9e8c
fix: add missing changefile
marcosmoura Aug 17, 2023
647b9e5
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 17, 2023
f384b82
fix: mismatch dependencies
marcosmoura Aug 17, 2023
ce4d183
feat: add motion docs to public site
marcosmoura Aug 17, 2023
05ba7e1
docs: add documentatio for the hook
marcosmoura Aug 17, 2023
e9e8bbe
feat: create useMotion hook accepting either a boolean or motion state
marcosmoura Aug 21, 2023
9152d81
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 21, 2023
3872d0a
fix: upgrade stories to use latest changes to hook
marcosmoura Aug 21, 2023
6debd98
feat: make package public
marcosmoura Aug 21, 2023
7f27429
fix: add missing change file
marcosmoura Aug 21, 2023
9593026
fix: join two related hooks in one file to be easier to test
marcosmoura Aug 21, 2023
fd9970f
fix: remove unused imports
marcosmoura Aug 21, 2023
5cb0a56
docs: move stories to public site
marcosmoura Aug 21, 2023
92ecfed
docs: add title to example
marcosmoura Aug 21, 2023
190493f
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 21, 2023
9086d1a
fix: remove leftover property
marcosmoura Aug 22, 2023
969ce87
fix: add type to improve useMemo
marcosmoura Aug 22, 2023
1d8e9b8
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 22, 2023
c437db6
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 22, 2023
f09ff57
feat: use boolean instead of function
marcosmoura Aug 22, 2023
e6bb24b
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 23, 2023
a1616d2
fix: remove outdated changefile
marcosmoura Aug 23, 2023
74b8257
fix: use correct boolean values
marcosmoura Aug 23, 2023
7942e80
fix: improve typings and documentation
marcosmoura Aug 23, 2023
2d89ef2
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 23, 2023
f006b19
fix: use correct type for MotionOptions
marcosmoura Aug 23, 2023
ab6f39b
feat: refactor useMotion to a much more clean/performant logic
marcosmoura Aug 25, 2023
f66a01e
fix: remove debug function
marcosmoura Aug 25, 2023
006fc84
fix: set motion as active when animations are disabled
marcosmoura Aug 25, 2023
03a806a
fix: upgrade tests
marcosmoura Aug 25, 2023
bb450b8
fix: remove duplicated code due to a merge conflict
marcosmoura Aug 25, 2023
e135084
fix: revert changes to CODEOWNERS
marcosmoura Aug 25, 2023
55aee81
fix: generate new API documentation
marcosmoura Aug 26, 2023
a9c61f3
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 26, 2023
c5e204d
fix: remove ref from dependencies
marcosmoura Aug 28, 2023
06ae5c6
Merge branch 'master' into feat/use-motion-presence-hook
marcosmoura Aug 28, 2023
83ef7e1
fix: wrong merge
marcosmoura Aug 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ packages/react-components/react-migration-v0-v9 @microsoft/teams-prg
packages/react-components/react-datepicker-compat @microsoft/cxe-red @sopranopillow @khmakoto
packages/react-components/react-migration-v8-v9 @microsoft/cxe-red @microsoft/cxe-coastal @geoffcoxmsft
packages/react-components/react-breadcrumb-preview @microsoft/cxe-prg
packages/react-components/react-drawer @microsoft/cxe-prg
packages/react-components/react-drawer @microsoft/cxe-prg @marcosmoura
packages/react-components/react-storybook-addon-codesandbox @microsoft/fluentui-react-build
packages/react-components/babel-preset-storybook-full-source @microsoft/fluentui-react-build
packages/react-components/react-jsx-runtime @microsoft/teams-prg
packages/react-components/react-toast @microsoft/teams-prg
packages/react-components/react-search-preview @microsoft/cxe-coastal
packages/react-components/react-colorpicker-compat @microsoft/cxe-red @sopranopillow
packages/react-components/react-motion-preview @microsoft/cxe-prg @marcosmoura
packages/react-components/react-nav-preview @microsoft/cxe-red @mltejera
# <%= NX-CODEOWNER-PLACEHOLDER %>

Expand Down
1 change: 1 addition & 0 deletions apps/public-docsite-v9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@fluentui/react-storybook-addon-codesandbox": "*",
"@fluentui/theme-designer": "*",
"@fluentui/react-search-preview": "*",
"@fluentui/react-motion-preview": "*",
"@griffel/react": "^1.5.14",
"react": "17.0.2",
"react-dom": "17.0.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as React from 'react';

import { useMotion } from '@fluentui/react-motion-preview';
import { Button, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';

const useStyles = makeStyles({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
rowGap: '24px',
},

rectangle: {
...shorthands.borderRadius('8px'),

width: '200px',
height: '150px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: tokens.colorBrandBackground2,
opacity: 0,
transform: 'translate3D(0, 0, 0) scale(0.25)',
transitionDuration: `${tokens.durationNormal}, ${tokens.durationNormal}, ${tokens.durationUltraSlow}`,
transitionDelay: `${tokens.durationFast}, 0, ${tokens.durationSlow}`,
transitionProperty: 'opacity, transform, background-color',
willChange: 'opacity, transform, background-color',
color: '#fff',
},

visible: {
opacity: 1,
transform: 'translate3D(0, 0, 0) scale(1)',
backgroundColor: tokens.colorBrandBackground,
},
});

export const MotionExample = () => {
const styles = useStyles();

const [open, setOpen] = React.useState(false);
const motion = useMotion<HTMLDivElement>(open);

return (
<div className={styles.root}>
<Button appearance="primary" onClick={() => setOpen(!open)}>
Toggle
</Button>

{motion.canRender() && (
<div ref={motion.ref} className={mergeClasses(styles.rectangle, motion.isActive() && styles.visible)}>
Lorem ipsum
</div>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Title, Subtitle, Meta, Description } from '@storybook/addon-docs';

import { MotionExample } from './MotionExample.stories';

<Title>useMotion</Title>

<Meta title="Utilities/Motion/useMotion" />

<Description>
A tracker hook, that monitors the state of animations and transitions for a particular element. This hook does not
directly create animations but instead synchronizes with CSS properties to determine the rendering status, visibility,
entering, leaving, and ongoing animation of a component. If any CSS changes or properties are overridden, this hook
will automatically adjust and stay synchronized.
</Description>

<Subtitle>Usage</Subtitle>

```tsx
import * as React from 'react';

import { useMotion } from '@fluentui/react-motion-preview';
import { Button, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';

const useStyles = makeStyles({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
rowGap: '24px',
},

rectangle: {
...shorthands.borderRadius('8px'),

width: '200px',
height: '150px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: tokens.colorBrandBackground2,
opacity: 0,
transform: 'translate3D(0, 0, 0) scale(0.25)',
transitionDuration: `${tokens.durationNormal}, ${tokens.durationNormal}, ${tokens.durationUltraSlow}`,
transitionDelay: `${tokens.durationFast}, 0, ${tokens.durationSlow}`,
transitionProperty: 'opacity, transform, background-color',
willChange: 'opacity, transform, background-color',
color: '#fff',
},

visible: {
opacity: 1,
transform: 'translate3D(0, 0, 0) scale(1)',
backgroundColor: tokens.colorBrandBackground,
},
});

export const MotionExample = () => {
const styles = useStyles();

const [open, setOpen] = React.useState(false);
const motion = useMotion<HTMLDivElement>(open);

return (
<div className={styles.root}>
<Button appearance="primary" onClick={() => setOpen(!open)}>
Toggle
</Button>

{motion.canRender() && (
<div ref={motion.ref} className={mergeClasses(styles.rectangle, motion.isActive() && styles.visible)}>
Lorem ipsum
</div>
)}
</div>
);
};
```

<Subtitle>Example</Subtitle>

<MotionExample />
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: create react-motion-preview package with useMotion hook",
"packageName": "@fluentui/react-motion-preview",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: create useAnimationFrame hook",
"packageName": "@fluentui/react-utilities",
"email": "[email protected]",
"dependentChangeType": "patch"
}
4 changes: 4 additions & 0 deletions packages/react-components/react-motion-preview/.babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../../.babelrc-v9.json",
"plugins": ["annotate-pure-calls", "@babel/transform-react-pure-annotations"]
}
4 changes: 4 additions & 0 deletions packages/react-components/react-motion-preview/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["plugin:@fluentui/eslint-plugin/react"],
"root": true
}
38 changes: 38 additions & 0 deletions packages/react-components/react-motion-preview/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.storybook/
.vscode/
bundle-size/
config/
coverage/
docs/
etc/
node_modules/
src/
stories/
dist/types/
temp/
__fixtures__
__mocks__
__tests__

*.api.json
*.log
*.spec.*
*.cy.*
*.test.*
*.yml

# config files
*config.*
*rc.*
.editorconfig
.eslint*
.git*
.prettierignore
.swcrc
project.json

# exclude gitignore patterns explicitly
!lib
!lib-commonjs
!lib-amd
!dist/*.d.ts
14 changes: 14 additions & 0 deletions packages/react-components/react-motion-preview/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const rootMain = require('../../../../.storybook/main');

module.exports = /** @type {Omit<import('../../../../.storybook/main'), 'typescript'|'babel'>} */ ({
...rootMain,
stories: [...rootMain.stories, '../stories/**/*.stories.mdx', '../stories/**/index.stories.@(ts|tsx)'],
addons: [...rootMain.addons],
webpackFinal: (config, options) => {
const localConfig = { ...rootMain.webpackFinal(config, options) };

// add your own webpack tweaks if needed

return localConfig;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as rootPreview from '../../../../.storybook/preview';

/** @type {typeof rootPreview.decorators} */
export const decorators = [...rootPreview.decorators];

/** @type {typeof rootPreview.parameters} */
export const parameters = { ...rootPreview.parameters };
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "",
"allowJs": true,
"checkJs": true,
"types": ["static-assets", "environment", "storybook__addons"]
},
"include": ["../stories/**/*.stories.ts", "../stories/**/*.stories.tsx", "*.js"]
}
30 changes: 30 additions & 0 deletions packages/react-components/react-motion-preview/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"exclude": [
"/testing",
"/**/*.cy.ts",
"/**/*.cy.tsx",
"/**/*.spec.ts",
"/**/*.spec.tsx",
"/**/*.test.ts",
"/**/*.test.tsx"
],
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"externalHelpers": true,
"transform": {
"react": {
"runtime": "classic",
"useSpread": true
}
},
"target": "es2019"
},
"minify": false,
"sourceMaps": true
}
15 changes: 15 additions & 0 deletions packages/react-components/react-motion-preview/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@fluentui/react-motion-preview

Copyright (c) Microsoft Corporation

All rights reserved.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license
5 changes: 5 additions & 0 deletions packages/react-components/react-motion-preview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @fluentui/react-motion-preview

**React Motion components for [Fluent UI React](https://react.fluentui.dev/)**

These are not production-ready components and **should never be used in product**. This space is useful for testing new components whose APIs might change before final release.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "@fluentui/scripts-api-extractor/api-extractor.common.v-next.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** Jest test setup file. */
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## API Report File for "@fluentui/react-motion-preview"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).

```ts

import * as React_2 from 'react';

// @public
export function getDefaultMotionState<Element extends HTMLElement>(): MotionState<Element>;

// @public (undocumented)
export type MotionShorthand<Element extends HTMLElement = HTMLElement> = MotionShorthandValue | MotionState<Element>;

// @public (undocumented)
export type MotionShorthandValue = boolean;

// @public (undocumented)
export type MotionState<Element extends HTMLElement = HTMLElement> = {
ref: React_2.Ref<Element>;
type: MotionType;
isActive(): boolean;
canRender(): boolean;
};

// @public (undocumented)
export type MotionType = 'unmounted' | 'entering' | 'entered' | 'idle' | 'exiting' | 'exited';

// @public
export function useMotion<Element extends HTMLElement>(shorthand: MotionShorthand<Element>, options?: UseMotionOptions): MotionState<Element>;

// @public (undocumented)
export type UseMotionOptions = {
animateOnFirstMount?: boolean;
};

// (No @packageDocumentation comment for this package)

```
21 changes: 21 additions & 0 deletions packages/react-components/react-motion-preview/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @ts-check

/**
* @type {import('@jest/types').Config.InitialOptions}
*/
module.exports = {
displayName: 'react-motion-preview',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
isolatedModules: true,
},
],
},
coverageDirectory: './coverage',
setupFilesAfterEnv: ['./config/tests.js'],
snapshotSerializers: ['@griffel/jest-serializer'],
};
5 changes: 5 additions & 0 deletions packages/react-components/react-motion-preview/just.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { preset, task } from '@fluentui/scripts-tasks';

preset();

task('build', 'build:react-components').cached?.();
Loading