@tamagui/animations-motion 2.0.0-rc.4 → 2.0.0-rc.40

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.
Files changed (40) hide show
  1. package/dist/cjs/createAnimations.cjs +552 -300
  2. package/dist/cjs/createAnimations.native.js +652 -330
  3. package/dist/cjs/createAnimations.native.js.map +1 -1
  4. package/dist/cjs/index.cjs +7 -5
  5. package/dist/cjs/index.native.js +21 -13
  6. package/dist/cjs/index.native.js.map +1 -1
  7. package/dist/cjs/polyfill.cjs +3 -1
  8. package/dist/cjs/polyfill.native.js +3 -1
  9. package/dist/cjs/polyfill.native.js.map +1 -1
  10. package/dist/esm/createAnimations.mjs +522 -273
  11. package/dist/esm/createAnimations.mjs.map +1 -1
  12. package/dist/esm/createAnimations.native.js +622 -303
  13. package/dist/esm/createAnimations.native.js.map +1 -1
  14. package/dist/esm/index.js +1 -2
  15. package/dist/esm/index.js.map +1 -6
  16. package/dist/esm/index.mjs +0 -1
  17. package/dist/esm/index.mjs.map +1 -1
  18. package/dist/esm/index.native.js +9 -3
  19. package/dist/esm/index.native.js.map +1 -1
  20. package/dist/esm/polyfill.mjs +3 -1
  21. package/dist/esm/polyfill.mjs.map +1 -1
  22. package/dist/esm/polyfill.native.js +3 -1
  23. package/dist/esm/polyfill.native.js.map +1 -1
  24. package/package.json +9 -12
  25. package/src/createAnimations.tsx +482 -360
  26. package/types/createAnimations.d.ts +2 -1
  27. package/types/createAnimations.d.ts.map +4 -4
  28. package/types/index.d.ts.map +2 -2
  29. package/types/index.native.d.ts.map +2 -2
  30. package/types/polyfill.d.ts.map +2 -2
  31. package/dist/cjs/createAnimations.js +0 -401
  32. package/dist/cjs/createAnimations.js.map +0 -6
  33. package/dist/cjs/index.js +0 -16
  34. package/dist/cjs/index.js.map +0 -6
  35. package/dist/cjs/polyfill.js +0 -2
  36. package/dist/cjs/polyfill.js.map +0 -6
  37. package/dist/esm/createAnimations.js +0 -405
  38. package/dist/esm/createAnimations.js.map +0 -6
  39. package/dist/esm/polyfill.js +0 -2
  40. package/dist/esm/polyfill.js.map +0 -6
@@ -2,243 +2,326 @@ var __create = Object.create;
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf,
6
- __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __export = (target, all) => {
8
- for (var name in all) __defProp(target, name, {
9
- get: all[name],
10
- enumerable: !0
11
- });
12
- },
13
- __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
15
16
  get: () => from[key],
16
17
  enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
18
  });
18
- return to;
19
- };
19
+ }
20
+ return to;
21
+ };
20
22
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
- value: mod,
27
- enumerable: !0
28
- }) : target, mod)),
29
- __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
30
- value: !0
31
- }), mod);
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
28
+ value: mod,
29
+ enumerable: true
30
+ }) : target, mod));
31
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
32
+ value: true
33
+ }), mod);
32
34
  var createAnimations_exports = {};
33
35
  __export(createAnimations_exports, {
34
- createAnimations: () => createAnimations
36
+ createAnimations: () => createAnimations,
37
+ disableAnimationProps: () => disableAnimationProps
35
38
  });
36
39
  module.exports = __toCommonJS(createAnimations_exports);
37
- var import_animation_helpers = require("@tamagui/animation-helpers"),
38
- import_use_presence = require("@tamagui/use-presence"),
39
- import_web = require("@tamagui/web"),
40
- import_react = require("motion/react"),
41
- import_react2 = __toESM(require("react"), 1),
42
- import_jsx_runtime = require("react/jsx-runtime");
43
- const MotionValueStrategy = /* @__PURE__ */new WeakMap(),
44
- nonPositionTransformRe = /scale|rotate|skew|matrix|perspective/;
45
- function createAnimations(animationsProp) {
46
- const animations = {};
47
- for (const key in animationsProp) {
48
- const config = animationsProp[key],
49
- isTimingBased = config.duration !== void 0 && config.damping === void 0 && config.stiffness === void 0 && config.mass === void 0;
50
- animations[key] = {
51
- type: isTimingBased ? "tween" : "spring",
52
- ...config,
53
- // Convert duration/delay from ms to seconds for motion library
54
- ...(config.duration ? {
55
- duration: config.duration / 1e3
56
- } : null),
57
- ...(config.delay ? {
58
- delay: config.delay / 1e3
59
- } : null)
60
- };
40
+ var import_animation_helpers = require("@tamagui/animation-helpers");
41
+ var import_use_presence = require("@tamagui/use-presence");
42
+ var import_web = require("@tamagui/web");
43
+ var import_react = require("motion/react");
44
+ var import_react2 = __toESM(require("react"), 1);
45
+ var import_jsx_runtime = require("react/jsx-runtime");
46
+ const isServer = typeof window === "undefined";
47
+ function useAnimateSSRSafe() {
48
+ if (isServer) {
49
+ return [(0, import_react2.useRef)(null), () => {}];
61
50
  }
51
+ return (0, import_react.useAnimate)();
52
+ }
53
+ const MotionValueStrategy = /* @__PURE__ */new WeakMap();
54
+ const PendingMotionOnFinish = /* @__PURE__ */new WeakMap();
55
+ function settlePendingMotionOnFinish(mv, controls) {
56
+ const onFinish = PendingMotionOnFinish.get(mv);
57
+ if (!onFinish) return;
58
+ PendingMotionOnFinish.delete(mv);
59
+ controls.then(() => onFinish()).catch(() => onFinish());
60
+ }
61
+ function createAnimations(animations) {
62
62
  let isHydratingGlobal;
63
63
  const hydratingComponents = /* @__PURE__ */new Set();
64
64
  return {
65
- // this is only used by Sheet basically for now to pass result of useAnimatedStyle to
66
65
  View: MotionView,
67
66
  Text: MotionText,
68
- isReactNative: !1,
69
- supportsCSS: !0,
67
+ isReactNative: false,
70
68
  inputStyle: "css",
71
69
  outputStyle: "inline",
72
- needsWebStyles: !0,
73
- avoidReRenders: !0,
70
+ avoidReRenders: true,
74
71
  animations,
75
72
  usePresence: import_use_presence.usePresence,
76
73
  ResetPresence: import_use_presence.ResetPresence,
77
74
  onMount() {
78
- isHydratingGlobal = !1, hydratingComponents.forEach(cb => cb());
75
+ isHydratingGlobal = false;
76
+ hydratingComponents.forEach(cb => cb());
79
77
  },
80
78
  useAnimations: animationProps => {
81
- isHydratingGlobal === void 0 && !(0, import_web.getConfig)().settings.disableSSR && (isHydratingGlobal = !0);
79
+ if (isHydratingGlobal === void 0 && !(0, import_web.getConfig)().settings.disableSSR) {
80
+ isHydratingGlobal = true;
81
+ }
82
82
  const {
83
- props,
84
- style,
85
- componentState,
86
- stateRef,
87
- useStyleEmitter,
88
- presence
89
- } = animationProps,
90
- animationKey = Array.isArray(props.transition) ? props.transition[0] : props.transition,
91
- isComponentHydrating = componentState.unmounted === !0,
92
- isMounting = componentState.unmounted === "should-enter",
93
- isEntering = !!componentState.unmounted,
94
- isExiting = presence?.[0] === !1,
95
- sendExitComplete = presence?.[1],
96
- wasEnteringRef = (0, import_react2.useRef)(isEntering),
97
- justFinishedEntering = wasEnteringRef.current && !isEntering;
83
+ props,
84
+ style,
85
+ componentState,
86
+ stateRef,
87
+ useStyleEmitter,
88
+ presence
89
+ } = animationProps;
90
+ const animationKey = Array.isArray(props.transition) ? props.transition[0] : props.transition;
91
+ const isComponentHydrating = componentState.unmounted === true;
92
+ const isMounting = componentState.unmounted === "should-enter";
93
+ const isEntering = !!componentState.unmounted;
94
+ const isExiting = presence?.[0] === false;
95
+ const sendExitComplete = presence?.[1];
96
+ const refs = (0, import_react2.useRef)(null);
97
+ if (!refs.current) {
98
+ refs.current = {
99
+ isFirstRender: true,
100
+ lastDoAnimate: null,
101
+ lastDontAnimate: null,
102
+ controls: null,
103
+ lastAnimateAt: 0,
104
+ disposed: false,
105
+ wasExiting: false,
106
+ isExiting: false,
107
+ sendExitComplete: void 0,
108
+ animationState: "default",
109
+ frozenExitTarget: null,
110
+ exitCompleteScheduled: false,
111
+ wasEntering: false
112
+ };
113
+ }
114
+ const justFinishedEntering = refs.current.wasEntering && !isEntering;
98
115
  (0, import_react2.useEffect)(() => {
99
- wasEnteringRef.current = isEntering;
116
+ refs.current.wasEntering = isEntering;
100
117
  });
101
- const animationState = isExiting ? "exit" : isMounting || justFinishedEntering ? "enter" : "default",
102
- disableAnimation = isComponentHydrating || isMounting || !animationKey,
103
- isFirstRender = (0, import_react2.useRef)(!0),
104
- [scope, animate] = (0, import_react.useAnimate)(),
105
- lastDoAnimate = (0, import_react2.useRef)(null),
106
- controls = (0, import_react2.useRef)(null),
107
- styleKey = JSON.stringify(style),
108
- shouldDebug =
109
- // process.env.NODE_ENV === 'development' &&
110
- props.debug && props.debug !== "profile",
111
- {
112
- dontAnimate = {},
113
- doAnimate,
114
- animationOptions
115
- } = (0, import_react2.useMemo)(() => getMotionAnimatedProps(props, style, disableAnimation, animationState), [isExiting, animationKey, styleKey, animationState, disableAnimation]),
116
- id = (0, import_react2.useId)(),
117
- debugId = process.env.NODE_ENV === "development" ? id : "",
118
- lastAnimateAt = (0, import_react2.useRef)(0),
119
- disposed = (0, import_react2.useRef)(!1),
120
- [firstRenderStyle] = (0, import_react2.useState)(style),
121
- lastDontAnimate = (0, import_react2.useRef)(firstRenderStyle),
122
- [isHydrating, setIsHydrating] = (0, import_react2.useState)(isHydratingGlobal);
123
- (0, import_react2.useLayoutEffect)(() => (isHydratingGlobal && hydratingComponents.add(() => {
124
- setIsHydrating(!1);
125
- }), () => {
126
- disposed.current = !0;
127
- }), []);
118
+ const animationState = isExiting ? "exit" : isMounting || justFinishedEntering ? "enter" : "default";
119
+ const disableAnimation = isComponentHydrating || isMounting || !animationKey;
120
+ const [scope, animate] = useAnimateSSRSafe();
121
+ refs.current.isExiting = isExiting;
122
+ refs.current.sendExitComplete = sendExitComplete;
123
+ refs.current.animationState = animationState;
124
+ const justStartedExiting = isExiting && !refs.current.wasExiting;
125
+ const justStoppedExiting = !isExiting && refs.current.wasExiting;
126
+ if (justStartedExiting || justStoppedExiting) {
127
+ refs.current.frozenExitTarget = null;
128
+ refs.current.exitCompleteScheduled = false;
129
+ }
130
+ (0, import_react2.useEffect)(() => {
131
+ refs.current.wasExiting = isExiting;
132
+ });
133
+ const {
134
+ dontAnimate = {},
135
+ doAnimate,
136
+ animationOptions
137
+ } = getMotionAnimatedProps(props, style, disableAnimation, animationState);
138
+ const [firstRenderStyle] = (0, import_react2.useState)(style);
139
+ if (refs.current.isFirstRender) {
140
+ refs.current.lastDontAnimate = firstRenderStyle;
141
+ }
142
+ const [isHydrating, setIsHydrating] = (0, import_react2.useState)(isHydratingGlobal);
143
+ (0, import_react2.useLayoutEffect)(() => {
144
+ if (isHydratingGlobal) {
145
+ hydratingComponents.add(() => {
146
+ setIsHydrating(false);
147
+ });
148
+ }
149
+ return () => {
150
+ refs.current.disposed = true;
151
+ };
152
+ }, []);
128
153
  const flushAnimation = ({
129
- doAnimate: doAnimate2 = {},
130
- animationOptions: animationOptions2 = {},
154
+ doAnimate: doAnimateRaw = {},
155
+ animationOptions: passedOptions = {},
131
156
  dontAnimate: dontAnimate2
132
157
  }) => {
158
+ let startedControls = null;
159
+ const isCurrentlyExiting = refs.current.isExiting;
160
+ const currentSendExitComplete = refs.current.sendExitComplete;
161
+ let doAnimate2 = doAnimateRaw;
162
+ if (isCurrentlyExiting && refs.current.frozenExitTarget) {
163
+ doAnimate2 = refs.current.frozenExitTarget;
164
+ }
165
+ const animationOptions2 = isCurrentlyExiting && currentSendExitComplete ? getAnimationOptions(props.transition ?? null, "exit") : passedOptions;
133
166
  try {
134
167
  const node = stateRef.current.host;
135
- if (isFirstRender.current && (lastDontAnimate.current = null, lastDoAnimate.current = null), shouldDebug && (console.groupCollapsed(`[motion] ${debugId} \u{1F30A} animate (${JSON.stringify(getDiff(lastDoAnimate.current, doAnimate2), null, 2)})`), console.info({
136
- props,
137
- componentState,
138
- doAnimate: doAnimate2,
139
- dontAnimate: dontAnimate2,
140
- animationOptions: animationOptions2,
141
- animationProps,
142
- lastDoAnimate: {
143
- ...lastDoAnimate.current
144
- },
145
- lastDontAnimate: {
146
- ...lastDontAnimate.current
147
- },
148
- isExiting,
149
- style,
150
- node
151
- }), console.groupCollapsed("trace >"), console.trace(), console.groupEnd(), console.groupEnd()), !(node instanceof HTMLElement)) return;
152
- const prevDont = lastDontAnimate.current;
153
- if (dontAnimate2) if (prevDont) {
154
- removeRemovedStyles(prevDont, dontAnimate2, node, doAnimate2);
155
- const changed = getDiff(prevDont, dontAnimate2);
156
- changed && Object.assign(node.style, changed);
157
- } else Object.assign(node.style, dontAnimate2);
168
+ if (refs.current.isFirstRender) {
169
+ refs.current.lastDontAnimate = null;
170
+ refs.current.lastDoAnimate = null;
171
+ }
172
+ if (process.env.NODE_ENV === "development") {
173
+ if (props["debug"] && props["debug"] !== "profile") {
174
+ console.groupCollapsed(`[motion] animate (${JSON.stringify(getDiff(refs.current.lastDoAnimate, doAnimate2), null, 2)})`);
175
+ console.info({
176
+ props,
177
+ componentState,
178
+ doAnimate: doAnimate2,
179
+ dontAnimate: dontAnimate2,
180
+ animationOptions: animationOptions2,
181
+ animationProps,
182
+ lastDoAnimate: {
183
+ ...refs.current.lastDoAnimate
184
+ },
185
+ lastDontAnimate: {
186
+ ...refs.current.lastDontAnimate
187
+ },
188
+ isExiting,
189
+ style,
190
+ node
191
+ });
192
+ console.groupCollapsed(`trace >`);
193
+ console.trace();
194
+ console.groupEnd();
195
+ console.groupEnd();
196
+ }
197
+ }
198
+ if (!(node instanceof HTMLElement)) {
199
+ return;
200
+ }
201
+ const prevDont = refs.current.lastDontAnimate;
202
+ if (dontAnimate2) {
203
+ if (prevDont) {
204
+ removeRemovedStyles(prevDont, dontAnimate2, node, doAnimate2);
205
+ const changed = getDiff(prevDont, dontAnimate2);
206
+ if (changed) {
207
+ Object.assign(node.style, changed);
208
+ }
209
+ } else {
210
+ Object.assign(node.style, dontAnimate2);
211
+ }
212
+ }
158
213
  if (doAnimate2) {
159
214
  if (prevDont) {
160
- const movedToAnimate = {};
161
- for (const key in prevDont) key in doAnimate2 && (node.style[key] = prevDont[key], movedToAnimate[key] = prevDont[key], lastDoAnimate.current && (lastDoAnimate.current[key] = prevDont[key]));
162
- Object.keys(movedToAnimate).length > 0 && animate(scope.current, {
163
- ...movedToAnimate
164
- }, {
165
- duration: 0
166
- });
215
+ for (const key in prevDont) {
216
+ if (key in doAnimate2) {
217
+ node.style[key] = prevDont[key];
218
+ if (refs.current.lastDoAnimate) {
219
+ refs.current.lastDoAnimate[key] = prevDont[key];
220
+ }
221
+ }
222
+ }
167
223
  }
168
- const lastAnimated = lastDoAnimate.current;
169
- lastAnimated && removeRemovedStyles(lastAnimated, doAnimate2, node, dontAnimate2);
170
- const diff = getDiff(lastDoAnimate.current, doAnimate2);
224
+ const lastAnimated = refs.current.lastDoAnimate;
225
+ if (lastAnimated) {
226
+ removeRemovedStyles(lastAnimated, doAnimate2, node, dontAnimate2);
227
+ }
228
+ const diff = getDiff(refs.current.lastDoAnimate, doAnimate2);
171
229
  if (diff) {
172
- const isRunning = controls.current?.state === "running",
173
- targetTransform = typeof diff.transform == "string" ? diff.transform : null,
174
- isPositionOnlyTransform = targetTransform && targetTransform.includes("translate") && !nonPositionTransformRe.test(targetTransform),
175
- isPopperElement = node.hasAttribute("data-popper-animate-position"),
176
- isEnteringPresenceChild = presence && justFinishedEntering;
177
- if (isRunning && controls.current && isPositionOnlyTransform && (isPopperElement || isEnteringPresenceChild)) {
178
- const currentTransform = getComputedStyle(node).transform;
179
- if (currentTransform && currentTransform !== "none") {
180
- const matrixMatch = currentTransform.match(/matrix\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*([^,]+),\s*([^)]+)\)/);
181
- if (matrixMatch) {
182
- controls.current.stop(), node.style.transform = currentTransform;
183
- const currentX = Number.parseFloat(matrixMatch[1]),
184
- currentY = Number.parseFloat(matrixMatch[2]),
185
- keyframeDiff = {
186
- ...diff,
187
- transform: [`translateX(${currentX}px) translateY(${currentY}px)`, targetTransform]
188
- };
189
- controls.current = animate(scope.current, keyframeDiff, animationOptions2), lastAnimateAt.current = Date.now(), lastDontAnimate.current = dontAnimate2 ? {
190
- ...dontAnimate2
191
- } : {}, lastDoAnimate.current = doAnimate2 ? {
192
- ...doAnimate2
193
- } : {};
194
- return;
230
+ if (isCurrentlyExiting && !refs.current.frozenExitTarget) {
231
+ refs.current.frozenExitTarget = {
232
+ ...doAnimate2
233
+ };
234
+ }
235
+ const isPopperPosition = node.hasAttribute("data-popper-animate-position");
236
+ let midFlightValues = null;
237
+ if (refs.current.controls) {
238
+ try {
239
+ const computed = getComputedStyle(node);
240
+ midFlightValues = {};
241
+ for (const key in diff) {
242
+ const val = computed[key];
243
+ if (val !== void 0 && val !== "") {
244
+ midFlightValues[key] = val;
245
+ }
246
+ }
247
+ } catch {}
248
+ if (isCurrentlyExiting) {
249
+ refs.current.controls.stop();
250
+ }
251
+ if (midFlightValues) {
252
+ for (const key in midFlightValues) {
253
+ ;
254
+ node.style[key] = midFlightValues[key];
195
255
  }
196
256
  }
257
+ if (isPopperPosition) {
258
+ const anims = node.getAnimations();
259
+ for (const anim of anims) {
260
+ anim.cancel();
261
+ }
262
+ }
263
+ }
264
+ const fixedDiff = fixTransparentColors(diff, refs.current.lastDoAnimate, doAnimate2);
265
+ if (midFlightValues?.transform && fixedDiff.transform) {
266
+ fixedDiff.transform = [midFlightValues.transform, fixedDiff.transform];
197
267
  }
198
- const fixedDiff = fixTransparentColors({
199
- ...diff
200
- }, lastDoAnimate.current);
201
- controls.current = animate(scope.current, fixedDiff, animationOptions2), lastAnimateAt.current = Date.now();
268
+ startedControls = animate(scope.current, fixedDiff, animationOptions2);
269
+ refs.current.controls = startedControls;
270
+ refs.current.lastAnimateAt = Date.now();
202
271
  }
203
272
  }
204
- lastDontAnimate.current = dontAnimate2 ? {
273
+ refs.current.lastDontAnimate = dontAnimate2 ? {
205
274
  ...dontAnimate2
206
- } : {}, lastDoAnimate.current = doAnimate2 ? {
275
+ } : {};
276
+ refs.current.lastDoAnimate = doAnimate2 ? {
207
277
  ...doAnimate2
208
278
  } : {};
209
279
  } finally {
210
- isExiting && (controls.current ? controls.current.finished.then(() => {
211
- sendExitComplete?.();
212
- }) : sendExitComplete?.());
280
+ if (isCurrentlyExiting && currentSendExitComplete) {
281
+ if (startedControls) {
282
+ refs.current.exitCompleteScheduled = true;
283
+ startedControls.finished.then(() => {
284
+ if (refs.current.isExiting) {
285
+ currentSendExitComplete();
286
+ }
287
+ }).catch(() => {
288
+ if (refs.current.isExiting) {
289
+ currentSendExitComplete();
290
+ }
291
+ });
292
+ } else if (!refs.current.exitCompleteScheduled) {
293
+ currentSendExitComplete();
294
+ }
295
+ }
213
296
  }
214
297
  };
215
- return useStyleEmitter?.(nextStyle => {
216
- const animationProps2 = getMotionAnimatedProps(props, nextStyle, disableAnimation, animationState);
298
+ useStyleEmitter?.((nextStyle, effectiveTransition) => {
299
+ const animationProps2 = getMotionAnimatedProps(props, nextStyle, disableAnimation, refs.current.animationState, effectiveTransition);
217
300
  flushAnimation(animationProps2);
218
- }), (0, import_web.useIsomorphicLayoutEffect)(() => {
219
- if (isFirstRender.current) {
220
- if (isFirstRender.current = !1, isHydrating) {
221
- const node = stateRef.current.host;
222
- node instanceof HTMLElement && (dontAnimate && (Object.assign(node.style, dontAnimate), animate(scope.current, {
223
- ...dontAnimate
224
- }, {
225
- duration: 0
226
- })), doAnimate && Object.keys(doAnimate).length > 0 ? (lastDoAnimate.current = {
227
- ...doAnimate
228
- }, animate(scope.current, {
229
- ...doAnimate
230
- }, {
231
- duration: 0
232
- })) : lastDoAnimate.current = dontAnimate ? {
233
- ...dontAnimate
234
- } : {}), lastDontAnimate.current = dontAnimate ? {
301
+ });
302
+ (0, import_web.useIsomorphicLayoutEffect)(() => {
303
+ if (refs.current.isFirstRender) {
304
+ refs.current.isFirstRender = false;
305
+ if (isHydrating) {
306
+ if (doAnimate && Object.keys(doAnimate).length > 0) {
307
+ refs.current.lastDoAnimate = {
308
+ ...doAnimate
309
+ };
310
+ } else {
311
+ refs.current.lastDoAnimate = dontAnimate ? {
312
+ ...dontAnimate
313
+ } : {};
314
+ }
315
+ refs.current.lastDontAnimate = dontAnimate ? {
235
316
  ...dontAnimate
236
- } : {}, lastAnimateAt.current = Date.now();
317
+ } : {};
318
+ refs.current.lastAnimateAt = Date.now();
237
319
  return;
238
320
  }
239
- lastDontAnimate.current = dontAnimate ? {
321
+ refs.current.lastDontAnimate = dontAnimate ? {
240
322
  ...dontAnimate
241
- } : {}, lastDoAnimate.current = doAnimate ? {
323
+ } : {};
324
+ refs.current.lastDoAnimate = doAnimate ? {
242
325
  ...doAnimate
243
326
  } : {};
244
327
  return;
@@ -248,18 +331,24 @@ function createAnimations(animationsProp) {
248
331
  dontAnimate,
249
332
  animationOptions
250
333
  });
251
- }, [styleKey, isExiting, disableAnimation]), shouldDebug && (console.groupCollapsed("[motion] \u{1F30A} render"), console.info({
252
- style,
253
- doAnimate,
254
- dontAnimate,
255
- styleKey,
256
- scope,
257
- animationOptions,
258
- isExiting,
259
- isFirstRender: isFirstRender.current,
260
- animationProps
261
- }), console.groupEnd()), {
262
- // we never change this, after first render on
334
+ }, [style, isExiting, disableAnimation]);
335
+ if (process.env.NODE_ENV === "development") {
336
+ if (props["debug"] && props["debug"] !== "profile") {
337
+ console.groupCollapsed(`[motion] render`);
338
+ console.info({
339
+ style,
340
+ doAnimate,
341
+ dontAnimate,
342
+ scope,
343
+ animationOptions,
344
+ isExiting,
345
+ isFirstRender: refs.current.isFirstRender,
346
+ animationProps
347
+ });
348
+ console.groupEnd();
349
+ }
350
+ }
351
+ return {
263
352
  style: firstRenderStyle,
264
353
  ref: scope,
265
354
  render: "div"
@@ -277,16 +366,24 @@ function createAnimations(animationsProp) {
277
366
  setValue(next, config = {
278
367
  type: "spring"
279
368
  }, onFinish) {
280
- if (config.type === "direct") MotionValueStrategy.set(motionValue, {
281
- type: "direct"
282
- }), motionValue.set(next), onFinish?.();else {
283
- if (MotionValueStrategy.set(motionValue, config), onFinish) {
284
- const unsubscribe = motionValue.on("change", value => {
285
- Math.abs(value - next) < 0.01 && (unsubscribe(), onFinish());
286
- });
287
- }
369
+ if (config.type === "direct") {
370
+ MotionValueStrategy.set(motionValue, {
371
+ type: "direct"
372
+ });
288
373
  motionValue.set(next);
374
+ onFinish?.();
375
+ return;
376
+ }
377
+ MotionValueStrategy.set(motionValue, config);
378
+ if (onFinish) {
379
+ const prior = PendingMotionOnFinish.get(motionValue);
380
+ if (prior) {
381
+ PendingMotionOnFinish.delete(motionValue);
382
+ prior();
383
+ }
384
+ PendingMotionOnFinish.set(motionValue, onFinish);
289
385
  }
386
+ motionValue.set(next);
290
387
  },
291
388
  stop() {
292
389
  motionValue.stop();
@@ -300,24 +397,49 @@ function createAnimations(animationsProp) {
300
397
  (0, import_react.useMotionValueEvent)(instance, "change", onValue);
301
398
  },
302
399
  useAnimatedNumberStyle(val, getStyleProp) {
303
- const motionValue = val.getInstance(),
304
- getStyleRef = (0, import_react2.useRef)(getStyleProp);
305
- return getStyleRef.current = getStyleProp, (0, import_react2.useMemo)(() => ({
306
- getStyle: cur => getStyleRef.current(cur),
307
- motionValue
308
- }), []);
400
+ const motionValue = val.getInstance();
401
+ const getStyleRef = (0, import_react2.useRef)(getStyleProp);
402
+ getStyleRef.current = getStyleProp;
403
+ return (0, import_react2.useMemo)(() => {
404
+ return {
405
+ getStyle: cur => {
406
+ return getStyleRef.current(cur);
407
+ },
408
+ motionValue
409
+ };
410
+ }, []);
411
+ },
412
+ useAnimatedNumbersStyle(vals, getStyleProp) {
413
+ const motionValues = vals.map(v => v.getInstance());
414
+ const getStyleRef = (0, import_react2.useRef)(getStyleProp);
415
+ getStyleRef.current = getStyleProp;
416
+ return (0, import_react2.useMemo)(() => {
417
+ return {
418
+ getStyle: (...currentValues) => getStyleRef.current(...currentValues),
419
+ motionValues
420
+ };
421
+ }, []);
309
422
  }
310
423
  };
311
- function getMotionAnimatedProps(props, style, disable, animationState = "default") {
312
- if (disable) return {
313
- dontAnimate: style
314
- };
315
- const animationOptions = transitionPropToAnimationConfig(props.transition, animationState);
316
- let dontAnimate, doAnimate;
424
+ function getMotionAnimatedProps(props, style, disable, animationState = "default", transitionOverride) {
425
+ if (disable) {
426
+ return {
427
+ dontAnimate: style
428
+ };
429
+ }
430
+ const animationOptions = getAnimationOptions(transitionOverride ?? props.transition ?? null, animationState);
431
+ let dontAnimate;
432
+ let doAnimate;
317
433
  const animateOnly = props.animateOnly;
318
434
  for (const key in style) {
319
435
  const value = style[key];
320
- disableAnimationProps.has(key) || animateOnly && !animateOnly.includes(key) ? (dontAnimate ||= {}, dontAnimate[key] = value) : (doAnimate ||= {}, doAnimate[key] = value);
436
+ if (disableAnimationProps.has(key) || animateOnly && !animateOnly.includes(key)) {
437
+ dontAnimate ||= {};
438
+ dontAnimate[key] = value;
439
+ } else {
440
+ doAnimate ||= {};
441
+ doAnimate[key] = value;
442
+ }
321
443
  }
322
444
  return {
323
445
  dontAnimate,
@@ -325,83 +447,168 @@ function createAnimations(animationsProp) {
325
447
  animationOptions
326
448
  };
327
449
  }
328
- function transitionPropToAnimationConfig(transitionProp, animationState = "default") {
329
- const normalized = (0, import_animation_helpers.normalizeTransition)(transitionProp),
330
- effectiveKey = (0, import_animation_helpers.getEffectiveAnimation)(normalized, animationState);
331
- if (!effectiveKey && Object.keys(normalized.properties).length === 0) return {};
332
- const defaultConfig = effectiveKey ? animations[effectiveKey] : null,
333
- delay = typeof normalized.delay == "number" ? normalized.delay / 1e3 : void 0,
334
- result = {};
335
- defaultConfig && (result.default = delay ? {
336
- ...defaultConfig,
337
- delay
338
- } : defaultConfig);
339
- for (const [propName, animationNameOrConfig] of Object.entries(normalized.properties)) if (typeof animationNameOrConfig == "string") result[propName] = animations[animationNameOrConfig];else if (animationNameOrConfig && typeof animationNameOrConfig == "object") {
340
- const baseConfig = animationNameOrConfig.type ? animations[animationNameOrConfig.type] : defaultConfig;
341
- result[propName] = {
342
- ...baseConfig,
343
- ...animationNameOrConfig
450
+ function getAnimationOptions(transitionProp, animationState = "default") {
451
+ const normalized = (0, import_animation_helpers.normalizeTransition)(transitionProp);
452
+ let effectiveKey = (0, import_animation_helpers.getEffectiveAnimation)(normalized, animationState);
453
+ if (!effectiveKey && animationState === "default") {
454
+ effectiveKey = normalized.enter || normalized.exit || null;
455
+ }
456
+ const globalConfigOverride = normalized.config ? {
457
+ ...normalized.config
458
+ } : void 0;
459
+ if (!effectiveKey && Object.keys(normalized.properties).length === 0 && !globalConfigOverride) {
460
+ return {};
461
+ }
462
+ const defaultConfig = effectiveKey ? withInferredType(animations[effectiveKey]) : null;
463
+ const delay = normalized.delay;
464
+ const result = {};
465
+ if (defaultConfig) {
466
+ Object.assign(result, defaultConfig);
467
+ }
468
+ if (globalConfigOverride) {
469
+ Object.assign(result, globalConfigOverride);
470
+ if (result.type === void 0 && result.duration !== void 0 && result.damping === void 0 && result.stiffness === void 0 && result.mass === void 0) {
471
+ result.type = "tween";
472
+ }
473
+ }
474
+ if (delay) {
475
+ result.delay = delay;
476
+ }
477
+ if (defaultConfig || globalConfigOverride || delay) {
478
+ result.default = {
479
+ ...defaultConfig,
480
+ ...globalConfigOverride,
481
+ ...(delay ? {
482
+ delay
483
+ } : null)
344
484
  };
345
485
  }
486
+ for (const [propName, animationNameOrConfig] of Object.entries(normalized.properties)) {
487
+ if (typeof animationNameOrConfig === "string") {
488
+ result[propName] = withInferredType(animations[animationNameOrConfig]);
489
+ } else if (animationNameOrConfig && typeof animationNameOrConfig === "object") {
490
+ const baseConfig = animationNameOrConfig.type ? withInferredType(animations[animationNameOrConfig.type]) : defaultConfig;
491
+ result[propName] = {
492
+ ...baseConfig,
493
+ ...animationNameOrConfig
494
+ };
495
+ }
496
+ }
497
+ convertMsToS(result);
498
+ convertMsToS(result.default);
499
+ for (const key in result) {
500
+ if (key !== "default" && typeof result[key] === "object") {
501
+ convertMsToS(result[key]);
502
+ }
503
+ }
346
504
  return result;
347
505
  }
348
506
  }
507
+ function withInferredType(config) {
508
+ if (!config) {
509
+ return {
510
+ type: "spring"
511
+ };
512
+ }
513
+ const isTimingBased = config.duration !== void 0 && config.damping === void 0 && config.stiffness === void 0 && config.mass === void 0;
514
+ return {
515
+ type: isTimingBased ? "tween" : "spring",
516
+ ...config
517
+ };
518
+ }
519
+ function convertMsToS(config) {
520
+ if (!config) return;
521
+ if (typeof config.delay === "number") config.delay = config.delay / 1e3;
522
+ if (typeof config.duration === "number") {
523
+ const isTimingBased = config.type === "tween" || config.type === void 0 && config.damping === void 0 && config.stiffness === void 0 && config.mass === void 0;
524
+ if (isTimingBased) {
525
+ config.duration = config.duration / 1e3;
526
+ }
527
+ }
528
+ }
349
529
  function removeRemovedStyles(prev, next, node, dontClearIfIn) {
350
- for (const key in prev) if (!(key in next)) {
351
- if (dontClearIfIn && key in dontClearIfIn) continue;
352
- node.style[key] = "";
530
+ for (const key in prev) {
531
+ if (!(key in next)) {
532
+ if (dontClearIfIn && key in dontClearIfIn) {
533
+ continue;
534
+ }
535
+ node.style[key] = "";
536
+ }
353
537
  }
354
538
  }
355
- const disableAnimationProps = /* @__PURE__ */new Set(["alignContent", "alignItems", "aspectRatio", "backdropFilter", "boxSizing", "contain", "containerType", "display", "flexBasis", "flexDirection", "flexGrow", "flexShrink", "fontFamily", "justifyContent", "marginBottom", "marginLeft", "marginRight", "marginTop", "maxHeight", "maxWidth", "minHeight", "minWidth", "overflow", "overflowX", "overflowY", "pointerEvents", "position", "textWrap", "transformOrigin", "userSelect", "WebkitBackdropFilter", "zIndex"]),
356
- MotionView = createMotionView("div"),
357
- MotionText = createMotionView("span");
539
+ const disableAnimationProps = /* @__PURE__ */new Set(["alignContent", "alignItems", "boxSizing", "contain", "containerType", "display", "flexBasis", "flexDirection", "fontFamily", "justifyContent", "overflow", "overflowX", "overflowY", "pointerEvents", "position", "textWrap", "userSelect"]);
540
+ const MotionView = createMotionView("div");
541
+ const MotionText = createMotionView("span");
358
542
  function createMotionView(defaultTag) {
359
- const isText = defaultTag === "span",
360
- Component = (0, import_react2.forwardRef)((propsIn, ref) => {
361
- const {
362
- forwardedRef,
363
- animation,
364
- render = defaultTag,
365
- style,
366
- ...propsRest
367
- } = propsIn,
368
- [scope, animate] = (0, import_react.useAnimate)(),
369
- hostRef = (0, import_react2.useRef)(null),
370
- composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref, hostRef, scope),
371
- stateRef = (0, import_react2.useRef)(null);
372
- stateRef.current || (stateRef.current = {
543
+ const isText = defaultTag === "span";
544
+ const Component = (0, import_react2.forwardRef)((propsIn, ref) => {
545
+ const {
546
+ forwardedRef,
547
+ animation,
548
+ render = defaultTag,
549
+ style,
550
+ ...propsRest
551
+ } = propsIn;
552
+ const [scope, animate] = useAnimateSSRSafe();
553
+ const hostRef = (0, import_react2.useRef)(null);
554
+ const composedRefs = (0, import_web.useComposedRefs)(forwardedRef, ref, hostRef, scope);
555
+ const stateRef = (0, import_react2.useRef)(null);
556
+ if (!stateRef.current) {
557
+ stateRef.current = {
373
558
  get host() {
374
559
  return hostRef.current;
375
560
  }
561
+ };
562
+ }
563
+ const [_, state] = (0, import_web.useThemeWithState)({});
564
+ const styles = Array.isArray(style) ? style : [style];
565
+ const [animatedStyle, nonAnimatedStyles] = (() => {
566
+ let animatedStyle2;
567
+ const nonAnimatedStyles2 = [];
568
+ for (const style2 of styles) {
569
+ if (style2.getStyle) {
570
+ animatedStyle2 = style2;
571
+ } else {
572
+ nonAnimatedStyles2.push(style2);
573
+ }
574
+ }
575
+ return [animatedStyle2, nonAnimatedStyles2];
576
+ })();
577
+ function getProps(props2) {
578
+ const out = (0, import_web.getSplitStyles)(props2, isText ? import_web.Text.staticConfig : import_web.View.staticConfig, state?.theme, state?.name, {
579
+ unmounted: false
580
+ }, {
581
+ isAnimated: false,
582
+ noClass: true,
583
+ resolveValues: "auto"
376
584
  });
377
- const [_, state] = (0, import_web.useThemeWithState)({}),
378
- styles = Array.isArray(style) ? style : [style],
379
- [animatedStyle, nonAnimatedStyles] = [styles.find(x => x.getStyle), styles.filter(x => !x.getStyle)];
380
- function getProps(props2) {
381
- const out = (0, import_web.getSplitStyles)(props2, isText ? import_web.Text.staticConfig : import_web.View.staticConfig, state?.theme, state?.name, {
382
- unmounted: !1
383
- }, {
384
- isAnimated: !1,
385
- noClass: !0,
386
- // noMergeStyle: true,
387
- resolveValues: "auto"
388
- });
389
- return out ? (out.viewProps.style && ((0, import_web.fixStyles)(out.viewProps.style), (0, import_web.styleToCSS)(out.viewProps.style)), out.viewProps) : {};
585
+ if (!out) {
586
+ return {};
390
587
  }
391
- const props = getProps({
392
- ...propsRest,
393
- style: nonAnimatedStyles
394
- }),
395
- Element = render || "div",
396
- transformedProps = import_web.hooks.usePropsTransform?.(render, props, stateRef, !1);
397
- return (0, import_react2.useEffect)(() => {
398
- if (animatedStyle) return animatedStyle.motionValue.on("change", value => {
399
- const nextStyle = animatedStyle.getStyle(value),
400
- animationConfig = MotionValueStrategy.get(animatedStyle.motionValue),
401
- node = hostRef.current,
402
- webStyle = getProps({
403
- style: nextStyle
404
- }).style;
588
+ if (out.viewProps.style) {
589
+ (0, import_web.fixStyles)(out.viewProps.style);
590
+ (0, import_web.styleToCSS)(out.viewProps.style);
591
+ }
592
+ return out.viewProps;
593
+ }
594
+ const props = getProps({
595
+ ...propsRest,
596
+ style: nonAnimatedStyles
597
+ });
598
+ const Element = render || "div";
599
+ const transformedProps = import_web.hooks.usePropsTransform?.(render, props, stateRef, false);
600
+ (0, import_react2.useEffect)(() => {
601
+ if (!animatedStyle) return;
602
+ if (animatedStyle.motionValues) {
603
+ const mvs = animatedStyle.motionValues;
604
+ const unsubs = mvs.map(mv => mv.on("change", () => {
605
+ const currentValues = mvs.map(v => v.get());
606
+ const nextStyle = animatedStyle.getStyle(...currentValues);
607
+ const animationConfig = MotionValueStrategy.get(mv);
608
+ const node = hostRef.current;
609
+ const webStyle = getProps({
610
+ style: nextStyle
611
+ }).style;
405
612
  if (webStyle && node instanceof HTMLElement) {
406
613
  const motionAnimationConfig = animationConfig?.type === "timing" ? {
407
614
  type: "tween",
@@ -413,34 +620,79 @@ function createMotionView(defaultTag) {
413
620
  type: "spring",
414
621
  ...animationConfig
415
622
  };
416
- animate(node, webStyle, motionAnimationConfig);
623
+ const controls = animate(node, webStyle, motionAnimationConfig);
624
+ settlePendingMotionOnFinish(mv, controls);
417
625
  }
418
- });
419
- }, [animatedStyle]), /* @__PURE__ */(0, import_jsx_runtime.jsx)(Element, {
420
- ...transformedProps,
421
- ref: composedRefs
626
+ }));
627
+ return () => unsubs.forEach(fn => fn());
628
+ }
629
+ if (!animatedStyle.motionValue) return;
630
+ return animatedStyle.motionValue.on("change", value => {
631
+ const nextStyle = animatedStyle.getStyle(value);
632
+ const animationConfig = MotionValueStrategy.get(animatedStyle.motionValue);
633
+ const node = hostRef.current;
634
+ const webStyle = getProps({
635
+ style: nextStyle
636
+ }).style;
637
+ if (webStyle && node instanceof HTMLElement) {
638
+ const motionAnimationConfig = animationConfig?.type === "timing" ? {
639
+ type: "tween",
640
+ duration: (animationConfig?.duration || 0) / 1e3
641
+ } : animationConfig?.type === "direct" ? {
642
+ type: "tween",
643
+ duration: 0
644
+ } : {
645
+ type: "spring",
646
+ ...animationConfig
647
+ };
648
+ const controls = animate(node, webStyle, motionAnimationConfig);
649
+ settlePendingMotionOnFinish(animatedStyle.motionValue, controls);
650
+ }
422
651
  });
652
+ }, [animatedStyle]);
653
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Element, {
654
+ ...transformedProps,
655
+ ref: composedRefs
423
656
  });
424
- return Component.acceptTagProp = !0, Component;
657
+ });
658
+ Component["acceptRenderProp"] = true;
659
+ return Component;
425
660
  }
426
661
  function getDiff(previous, next) {
427
- if (!previous) return next;
662
+ if (!previous) {
663
+ return next;
664
+ }
428
665
  let diff = null;
429
- for (const key in next) next[key] !== previous[key] && (diff ||= {}, diff[key] = next[key]);
666
+ for (const key in next) {
667
+ if (next[key] !== previous[key]) {
668
+ diff ||= {};
669
+ diff[key] = next[key];
670
+ }
671
+ }
430
672
  return diff;
431
673
  }
432
- function fixTransparentColors(diff, previous) {
674
+ function fixTransparentColors(diff, previous, next) {
433
675
  let result = diff;
434
- for (const key in diff) if (diff[key] === "transparent") {
435
- const prev = previous?.[key];
436
- let fixed = "rgba(0, 0, 0, 0)";
437
- if (typeof prev == "string") {
438
- const rgbaMatch = prev.match(/^rgba?\(([^,]+),\s*([^,]+),\s*([^,)]+)/);
439
- rgbaMatch && (fixed = `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, 0)`);
676
+ for (const key in diff) {
677
+ if (diff[key] === "transparent") {
678
+ let fixed = "rgba(0, 0, 0, 0)";
679
+ const candidates = [previous?.[key], next?.[key]];
680
+ for (const candidate of candidates) {
681
+ if (typeof candidate === "string" && candidate !== "transparent") {
682
+ const rgbaMatch = candidate.match(/^rgba?\(([^,]+),\s*([^,]+),\s*([^,)]+)/);
683
+ if (rgbaMatch) {
684
+ fixed = `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, 0)`;
685
+ break;
686
+ }
687
+ }
688
+ }
689
+ if (result === diff) {
690
+ result = {
691
+ ...diff
692
+ };
693
+ }
694
+ result[key] = fixed;
440
695
  }
441
- result === diff && (result = {
442
- ...diff
443
- }), result[key] = fixed;
444
696
  }
445
697
  return result;
446
698
  }