@tamagui/animations-motion 2.0.0-rc.8 → 2.0.0

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