Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
import { _ as _define_property } from "@swc/helpers/_/_define_property";
import * as React from 'react';
import { getNextChildMapping } from '../utils/groups/getNextChildMapping';
import { getChildMapping } from '../utils/groups/getChildMapping';
import { PresenceGroupItemProvider } from './PresenceGroupItemProvider';
/* eslint-disable @typescript-eslint/explicit-member-accessibility */ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/member-ordering */ export class PresenceGroup extends React.Component {
static getDerivedStateFromProps(nextProps, { childMapping: prevChildMapping, firstRender }) {
const nextChildMapping = getChildMapping(nextProps.children);
return {
childMapping: firstRender ? nextChildMapping : getNextChildMapping(prevChildMapping, nextChildMapping),
firstRender: false
};
}
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
render() {
return /*#__PURE__*/ React.createElement(React.Fragment, null, Object.entries(this.state.childMapping).map(([childKey, childProps])=>/*#__PURE__*/ React.createElement(PresenceGroupItemProvider, {
...childProps,
childKey: childKey,
key: childKey,
onExit: this.handleExit
}, childProps.element)));
}
constructor(props, context){
super(props, context);
_define_property(this, "mounted", false);
_define_property(this, "handleExit", (childKey)=>{
const currentChildMapping = getChildMapping(this.props.children);
if (childKey in currentChildMapping) {
return;
}
if (this.mounted) {
this.setState((state)=>{
const childMapping = {
...state.childMapping
};
delete childMapping[childKey];
return {
childMapping
};
});
}
});
this.state = {
childMapping: {},
firstRender: true
};
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/PresenceGroup.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { getNextChildMapping } from '../utils/groups/getNextChildMapping';\nimport { getChildMapping } from '../utils/groups/getChildMapping';\nimport type { PresenceGroupChildMapping } from '../utils/groups/types';\nimport { PresenceGroupItemProvider } from './PresenceGroupItemProvider';\n\ntype PresenceGroupProps = {\n children: React.ReactNode;\n};\n\ntype PresenceGroupState = {\n childMapping: PresenceGroupChildMapping;\n firstRender: boolean;\n};\n\n/* eslint-disable @typescript-eslint/explicit-member-accessibility */\n/* eslint-disable @typescript-eslint/naming-convention */\n/* eslint-disable @typescript-eslint/member-ordering */\n\nexport class PresenceGroup extends React.Component<PresenceGroupProps, PresenceGroupState> {\n private mounted: boolean = false;\n\n static getDerivedStateFromProps(\n nextProps: PresenceGroupProps,\n { childMapping: prevChildMapping, firstRender }: PresenceGroupState,\n ) {\n const nextChildMapping = getChildMapping(nextProps.children);\n\n return {\n childMapping: firstRender ? nextChildMapping : getNextChildMapping(prevChildMapping, nextChildMapping),\n firstRender: false,\n };\n }\n\n constructor(props: PresenceGroupProps, context: unknown) {\n super(props, context);\n\n this.state = {\n childMapping: {},\n firstRender: true,\n };\n }\n\n private handleExit = (childKey: string) => {\n const currentChildMapping = getChildMapping(this.props.children);\n\n if (childKey in currentChildMapping) {\n return;\n }\n\n if (this.mounted) {\n this.setState(state => {\n const childMapping = { ...state.childMapping };\n delete childMapping[childKey];\n\n return { childMapping };\n });\n }\n };\n\n componentDidMount() {\n this.mounted = true;\n }\n\n componentWillUnmount() {\n this.mounted = false;\n }\n\n render() {\n return (\n <>\n {Object.entries(this.state.childMapping).map(([childKey, childProps]) => (\n <PresenceGroupItemProvider {...childProps} childKey={childKey} key={childKey} onExit={this.handleExit}>\n {childProps.element}\n </PresenceGroupItemProvider>\n ))}\n </>\n );\n }\n}\n"],"names":["React","getNextChildMapping","getChildMapping","PresenceGroupItemProvider","PresenceGroup","Component","getDerivedStateFromProps","nextProps","childMapping","prevChildMapping","firstRender","nextChildMapping","children","componentDidMount","mounted","componentWillUnmount","render","Object","entries","state","map","childKey","childProps","key","onExit","handleExit","element","constructor","props","context","currentChildMapping","setState"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";AAAA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,mBAAmB,QAAQ,sCAAsC;AAC1E,SAASC,eAAe,QAAQ,kCAAkC;AAElE,SAASC,yBAAyB,QAAQ,8BAA8B;AAWxE,mEAAmE,GACnE,uDAAuD,GACvD,qDAAqD,GAErD,OAAO,MAAMC,sBAAsBJ,MAAMK,SAAS;IAGhD,OAAOC,yBACLC,SAA6B,EAC7B,EAAEC,cAAcC,gBAAgB,EAAEC,WAAW,EAAsB,EACnE;QACA,MAAMC,mBAAmBT,gBAAgBK,UAAUK,QAAQ;QAE3D,OAAO;YACLJ,cAAcE,cAAcC,mBAAmBV,oBAAoBQ,kBAAkBE;YACrFD,aAAa;QACf;IACF;IA4BAG,oBAAoB;QAClB,IAAI,CAACC,OAAO,GAAG;IACjB;IAEAC,uBAAuB;QACrB,IAAI,CAACD,OAAO,GAAG;IACjB;IAEAE,SAAS;QACP,qBACE,0CACGC,OAAOC,OAAO,CAAC,IAAI,CAACC,KAAK,CAACX,YAAY,EAAEY,GAAG,CAAC,CAAC,CAACC,UAAUC,WAAW,iBAClE,oBAACnB;gBAA2B,GAAGmB,UAAU;gBAAED,UAAUA;gBAAUE,KAAKF;gBAAUG,QAAQ,IAAI,CAACC,UAAU;eAClGH,WAAWI,OAAO;IAK7B;IA5CAC,YAAYC,KAAyB,EAAEC,OAAgB,CAAE;QACvD,KAAK,CAACD,OAAOC;QAff,uBAAQf,WAAmB;QAuB3B,uBAAQW,cAAa,CAACJ;YACpB,MAAMS,sBAAsB5B,gBAAgB,IAAI,CAAC0B,KAAK,CAAChB,QAAQ;YAE/D,IAAIS,YAAYS,qBAAqB;gBACnC;YACF;YAEA,IAAI,IAAI,CAAChB,OAAO,EAAE;gBAChB,IAAI,CAACiB,QAAQ,CAACZ,CAAAA;oBACZ,MAAMX,eAAe;wBAAE,GAAGW,MAAMX,YAAY;oBAAC;oBAC7C,OAAOA,YAAY,CAACa,SAAS;oBAE7B,OAAO;wBAAEb;oBAAa;gBACxB;YACF;QACF;QArBE,IAAI,CAACW,KAAK,GAAG;YACXX,cAAc,CAAC;YACfE,aAAa;QACf;IACF;AAsCF"}
@@ -0,0 +1,25 @@
import * as React from 'react';
import { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';
/**
* @internal
*
* Provides context for a single child of a `PresenceGroup`. Exists only to make a stable context value for a child.
* Not intended for direct use.
*/ export const PresenceGroupItemProvider = (props)=>{
const { appear, childKey, onExit, visible, unmountOnExit } = props;
const contextValue = React.useMemo(()=>({
appear,
visible,
onExit: ()=>onExit(childKey),
unmountOnExit
}), [
appear,
childKey,
onExit,
visible,
unmountOnExit
]);
return /*#__PURE__*/ React.createElement(PresenceGroupChildContext.Provider, {
value: contextValue
}, props.children);
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/PresenceGroupItemProvider.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';\nimport type { PresenceGroupChildContextValue } from '../contexts/PresenceGroupChildContext';\n\ntype PresenceGroupItemProviderProps = Omit<PresenceGroupChildContextValue, 'onExit'> & {\n children: React.ReactElement;\n childKey: string;\n // That's an internal callback, so we don't need to enforce the type here\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onExit: (childKey: string) => void;\n};\n\n/**\n * @internal\n *\n * Provides context for a single child of a `PresenceGroup`. Exists only to make a stable context value for a child.\n * Not intended for direct use.\n */\nexport const PresenceGroupItemProvider: React.FC<PresenceGroupItemProviderProps> = props => {\n const { appear, childKey, onExit, visible, unmountOnExit } = props;\n const contextValue = React.useMemo(\n () => ({\n appear,\n visible,\n onExit: () => onExit(childKey),\n unmountOnExit,\n }),\n [appear, childKey, onExit, visible, unmountOnExit],\n );\n\n return <PresenceGroupChildContext.Provider value={contextValue}>{props.children}</PresenceGroupChildContext.Provider>;\n};\n"],"names":["React","PresenceGroupChildContext","PresenceGroupItemProvider","props","appear","childKey","onExit","visible","unmountOnExit","contextValue","useMemo","Provider","value","children"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,yBAAyB,QAAQ,wCAAwC;AAWlF;;;;;CAKC,GACD,OAAO,MAAMC,4BAAsEC,CAAAA;IACjF,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,OAAO,EAAEC,aAAa,EAAE,GAAGL;IAC7D,MAAMM,eAAeT,MAAMU,OAAO,CAChC,IAAO,CAAA;YACLN;YACAG;YACAD,QAAQ,IAAMA,OAAOD;YACrBG;QACF,CAAA,GACA;QAACJ;QAAQC;QAAUC;QAAQC;QAASC;KAAc;IAGpD,qBAAO,oBAACP,0BAA0BU,QAAQ;QAACC,OAAOH;OAAeN,MAAMU,QAAQ;AACjF,EAAE"}
@@ -0,0 +1,7 @@
import * as React from 'react';
const MotionBehaviourContext = React.createContext(undefined);
export const MotionBehaviourProvider = MotionBehaviourContext.Provider;
export const useMotionBehaviourContext = ()=>{
var _React_useContext;
return (_React_useContext = React.useContext(MotionBehaviourContext)) !== null && _React_useContext !== void 0 ? _React_useContext : 'default';
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/contexts/MotionBehaviourContext.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * Specifies the behaviour of child motion component under @see MotionBehaviourProvider.\n */\nexport type MotionBehaviourType = 'skip' | 'default';\n\nconst MotionBehaviourContext = React.createContext<MotionBehaviourType | undefined>(undefined);\n\nexport const MotionBehaviourProvider = MotionBehaviourContext.Provider;\nexport const useMotionBehaviourContext = () => React.useContext(MotionBehaviourContext) ?? 'default';\n"],"names":["React","MotionBehaviourContext","createContext","undefined","MotionBehaviourProvider","Provider","useMotionBehaviourContext","useContext"],"rangeMappings":";;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAO/B,MAAMC,yBAAyBD,MAAME,aAAa,CAAkCC;AAEpF,OAAO,MAAMC,0BAA0BH,uBAAuBI,QAAQ,CAAC;AACvE,OAAO,MAAMC,4BAA4B;QAAMN;WAAAA,CAAAA,oBAAAA,MAAMO,UAAU,CAACN,qCAAjBD,+BAAAA,oBAA4C;AAAQ,EAAE"}
@@ -0,0 +1,4 @@
import * as React from 'react';
/**
* @internal
*/ export const PresenceGroupChildContext = React.createContext(undefined);
@@ -0,0 +1 @@
{"version":3,"sources":["../src/contexts/PresenceGroupChildContext.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * @internal\n */\nexport type PresenceGroupChildContextValue = {\n appear: boolean;\n visible: boolean;\n unmountOnExit: boolean;\n\n onExit: () => void;\n};\n\n/**\n * @internal\n */\nexport const PresenceGroupChildContext = React.createContext<PresenceGroupChildContextValue | undefined>(undefined);\n"],"names":["React","PresenceGroupChildContext","createContext","undefined"],"rangeMappings":";;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAa/B;;CAEC,GACD,OAAO,MAAMC,4BAA4BD,MAAME,aAAa,CAA6CC,WAAW"}
@@ -0,0 +1,77 @@
import { useEventCallback, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';
import * as React from 'react';
import { useAnimateAtoms } from '../hooks/useAnimateAtoms';
import { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';
import { useIsReducedMotion } from '../hooks/useIsReducedMotion';
import { getChildElement } from '../utils/getChildElement';
import { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';
/**
* Creates a component that will animate the children using the provided motion.
*
* @param value - A motion definition.
*/ export function createMotionComponent(value) {
const Atom = (props)=>{
'use no memo';
const { children, imperativeRef, onMotionFinish: onMotionFinishProp, onMotionStart: onMotionStartProp, onMotionCancel: onMotionCancelProp, ..._rest } = props;
const params = _rest;
const child = getChildElement(children);
const handleRef = useMotionImperativeRef(imperativeRef);
const elementRef = React.useRef();
const skipMotions = useMotionBehaviourContext() === 'skip';
const optionsRef = React.useRef({
skipMotions,
params
});
const animateAtoms = useAnimateAtoms();
const isReducedMotion = useIsReducedMotion();
const onMotionStart = useEventCallback(()=>{
onMotionStartProp === null || onMotionStartProp === void 0 ? void 0 : onMotionStartProp(null);
});
const onMotionFinish = useEventCallback(()=>{
onMotionFinishProp === null || onMotionFinishProp === void 0 ? void 0 : onMotionFinishProp(null);
});
const onMotionCancel = useEventCallback(()=>{
onMotionCancelProp === null || onMotionCancelProp === void 0 ? void 0 : onMotionCancelProp(null);
});
useIsomorphicLayoutEffect(()=>{
// Heads up!
// We store the params in a ref to avoid re-rendering the component when the params change.
optionsRef.current = {
skipMotions,
params
};
});
useIsomorphicLayoutEffect(()=>{
const element = elementRef.current;
if (element) {
const atoms = typeof value === 'function' ? value({
element,
...optionsRef.current.params
}) : value;
onMotionStart();
const handle = animateAtoms(element, atoms, {
isReducedMotion: isReducedMotion()
});
handleRef.current = handle;
handle.setMotionEndCallbacks(onMotionFinish, onMotionCancel);
if (optionsRef.current.skipMotions) {
handle.finish();
}
return ()=>{
handle.cancel();
};
}
}, [
animateAtoms,
handleRef,
isReducedMotion,
onMotionFinish,
onMotionStart,
onMotionCancel
]);
return React.cloneElement(children, {
ref: useMergedRefs(elementRef, child.ref)
});
};
return Atom;
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,123 @@
import { useEventCallback, useFirstMount, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';
import * as React from 'react';
import { PresenceGroupChildContext } from '../contexts/PresenceGroupChildContext';
import { useAnimateAtoms } from '../hooks/useAnimateAtoms';
import { useMotionImperativeRef } from '../hooks/useMotionImperativeRef';
import { useMountedState } from '../hooks/useMountedState';
import { useIsReducedMotion } from '../hooks/useIsReducedMotion';
import { getChildElement } from '../utils/getChildElement';
import { useMotionBehaviourContext } from '../contexts/MotionBehaviourContext';
/**
* @internal A private symbol to store the motion definition on the component for variants.
*/ export const MOTION_DEFINITION = Symbol('MOTION_DEFINITION');
function shouldSkipAnimation(appear, isFirstMount, visible) {
return !appear && isFirstMount && !!visible;
}
export function createPresenceComponent(value) {
return Object.assign((props)=>{
'use no memo';
const itemContext = React.useContext(PresenceGroupChildContext);
const merged = {
...itemContext,
...props
};
const skipMotions = useMotionBehaviourContext() === 'skip';
const { appear, children, imperativeRef, onExit, onMotionFinish, onMotionStart, onMotionCancel, visible, unmountOnExit, ..._rest } = merged;
const params = _rest;
const [mounted, setMounted] = useMountedState(visible, unmountOnExit);
const child = getChildElement(children);
const handleRef = useMotionImperativeRef(imperativeRef);
const elementRef = React.useRef();
const ref = useMergedRefs(elementRef, child.ref);
const optionsRef = React.useRef({
appear,
params,
skipMotions
});
const animateAtoms = useAnimateAtoms();
const isFirstMount = useFirstMount();
const isReducedMotion = useIsReducedMotion();
const handleMotionStart = useEventCallback((direction)=>{
onMotionStart === null || onMotionStart === void 0 ? void 0 : onMotionStart(null, {
direction
});
});
const handleMotionFinish = useEventCallback((direction)=>{
onMotionFinish === null || onMotionFinish === void 0 ? void 0 : onMotionFinish(null, {
direction
});
if (direction === 'exit' && unmountOnExit) {
setMounted(false);
onExit === null || onExit === void 0 ? void 0 : onExit();
}
});
const handleMotionCancel = useEventCallback((direction)=>{
onMotionCancel === null || onMotionCancel === void 0 ? void 0 : onMotionCancel(null, {
direction
});
});
useIsomorphicLayoutEffect(()=>{
// Heads up!
// We store the params in a ref to avoid re-rendering the component when the params change.
optionsRef.current = {
appear,
params,
skipMotions
};
});
useIsomorphicLayoutEffect(()=>{
const element = elementRef.current;
if (!element || shouldSkipAnimation(optionsRef.current.appear, isFirstMount, visible)) {
return;
}
const presenceMotion = typeof value === 'function' ? value({
element,
...optionsRef.current.params
}) : value;
const atoms = visible ? presenceMotion.enter : presenceMotion.exit;
const direction = visible ? 'enter' : 'exit';
const applyInitialStyles = !visible && isFirstMount;
const skipAnimation = optionsRef.current.skipMotions;
if (!applyInitialStyles) {
handleMotionStart(direction);
}
const handle = animateAtoms(element, atoms, {
isReducedMotion: isReducedMotion()
});
if (applyInitialStyles) {
// Heads up!
// .finish() is used in this case to skip animation and apply animation styles immediately
handle.finish();
return;
}
handleRef.current = handle;
handle.setMotionEndCallbacks(()=>handleMotionFinish(direction), ()=>handleMotionCancel(direction));
if (skipAnimation) {
handle.finish();
}
return ()=>{
handle.cancel();
};
}, // Excluding `isFirstMount` from deps to prevent re-triggering the animation on subsequent renders
// eslint-disable-next-line react-hooks/exhaustive-deps
[
animateAtoms,
handleRef,
isReducedMotion,
handleMotionFinish,
handleMotionStart,
handleMotionCancel,
visible
]);
if (mounted) {
return React.cloneElement(child, {
ref
});
}
return null;
}, {
// Heads up!
// Always normalize it to a function to simplify types
[MOTION_DEFINITION]: typeof value === 'function' ? value : ()=>value
});
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
import { MOTION_DEFINITION, createPresenceComponent } from './createPresenceComponent';
/**
* @internal
*/ export function overridePresenceMotion(presenceMotion, override) {
return (...args)=>{
const { enter, exit } = presenceMotion(...args);
return {
enter: {
...enter,
...override.all,
...override.enter
},
exit: {
...exit,
...override.all,
...override.exit
}
};
};
}
export function createPresenceComponentVariant(component, override) {
return createPresenceComponent(overridePresenceMotion(component[MOTION_DEFINITION], override));
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/factories/createPresenceComponentVariant.ts"],"sourcesContent":["import type { MotionParam, PresenceDirection, PresenceMotionFn } from '../types';\nimport { MOTION_DEFINITION, createPresenceComponent, PresenceComponent } from './createPresenceComponent';\n\n/**\n * @internal\n */\ntype PresenceOverrideFields = {\n duration: KeyframeEffectOptions['duration'];\n easing: KeyframeEffectOptions['easing'];\n};\n\n/**\n * @internal\n *\n * Override properties for presence transitions.\n *\n * @example <caption>Override duration for all transitions</caption>\n * ```\n * const override: PresenceOverride = {\n * all: { duration: 1000 },\n * };\n * ```\n *\n * @example <caption>Override easing for exit transition</caption>\n * ```\n * const override: PresenceOverride = {\n * exit: { easing: 'ease-out' },\n * };\n * ```\n */\ntype PresenceOverride = Partial<Record<PresenceDirection | 'all', Partial<PresenceOverrideFields>>>;\n\n/**\n * @internal\n */\nexport function overridePresenceMotion<MotionParams extends Record<string, MotionParam> = {}>(\n presenceMotion: PresenceMotionFn<MotionParams>,\n override: PresenceOverride,\n): PresenceMotionFn<MotionParams> {\n return (...args: Parameters<PresenceMotionFn<MotionParams>>) => {\n const { enter, exit } = presenceMotion(...args);\n\n return {\n enter: { ...enter, ...override.all, ...override.enter },\n exit: { ...exit, ...override.all, ...override.exit },\n };\n };\n}\n\nexport function createPresenceComponentVariant<MotionParams extends Record<string, MotionParam> = {}>(\n component: PresenceComponent<MotionParams>,\n override: PresenceOverride,\n): PresenceComponent<MotionParams> {\n return createPresenceComponent(overridePresenceMotion(component[MOTION_DEFINITION], override));\n}\n"],"names":["MOTION_DEFINITION","createPresenceComponent","overridePresenceMotion","presenceMotion","override","args","enter","exit","all","createPresenceComponentVariant","component"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,iBAAiB,EAAEC,uBAAuB,QAA2B,4BAA4B;AA+B1G;;CAEC,GACD,OAAO,SAASC,uBACdC,cAA8C,EAC9CC,QAA0B;IAE1B,OAAO,CAAC,GAAGC;QACT,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGJ,kBAAkBE;QAE1C,OAAO;YACLC,OAAO;gBAAE,GAAGA,KAAK;gBAAE,GAAGF,SAASI,GAAG;gBAAE,GAAGJ,SAASE,KAAK;YAAC;YACtDC,MAAM;gBAAE,GAAGA,IAAI;gBAAE,GAAGH,SAASI,GAAG;gBAAE,GAAGJ,SAASG,IAAI;YAAC;QACrD;IACF;AACF;AAEA,OAAO,SAASE,+BACdC,SAA0C,EAC1CN,QAA0B;IAE1B,OAAOH,wBAAwBC,uBAAuBQ,SAAS,CAACV,kBAAkB,EAAEI;AACtF"}
+142
View File
@@ -0,0 +1,142 @@
import * as React from 'react';
export const DEFAULT_ANIMATION_OPTIONS = {
fill: 'forwards'
};
// A motion atom's default reduced motion is a simple 1 ms duration.
// But an atom can define a custom reduced motion, overriding keyframes and/or params like duration, easing, iterations, etc.
const DEFAULT_REDUCED_MOTION_ATOM = {
duration: 1
};
function useAnimateAtomsInSupportedEnvironment() {
var _window_Animation;
// eslint-disable-next-line @nx/workspace-no-restricted-globals
const SUPPORTS_PERSIST = typeof window !== 'undefined' && typeof ((_window_Animation = window.Animation) === null || _window_Animation === void 0 ? void 0 : _window_Animation.prototype.persist) === 'function';
return React.useCallback((element, value, options)=>{
const atoms = Array.isArray(value) ? value : [
value
];
const { isReducedMotion } = options;
const animations = atoms.map((motion)=>{
// Grab the custom reduced motion definition if it exists, or fall back to the default reduced motion.
const { keyframes: motionKeyframes, reducedMotion = DEFAULT_REDUCED_MOTION_ATOM, ...params } = motion;
// Grab the reduced motion keyframes if they exist, or fall back to the regular keyframes.
const { keyframes: reducedMotionKeyframes = motionKeyframes, ...reducedMotionParams } = reducedMotion;
const animationKeyframes = isReducedMotion ? reducedMotionKeyframes : motionKeyframes;
const animationParams = {
...DEFAULT_ANIMATION_OPTIONS,
...params,
// Use reduced motion overrides (e.g. duration, easing) when reduced motion is enabled
...isReducedMotion && reducedMotionParams
};
const animation = element.animate(animationKeyframes, animationParams);
if (SUPPORTS_PERSIST) {
animation.persist();
} else {
const resultKeyframe = animationKeyframes[animationKeyframes.length - 1];
var _element_style;
Object.assign((_element_style = element.style) !== null && _element_style !== void 0 ? _element_style : {}, resultKeyframe);
}
return animation;
});
return {
set playbackRate (rate){
animations.forEach((animation)=>{
animation.playbackRate = rate;
});
},
setMotionEndCallbacks (onfinish, oncancel) {
// Heads up!
// This could use "Animation:finished", but it's causing a memory leak in Chromium.
// See: https://issues.chromium.org/u/2/issues/383016426
const promises = animations.map((animation)=>{
return new Promise((resolve, reject)=>{
animation.onfinish = ()=>resolve();
animation.oncancel = ()=>reject();
});
});
Promise.all(promises).then(()=>{
onfinish();
}).catch(()=>{
oncancel();
});
},
cancel: ()=>{
animations.forEach((animation)=>{
animation.cancel();
});
},
pause: ()=>{
animations.forEach((animation)=>{
animation.pause();
});
},
play: ()=>{
animations.forEach((animation)=>{
animation.play();
});
},
finish: ()=>{
animations.forEach((animation)=>{
animation.finish();
});
}
};
}, [
SUPPORTS_PERSIST
]);
}
/**
* In test environments, this hook is used to delay the execution of a callback until the next render. This is necessary
* to ensure that the callback is not executed synchronously, which would cause the test to fail.
*
* @see https://github.com/microsoft/fluentui/issues/31701
*/ function useAnimateAtomsInTestEnvironment() {
const [count, setCount] = React.useState(0);
const callbackRef = React.useRef();
const realAnimateAtoms = useAnimateAtomsInSupportedEnvironment();
React.useEffect(()=>{
if (count > 0) {
var _callbackRef_current;
(_callbackRef_current = callbackRef.current) === null || _callbackRef_current === void 0 ? void 0 : _callbackRef_current.call(callbackRef);
}
}, [
count
]);
return React.useCallback((element, value, options)=>{
const ELEMENT_SUPPORTS_WEB_ANIMATIONS = typeof element.animate === 'function';
// Heads up!
// If the environment supports Web Animations API, we can use the native implementation.
if (ELEMENT_SUPPORTS_WEB_ANIMATIONS) {
return realAnimateAtoms(element, value, options);
}
return {
setMotionEndCallbacks (onfinish) {
callbackRef.current = onfinish;
setCount((v)=>v + 1);
},
set playbackRate (rate){
/* no-op */ },
cancel () {
/* no-op */ },
pause () {
/* no-op */ },
play () {
/* no-op */ },
finish () {
/* no-op */ }
};
}, [
realAnimateAtoms
]);
}
/**
* @internal
*/ export function useAnimateAtoms() {
'use no memo';
if (process.env.NODE_ENV === 'test') {
// eslint-disable-next-line react-hooks/rules-of-hooks
return useAnimateAtomsInTestEnvironment();
}
// eslint-disable-next-line react-hooks/rules-of-hooks
return useAnimateAtomsInSupportedEnvironment();
}
File diff suppressed because one or more lines are too long
+31
View File
@@ -0,0 +1,31 @@
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
import * as React from 'react';
const REDUCED_MEDIA_QUERY = 'screen and (prefers-reduced-motion: reduce)';
// TODO: find a better approach there as each hook creates a separate subscription
export function useIsReducedMotion() {
const { targetDocument } = useFluent();
var _targetDocument_defaultView;
const targetWindow = (_targetDocument_defaultView = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) !== null && _targetDocument_defaultView !== void 0 ? _targetDocument_defaultView : null;
const queryValue = React.useRef(false);
const isEnabled = React.useCallback(()=>queryValue.current, []);
useIsomorphicLayoutEffect(()=>{
if (targetWindow === null || typeof targetWindow.matchMedia !== 'function') {
return;
}
const queryMatch = targetWindow.matchMedia(REDUCED_MEDIA_QUERY);
if (queryMatch.matches) {
queryValue.current = true;
}
const matchListener = (e)=>{
queryValue.current = e.matches;
};
queryMatch.addEventListener('change', matchListener);
return ()=>{
queryMatch.removeEventListener('change', matchListener);
};
}, [
targetWindow
]);
return isEnabled;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useIsReducedMotion.ts"],"sourcesContent":["import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nconst REDUCED_MEDIA_QUERY = 'screen and (prefers-reduced-motion: reduce)';\n\n// TODO: find a better approach there as each hook creates a separate subscription\n\nexport function useIsReducedMotion(): () => boolean {\n const { targetDocument } = useFluent();\n const targetWindow: Window | null = targetDocument?.defaultView ?? null;\n\n const queryValue = React.useRef<boolean>(false);\n const isEnabled = React.useCallback(() => queryValue.current, []);\n\n useIsomorphicLayoutEffect(() => {\n if (targetWindow === null || typeof targetWindow.matchMedia !== 'function') {\n return;\n }\n\n const queryMatch = targetWindow.matchMedia(REDUCED_MEDIA_QUERY);\n\n if (queryMatch.matches) {\n queryValue.current = true;\n }\n\n const matchListener = (e: MediaQueryListEvent) => {\n queryValue.current = e.matches;\n };\n\n queryMatch.addEventListener('change', matchListener);\n\n return () => {\n queryMatch.removeEventListener('change', matchListener);\n };\n }, [targetWindow]);\n\n return isEnabled;\n}\n"],"names":["useFluent_unstable","useFluent","useIsomorphicLayoutEffect","React","REDUCED_MEDIA_QUERY","useIsReducedMotion","targetDocument","targetWindow","defaultView","queryValue","useRef","isEnabled","useCallback","current","matchMedia","queryMatch","matches","matchListener","e","addEventListener","removeEventListener"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,yBAAyB,QAAQ,4BAA4B;AACtE,YAAYC,WAAW,QAAQ;AAE/B,MAAMC,sBAAsB;AAE5B,kFAAkF;AAElF,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGL;QACSK;IAApC,MAAMC,eAA8BD,CAAAA,8BAAAA,2BAAAA,qCAAAA,eAAgBE,WAAW,cAA3BF,yCAAAA,8BAA+B;IAEnE,MAAMG,aAAaN,MAAMO,MAAM,CAAU;IACzC,MAAMC,YAAYR,MAAMS,WAAW,CAAC,IAAMH,WAAWI,OAAO,EAAE,EAAE;IAEhEX,0BAA0B;QACxB,IAAIK,iBAAiB,QAAQ,OAAOA,aAAaO,UAAU,KAAK,YAAY;YAC1E;QACF;QAEA,MAAMC,aAAaR,aAAaO,UAAU,CAACV;QAE3C,IAAIW,WAAWC,OAAO,EAAE;YACtBP,WAAWI,OAAO,GAAG;QACvB;QAEA,MAAMI,gBAAgB,CAACC;YACrBT,WAAWI,OAAO,GAAGK,EAAEF,OAAO;QAChC;QAEAD,WAAWI,gBAAgB,CAAC,UAAUF;QAEtC,OAAO;YACLF,WAAWK,mBAAmB,CAAC,UAAUH;QAC3C;IACF,GAAG;QAACV;KAAa;IAEjB,OAAOI;AACT"}
@@ -0,0 +1,22 @@
import * as React from 'react';
export function useMotionImperativeRef(imperativeRef) {
const animationRef = React.useRef();
React.useImperativeHandle(imperativeRef, ()=>({
setPlayState: (state)=>{
if (state === 'running') {
var _animationRef_current;
(_animationRef_current = animationRef.current) === null || _animationRef_current === void 0 ? void 0 : _animationRef_current.play();
}
if (state === 'paused') {
var _animationRef_current1;
(_animationRef_current1 = animationRef.current) === null || _animationRef_current1 === void 0 ? void 0 : _animationRef_current1.pause();
}
},
setPlaybackRate: (rate)=>{
if (animationRef.current) {
animationRef.current.playbackRate = rate;
}
}
}));
return animationRef;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useMotionImperativeRef.ts"],"sourcesContent":["import * as React from 'react';\nimport type { AnimationHandle, MotionImperativeRef } from '../types';\n\nexport function useMotionImperativeRef(imperativeRef: React.Ref<MotionImperativeRef | undefined> | undefined) {\n const animationRef = React.useRef<AnimationHandle | undefined>();\n\n React.useImperativeHandle(imperativeRef, () => ({\n setPlayState: state => {\n if (state === 'running') {\n animationRef.current?.play();\n }\n\n if (state === 'paused') {\n animationRef.current?.pause();\n }\n },\n setPlaybackRate: rate => {\n if (animationRef.current) {\n animationRef.current.playbackRate = rate;\n }\n },\n }));\n\n return animationRef;\n}\n"],"names":["React","useMotionImperativeRef","imperativeRef","animationRef","useRef","useImperativeHandle","setPlayState","state","current","play","pause","setPlaybackRate","rate","playbackRate"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAG/B,OAAO,SAASC,uBAAuBC,aAAqE;IAC1G,MAAMC,eAAeH,MAAMI,MAAM;IAEjCJ,MAAMK,mBAAmB,CAACH,eAAe,IAAO,CAAA;YAC9CI,cAAcC,CAAAA;gBACZ,IAAIA,UAAU,WAAW;wBACvBJ;qBAAAA,wBAAAA,aAAaK,OAAO,cAApBL,4CAAAA,sBAAsBM,IAAI;gBAC5B;gBAEA,IAAIF,UAAU,UAAU;wBACtBJ;qBAAAA,yBAAAA,aAAaK,OAAO,cAApBL,6CAAAA,uBAAsBO,KAAK;gBAC7B;YACF;YACAC,iBAAiBC,CAAAA;gBACf,IAAIT,aAAaK,OAAO,EAAE;oBACxBL,aAAaK,OAAO,CAACK,YAAY,GAAGD;gBACtC;YACF;QACF,CAAA;IAEA,OAAOT;AACT"}
+26
View File
@@ -0,0 +1,26 @@
import { useForceUpdate } from '@fluentui/react-utilities';
import * as React from 'react';
/**
* This hook manages the mounted state of a component, based on the "visible" and "unmountOnExit" props.
* It simulates the behavior of getDerivedStateFromProps(), which is not available in functional components.
*/ export function useMountedState(visible = false, unmountOnExit = false) {
const mountedRef = React.useRef(unmountOnExit ? visible : true);
const forceUpdate = useForceUpdate();
const setMounted = React.useCallback((newValue)=>{
if (mountedRef.current !== newValue) {
mountedRef.current = newValue;
forceUpdate();
}
}, [
forceUpdate
]);
React.useEffect(()=>{
if (visible) {
mountedRef.current = visible;
}
});
return [
visible || mountedRef.current,
setMounted
];
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useMountedState.ts"],"sourcesContent":["import { useForceUpdate } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\n/**\n * This hook manages the mounted state of a component, based on the \"visible\" and \"unmountOnExit\" props.\n * It simulates the behavior of getDerivedStateFromProps(), which is not available in functional components.\n */\nexport function useMountedState(\n visible: boolean = false,\n unmountOnExit: boolean = false,\n): [boolean, (value: boolean) => void] {\n const mountedRef = React.useRef<boolean>(unmountOnExit ? visible : true);\n const forceUpdate = useForceUpdate();\n\n const setMounted = React.useCallback(\n (newValue: boolean) => {\n if (mountedRef.current !== newValue) {\n mountedRef.current = newValue;\n forceUpdate();\n }\n },\n [forceUpdate],\n );\n\n React.useEffect(() => {\n if (visible) {\n mountedRef.current = visible;\n }\n });\n\n return [visible || mountedRef.current, setMounted];\n}\n"],"names":["useForceUpdate","React","useMountedState","visible","unmountOnExit","mountedRef","useRef","forceUpdate","setMounted","useCallback","newValue","current","useEffect"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,cAAc,QAAQ,4BAA4B;AAC3D,YAAYC,WAAW,QAAQ;AAE/B;;;CAGC,GACD,OAAO,SAASC,gBACdC,UAAmB,KAAK,EACxBC,gBAAyB,KAAK;IAE9B,MAAMC,aAAaJ,MAAMK,MAAM,CAAUF,gBAAgBD,UAAU;IACnE,MAAMI,cAAcP;IAEpB,MAAMQ,aAAaP,MAAMQ,WAAW,CAClC,CAACC;QACC,IAAIL,WAAWM,OAAO,KAAKD,UAAU;YACnCL,WAAWM,OAAO,GAAGD;YACrBH;QACF;IACF,GACA;QAACA;KAAY;IAGfN,MAAMW,SAAS,CAAC;QACd,IAAIT,SAAS;YACXE,WAAWM,OAAO,GAAGR;QACvB;IACF;IAEA,OAAO;QAACA,WAAWE,WAAWM,OAAO;QAAEH;KAAW;AACpD"}
+7
View File
@@ -0,0 +1,7 @@
export { motionTokens, durations, curves } from './motions/motionTokens';
export { createMotionComponent } from './factories/createMotionComponent';
export { createPresenceComponent } from './factories/createPresenceComponent';
export { createPresenceComponentVariant } from './factories/createPresenceComponentVariant';
export { PresenceGroup } from './components/PresenceGroup';
export { presenceMotionSlot } from './slots/presenceMotionSlot';
export { MotionBehaviourProvider } from './contexts/MotionBehaviourContext';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { motionTokens, durations, curves } from './motions/motionTokens';\n\nexport { createMotionComponent, type MotionComponentProps } from './factories/createMotionComponent';\nexport {\n createPresenceComponent,\n type PresenceComponentProps,\n type PresenceComponent,\n} from './factories/createPresenceComponent';\nexport { createPresenceComponentVariant } from './factories/createPresenceComponentVariant';\n\nexport { PresenceGroup } from './components/PresenceGroup';\n\nexport { presenceMotionSlot, type PresenceMotionSlotProps } from './slots/presenceMotionSlot';\n\nexport type {\n AtomMotion,\n AtomMotionFn,\n PresenceMotion,\n PresenceMotionFn,\n PresenceDirection,\n MotionImperativeRef,\n MotionParam,\n} from './types';\n\nexport { MotionBehaviourProvider } from './contexts/MotionBehaviourContext';\n"],"names":["motionTokens","durations","curves","createMotionComponent","createPresenceComponent","createPresenceComponentVariant","PresenceGroup","presenceMotionSlot","MotionBehaviourProvider"],"rangeMappings":";;;;;;","mappings":"AAAA,SAASA,YAAY,EAAEC,SAAS,EAAEC,MAAM,QAAQ,yBAAyB;AAEzE,SAASC,qBAAqB,QAAmC,oCAAoC;AACrG,SACEC,uBAAuB,QAGlB,sCAAsC;AAC7C,SAASC,8BAA8B,QAAQ,6CAA6C;AAE5F,SAASC,aAAa,QAAQ,6BAA6B;AAE3D,SAASC,kBAAkB,QAAsC,6BAA6B;AAY9F,SAASC,uBAAuB,QAAQ,oCAAoC"}
+40
View File
@@ -0,0 +1,40 @@
// Copied from packages/tokens/src/global/durations.ts
// Values are numeric in milliseconds for ease of use in Web Animations API
// (rather than parsing '__ms')
export const durations = {
durationUltraFast: 50,
durationFaster: 100,
durationFast: 150,
durationNormal: 200,
durationGentle: 250,
durationSlow: 300,
durationSlower: 400,
durationUltraSlow: 500
};
// Copied from packages/tokens/src/global/curves.ts
// Names and values are preserved exactly
export const curves = {
curveAccelerateMax: 'cubic-bezier(0.9,0.1,1,0.2)',
curveAccelerateMid: 'cubic-bezier(1,0,1,1)',
curveAccelerateMin: 'cubic-bezier(0.8,0,0.78,1)',
curveDecelerateMax: 'cubic-bezier(0.1,0.9,0.2,1)',
curveDecelerateMid: 'cubic-bezier(0,0,0,1)',
curveDecelerateMin: 'cubic-bezier(0.33,0,0.1,1)',
curveEasyEaseMax: 'cubic-bezier(0.8,0,0.2,1)',
curveEasyEase: 'cubic-bezier(0.33,0,0.67,1)',
curveLinear: 'cubic-bezier(0,0,1,1)'
};
// A merged flat lookup for convenience
export const motionTokens = {
...durations,
...curves
}; /*
TODO: enforce naming conventions when TypeScript 4.4 features are supported in Fluent:
type DurationKey = `duration${Capitalize<string>}`;
type CurveKey = `curve${Capitalize<string>}`;
type CurveValue = `cubic-bezier(${number},${number},${number},${number})`;
type DurationTokens = Record<DurationKey, number>;
type CurveTokens = Record<CurveKey, CurveValue>;
*/
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/motions/motionTokens.ts"],"sourcesContent":["// Copied from packages/tokens/src/global/durations.ts\n// Values are numeric in milliseconds for ease of use in Web Animations API\n// (rather than parsing '__ms')\nexport const durations = {\n durationUltraFast: 50,\n durationFaster: 100,\n durationFast: 150,\n durationNormal: 200,\n durationGentle: 250,\n durationSlow: 300,\n durationSlower: 400,\n durationUltraSlow: 500,\n} as const;\n\n// Copied from packages/tokens/src/global/curves.ts\n// Names and values are preserved exactly\nexport const curves = {\n curveAccelerateMax: 'cubic-bezier(0.9,0.1,1,0.2)',\n curveAccelerateMid: 'cubic-bezier(1,0,1,1)',\n curveAccelerateMin: 'cubic-bezier(0.8,0,0.78,1)',\n curveDecelerateMax: 'cubic-bezier(0.1,0.9,0.2,1)',\n curveDecelerateMid: 'cubic-bezier(0,0,0,1)',\n curveDecelerateMin: 'cubic-bezier(0.33,0,0.1,1)',\n curveEasyEaseMax: 'cubic-bezier(0.8,0,0.2,1)',\n curveEasyEase: 'cubic-bezier(0.33,0,0.67,1)',\n curveLinear: 'cubic-bezier(0,0,1,1)',\n} as const;\n\n// A merged flat lookup for convenience\nexport const motionTokens = {\n ...durations,\n ...curves,\n};\n\n/*\nTODO: enforce naming conventions when TypeScript 4.4 features are supported in Fluent:\n\ntype DurationKey = `duration${Capitalize<string>}`;\ntype CurveKey = `curve${Capitalize<string>}`;\ntype CurveValue = `cubic-bezier(${number},${number},${number},${number})`;\n\ntype DurationTokens = Record<DurationKey, number>;\ntype CurveTokens = Record<CurveKey, CurveValue>;\n*/\n"],"names":["durations","durationUltraFast","durationFaster","durationFast","durationNormal","durationGentle","durationSlow","durationSlower","durationUltraSlow","curves","curveAccelerateMax","curveAccelerateMid","curveAccelerateMin","curveDecelerateMax","curveDecelerateMid","curveDecelerateMin","curveEasyEaseMax","curveEasyEase","curveLinear","motionTokens"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,sDAAsD;AACtD,2EAA2E;AAC3E,+BAA+B;AAC/B,OAAO,MAAMA,YAAY;IACvBC,mBAAmB;IACnBC,gBAAgB;IAChBC,cAAc;IACdC,gBAAgB;IAChBC,gBAAgB;IAChBC,cAAc;IACdC,gBAAgB;IAChBC,mBAAmB;AACrB,EAAW;AAEX,mDAAmD;AACnD,yCAAyC;AACzC,OAAO,MAAMC,SAAS;IACpBC,oBAAoB;IACpBC,oBAAoB;IACpBC,oBAAoB;IACpBC,oBAAoB;IACpBC,oBAAoB;IACpBC,oBAAoB;IACpBC,kBAAkB;IAClBC,eAAe;IACfC,aAAa;AACf,EAAW;AAEX,uCAAuC;AACvC,OAAO,MAAMC,eAAe;IAC1B,GAAGnB,SAAS;IACZ,GAAGS,MAAM;AACX,EAAE,CAEF;;;;;;;;;AASA"}
+40
View File
@@ -0,0 +1,40 @@
import { SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from '@fluentui/react-utilities';
import * as React from 'react';
export function presenceMotionSlot(motion, options) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const { as, children, ...rest } = motion !== null && motion !== void 0 ? motion : {};
if (process.env.NODE_ENV !== 'production') {
if (typeof as !== 'undefined') {
throw new Error(`@fluentui/react-motion: "as" property is not supported on motion slots.`);
}
}
if (motion === null) {
// Heads up!
// Render function is used there to avoid rendering a motion component and handle unmounting logic
const isUnmounted = !options.defaultProps.visible && options.defaultProps.unmountOnExit;
const renderFn = (_, props)=>isUnmounted ? null : /*#__PURE__*/ React.createElement(React.Fragment, null, props.children);
/**
* Casting is required here as SlotComponentType is a function, not an object.
* Although SlotComponentType has a function signature, it is still just an object.
* This is required to make a slot callable (JSX compatible), this is the exact same approach
* that is used on `@types/react` components
*/ return {
[SLOT_RENDER_FUNCTION_SYMBOL]: renderFn,
[SLOT_ELEMENT_TYPE_SYMBOL]: options.elementType
};
}
/**
* Casting is required here as SlotComponentType is a function, not an object.
* Although SlotComponentType has a function signature, it is still just an object.
* This is required to make a slot callable (JSX compatible), this is the exact same approach
* that is used on `@types/react` components
*/ const propsWithMetadata = {
...options.defaultProps,
...rest,
[SLOT_ELEMENT_TYPE_SYMBOL]: options.elementType
};
if (typeof children === 'function') {
propsWithMetadata[SLOT_RENDER_FUNCTION_SYMBOL] = children;
}
return propsWithMetadata;
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export { };
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["type AtomCore = { keyframes: Keyframe[] } & KeyframeEffectOptions;\n\nexport type AtomMotion = AtomCore & {\n /**\n * Allows to specify a reduced motion version of the animation. If provided, the settings will be used when the\n * user has enabled the reduced motion setting in the operating system (i.e `prefers-reduced-motion` media query is\n * active). If not provided, the duration of the animation will be overridden to be 1ms.\n *\n * Note, if `keyframes` are provided, they will be used instead of the regular `keyframes`.\n */\n reducedMotion?: Partial<AtomCore>;\n};\n\nexport type PresenceDirection = 'enter' | 'exit';\n\nexport type PresenceMotion = Record<PresenceDirection, AtomMotion | AtomMotion[]>;\n\n/**\n * A motion param should be a primitive value that can be serialized to JSON and could be potentially used a plain\n * dependency for React hooks.\n */\nexport type MotionParam = boolean | number | string;\n\nexport type AtomMotionFn<MotionParams extends Record<string, MotionParam> = {}> = (\n params: { element: HTMLElement } & MotionParams,\n) => AtomMotion | AtomMotion[];\n\nexport type PresenceMotionFn<MotionParams extends Record<string, MotionParam> = {}> = (\n params: { element: HTMLElement } & MotionParams,\n) => PresenceMotion;\n\n// ---\n\nexport type AnimationHandle = Pick<Animation, 'cancel' | 'finish' | 'pause' | 'play' | 'playbackRate'> & {\n setMotionEndCallbacks: (onfinish: () => void, oncancel: () => void) => void;\n};\n\nexport type MotionImperativeRef = {\n /** Sets the playback rate of the animation, where 1 is normal speed. */\n setPlaybackRate: (rate: number) => void;\n\n /** Sets the state of the animation to running or paused. */\n setPlayState: (state: 'running' | 'paused') => void;\n};\n"],"names":[],"rangeMappings":"","mappings":"AAqCA,WAME"}
+18
View File
@@ -0,0 +1,18 @@
import * as React from 'react';
import * as ReactIs from 'react-is';
export function getChildElement(children) {
try {
const child = React.Children.only(children);
if (typeof child.type === 'string' || ReactIs.isForwardRef(child)) {
return child;
}
// We don't need to do anything here: we catch the exception from React to throw a more meaningful error
// eslint-disable-next-line no-empty
} catch {}
throw new Error([
'@fluentui/react-motion: Invalid child element.',
'\n',
'Motion factories require a single child element to be passed. ',
'That element element should support ref forwarding i.e. it should be either an intrinsic element (e.g. div) or a component that uses React.forwardRef().'
].join(''));
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/getChildElement.ts"],"sourcesContent":["import * as React from 'react';\nimport * as ReactIs from 'react-is';\n\nexport function getChildElement(children: React.ReactElement) {\n try {\n const child = React.Children.only(children) as React.ReactElement & { ref: React.Ref<HTMLElement> };\n\n if (typeof child.type === 'string' || ReactIs.isForwardRef(child)) {\n return child as React.ReactElement & { ref: React.Ref<HTMLElement> };\n }\n\n // We don't need to do anything here: we catch the exception from React to throw a more meaningful error\n // eslint-disable-next-line no-empty\n } catch {}\n\n throw new Error(\n [\n '@fluentui/react-motion: Invalid child element.',\n '\\n',\n 'Motion factories require a single child element to be passed. ',\n 'That element element should support ref forwarding i.e. it should be either an intrinsic element (e.g. div) or a component that uses React.forwardRef().',\n ].join(''),\n );\n}\n"],"names":["React","ReactIs","getChildElement","children","child","Children","only","type","isForwardRef","Error","join"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,YAAYC,aAAa,WAAW;AAEpC,OAAO,SAASC,gBAAgBC,QAA4B;IAC1D,IAAI;QACF,MAAMC,QAAQJ,MAAMK,QAAQ,CAACC,IAAI,CAACH;QAElC,IAAI,OAAOC,MAAMG,IAAI,KAAK,YAAYN,QAAQO,YAAY,CAACJ,QAAQ;YACjE,OAAOA;QACT;IAEA,wGAAwG;IACxG,oCAAoC;IACtC,EAAE,OAAM,CAAC;IAET,MAAM,IAAIK,MACR;QACE;QACA;QACA;QACA;KACD,CAACC,IAAI,CAAC;AAEX"}
@@ -0,0 +1,20 @@
import * as React from 'react';
/**
* Given `children`, return an object mapping key to child.
*/ export function getChildMapping(children) {
const childMapping = {};
if (children) {
React.Children.toArray(children).forEach((child)=>{
if (React.isValidElement(child)) {
var _child_key;
childMapping[(_child_key = child.key) !== null && _child_key !== void 0 ? _child_key : ''] = {
appear: false,
element: child,
visible: true,
unmountOnExit: true
};
}
});
}
return childMapping;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/groups/getChildMapping.ts"],"sourcesContent":["import * as React from 'react';\nimport type { PresenceGroupChildMapping } from './types';\n\n/**\n * Given `children`, return an object mapping key to child.\n */\nexport function getChildMapping(children: React.ReactNode | undefined) {\n const childMapping: PresenceGroupChildMapping = {};\n\n if (children) {\n React.Children.toArray(children).forEach(child => {\n if (React.isValidElement(child)) {\n childMapping[child.key ?? ''] = {\n appear: false,\n element: child,\n visible: true,\n unmountOnExit: true,\n };\n }\n });\n }\n\n return childMapping;\n}\n"],"names":["React","getChildMapping","children","childMapping","Children","toArray","forEach","child","isValidElement","key","appear","element","visible","unmountOnExit"],"rangeMappings":";;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAG/B;;CAEC,GACD,OAAO,SAASC,gBAAgBC,QAAqC;IACnE,MAAMC,eAA0C,CAAC;IAEjD,IAAID,UAAU;QACZF,MAAMI,QAAQ,CAACC,OAAO,CAACH,UAAUI,OAAO,CAACC,CAAAA;YACvC,IAAIP,MAAMQ,cAAc,CAACD,QAAQ;oBAClBA;gBAAbJ,YAAY,CAACI,CAAAA,aAAAA,MAAME,GAAG,cAATF,wBAAAA,aAAa,GAAG,GAAG;oBAC9BG,QAAQ;oBACRC,SAASJ;oBACTK,SAAS;oBACTC,eAAe;gBACjB;YACF;QACF;IACF;IAEA,OAAOV;AACT"}
@@ -0,0 +1,30 @@
import { mergeChildMappings } from './mergeChildMappings';
export function getNextChildMapping(prevChildMapping, nextChildMapping) {
const childrenMapping = mergeChildMappings(prevChildMapping, nextChildMapping);
Object.entries(childrenMapping).forEach(([key, childDefinition])=>{
const hasPrev = key in prevChildMapping;
const hasNext = key in nextChildMapping;
if (hasNext) {
// Case 1: item hasn't changed transition states
if (hasPrev) {
childrenMapping[key] = {
...childDefinition
};
return;
}
// Case 2: item is new (entering)
childrenMapping[key] = {
...childDefinition,
appear: true,
visible: true
};
return;
}
// Case 3: item is leaving
childrenMapping[key] = {
...childDefinition,
visible: false
};
});
return childrenMapping;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/groups/getNextChildMapping.ts"],"sourcesContent":["import { mergeChildMappings } from './mergeChildMappings';\nimport type { PresenceGroupChildMapping } from './types';\n\nexport function getNextChildMapping(\n prevChildMapping: PresenceGroupChildMapping,\n nextChildMapping: PresenceGroupChildMapping,\n) {\n const childrenMapping = mergeChildMappings(prevChildMapping, nextChildMapping);\n\n Object.entries(childrenMapping).forEach(([key, childDefinition]) => {\n const hasPrev = key in prevChildMapping;\n const hasNext = key in nextChildMapping;\n\n if (hasNext) {\n // Case 1: item hasn't changed transition states\n if (hasPrev) {\n childrenMapping[key] = { ...childDefinition };\n return;\n }\n\n // Case 2: item is new (entering)\n childrenMapping[key] = {\n ...childDefinition,\n appear: true,\n visible: true,\n };\n return;\n }\n\n // Case 3: item is leaving\n childrenMapping[key] = {\n ...childDefinition,\n visible: false,\n };\n });\n\n return childrenMapping;\n}\n"],"names":["mergeChildMappings","getNextChildMapping","prevChildMapping","nextChildMapping","childrenMapping","Object","entries","forEach","key","childDefinition","hasPrev","hasNext","appear","visible"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,kBAAkB,QAAQ,uBAAuB;AAG1D,OAAO,SAASC,oBACdC,gBAA2C,EAC3CC,gBAA2C;IAE3C,MAAMC,kBAAkBJ,mBAAmBE,kBAAkBC;IAE7DE,OAAOC,OAAO,CAACF,iBAAiBG,OAAO,CAAC,CAAC,CAACC,KAAKC,gBAAgB;QAC7D,MAAMC,UAAUF,OAAON;QACvB,MAAMS,UAAUH,OAAOL;QAEvB,IAAIQ,SAAS;YACX,gDAAgD;YAChD,IAAID,SAAS;gBACXN,eAAe,CAACI,IAAI,GAAG;oBAAE,GAAGC,eAAe;gBAAC;gBAC5C;YACF;YAEA,iCAAiC;YACjCL,eAAe,CAACI,IAAI,GAAG;gBACrB,GAAGC,eAAe;gBAClBG,QAAQ;gBACRC,SAAS;YACX;YACA;QACF;QAEA,0BAA0B;QAC1BT,eAAe,CAACI,IAAI,GAAG;YACrB,GAAGC,eAAe;YAClBI,SAAS;QACX;IACF;IAEA,OAAOT;AACT"}
@@ -0,0 +1,39 @@
/**
* When you're adding or removing children some may be added or removed in the same render pass. We want to show *both*
* since we want to simultaneously animate elements in and out. This function takes a previous set of keys and a new set
* of keys and merges them with its best guess of the correct ordering.
*/ export function mergeChildMappings(prevMapping, nextMapping) {
function getValueForKey(key) {
return key in nextMapping ? nextMapping[key] : prevMapping[key];
}
// For each key of `next`, the list of keys to insert before that key in
// the combined list
const nextKeysPending = {};
let pendingKeys = [];
// eslint-disable-next-line guard-for-in
for(const prevKey in prevMapping){
if (prevKey in nextMapping) {
if (pendingKeys.length) {
nextKeysPending[prevKey] = pendingKeys;
pendingKeys = [];
}
continue;
}
pendingKeys.push(prevKey);
}
const childMapping = {};
// eslint-disable-next-line guard-for-in
for(const nextKey in nextMapping){
if (nextKeysPending[nextKey]) {
for (const pendingNextKey of nextKeysPending[nextKey]){
childMapping[pendingNextKey] = getValueForKey(pendingNextKey);
}
}
childMapping[nextKey] = getValueForKey(nextKey);
}
// Finally, add the keys which didn't appear before any key in `next`
for (const pendingKey of pendingKeys){
childMapping[pendingKey] = getValueForKey(pendingKey);
}
return childMapping;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/groups/mergeChildMappings.ts"],"sourcesContent":["import type { PresenceGroupChildMapping } from './types';\n\n/**\n * When you're adding or removing children some may be added or removed in the same render pass. We want to show *both*\n * since we want to simultaneously animate elements in and out. This function takes a previous set of keys and a new set\n * of keys and merges them with its best guess of the correct ordering.\n */\nexport function mergeChildMappings(\n prevMapping: PresenceGroupChildMapping,\n nextMapping: PresenceGroupChildMapping,\n): PresenceGroupChildMapping {\n function getValueForKey(key: string) {\n return key in nextMapping ? nextMapping[key] : prevMapping[key];\n }\n\n // For each key of `next`, the list of keys to insert before that key in\n // the combined list\n const nextKeysPending: Record<string, string[]> = {};\n let pendingKeys: string[] = [];\n\n // eslint-disable-next-line guard-for-in\n for (const prevKey in prevMapping) {\n if (prevKey in nextMapping) {\n if (pendingKeys.length) {\n nextKeysPending[prevKey] = pendingKeys;\n pendingKeys = [];\n }\n\n continue;\n }\n\n pendingKeys.push(prevKey);\n }\n\n const childMapping: PresenceGroupChildMapping = {};\n\n // eslint-disable-next-line guard-for-in\n for (const nextKey in nextMapping) {\n if (nextKeysPending[nextKey]) {\n for (const pendingNextKey of nextKeysPending[nextKey]) {\n childMapping[pendingNextKey] = getValueForKey(pendingNextKey);\n }\n }\n\n childMapping[nextKey] = getValueForKey(nextKey);\n }\n\n // Finally, add the keys which didn't appear before any key in `next`\n for (const pendingKey of pendingKeys) {\n childMapping[pendingKey] = getValueForKey(pendingKey);\n }\n\n return childMapping;\n}\n"],"names":["mergeChildMappings","prevMapping","nextMapping","getValueForKey","key","nextKeysPending","pendingKeys","prevKey","length","push","childMapping","nextKey","pendingNextKey","pendingKey"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA;;;;CAIC,GACD,OAAO,SAASA,mBACdC,WAAsC,EACtCC,WAAsC;IAEtC,SAASC,eAAeC,GAAW;QACjC,OAAOA,OAAOF,cAAcA,WAAW,CAACE,IAAI,GAAGH,WAAW,CAACG,IAAI;IACjE;IAEA,wEAAwE;IACxE,oBAAoB;IACpB,MAAMC,kBAA4C,CAAC;IACnD,IAAIC,cAAwB,EAAE;IAE9B,wCAAwC;IACxC,IAAK,MAAMC,WAAWN,YAAa;QACjC,IAAIM,WAAWL,aAAa;YAC1B,IAAII,YAAYE,MAAM,EAAE;gBACtBH,eAAe,CAACE,QAAQ,GAAGD;gBAC3BA,cAAc,EAAE;YAClB;YAEA;QACF;QAEAA,YAAYG,IAAI,CAACF;IACnB;IAEA,MAAMG,eAA0C,CAAC;IAEjD,wCAAwC;IACxC,IAAK,MAAMC,WAAWT,YAAa;QACjC,IAAIG,eAAe,CAACM,QAAQ,EAAE;YAC5B,KAAK,MAAMC,kBAAkBP,eAAe,CAACM,QAAQ,CAAE;gBACrDD,YAAY,CAACE,eAAe,GAAGT,eAAeS;YAChD;QACF;QAEAF,YAAY,CAACC,QAAQ,GAAGR,eAAeQ;IACzC;IAEA,qEAAqE;IACrE,KAAK,MAAME,cAAcP,YAAa;QACpCI,YAAY,CAACG,WAAW,GAAGV,eAAeU;IAC5C;IAEA,OAAOH;AACT"}
+1
View File
@@ -0,0 +1 @@
import * as React from 'react';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/groups/types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type PresenceGroupChild = {\n element: React.ReactElement;\n\n appear: boolean;\n visible: boolean;\n unmountOnExit: boolean;\n};\n\nexport type PresenceGroupChildMapping = Record<string, PresenceGroupChild>;\n"],"names":["React"],"rangeMappings":"","mappings":"AAAA,YAAYA,WAAW,QAAQ"}