@fluentui/react-motion 9.6.7 → 9.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,33 @@
1
1
  # Change Log - @fluentui/react-motion
2
2
 
3
- This log was last generated on Wed, 22 Jan 2025 13:55:29 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 19 Mar 2025 15:36:13 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.6.9](https://github.com/microsoft/fluentui/tree/@fluentui/react-motion_v9.6.9)
8
+
9
+ Wed, 19 Mar 2025 15:36:13 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-motion_v9.6.8..@fluentui/react-motion_v9.6.9)
11
+
12
+ ### Patches
13
+
14
+ - Bump @fluentui/react-shared-contexts to v9.23.0 ([PR #34032](https://github.com/microsoft/fluentui/pull/34032) by beachball)
15
+ - Bump @fluentui/react-utilities to v9.18.22 ([PR #34032](https://github.com/microsoft/fluentui/pull/34032) by beachball)
16
+
17
+ ## [9.6.8](https://github.com/microsoft/fluentui/tree/@fluentui/react-motion_v9.6.8)
18
+
19
+ Tue, 11 Mar 2025 18:58:51 GMT
20
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-motion_v9.6.7..@fluentui/react-motion_v9.6.8)
21
+
22
+ ### Patches
23
+
24
+ - fix: apply initial styles consistently ([PR #33810](https://github.com/microsoft/fluentui/pull/33810) by olfedias@microsoft.com)
25
+ - Bump @fluentui/react-shared-contexts to v9.22.0 ([PR #33927](https://github.com/microsoft/fluentui/pull/33927) by beachball)
26
+ - Bump @fluentui/react-utilities to v9.18.21 ([PR #33927](https://github.com/microsoft/fluentui/pull/33927) by beachball)
27
+
7
28
  ## [9.6.7](https://github.com/microsoft/fluentui/tree/@fluentui/react-motion_v9.6.7)
8
29
 
9
- Wed, 22 Jan 2025 13:55:29 GMT
30
+ Wed, 22 Jan 2025 14:00:19 GMT
10
31
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-motion_v9.6.6..@fluentui/react-motion_v9.6.7)
11
32
 
12
33
  ### Patches
@@ -10,9 +10,6 @@ import { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';
10
10
  /**
11
11
  * @internal A private symbol to store the motion definition on the component for variants.
12
12
  */ export const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');
13
- function shouldSkipAnimation(appear, isFirstMount, visible) {
14
- return !appear && isFirstMount && !!visible;
15
- }
16
13
  export function createPresenceComponent(value) {
17
14
  return Object.assign((props)=>{
18
15
  'use no memo';
@@ -67,7 +64,7 @@ export function createPresenceComponent(value) {
67
64
  });
68
65
  useIsomorphicLayoutEffect(()=>{
69
66
  const element = elementRef.current;
70
- if (!element || shouldSkipAnimation(optionsRef.current.appear, isFirstMount, visible)) {
67
+ if (!element) {
71
68
  return;
72
69
  }
73
70
  const presenceMotion = typeof value === 'function' ? value({
@@ -76,8 +73,10 @@ export function createPresenceComponent(value) {
76
73
  }) : value;
77
74
  const atoms = visible ? presenceMotion.enter : presenceMotion.exit;
78
75
  const direction = visible ? 'enter' : 'exit';
79
- const applyInitialStyles = !visible && isFirstMount;
80
- const skipAnimation = optionsRef.current.skipMotions;
76
+ // Heads up!
77
+ // Initial styles are applied when the component is mounted for the first time and "appear" is set to "false" (otherwise animations are triggered)
78
+ const applyInitialStyles = !optionsRef.current.appear && isFirstMount;
79
+ const skipAnimationByConfig = optionsRef.current.skipMotions;
81
80
  if (!applyInitialStyles) {
82
81
  handleMotionStart(direction);
83
82
  }
@@ -92,7 +91,7 @@ export function createPresenceComponent(value) {
92
91
  }
93
92
  handleRef.current = handle;
94
93
  handle.setMotionEndCallbacks(()=>handleMotionFinish(direction), ()=>handleMotionCancel(direction));
95
- if (skipAnimation) {
94
+ if (skipAnimationByConfig) {
96
95
  handle.finish();
97
96
  }
98
97
  return ()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/factories/createPresenceComponent.ts"],"sourcesContent":["import { useEventCallback, useFirstMount, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';\nimport { useAnimateAtoms } from '../hooks/useAnimateAtoms';\nimport { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';\nimport { useMountedState } from '../hooks/useMountedState';\nimport { useIsReducedMotion } from '../hooks/useIsReducedMotion';\nimport { getChildElement } from '../utils/getChildElement';\nimport type { MotionParam, PresenceMotion, MotionImperativeRef, PresenceMotionFn, PresenceDirection } from '../types';\nimport { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';\n\n/**\n * @internal A private symbol to store the motion definition on the component for variants.\n */\nexport const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');\n\nexport type PresenceComponentProps = {\n /**\n * By default, the child component won't execute the \"enter\" motion when it initially mounts, regardless of the value\n * of \"visible\". If you desire this behavior, ensure both \"appear\" and \"visible\" are set to \"true\".\n */\n appear?: boolean;\n\n /** A React element that will be cloned and will have motion effects applied to it. */\n children: React.ReactElement;\n\n /** Provides imperative controls for the animation. */\n imperativeRef?: React.Ref<MotionImperativeRef | undefined>;\n\n /**\n * Callback that is called when the whole motion finishes.\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionFinish?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion is cancelled. When a motion is cancelled it does not\n * emit a finish event but a specific cancel event\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionCancel?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion starts.\n *\n * A motion definition can contain multiple animations and therefore multiple \"start\" events. The callback is\n * triggered when the first animation is started. There is no official \"start\" event with the Web Animations API.\n * so the callback is triggered with \"null\".\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionStart?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /** Defines whether a component is visible; triggers the \"enter\" or \"exit\" motions. */\n visible?: boolean;\n\n /**\n * By default, the child component remains mounted after it reaches the \"finished\" state. Set \"unmountOnExit\" if\n * you prefer to unmount the component after it finishes exiting.\n */\n unmountOnExit?: boolean;\n};\n\nexport type PresenceComponent<MotionParams extends Record<string, MotionParam> = {}> = {\n (props: PresenceComponentProps & MotionParams): React.ReactElement | null;\n [MOTION_DEFINITION]: PresenceMotionFn<MotionParams>;\n};\n\nfunction shouldSkipAnimation(appear: boolean | undefined, isFirstMount: boolean, visible: boolean | undefined) {\n return !appear && isFirstMount && !!visible;\n}\n\nexport function createPresenceComponent<MotionParams extends Record<string, MotionParam> = {}>(\n value: PresenceMotion | PresenceMotionFn<MotionParams>,\n): PresenceComponent<MotionParams> {\n return Object.assign(\n (props: PresenceComponentProps & MotionParams) => {\n 'use no memo';\n\n const itemContext = React.useContext(PresenceGroupChildContext);\n const merged = { ...itemContext, ...props };\n const skipMotions = useMotionBehaviourContext() === 'skip';\n\n const {\n appear,\n children,\n imperativeRef,\n onExit,\n onMotionFinish,\n onMotionStart,\n onMotionCancel,\n visible,\n unmountOnExit,\n ..._rest\n } = merged;\n const params = _rest as Exclude<typeof merged, PresenceComponentProps | typeof itemContext>;\n\n const [mounted, setMounted] = useMountedState(visible, unmountOnExit);\n const child = getChildElement(children);\n\n const handleRef = useMotionImperativeRef(imperativeRef);\n const elementRef = React.useRef<HTMLElement>();\n const ref = useMergedRefs(elementRef, child.ref);\n const optionsRef = React.useRef<{ appear?: boolean; params: MotionParams; skipMotions: boolean }>({\n appear,\n params,\n skipMotions,\n });\n\n const animateAtoms = useAnimateAtoms();\n const isFirstMount = useFirstMount();\n const isReducedMotion = useIsReducedMotion();\n\n const handleMotionStart = useEventCallback((direction: PresenceDirection) => {\n onMotionStart?.(null, { direction });\n });\n const handleMotionFinish = useEventCallback((direction: PresenceDirection) => {\n onMotionFinish?.(null, { direction });\n\n if (direction === 'exit' && unmountOnExit) {\n setMounted(false);\n onExit?.();\n }\n });\n\n const handleMotionCancel = useEventCallback((direction: PresenceDirection) => {\n onMotionCancel?.(null, { direction });\n });\n\n useIsomorphicLayoutEffect(() => {\n // Heads up!\n // We store the params in a ref to avoid re-rendering the component when the params change.\n optionsRef.current = { appear, params, skipMotions };\n });\n\n useIsomorphicLayoutEffect(\n () => {\n const element = elementRef.current;\n\n if (!element || shouldSkipAnimation(optionsRef.current.appear, isFirstMount, visible)) {\n return;\n }\n\n const presenceMotion =\n typeof value === 'function' ? value({ element, ...optionsRef.current.params }) : (value as PresenceMotion);\n const atoms = visible ? presenceMotion.enter : presenceMotion.exit;\n\n const direction: PresenceDirection = visible ? 'enter' : 'exit';\n const applyInitialStyles = !visible && isFirstMount;\n const skipAnimation = optionsRef.current.skipMotions;\n\n if (!applyInitialStyles) {\n handleMotionStart(direction);\n }\n\n const handle = animateAtoms(element, atoms, { isReducedMotion: isReducedMotion() });\n\n if (applyInitialStyles) {\n // Heads up!\n // .finish() is used in this case to skip animation and apply animation styles immediately\n handle.finish();\n return;\n }\n\n handleRef.current = handle;\n handle.setMotionEndCallbacks(\n () => handleMotionFinish(direction),\n () => handleMotionCancel(direction),\n );\n\n if (skipAnimation) {\n handle.finish();\n }\n\n return () => {\n handle.cancel();\n };\n },\n // Excluding `isFirstMount` from deps to prevent re-triggering the animation on subsequent renders\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [animateAtoms, handleRef, isReducedMotion, handleMotionFinish, handleMotionStart, handleMotionCancel, visible],\n );\n\n if (mounted) {\n return React.cloneElement(child, { ref });\n }\n\n return null;\n },\n {\n // Heads up!\n // Always normalize it to a function to simplify types\n [MOTION_DEFINITION]: typeof value === 'function' ? value : () => value,\n },\n );\n}\n"],"names":["useEventCallback","useFirstMount","useIsomorphicLayoutEffect","useMergedRefs","React","PresenceGroupChildContext","useAnimateAtoms","useMotionImperativeRef","useMountedState","useIsReducedMotion","getChildElement","useMotionBehaviourContext","MOTION_DEFINITION","Symbol","shouldSkipAnimation","appear","isFirstMount","visible","createPresenceComponent","value","Object","assign","props","itemContext","useContext","merged","skipMotions","children","imperativeRef","onExit","onMotionFinish","onMotionStart","onMotionCancel","unmountOnExit","_rest","params","mounted","setMounted","child","handleRef","elementRef","useRef","ref","optionsRef","animateAtoms","isReducedMotion","handleMotionStart","direction","handleMotionFinish","handleMotionCancel","current","element","presenceMotion","atoms","enter","exit","applyInitialStyles","skipAnimation","handle","finish","setMotionEndCallbacks","cancel","cloneElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/factories/createPresenceComponent.ts"],"sourcesContent":["import { useEventCallback, useFirstMount, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';\nimport { useAnimateAtoms } from '../hooks/useAnimateAtoms';\nimport { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';\nimport { useMountedState } from '../hooks/useMountedState';\nimport { useIsReducedMotion } from '../hooks/useIsReducedMotion';\nimport { getChildElement } from '../utils/getChildElement';\nimport type { MotionParam, PresenceMotion, MotionImperativeRef, PresenceMotionFn, PresenceDirection } from '../types';\nimport { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';\n\n/**\n * @internal A private symbol to store the motion definition on the component for variants.\n */\nexport const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');\n\nexport type PresenceComponentProps = {\n /**\n * By default, the child component won't execute the \"enter\" motion when it initially mounts, regardless of the value\n * of \"visible\". If you desire this behavior, ensure both \"appear\" and \"visible\" are set to \"true\".\n */\n appear?: boolean;\n\n /** A React element that will be cloned and will have motion effects applied to it. */\n children: React.ReactElement;\n\n /** Provides imperative controls for the animation. */\n imperativeRef?: React.Ref<MotionImperativeRef | undefined>;\n\n /**\n * Callback that is called when the whole motion finishes.\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionFinish?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion is cancelled. When a motion is cancelled it does not\n * emit a finish event but a specific cancel event\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionCancel?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion starts.\n *\n * A motion definition can contain multiple animations and therefore multiple \"start\" events. The callback is\n * triggered when the first animation is started. There is no official \"start\" event with the Web Animations API.\n * so the callback is triggered with \"null\".\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionStart?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /** Defines whether a component is visible; triggers the \"enter\" or \"exit\" motions. */\n visible?: boolean;\n\n /**\n * By default, the child component remains mounted after it reaches the \"finished\" state. Set \"unmountOnExit\" if\n * you prefer to unmount the component after it finishes exiting.\n */\n unmountOnExit?: boolean;\n};\n\nexport type PresenceComponent<MotionParams extends Record<string, MotionParam> = {}> = {\n (props: PresenceComponentProps & MotionParams): React.ReactElement | null;\n [MOTION_DEFINITION]: PresenceMotionFn<MotionParams>;\n};\n\nexport function createPresenceComponent<MotionParams extends Record<string, MotionParam> = {}>(\n value: PresenceMotion | PresenceMotionFn<MotionParams>,\n): PresenceComponent<MotionParams> {\n return Object.assign(\n (props: PresenceComponentProps & MotionParams) => {\n 'use no memo';\n\n const itemContext = React.useContext(PresenceGroupChildContext);\n const merged = { ...itemContext, ...props };\n const skipMotions = useMotionBehaviourContext() === 'skip';\n\n const {\n appear,\n children,\n imperativeRef,\n onExit,\n onMotionFinish,\n onMotionStart,\n onMotionCancel,\n visible,\n unmountOnExit,\n ..._rest\n } = merged;\n const params = _rest as Exclude<typeof merged, PresenceComponentProps | typeof itemContext>;\n\n const [mounted, setMounted] = useMountedState(visible, unmountOnExit);\n const child = getChildElement(children);\n\n const handleRef = useMotionImperativeRef(imperativeRef);\n const elementRef = React.useRef<HTMLElement>();\n const ref = useMergedRefs(elementRef, child.ref);\n const optionsRef = React.useRef<{ appear?: boolean; params: MotionParams; skipMotions: boolean }>({\n appear,\n params,\n skipMotions,\n });\n\n const animateAtoms = useAnimateAtoms();\n const isFirstMount = useFirstMount();\n const isReducedMotion = useIsReducedMotion();\n\n const handleMotionStart = useEventCallback((direction: PresenceDirection) => {\n onMotionStart?.(null, { direction });\n });\n const handleMotionFinish = useEventCallback((direction: PresenceDirection) => {\n onMotionFinish?.(null, { direction });\n\n if (direction === 'exit' && unmountOnExit) {\n setMounted(false);\n onExit?.();\n }\n });\n\n const handleMotionCancel = useEventCallback((direction: PresenceDirection) => {\n onMotionCancel?.(null, { direction });\n });\n\n useIsomorphicLayoutEffect(() => {\n // Heads up!\n // We store the params in a ref to avoid re-rendering the component when the params change.\n optionsRef.current = { appear, params, skipMotions };\n });\n\n useIsomorphicLayoutEffect(\n () => {\n const element = elementRef.current;\n\n if (!element) {\n return;\n }\n\n const presenceMotion =\n typeof value === 'function' ? value({ element, ...optionsRef.current.params }) : (value as PresenceMotion);\n\n const atoms = visible ? presenceMotion.enter : presenceMotion.exit;\n const direction: PresenceDirection = visible ? 'enter' : 'exit';\n\n // Heads up!\n // Initial styles are applied when the component is mounted for the first time and \"appear\" is set to \"false\" (otherwise animations are triggered)\n const applyInitialStyles = !optionsRef.current.appear && isFirstMount;\n const skipAnimationByConfig = optionsRef.current.skipMotions;\n\n if (!applyInitialStyles) {\n handleMotionStart(direction);\n }\n\n const handle = animateAtoms(element, atoms, { isReducedMotion: isReducedMotion() });\n\n if (applyInitialStyles) {\n // Heads up!\n // .finish() is used in this case to skip animation and apply animation styles immediately\n handle.finish();\n return;\n }\n\n handleRef.current = handle;\n handle.setMotionEndCallbacks(\n () => handleMotionFinish(direction),\n () => handleMotionCancel(direction),\n );\n\n if (skipAnimationByConfig) {\n handle.finish();\n }\n\n return () => {\n handle.cancel();\n };\n },\n // Excluding `isFirstMount` from deps to prevent re-triggering the animation on subsequent renders\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [animateAtoms, handleRef, isReducedMotion, handleMotionFinish, handleMotionStart, handleMotionCancel, visible],\n );\n\n if (mounted) {\n return React.cloneElement(child, { ref });\n }\n\n return null;\n },\n {\n // Heads up!\n // Always normalize it to a function to simplify types\n [MOTION_DEFINITION]: typeof value === 'function' ? value : () => value,\n },\n );\n}\n"],"names":["useEventCallback","useFirstMount","useIsomorphicLayoutEffect","useMergedRefs","React","PresenceGroupChildContext","useAnimateAtoms","useMotionImperativeRef","useMountedState","useIsReducedMotion","getChildElement","useMotionBehaviourContext","MOTION_DEFINITION","Symbol","createPresenceComponent","value","Object","assign","props","itemContext","useContext","merged","skipMotions","appear","children","imperativeRef","onExit","onMotionFinish","onMotionStart","onMotionCancel","visible","unmountOnExit","_rest","params","mounted","setMounted","child","handleRef","elementRef","useRef","ref","optionsRef","animateAtoms","isFirstMount","isReducedMotion","handleMotionStart","direction","handleMotionFinish","handleMotionCancel","current","element","presenceMotion","atoms","enter","exit","applyInitialStyles","skipAnimationByConfig","handle","finish","setMotionEndCallbacks","cancel","cloneElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,gBAAgB,EAAEC,aAAa,EAAEC,yBAAyB,EAAEC,aAAa,QAAQ,4BAA4B;AACtH,YAAYC,WAAW,QAAQ;AAE/B,SAASC,yBAAyB,QAAQ,wCAAwC;AAClF,SAASC,eAAe,QAAQ,2BAA2B;AAC3D,SAASC,sBAAsB,QAAQ,kCAAkC;AACzE,SAASC,eAAe,QAAQ,2BAA2B;AAC3D,SAASC,kBAAkB,QAAQ,8BAA8B;AACjE,SAASC,eAAe,QAAQ,2BAA2B;AAE3D,SAASC,yBAAyB,QAAQ,qCAAqC;AAE/E;;CAEC,GACD,OAAO,MAAMC,oBAAoBC,OAAO,qBAAqB;AA2D7D,OAAO,SAASC,wBACdC,KAAsD;IAEtD,OAAOC,OAAOC,MAAM,CAClB,CAACC;QACC;QAEA,MAAMC,cAAcf,MAAMgB,UAAU,CAACf;QACrC,MAAMgB,SAAS;YAAE,GAAGF,WAAW;YAAE,GAAGD,KAAK;QAAC;QAC1C,MAAMI,cAAcX,gCAAgC;QAEpD,MAAM,EACJY,MAAM,EACNC,QAAQ,EACRC,aAAa,EACbC,MAAM,EACNC,cAAc,EACdC,aAAa,EACbC,cAAc,EACdC,OAAO,EACPC,aAAa,EACb,GAAGC,OACJ,GAAGX;QACJ,MAAMY,SAASD;QAEf,MAAM,CAACE,SAASC,WAAW,GAAG3B,gBAAgBsB,SAASC;QACvD,MAAMK,QAAQ1B,gBAAgBc;QAE9B,MAAMa,YAAY9B,uBAAuBkB;QACzC,MAAMa,aAAalC,MAAMmC,MAAM;QAC/B,MAAMC,MAAMrC,cAAcmC,YAAYF,MAAMI,GAAG;QAC/C,MAAMC,aAAarC,MAAMmC,MAAM,CAAmE;YAChGhB;YACAU;YACAX;QACF;QAEA,MAAMoB,eAAepC;QACrB,MAAMqC,eAAe1C;QACrB,MAAM2C,kBAAkBnC;QAExB,MAAMoC,oBAAoB7C,iBAAiB,CAAC8C;YAC1ClB,0BAAAA,oCAAAA,cAAgB,MAAM;gBAAEkB;YAAU;QACpC;QACA,MAAMC,qBAAqB/C,iBAAiB,CAAC8C;YAC3CnB,2BAAAA,qCAAAA,eAAiB,MAAM;gBAAEmB;YAAU;YAEnC,IAAIA,cAAc,UAAUf,eAAe;gBACzCI,WAAW;gBACXT,mBAAAA,6BAAAA;YACF;QACF;QAEA,MAAMsB,qBAAqBhD,iBAAiB,CAAC8C;YAC3CjB,2BAAAA,qCAAAA,eAAiB,MAAM;gBAAEiB;YAAU;QACrC;QAEA5C,0BAA0B;YACxB,YAAY;YACZ,2FAA2F;YAC3FuC,WAAWQ,OAAO,GAAG;gBAAE1B;gBAAQU;gBAAQX;YAAY;QACrD;QAEApB,0BACE;YACE,MAAMgD,UAAUZ,WAAWW,OAAO;YAElC,IAAI,CAACC,SAAS;gBACZ;YACF;YAEA,MAAMC,iBACJ,OAAOpC,UAAU,aAAaA,MAAM;gBAAEmC;gBAAS,GAAGT,WAAWQ,OAAO,CAAChB,MAAM;YAAC,KAAMlB;YAEpF,MAAMqC,QAAQtB,UAAUqB,eAAeE,KAAK,GAAGF,eAAeG,IAAI;YAClE,MAAMR,YAA+BhB,UAAU,UAAU;YAEzD,YAAY;YACZ,kJAAkJ;YAClJ,MAAMyB,qBAAqB,CAACd,WAAWQ,OAAO,CAAC1B,MAAM,IAAIoB;YACzD,MAAMa,wBAAwBf,WAAWQ,OAAO,CAAC3B,WAAW;YAE5D,IAAI,CAACiC,oBAAoB;gBACvBV,kBAAkBC;YACpB;YAEA,MAAMW,SAASf,aAAaQ,SAASE,OAAO;gBAAER,iBAAiBA;YAAkB;YAEjF,IAAIW,oBAAoB;gBACtB,YAAY;gBACZ,0FAA0F;gBAC1FE,OAAOC,MAAM;gBACb;YACF;YAEArB,UAAUY,OAAO,GAAGQ;YACpBA,OAAOE,qBAAqB,CAC1B,IAAMZ,mBAAmBD,YACzB,IAAME,mBAAmBF;YAG3B,IAAIU,uBAAuB;gBACzBC,OAAOC,MAAM;YACf;YAEA,OAAO;gBACLD,OAAOG,MAAM;YACf;QACF,GACA,kGAAkG;QAClG,uDAAuD;QACvD;YAAClB;YAAcL;YAAWO;YAAiBG;YAAoBF;YAAmBG;YAAoBlB;SAAQ;QAGhH,IAAII,SAAS;YACX,OAAO9B,MAAMyD,YAAY,CAACzB,OAAO;gBAAEI;YAAI;QACzC;QAEA,OAAO;IACT,GACA;QACE,YAAY;QACZ,sDAAsD;QACtD,CAAC5B,kBAAkB,EAAE,OAAOG,UAAU,aAAaA,QAAQ,IAAMA;IACnE;AAEJ"}
@@ -27,9 +27,6 @@ const _useIsReducedMotion = require("../hooks/useIsReducedMotion");
27
27
  const _getChildElement = require("../utils/getChildElement");
28
28
  const _MotionBehaviourContext = require("../contexts/MotionBehaviourContext");
29
29
  const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');
30
- function shouldSkipAnimation(appear, isFirstMount, visible) {
31
- return !appear && isFirstMount && !!visible;
32
- }
33
30
  function createPresenceComponent(value) {
34
31
  return Object.assign((props)=>{
35
32
  'use no memo';
@@ -84,7 +81,7 @@ function createPresenceComponent(value) {
84
81
  });
85
82
  (0, _reactutilities.useIsomorphicLayoutEffect)(()=>{
86
83
  const element = elementRef.current;
87
- if (!element || shouldSkipAnimation(optionsRef.current.appear, isFirstMount, visible)) {
84
+ if (!element) {
88
85
  return;
89
86
  }
90
87
  const presenceMotion = typeof value === 'function' ? value({
@@ -93,8 +90,10 @@ function createPresenceComponent(value) {
93
90
  }) : value;
94
91
  const atoms = visible ? presenceMotion.enter : presenceMotion.exit;
95
92
  const direction = visible ? 'enter' : 'exit';
96
- const applyInitialStyles = !visible && isFirstMount;
97
- const skipAnimation = optionsRef.current.skipMotions;
93
+ // Heads up!
94
+ // Initial styles are applied when the component is mounted for the first time and "appear" is set to "false" (otherwise animations are triggered)
95
+ const applyInitialStyles = !optionsRef.current.appear && isFirstMount;
96
+ const skipAnimationByConfig = optionsRef.current.skipMotions;
98
97
  if (!applyInitialStyles) {
99
98
  handleMotionStart(direction);
100
99
  }
@@ -109,7 +108,7 @@ function createPresenceComponent(value) {
109
108
  }
110
109
  handleRef.current = handle;
111
110
  handle.setMotionEndCallbacks(()=>handleMotionFinish(direction), ()=>handleMotionCancel(direction));
112
- if (skipAnimation) {
111
+ if (skipAnimationByConfig) {
113
112
  handle.finish();
114
113
  }
115
114
  return ()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/factories/createPresenceComponent.ts"],"sourcesContent":["import { useEventCallback, useFirstMount, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';\nimport { useAnimateAtoms } from '../hooks/useAnimateAtoms';\nimport { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';\nimport { useMountedState } from '../hooks/useMountedState';\nimport { useIsReducedMotion } from '../hooks/useIsReducedMotion';\nimport { getChildElement } from '../utils/getChildElement';\nimport type { MotionParam, PresenceMotion, MotionImperativeRef, PresenceMotionFn, PresenceDirection } from '../types';\nimport { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';\n\n/**\n * @internal A private symbol to store the motion definition on the component for variants.\n */\nexport const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');\n\nexport type PresenceComponentProps = {\n /**\n * By default, the child component won't execute the \"enter\" motion when it initially mounts, regardless of the value\n * of \"visible\". If you desire this behavior, ensure both \"appear\" and \"visible\" are set to \"true\".\n */\n appear?: boolean;\n\n /** A React element that will be cloned and will have motion effects applied to it. */\n children: React.ReactElement;\n\n /** Provides imperative controls for the animation. */\n imperativeRef?: React.Ref<MotionImperativeRef | undefined>;\n\n /**\n * Callback that is called when the whole motion finishes.\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionFinish?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion is cancelled. When a motion is cancelled it does not\n * emit a finish event but a specific cancel event\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionCancel?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion starts.\n *\n * A motion definition can contain multiple animations and therefore multiple \"start\" events. The callback is\n * triggered when the first animation is started. There is no official \"start\" event with the Web Animations API.\n * so the callback is triggered with \"null\".\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionStart?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /** Defines whether a component is visible; triggers the \"enter\" or \"exit\" motions. */\n visible?: boolean;\n\n /**\n * By default, the child component remains mounted after it reaches the \"finished\" state. Set \"unmountOnExit\" if\n * you prefer to unmount the component after it finishes exiting.\n */\n unmountOnExit?: boolean;\n};\n\nexport type PresenceComponent<MotionParams extends Record<string, MotionParam> = {}> = {\n (props: PresenceComponentProps & MotionParams): React.ReactElement | null;\n [MOTION_DEFINITION]: PresenceMotionFn<MotionParams>;\n};\n\nfunction shouldSkipAnimation(appear: boolean | undefined, isFirstMount: boolean, visible: boolean | undefined) {\n return !appear && isFirstMount && !!visible;\n}\n\nexport function createPresenceComponent<MotionParams extends Record<string, MotionParam> = {}>(\n value: PresenceMotion | PresenceMotionFn<MotionParams>,\n): PresenceComponent<MotionParams> {\n return Object.assign(\n (props: PresenceComponentProps & MotionParams) => {\n 'use no memo';\n\n const itemContext = React.useContext(PresenceGroupChildContext);\n const merged = { ...itemContext, ...props };\n const skipMotions = useMotionBehaviourContext() === 'skip';\n\n const {\n appear,\n children,\n imperativeRef,\n onExit,\n onMotionFinish,\n onMotionStart,\n onMotionCancel,\n visible,\n unmountOnExit,\n ..._rest\n } = merged;\n const params = _rest as Exclude<typeof merged, PresenceComponentProps | typeof itemContext>;\n\n const [mounted, setMounted] = useMountedState(visible, unmountOnExit);\n const child = getChildElement(children);\n\n const handleRef = useMotionImperativeRef(imperativeRef);\n const elementRef = React.useRef<HTMLElement>();\n const ref = useMergedRefs(elementRef, child.ref);\n const optionsRef = React.useRef<{ appear?: boolean; params: MotionParams; skipMotions: boolean }>({\n appear,\n params,\n skipMotions,\n });\n\n const animateAtoms = useAnimateAtoms();\n const isFirstMount = useFirstMount();\n const isReducedMotion = useIsReducedMotion();\n\n const handleMotionStart = useEventCallback((direction: PresenceDirection) => {\n onMotionStart?.(null, { direction });\n });\n const handleMotionFinish = useEventCallback((direction: PresenceDirection) => {\n onMotionFinish?.(null, { direction });\n\n if (direction === 'exit' && unmountOnExit) {\n setMounted(false);\n onExit?.();\n }\n });\n\n const handleMotionCancel = useEventCallback((direction: PresenceDirection) => {\n onMotionCancel?.(null, { direction });\n });\n\n useIsomorphicLayoutEffect(() => {\n // Heads up!\n // We store the params in a ref to avoid re-rendering the component when the params change.\n optionsRef.current = { appear, params, skipMotions };\n });\n\n useIsomorphicLayoutEffect(\n () => {\n const element = elementRef.current;\n\n if (!element || shouldSkipAnimation(optionsRef.current.appear, isFirstMount, visible)) {\n return;\n }\n\n const presenceMotion =\n typeof value === 'function' ? value({ element, ...optionsRef.current.params }) : (value as PresenceMotion);\n const atoms = visible ? presenceMotion.enter : presenceMotion.exit;\n\n const direction: PresenceDirection = visible ? 'enter' : 'exit';\n const applyInitialStyles = !visible && isFirstMount;\n const skipAnimation = optionsRef.current.skipMotions;\n\n if (!applyInitialStyles) {\n handleMotionStart(direction);\n }\n\n const handle = animateAtoms(element, atoms, { isReducedMotion: isReducedMotion() });\n\n if (applyInitialStyles) {\n // Heads up!\n // .finish() is used in this case to skip animation and apply animation styles immediately\n handle.finish();\n return;\n }\n\n handleRef.current = handle;\n handle.setMotionEndCallbacks(\n () => handleMotionFinish(direction),\n () => handleMotionCancel(direction),\n );\n\n if (skipAnimation) {\n handle.finish();\n }\n\n return () => {\n handle.cancel();\n };\n },\n // Excluding `isFirstMount` from deps to prevent re-triggering the animation on subsequent renders\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [animateAtoms, handleRef, isReducedMotion, handleMotionFinish, handleMotionStart, handleMotionCancel, visible],\n );\n\n if (mounted) {\n return React.cloneElement(child, { ref });\n }\n\n return null;\n },\n {\n // Heads up!\n // Always normalize it to a function to simplify types\n [MOTION_DEFINITION]: typeof value === 'function' ? value : () => value,\n },\n );\n}\n"],"names":["MOTION_DEFINITION","createPresenceComponent","Symbol","shouldSkipAnimation","appear","isFirstMount","visible","value","Object","assign","props","itemContext","React","useContext","PresenceGroupChildContext","merged","skipMotions","useMotionBehaviourContext","children","imperativeRef","onExit","onMotionFinish","onMotionStart","onMotionCancel","unmountOnExit","_rest","params","mounted","setMounted","useMountedState","child","getChildElement","handleRef","useMotionImperativeRef","elementRef","useRef","ref","useMergedRefs","optionsRef","animateAtoms","useAnimateAtoms","useFirstMount","isReducedMotion","useIsReducedMotion","handleMotionStart","useEventCallback","direction","handleMotionFinish","handleMotionCancel","useIsomorphicLayoutEffect","current","element","presenceMotion","atoms","enter","exit","applyInitialStyles","skipAnimation","handle","finish","setMotionEndCallbacks","cancel","cloneElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/factories/createPresenceComponent.ts"],"sourcesContent":["import { useEventCallback, useFirstMount, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';\nimport { useAnimateAtoms } from '../hooks/useAnimateAtoms';\nimport { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';\nimport { useMountedState } from '../hooks/useMountedState';\nimport { useIsReducedMotion } from '../hooks/useIsReducedMotion';\nimport { getChildElement } from '../utils/getChildElement';\nimport type { MotionParam, PresenceMotion, MotionImperativeRef, PresenceMotionFn, PresenceDirection } from '../types';\nimport { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';\n\n/**\n * @internal A private symbol to store the motion definition on the component for variants.\n */\nexport const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');\n\nexport type PresenceComponentProps = {\n /**\n * By default, the child component won't execute the \"enter\" motion when it initially mounts, regardless of the value\n * of \"visible\". If you desire this behavior, ensure both \"appear\" and \"visible\" are set to \"true\".\n */\n appear?: boolean;\n\n /** A React element that will be cloned and will have motion effects applied to it. */\n children: React.ReactElement;\n\n /** Provides imperative controls for the animation. */\n imperativeRef?: React.Ref<MotionImperativeRef | undefined>;\n\n /**\n * Callback that is called when the whole motion finishes.\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionFinish?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion is cancelled. When a motion is cancelled it does not\n * emit a finish event but a specific cancel event\n *\n * A motion definition can contain multiple animations and therefore multiple \"finish\" events. The callback is\n * triggered once all animations have finished with \"null\" instead of an event object to avoid ambiguity.\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionCancel?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /**\n * Callback that is called when the whole motion starts.\n *\n * A motion definition can contain multiple animations and therefore multiple \"start\" events. The callback is\n * triggered when the first animation is started. There is no official \"start\" event with the Web Animations API.\n * so the callback is triggered with \"null\".\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- EventHandler<T> does not support \"null\"\n onMotionStart?: (ev: null, data: { direction: PresenceDirection }) => void;\n\n /** Defines whether a component is visible; triggers the \"enter\" or \"exit\" motions. */\n visible?: boolean;\n\n /**\n * By default, the child component remains mounted after it reaches the \"finished\" state. Set \"unmountOnExit\" if\n * you prefer to unmount the component after it finishes exiting.\n */\n unmountOnExit?: boolean;\n};\n\nexport type PresenceComponent<MotionParams extends Record<string, MotionParam> = {}> = {\n (props: PresenceComponentProps & MotionParams): React.ReactElement | null;\n [MOTION_DEFINITION]: PresenceMotionFn<MotionParams>;\n};\n\nexport function createPresenceComponent<MotionParams extends Record<string, MotionParam> = {}>(\n value: PresenceMotion | PresenceMotionFn<MotionParams>,\n): PresenceComponent<MotionParams> {\n return Object.assign(\n (props: PresenceComponentProps & MotionParams) => {\n 'use no memo';\n\n const itemContext = React.useContext(PresenceGroupChildContext);\n const merged = { ...itemContext, ...props };\n const skipMotions = useMotionBehaviourContext() === 'skip';\n\n const {\n appear,\n children,\n imperativeRef,\n onExit,\n onMotionFinish,\n onMotionStart,\n onMotionCancel,\n visible,\n unmountOnExit,\n ..._rest\n } = merged;\n const params = _rest as Exclude<typeof merged, PresenceComponentProps | typeof itemContext>;\n\n const [mounted, setMounted] = useMountedState(visible, unmountOnExit);\n const child = getChildElement(children);\n\n const handleRef = useMotionImperativeRef(imperativeRef);\n const elementRef = React.useRef<HTMLElement>();\n const ref = useMergedRefs(elementRef, child.ref);\n const optionsRef = React.useRef<{ appear?: boolean; params: MotionParams; skipMotions: boolean }>({\n appear,\n params,\n skipMotions,\n });\n\n const animateAtoms = useAnimateAtoms();\n const isFirstMount = useFirstMount();\n const isReducedMotion = useIsReducedMotion();\n\n const handleMotionStart = useEventCallback((direction: PresenceDirection) => {\n onMotionStart?.(null, { direction });\n });\n const handleMotionFinish = useEventCallback((direction: PresenceDirection) => {\n onMotionFinish?.(null, { direction });\n\n if (direction === 'exit' && unmountOnExit) {\n setMounted(false);\n onExit?.();\n }\n });\n\n const handleMotionCancel = useEventCallback((direction: PresenceDirection) => {\n onMotionCancel?.(null, { direction });\n });\n\n useIsomorphicLayoutEffect(() => {\n // Heads up!\n // We store the params in a ref to avoid re-rendering the component when the params change.\n optionsRef.current = { appear, params, skipMotions };\n });\n\n useIsomorphicLayoutEffect(\n () => {\n const element = elementRef.current;\n\n if (!element) {\n return;\n }\n\n const presenceMotion =\n typeof value === 'function' ? value({ element, ...optionsRef.current.params }) : (value as PresenceMotion);\n\n const atoms = visible ? presenceMotion.enter : presenceMotion.exit;\n const direction: PresenceDirection = visible ? 'enter' : 'exit';\n\n // Heads up!\n // Initial styles are applied when the component is mounted for the first time and \"appear\" is set to \"false\" (otherwise animations are triggered)\n const applyInitialStyles = !optionsRef.current.appear && isFirstMount;\n const skipAnimationByConfig = optionsRef.current.skipMotions;\n\n if (!applyInitialStyles) {\n handleMotionStart(direction);\n }\n\n const handle = animateAtoms(element, atoms, { isReducedMotion: isReducedMotion() });\n\n if (applyInitialStyles) {\n // Heads up!\n // .finish() is used in this case to skip animation and apply animation styles immediately\n handle.finish();\n return;\n }\n\n handleRef.current = handle;\n handle.setMotionEndCallbacks(\n () => handleMotionFinish(direction),\n () => handleMotionCancel(direction),\n );\n\n if (skipAnimationByConfig) {\n handle.finish();\n }\n\n return () => {\n handle.cancel();\n };\n },\n // Excluding `isFirstMount` from deps to prevent re-triggering the animation on subsequent renders\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [animateAtoms, handleRef, isReducedMotion, handleMotionFinish, handleMotionStart, handleMotionCancel, visible],\n );\n\n if (mounted) {\n return React.cloneElement(child, { ref });\n }\n\n return null;\n },\n {\n // Heads up!\n // Always normalize it to a function to simplify types\n [MOTION_DEFINITION]: typeof value === 'function' ? value : () => value,\n },\n );\n}\n"],"names":["MOTION_DEFINITION","createPresenceComponent","Symbol","value","Object","assign","props","itemContext","React","useContext","PresenceGroupChildContext","merged","skipMotions","useMotionBehaviourContext","appear","children","imperativeRef","onExit","onMotionFinish","onMotionStart","onMotionCancel","visible","unmountOnExit","_rest","params","mounted","setMounted","useMountedState","child","getChildElement","handleRef","useMotionImperativeRef","elementRef","useRef","ref","useMergedRefs","optionsRef","animateAtoms","useAnimateAtoms","isFirstMount","useFirstMount","isReducedMotion","useIsReducedMotion","handleMotionStart","useEventCallback","direction","handleMotionFinish","handleMotionCancel","useIsomorphicLayoutEffect","current","element","presenceMotion","atoms","enter","exit","applyInitialStyles","skipAnimationByConfig","handle","finish","setMotionEndCallbacks","cancel","cloneElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-motion",
3
- "version": "9.6.7",
3
+ "version": "9.6.9",
4
4
  "description": "A package with utilities & motion definitions using Web Animations API",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -25,8 +25,8 @@
25
25
  "@fluentui/scripts-cypress": "*"
26
26
  },
27
27
  "dependencies": {
28
- "@fluentui/react-shared-contexts": "^9.21.2",
29
- "@fluentui/react-utilities": "^9.18.20",
28
+ "@fluentui/react-shared-contexts": "^9.23.0",
29
+ "@fluentui/react-utilities": "^9.18.22",
30
30
  "@swc/helpers": "^0.5.1",
31
31
  "react-is": "^17.0.2"
32
32
  },