@tamagui/animations-react-native 1.0.1-beta.105 → 1.0.1-beta.108

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.
@@ -56,14 +56,10 @@ function createAnimations(animations) {
56
56
  View: AnimatedView,
57
57
  Text: AnimatedText,
58
58
  useAnimations: (props, helpers) => {
59
- var _a, _b, _c;
60
- const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers;
59
+ var _a;
60
+ const { onDidAnimate, delay, getStyle, state } = helpers;
61
61
  const [isPresent, sendExitComplete] = (0, import_animate_presence.usePresence)();
62
62
  const presence = (0, import_react.useContext)(import_animate_presence.PresenceContext);
63
- const exitStyle = (presence == null ? void 0 : presence.exitVariant) ? ((_b = (_a = staticConfig.variantsParsed) == null ? void 0 : _a[presence.exitVariant]) == null ? void 0 : _b.true) || pseudos.exitStyle : pseudos.exitStyle;
64
- const onDidAnimateCb = (0, import_react.useCallback)((...args2) => {
65
- onDidAnimate == null ? void 0 : onDidAnimate(...args2);
66
- }, [onDidAnimate]);
67
63
  const isExiting = isPresent === false;
68
64
  const isEntering = !state.mounted;
69
65
  const all = getStyle({
@@ -74,30 +70,57 @@ function createAnimations(animations) {
74
70
  });
75
71
  const animateStyles = (0, import_react.useRef)({});
76
72
  const animatedTranforms = (0, import_react.useRef)([]);
77
- const interpolations = /* @__PURE__ */ new WeakMap();
73
+ const interpolations = (0, import_react.useRef)(/* @__PURE__ */ new WeakMap());
78
74
  const runners = [];
79
- function update(animated, valIn) {
80
- let val = valIn;
81
- let postfix = "";
82
- if (typeof val === "string") {
83
- const [numbers, after] = val.split(/[0-9]+/);
84
- postfix = after;
85
- val = +numbers;
75
+ const completions = [];
76
+ function update(key, animated, valIn) {
77
+ const [val, type] = getValue(valIn);
78
+ const value = animated || new import_react_native.Animated.Value(val);
79
+ if (type) {
80
+ interpolations.current.set(value, getInterpolated(value, type, val));
86
81
  }
87
82
  if (animated) {
88
- const animationConfig = typeof props.animation === "string" && animations[props.animation];
83
+ const animationConfig = getAnimationConfig(key, animations, props.animation);
84
+ let resolve;
85
+ const promise = new Promise((res) => {
86
+ resolve = res;
87
+ });
88
+ completions.push(promise);
89
89
  runners.push(() => {
90
90
  import_react_native.Animated.spring(animated, __spreadValues({
91
91
  toValue: val,
92
92
  useNativeDriver: !import_core.isWeb
93
- }, animationConfig)).start();
93
+ }, animationConfig)).start(({ finished }) => {
94
+ if (finished) {
95
+ resolve();
96
+ }
97
+ });
94
98
  });
95
- return animated;
96
- } else {
97
- const res = new import_react_native.Animated.Value(val);
98
- interpolations.set(res, postfix);
99
- return res;
100
99
  }
100
+ return value;
101
+ }
102
+ function getValue(input) {
103
+ if (typeof input !== "string") {
104
+ return [input];
105
+ }
106
+ const neg = input[0] === "-";
107
+ if (neg)
108
+ input = input.slice(1);
109
+ const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? [];
110
+ return [+number * (neg ? -1 : 1), after];
111
+ }
112
+ function getInterpolated(val, postfix, next) {
113
+ const cur = val["_value"];
114
+ const inputRange = [cur, next];
115
+ const outputRange = [`${cur}deg`, `${next}deg`];
116
+ if (next < cur) {
117
+ inputRange.reverse();
118
+ outputRange.reverse();
119
+ }
120
+ return val.interpolate({
121
+ inputRange,
122
+ outputRange
123
+ });
101
124
  }
102
125
  const nonAnimatedStyle = {};
103
126
  for (const key of Object.keys(all)) {
@@ -110,19 +133,23 @@ function createAnimations(animations) {
110
133
  continue;
111
134
  const tkey = Object.keys(transform)[0];
112
135
  animatedTranforms.current[index] = {
113
- [tkey]: update((_c = animatedTranforms.current[index]) == null ? void 0 : _c[tkey], transform[tkey])
136
+ [tkey]: update(tkey, (_a = animatedTranforms.current[index]) == null ? void 0 : _a[tkey], transform[tkey])
114
137
  };
115
138
  }
116
139
  }
117
140
  } else {
118
- animateStyles.current[key] = update(animateStyles.current[key], val);
141
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
119
142
  }
120
143
  } else {
121
144
  nonAnimatedStyle[key] = val;
122
145
  }
123
146
  }
124
- const animatedStyle = __spreadProps(__spreadValues({}, animateStyles.current), {
125
- transform: animatedTranforms.current
147
+ const animatedStyle = __spreadProps(__spreadValues({}, Object.fromEntries(Object.entries(__spreadValues({}, animateStyles.current)).map(([k, v]) => [k, interpolations.current.get(v) || v]))), {
148
+ transform: animatedTranforms.current.map((r) => {
149
+ const key = Object.keys(r)[0];
150
+ const val = interpolations.current.get(r[key]) || r[key];
151
+ return { [key]: val };
152
+ })
126
153
  });
127
154
  const args = [
128
155
  JSON.stringify(all),
@@ -134,15 +161,19 @@ function createAnimations(animations) {
134
161
  delay,
135
162
  isPresent,
136
163
  onDidAnimate,
137
- onDidAnimateCb,
138
164
  presence == null ? void 0 : presence.exitVariant,
139
165
  presence == null ? void 0 : presence.enterVariant
140
166
  ];
141
- (0, import_react.useLayoutEffect)(() => {
167
+ (0, import_core.useIsomorphicLayoutEffect)(() => {
142
168
  for (const runner of runners) {
143
- console.log("gogo");
144
169
  runner();
145
170
  }
171
+ Promise.all(completions).then(() => {
172
+ onDidAnimate == null ? void 0 : onDidAnimate();
173
+ if (isExiting) {
174
+ sendExitComplete == null ? void 0 : sendExitComplete();
175
+ }
176
+ });
146
177
  }, args);
147
178
  return (0, import_react.useMemo)(() => {
148
179
  return {
@@ -152,6 +183,34 @@ function createAnimations(animations) {
152
183
  }
153
184
  };
154
185
  }
186
+ function getAnimationConfig(key, animations, animation) {
187
+ if (typeof animation === "string") {
188
+ return animations[animation];
189
+ }
190
+ let type = "";
191
+ let extraConf;
192
+ if (Array.isArray(animation)) {
193
+ type = animation[0];
194
+ const conf = animation[1] && animation[1][key];
195
+ if (conf) {
196
+ if (typeof conf === "string") {
197
+ type = conf;
198
+ } else {
199
+ type = conf.type || type;
200
+ extraConf = conf;
201
+ }
202
+ }
203
+ } else {
204
+ const val = animation == null ? void 0 : animation[key];
205
+ type = val == null ? void 0 : val.type;
206
+ extraConf = val;
207
+ }
208
+ const found = animations[type];
209
+ if (!found) {
210
+ throw new Error(`No animation of type "${type}" for key "${key}"`);
211
+ }
212
+ return __spreadValues(__spreadValues({}, found), extraConf);
213
+ }
155
214
  // Annotate the CommonJS export names for ESM import in node:
156
215
  0 && (module.exports = {
157
216
  createAnimations
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/createAnimations.tsx"],
4
- "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb } from '@tamagui/core'\nimport { useCallback, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n// | ({ type: 'timing'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithTimingConfig)\n// | ({ type: 'spring'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithSpringConfig)\n// | ({ type: 'decay'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithDecayConfig)\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n const exitStyle = presence?.exitVariant\n ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n : pseudos.exitStyle\n\n const onDidAnimateCb = useCallback<NonNullable<typeof onDidAnimate>>(\n (...args) => {\n onDidAnimate?.(...args)\n },\n [onDidAnimate]\n )\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = new WeakMap<Animated.Value, string>()\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n\n function update(animated: Animated.Value | undefined, valIn: any) {\n let val = valIn\n let postfix = ''\n if (typeof val === 'string') {\n const [numbers, after] = val.split(/[0-9]+/)\n postfix = after\n val = +numbers\n }\n if (animated) {\n const animationConfig = typeof props.animation === 'string' && animations[props.animation]\n runners.push(() => {\n // console.log('animate to', val, animationConfig)\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\n })\n return animated\n } else {\n const res = new Animated.Value(val)\n // console.log('set up', res, (val) =>\n // Animated.spring(res, { toValue: val, useNativeDriver: false }).start()\n // )\n interpolations.set(res, postfix)\n return res\n }\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n // console.log('tkey', tkey)\n animatedTranforms.current[index] = {\n [tkey]: update(animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...animateStyles.current,\n transform: animatedTranforms.current,\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\n console.log('gogo')\n runner()\n }\n }, args)\n\n // const callback = (\n // isExiting: boolean,\n // exitingStyleProps: Record<string, boolean>,\n // key: string,\n // value: any\n // ) => {\n // return (completed, current) => {\n // onDidAnimateCb(key, completed, current, {\n // attemptedValue: value,\n // })\n // if (isExiting) {\n // exitingStyleProps[key] = false\n // const areStylesExiting = Object.values(exitingStyleProps).some(Boolean)\n // // if this is true, then we've finished our exit animations\n // if (!areStylesExiting) {\n // sendExitComplete?.()\n // }\n // }\n // }\n // }\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'\nimport { useContext, useMemo, useRef } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { onDidAnimate, delay, getStyle, state } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n // const exitStyle = presence?.exitVariant\n // ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n // : pseudos.exitStyle\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = useRef(new WeakMap<Animated.Value, Animated.AnimatedInterpolation>())\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n const completions: Promise<void>[] = []\n\n function update(key: string, animated: Animated.Value | undefined, valIn: string | number) {\n const [val, type] = getValue(valIn)\n const value = animated || new Animated.Value(val)\n if (type) {\n interpolations.current.set(value, getInterpolated(value, type, val))\n }\n if (animated) {\n const animationConfig = getAnimationConfig(key, animations, props.animation)\n\n let resolve\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n completions.push(promise)\n\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start(({ finished }) => {\n if (finished) {\n resolve()\n }\n })\n })\n }\n return value\n }\n\n function getValue(input: number | string) {\n if (typeof input !== 'string') {\n return [input] as const\n }\n const neg = input[0] === '-'\n if (neg) input = input.slice(1)\n const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? []\n return [+number * (neg ? -1 : 1), after] as const\n }\n\n function getInterpolated(val: Animated.Value, postfix: string, next: number) {\n const cur = val['_value'] as number\n const inputRange = [cur, next]\n const outputRange = [`${cur}deg`, `${next}deg`]\n if (next < cur) {\n inputRange.reverse()\n outputRange.reverse()\n }\n return val.interpolate({\n inputRange,\n outputRange,\n })\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n animatedTranforms.current[index] = {\n [tkey]: update(tkey, animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(key, animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...Object.fromEntries(\n Object.entries({\n ...animateStyles.current,\n }).map(([k, v]) => [k, interpolations.current.get(v) || v])\n ),\n transform: animatedTranforms.current.map((r) => {\n const key = Object.keys(r)[0]\n const val = interpolations.current.get(r[key]) || r[key]\n return { [key]: val }\n }),\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useIsomorphicLayoutEffect(() => {\n //\n for (const runner of runners) {\n runner()\n }\n Promise.all(completions).then(() => {\n onDidAnimate?.()\n if (isExiting) {\n sendExitComplete?.()\n }\n })\n }, args)\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n\nfunction getAnimationConfig(key: string, animations: AnimationsConfig, animation?: AnimationProp) {\n if (typeof animation === 'string') {\n return animations[animation]\n }\n let type = ''\n let extraConf: any\n if (Array.isArray(animation)) {\n type = animation[0] as string\n const conf = animation[1] && animation[1][key]\n if (conf) {\n if (typeof conf === 'string') {\n type = conf\n } else {\n type = (conf as any).type || type\n extraConf = conf\n }\n }\n } else {\n const val = animation?.[key]\n type = val?.type\n extraConf = val\n }\n const found = animations[type]\n if (!found) {\n throw new Error(`No animation of type \"${type}\" for key \"${key}\"`)\n }\n return {\n ...found,\n ...extraConf,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/cjs/index.js CHANGED
@@ -14,5 +14,6 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
14
14
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
15
  var src_exports = {};
16
16
  module.exports = __toCommonJS(src_exports);
17
+ var import_polyfill = require("./polyfill");
17
18
  __reExport(src_exports, require("./createAnimations"), module.exports);
18
19
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.tsx"],
4
- "sourcesContent": ["export * from './createAnimations'\n"],
5
- "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,+BAAd;",
4
+ "sourcesContent": ["import './polyfill'\n\nexport * from './createAnimations'\n"],
5
+ "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;AAAA,sBAAO;AAEP,wBAAc,+BAFd;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,4 @@
1
+ if (typeof requestAnimationFrame === "undefined") {
2
+ globalThis["requestAnimationFrame"] = setImmediate;
3
+ }
4
+ //# sourceMappingURL=polyfill.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/polyfill.ts"],
4
+ "sourcesContent": ["// for SSR\nif (typeof requestAnimationFrame === 'undefined') {\n globalThis['requestAnimationFrame'] = setImmediate\n}\n"],
5
+ "mappings": "AACA,IAAI,OAAO,0BAA0B,aAAa;AAChD,aAAW,2BAA2B;AACxC;",
6
+ "names": []
7
+ }
@@ -18,8 +18,8 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  import { PresenceContext, usePresence } from "@tamagui/animate-presence";
21
- import { isWeb } from "@tamagui/core";
22
- import { useCallback, useContext, useLayoutEffect, useMemo, useRef } from "react";
21
+ import { isWeb, useIsomorphicLayoutEffect } from "@tamagui/core";
22
+ import { useContext, useMemo, useRef } from "react";
23
23
  import { Animated } from "react-native";
24
24
  const animatedStyleKey = {
25
25
  transform: true,
@@ -36,14 +36,10 @@ function createAnimations(animations) {
36
36
  View: AnimatedView,
37
37
  Text: AnimatedText,
38
38
  useAnimations: (props, helpers) => {
39
- var _a, _b, _c;
40
- const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers;
39
+ var _a;
40
+ const { onDidAnimate, delay, getStyle, state } = helpers;
41
41
  const [isPresent, sendExitComplete] = usePresence();
42
42
  const presence = useContext(PresenceContext);
43
- const exitStyle = (presence == null ? void 0 : presence.exitVariant) ? ((_b = (_a = staticConfig.variantsParsed) == null ? void 0 : _a[presence.exitVariant]) == null ? void 0 : _b.true) || pseudos.exitStyle : pseudos.exitStyle;
44
- const onDidAnimateCb = useCallback((...args2) => {
45
- onDidAnimate == null ? void 0 : onDidAnimate(...args2);
46
- }, [onDidAnimate]);
47
43
  const isExiting = isPresent === false;
48
44
  const isEntering = !state.mounted;
49
45
  const all = getStyle({
@@ -54,30 +50,57 @@ function createAnimations(animations) {
54
50
  });
55
51
  const animateStyles = useRef({});
56
52
  const animatedTranforms = useRef([]);
57
- const interpolations = /* @__PURE__ */ new WeakMap();
53
+ const interpolations = useRef(/* @__PURE__ */ new WeakMap());
58
54
  const runners = [];
59
- function update(animated, valIn) {
60
- let val = valIn;
61
- let postfix = "";
62
- if (typeof val === "string") {
63
- const [numbers, after] = val.split(/[0-9]+/);
64
- postfix = after;
65
- val = +numbers;
55
+ const completions = [];
56
+ function update(key, animated, valIn) {
57
+ const [val, type] = getValue(valIn);
58
+ const value = animated || new Animated.Value(val);
59
+ if (type) {
60
+ interpolations.current.set(value, getInterpolated(value, type, val));
66
61
  }
67
62
  if (animated) {
68
- const animationConfig = typeof props.animation === "string" && animations[props.animation];
63
+ const animationConfig = getAnimationConfig(key, animations, props.animation);
64
+ let resolve;
65
+ const promise = new Promise((res) => {
66
+ resolve = res;
67
+ });
68
+ completions.push(promise);
69
69
  runners.push(() => {
70
70
  Animated.spring(animated, __spreadValues({
71
71
  toValue: val,
72
72
  useNativeDriver: !isWeb
73
- }, animationConfig)).start();
73
+ }, animationConfig)).start(({ finished }) => {
74
+ if (finished) {
75
+ resolve();
76
+ }
77
+ });
74
78
  });
75
- return animated;
76
- } else {
77
- const res = new Animated.Value(val);
78
- interpolations.set(res, postfix);
79
- return res;
80
79
  }
80
+ return value;
81
+ }
82
+ function getValue(input) {
83
+ if (typeof input !== "string") {
84
+ return [input];
85
+ }
86
+ const neg = input[0] === "-";
87
+ if (neg)
88
+ input = input.slice(1);
89
+ const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? [];
90
+ return [+number * (neg ? -1 : 1), after];
91
+ }
92
+ function getInterpolated(val, postfix, next) {
93
+ const cur = val["_value"];
94
+ const inputRange = [cur, next];
95
+ const outputRange = [`${cur}deg`, `${next}deg`];
96
+ if (next < cur) {
97
+ inputRange.reverse();
98
+ outputRange.reverse();
99
+ }
100
+ return val.interpolate({
101
+ inputRange,
102
+ outputRange
103
+ });
81
104
  }
82
105
  const nonAnimatedStyle = {};
83
106
  for (const key of Object.keys(all)) {
@@ -90,19 +113,23 @@ function createAnimations(animations) {
90
113
  continue;
91
114
  const tkey = Object.keys(transform)[0];
92
115
  animatedTranforms.current[index] = {
93
- [tkey]: update((_c = animatedTranforms.current[index]) == null ? void 0 : _c[tkey], transform[tkey])
116
+ [tkey]: update(tkey, (_a = animatedTranforms.current[index]) == null ? void 0 : _a[tkey], transform[tkey])
94
117
  };
95
118
  }
96
119
  }
97
120
  } else {
98
- animateStyles.current[key] = update(animateStyles.current[key], val);
121
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
99
122
  }
100
123
  } else {
101
124
  nonAnimatedStyle[key] = val;
102
125
  }
103
126
  }
104
- const animatedStyle = __spreadProps(__spreadValues({}, animateStyles.current), {
105
- transform: animatedTranforms.current
127
+ const animatedStyle = __spreadProps(__spreadValues({}, Object.fromEntries(Object.entries(__spreadValues({}, animateStyles.current)).map(([k, v]) => [k, interpolations.current.get(v) || v]))), {
128
+ transform: animatedTranforms.current.map((r) => {
129
+ const key = Object.keys(r)[0];
130
+ const val = interpolations.current.get(r[key]) || r[key];
131
+ return { [key]: val };
132
+ })
106
133
  });
107
134
  const args = [
108
135
  JSON.stringify(all),
@@ -114,15 +141,19 @@ function createAnimations(animations) {
114
141
  delay,
115
142
  isPresent,
116
143
  onDidAnimate,
117
- onDidAnimateCb,
118
144
  presence == null ? void 0 : presence.exitVariant,
119
145
  presence == null ? void 0 : presence.enterVariant
120
146
  ];
121
- useLayoutEffect(() => {
147
+ useIsomorphicLayoutEffect(() => {
122
148
  for (const runner of runners) {
123
- console.log("gogo");
124
149
  runner();
125
150
  }
151
+ Promise.all(completions).then(() => {
152
+ onDidAnimate == null ? void 0 : onDidAnimate();
153
+ if (isExiting) {
154
+ sendExitComplete == null ? void 0 : sendExitComplete();
155
+ }
156
+ });
126
157
  }, args);
127
158
  return useMemo(() => {
128
159
  return {
@@ -132,6 +163,34 @@ function createAnimations(animations) {
132
163
  }
133
164
  };
134
165
  }
166
+ function getAnimationConfig(key, animations, animation) {
167
+ if (typeof animation === "string") {
168
+ return animations[animation];
169
+ }
170
+ let type = "";
171
+ let extraConf;
172
+ if (Array.isArray(animation)) {
173
+ type = animation[0];
174
+ const conf = animation[1] && animation[1][key];
175
+ if (conf) {
176
+ if (typeof conf === "string") {
177
+ type = conf;
178
+ } else {
179
+ type = conf.type || type;
180
+ extraConf = conf;
181
+ }
182
+ }
183
+ } else {
184
+ const val = animation == null ? void 0 : animation[key];
185
+ type = val == null ? void 0 : val.type;
186
+ extraConf = val;
187
+ }
188
+ const found = animations[type];
189
+ if (!found) {
190
+ throw new Error(`No animation of type "${type}" for key "${key}"`);
191
+ }
192
+ return __spreadValues(__spreadValues({}, found), extraConf);
193
+ }
135
194
  export {
136
195
  createAnimations
137
196
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/createAnimations.tsx"],
4
- "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb } from '@tamagui/core'\nimport { useCallback, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n// | ({ type: 'timing'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithTimingConfig)\n// | ({ type: 'spring'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithSpringConfig)\n// | ({ type: 'decay'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithDecayConfig)\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n const exitStyle = presence?.exitVariant\n ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n : pseudos.exitStyle\n\n const onDidAnimateCb = useCallback<NonNullable<typeof onDidAnimate>>(\n (...args) => {\n onDidAnimate?.(...args)\n },\n [onDidAnimate]\n )\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = new WeakMap<Animated.Value, string>()\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n\n function update(animated: Animated.Value | undefined, valIn: any) {\n let val = valIn\n let postfix = ''\n if (typeof val === 'string') {\n const [numbers, after] = val.split(/[0-9]+/)\n postfix = after\n val = +numbers\n }\n if (animated) {\n const animationConfig = typeof props.animation === 'string' && animations[props.animation]\n runners.push(() => {\n // console.log('animate to', val, animationConfig)\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\n })\n return animated\n } else {\n const res = new Animated.Value(val)\n // console.log('set up', res, (val) =>\n // Animated.spring(res, { toValue: val, useNativeDriver: false }).start()\n // )\n interpolations.set(res, postfix)\n return res\n }\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n // console.log('tkey', tkey)\n animatedTranforms.current[index] = {\n [tkey]: update(animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...animateStyles.current,\n transform: animatedTranforms.current,\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\n console.log('gogo')\n runner()\n }\n }, args)\n\n // const callback = (\n // isExiting: boolean,\n // exitingStyleProps: Record<string, boolean>,\n // key: string,\n // value: any\n // ) => {\n // return (completed, current) => {\n // onDidAnimateCb(key, completed, current, {\n // attemptedValue: value,\n // })\n // if (isExiting) {\n // exitingStyleProps[key] = false\n // const areStylesExiting = Object.values(exitingStyleProps).some(Boolean)\n // // if this is true, then we've finished our exit animations\n // if (!areStylesExiting) {\n // sendExitComplete?.()\n // }\n // }\n // }\n // }\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'\nimport { useContext, useMemo, useRef } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { onDidAnimate, delay, getStyle, state } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n // const exitStyle = presence?.exitVariant\n // ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n // : pseudos.exitStyle\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = useRef(new WeakMap<Animated.Value, Animated.AnimatedInterpolation>())\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n const completions: Promise<void>[] = []\n\n function update(key: string, animated: Animated.Value | undefined, valIn: string | number) {\n const [val, type] = getValue(valIn)\n const value = animated || new Animated.Value(val)\n if (type) {\n interpolations.current.set(value, getInterpolated(value, type, val))\n }\n if (animated) {\n const animationConfig = getAnimationConfig(key, animations, props.animation)\n\n let resolve\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n completions.push(promise)\n\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start(({ finished }) => {\n if (finished) {\n resolve()\n }\n })\n })\n }\n return value\n }\n\n function getValue(input: number | string) {\n if (typeof input !== 'string') {\n return [input] as const\n }\n const neg = input[0] === '-'\n if (neg) input = input.slice(1)\n const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? []\n return [+number * (neg ? -1 : 1), after] as const\n }\n\n function getInterpolated(val: Animated.Value, postfix: string, next: number) {\n const cur = val['_value'] as number\n const inputRange = [cur, next]\n const outputRange = [`${cur}deg`, `${next}deg`]\n if (next < cur) {\n inputRange.reverse()\n outputRange.reverse()\n }\n return val.interpolate({\n inputRange,\n outputRange,\n })\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n animatedTranforms.current[index] = {\n [tkey]: update(tkey, animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(key, animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...Object.fromEntries(\n Object.entries({\n ...animateStyles.current,\n }).map(([k, v]) => [k, interpolations.current.get(v) || v])\n ),\n transform: animatedTranforms.current.map((r) => {\n const key = Object.keys(r)[0]\n const val = interpolations.current.get(r[key]) || r[key]\n return { [key]: val }\n }),\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useIsomorphicLayoutEffect(() => {\n //\n for (const runner of runners) {\n runner()\n }\n Promise.all(completions).then(() => {\n onDidAnimate?.()\n if (isExiting) {\n sendExitComplete?.()\n }\n })\n }, args)\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n\nfunction getAnimationConfig(key: string, animations: AnimationsConfig, animation?: AnimationProp) {\n if (typeof animation === 'string') {\n return animations[animation]\n }\n let type = ''\n let extraConf: any\n if (Array.isArray(animation)) {\n type = animation[0] as string\n const conf = animation[1] && animation[1][key]\n if (conf) {\n if (typeof conf === 'string') {\n type = conf\n } else {\n type = (conf as any).type || type\n extraConf = conf\n }\n }\n } else {\n const val = animation?.[key]\n type = val?.type\n extraConf = val\n }\n const found = animations[type]\n if (!found) {\n throw new Error(`No animation of type \"${type}\" for key \"${key}\"`)\n }\n return {\n ...found,\n ...extraConf,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ import "./polyfill";
1
2
  export * from "./createAnimations";
2
3
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.tsx"],
4
- "sourcesContent": ["export * from './createAnimations'\n"],
5
- "mappings": "AAAA;",
4
+ "sourcesContent": ["import './polyfill'\n\nexport * from './createAnimations'\n"],
5
+ "mappings": "AAAA;AAEA;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,4 @@
1
+ if (typeof requestAnimationFrame === "undefined") {
2
+ globalThis["requestAnimationFrame"] = setImmediate;
3
+ }
4
+ //# sourceMappingURL=polyfill.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/polyfill.ts"],
4
+ "sourcesContent": ["// for SSR\nif (typeof requestAnimationFrame === 'undefined') {\n globalThis['requestAnimationFrame'] = setImmediate\n}\n"],
5
+ "mappings": "AACA,IAAI,OAAO,0BAA0B,aAAa;AAChD,aAAW,2BAA2B;AACxC;",
6
+ "names": []
7
+ }
@@ -1,6 +1,6 @@
1
1
  import { PresenceContext, usePresence } from "@tamagui/animate-presence";
2
- import { isWeb } from "@tamagui/core";
3
- import { useCallback, useContext, useLayoutEffect, useMemo, useRef } from "react";
2
+ import { isWeb, useIsomorphicLayoutEffect } from "@tamagui/core";
3
+ import { useContext, useMemo, useRef } from "react";
4
4
  import { Animated } from "react-native";
5
5
  const animatedStyleKey = {
6
6
  transform: true,
@@ -17,14 +17,10 @@ function createAnimations(animations) {
17
17
  View: AnimatedView,
18
18
  Text: AnimatedText,
19
19
  useAnimations: (props, helpers) => {
20
- var _a, _b, _c;
21
- const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers;
20
+ var _a;
21
+ const { onDidAnimate, delay, getStyle, state } = helpers;
22
22
  const [isPresent, sendExitComplete] = usePresence();
23
23
  const presence = useContext(PresenceContext);
24
- const exitStyle = (presence == null ? void 0 : presence.exitVariant) ? ((_b = (_a = staticConfig.variantsParsed) == null ? void 0 : _a[presence.exitVariant]) == null ? void 0 : _b.true) || pseudos.exitStyle : pseudos.exitStyle;
25
- const onDidAnimateCb = useCallback((...args2) => {
26
- onDidAnimate == null ? void 0 : onDidAnimate(...args2);
27
- }, [onDidAnimate]);
28
24
  const isExiting = isPresent === false;
29
25
  const isEntering = !state.mounted;
30
26
  const all = getStyle({
@@ -35,31 +31,59 @@ function createAnimations(animations) {
35
31
  });
36
32
  const animateStyles = useRef({});
37
33
  const animatedTranforms = useRef([]);
38
- const interpolations = /* @__PURE__ */ new WeakMap();
34
+ const interpolations = useRef(/* @__PURE__ */ new WeakMap());
39
35
  const runners = [];
40
- function update(animated, valIn) {
41
- let val = valIn;
42
- let postfix = "";
43
- if (typeof val === "string") {
44
- const [numbers, after] = val.split(/[0-9]+/);
45
- postfix = after;
46
- val = +numbers;
36
+ const completions = [];
37
+ function update(key, animated, valIn) {
38
+ const [val, type] = getValue(valIn);
39
+ const value = animated || new Animated.Value(val);
40
+ if (type) {
41
+ interpolations.current.set(value, getInterpolated(value, type, val));
47
42
  }
48
43
  if (animated) {
49
- const animationConfig = typeof props.animation === "string" && animations[props.animation];
44
+ const animationConfig = getAnimationConfig(key, animations, props.animation);
45
+ let resolve;
46
+ const promise = new Promise((res) => {
47
+ resolve = res;
48
+ });
49
+ completions.push(promise);
50
50
  runners.push(() => {
51
51
  Animated.spring(animated, {
52
52
  toValue: val,
53
53
  useNativeDriver: !isWeb,
54
54
  ...animationConfig
55
- }).start();
55
+ }).start(({ finished }) => {
56
+ if (finished) {
57
+ resolve();
58
+ }
59
+ });
56
60
  });
57
- return animated;
58
- } else {
59
- const res = new Animated.Value(val);
60
- interpolations.set(res, postfix);
61
- return res;
62
61
  }
62
+ return value;
63
+ }
64
+ function getValue(input) {
65
+ var _a2;
66
+ if (typeof input !== "string") {
67
+ return [input];
68
+ }
69
+ const neg = input[0] === "-";
70
+ if (neg)
71
+ input = input.slice(1);
72
+ const [_, number, after] = (_a2 = input.match(/([-0-9]+)(deg|%)/)) != null ? _a2 : [];
73
+ return [+number * (neg ? -1 : 1), after];
74
+ }
75
+ function getInterpolated(val, postfix, next) {
76
+ const cur = val["_value"];
77
+ const inputRange = [cur, next];
78
+ const outputRange = [`${cur}deg`, `${next}deg`];
79
+ if (next < cur) {
80
+ inputRange.reverse();
81
+ outputRange.reverse();
82
+ }
83
+ return val.interpolate({
84
+ inputRange,
85
+ outputRange
86
+ });
63
87
  }
64
88
  const nonAnimatedStyle = {};
65
89
  for (const key of Object.keys(all)) {
@@ -72,20 +96,26 @@ function createAnimations(animations) {
72
96
  continue;
73
97
  const tkey = Object.keys(transform)[0];
74
98
  animatedTranforms.current[index] = {
75
- [tkey]: update((_c = animatedTranforms.current[index]) == null ? void 0 : _c[tkey], transform[tkey])
99
+ [tkey]: update(tkey, (_a = animatedTranforms.current[index]) == null ? void 0 : _a[tkey], transform[tkey])
76
100
  };
77
101
  }
78
102
  }
79
103
  } else {
80
- animateStyles.current[key] = update(animateStyles.current[key], val);
104
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
81
105
  }
82
106
  } else {
83
107
  nonAnimatedStyle[key] = val;
84
108
  }
85
109
  }
86
110
  const animatedStyle = {
87
- ...animateStyles.current,
88
- transform: animatedTranforms.current
111
+ ...Object.fromEntries(Object.entries({
112
+ ...animateStyles.current
113
+ }).map(([k, v]) => [k, interpolations.current.get(v) || v])),
114
+ transform: animatedTranforms.current.map((r) => {
115
+ const key = Object.keys(r)[0];
116
+ const val = interpolations.current.get(r[key]) || r[key];
117
+ return { [key]: val };
118
+ })
89
119
  };
90
120
  const args = [
91
121
  JSON.stringify(all),
@@ -97,15 +127,19 @@ function createAnimations(animations) {
97
127
  delay,
98
128
  isPresent,
99
129
  onDidAnimate,
100
- onDidAnimateCb,
101
130
  presence == null ? void 0 : presence.exitVariant,
102
131
  presence == null ? void 0 : presence.enterVariant
103
132
  ];
104
- useLayoutEffect(() => {
133
+ useIsomorphicLayoutEffect(() => {
105
134
  for (const runner of runners) {
106
- console.log("gogo");
107
135
  runner();
108
136
  }
137
+ Promise.all(completions).then(() => {
138
+ onDidAnimate == null ? void 0 : onDidAnimate();
139
+ if (isExiting) {
140
+ sendExitComplete == null ? void 0 : sendExitComplete();
141
+ }
142
+ });
109
143
  }, args);
110
144
  return useMemo(() => {
111
145
  return {
@@ -115,6 +149,37 @@ function createAnimations(animations) {
115
149
  }
116
150
  };
117
151
  }
152
+ function getAnimationConfig(key, animations, animation) {
153
+ if (typeof animation === "string") {
154
+ return animations[animation];
155
+ }
156
+ let type = "";
157
+ let extraConf;
158
+ if (Array.isArray(animation)) {
159
+ type = animation[0];
160
+ const conf = animation[1] && animation[1][key];
161
+ if (conf) {
162
+ if (typeof conf === "string") {
163
+ type = conf;
164
+ } else {
165
+ type = conf.type || type;
166
+ extraConf = conf;
167
+ }
168
+ }
169
+ } else {
170
+ const val = animation == null ? void 0 : animation[key];
171
+ type = val == null ? void 0 : val.type;
172
+ extraConf = val;
173
+ }
174
+ const found = animations[type];
175
+ if (!found) {
176
+ throw new Error(`No animation of type "${type}" for key "${key}"`);
177
+ }
178
+ return {
179
+ ...found,
180
+ ...extraConf
181
+ };
182
+ }
118
183
  export {
119
184
  createAnimations
120
185
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/createAnimations.tsx"],
4
- "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb } from '@tamagui/core'\nimport { useCallback, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n// | ({ type: 'timing'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithTimingConfig)\n// | ({ type: 'spring'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithSpringConfig)\n// | ({ type: 'decay'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithDecayConfig)\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n const exitStyle = presence?.exitVariant\n ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n : pseudos.exitStyle\n\n const onDidAnimateCb = useCallback<NonNullable<typeof onDidAnimate>>(\n (...args) => {\n onDidAnimate?.(...args)\n },\n [onDidAnimate]\n )\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = new WeakMap<Animated.Value, string>()\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n\n function update(animated: Animated.Value | undefined, valIn: any) {\n let val = valIn\n let postfix = ''\n if (typeof val === 'string') {\n const [numbers, after] = val.split(/[0-9]+/)\n postfix = after\n val = +numbers\n }\n if (animated) {\n const animationConfig = typeof props.animation === 'string' && animations[props.animation]\n runners.push(() => {\n // console.log('animate to', val, animationConfig)\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\n })\n return animated\n } else {\n const res = new Animated.Value(val)\n // console.log('set up', res, (val) =>\n // Animated.spring(res, { toValue: val, useNativeDriver: false }).start()\n // )\n interpolations.set(res, postfix)\n return res\n }\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n // console.log('tkey', tkey)\n animatedTranforms.current[index] = {\n [tkey]: update(animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...animateStyles.current,\n transform: animatedTranforms.current,\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\n console.log('gogo')\n runner()\n }\n }, args)\n\n // const callback = (\n // isExiting: boolean,\n // exitingStyleProps: Record<string, boolean>,\n // key: string,\n // value: any\n // ) => {\n // return (completed, current) => {\n // onDidAnimateCb(key, completed, current, {\n // attemptedValue: value,\n // })\n // if (isExiting) {\n // exitingStyleProps[key] = false\n // const areStylesExiting = Object.values(exitingStyleProps).some(Boolean)\n // // if this is true, then we've finished our exit animations\n // if (!areStylesExiting) {\n // sendExitComplete?.()\n // }\n // }\n // }\n // }\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { PresenceContext, usePresence } from '@tamagui/animate-presence'\nimport { AnimationDriver, AnimationProp, isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'\nimport { useContext, useMemo, useRef } from 'react'\nimport { Animated } from 'react-native'\n\ntype AnimationsConfig<A extends Object = any> = {\n [Key in keyof A]: AnimationConfig\n}\n\ntype AnimationConfig = Partial<\n Pick<\n Animated.SpringAnimationConfig,\n | 'delay'\n | 'bounciness'\n | 'damping'\n | 'friction'\n | 'mass'\n | 'overshootClamping'\n | 'speed'\n | 'stiffness'\n | 'tension'\n | 'velocity'\n >\n>\n\nconst animatedStyleKey = {\n transform: true,\n opacity: true,\n}\n\nexport function createAnimations<A extends AnimationsConfig>(animations: A): AnimationDriver<A> {\n const AnimatedView = Animated.View\n const AnimatedText = Animated.Text\n\n AnimatedView['displayName'] = 'AnimatedView'\n AnimatedText['displayName'] = 'AnimatedText'\n\n return {\n avoidClasses: true,\n animations,\n View: AnimatedView,\n Text: AnimatedText,\n useAnimations: (props, helpers) => {\n const { onDidAnimate, delay, getStyle, state } = helpers\n const [isPresent, sendExitComplete] = usePresence()\n const presence = useContext(PresenceContext)\n\n // const exitStyle = presence?.exitVariant\n // ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle\n // : pseudos.exitStyle\n\n const isExiting = isPresent === false\n const isEntering = !state.mounted\n\n const all = getStyle({\n isExiting,\n isEntering,\n exitVariant: presence?.exitVariant,\n enterVariant: presence?.enterVariant,\n })\n\n const animateStyles = useRef<Record<string, Animated.Value>>({})\n const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])\n const interpolations = useRef(new WeakMap<Animated.Value, Animated.AnimatedInterpolation>())\n\n // TODO loop and create values, run them if they change\n\n const runners: Function[] = []\n const completions: Promise<void>[] = []\n\n function update(key: string, animated: Animated.Value | undefined, valIn: string | number) {\n const [val, type] = getValue(valIn)\n const value = animated || new Animated.Value(val)\n if (type) {\n interpolations.current.set(value, getInterpolated(value, type, val))\n }\n if (animated) {\n const animationConfig = getAnimationConfig(key, animations, props.animation)\n\n let resolve\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n completions.push(promise)\n\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start(({ finished }) => {\n if (finished) {\n resolve()\n }\n })\n })\n }\n return value\n }\n\n function getValue(input: number | string) {\n if (typeof input !== 'string') {\n return [input] as const\n }\n const neg = input[0] === '-'\n if (neg) input = input.slice(1)\n const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? []\n return [+number * (neg ? -1 : 1), after] as const\n }\n\n function getInterpolated(val: Animated.Value, postfix: string, next: number) {\n const cur = val['_value'] as number\n const inputRange = [cur, next]\n const outputRange = [`${cur}deg`, `${next}deg`]\n if (next < cur) {\n inputRange.reverse()\n outputRange.reverse()\n }\n return val.interpolate({\n inputRange,\n outputRange,\n })\n }\n\n const nonAnimatedStyle = {}\n for (const key of Object.keys(all)) {\n const val = all[key]\n if (animatedStyleKey[key]) {\n if (key === 'transform') {\n // for now just support one transform key\n if (val) {\n for (const [index, transform] of val.entries()) {\n if (!transform) continue\n const tkey = Object.keys(transform)[0]\n animatedTranforms.current[index] = {\n [tkey]: update(tkey, animatedTranforms.current[index]?.[tkey], transform[tkey]),\n }\n }\n }\n } else {\n animateStyles.current[key] = update(key, animateStyles.current[key], val)\n }\n } else {\n nonAnimatedStyle[key] = val\n }\n }\n\n const animatedStyle = {\n ...Object.fromEntries(\n Object.entries({\n ...animateStyles.current,\n }).map(([k, v]) => [k, interpolations.current.get(v) || v])\n ),\n transform: animatedTranforms.current.map((r) => {\n const key = Object.keys(r)[0]\n const val = interpolations.current.get(r[key]) || r[key]\n return { [key]: val }\n }),\n }\n\n const args = [\n JSON.stringify(all),\n state.mounted,\n state.hover,\n state.press,\n state.pressIn,\n state.focus,\n delay,\n isPresent,\n onDidAnimate,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useIsomorphicLayoutEffect(() => {\n //\n for (const runner of runners) {\n runner()\n }\n Promise.all(completions).then(() => {\n onDidAnimate?.()\n if (isExiting) {\n sendExitComplete?.()\n }\n })\n }, args)\n\n return useMemo(() => {\n return {\n style: [nonAnimatedStyle, animatedStyle],\n }\n }, args)\n },\n }\n}\n\nfunction getAnimationConfig(key: string, animations: AnimationsConfig, animation?: AnimationProp) {\n if (typeof animation === 'string') {\n return animations[animation]\n }\n let type = ''\n let extraConf: any\n if (Array.isArray(animation)) {\n type = animation[0] as string\n const conf = animation[1] && animation[1][key]\n if (conf) {\n if (typeof conf === 'string') {\n type = conf\n } else {\n type = (conf as any).type || type\n extraConf = conf\n }\n }\n } else {\n const val = animation?.[key]\n type = val?.type\n extraConf = val\n }\n const found = animations[type]\n if (!found) {\n throw new Error(`No animation of type \"${type}\" for key \"${key}\"`)\n }\n return {\n ...found,\n ...extraConf,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/jsx/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ import "./polyfill";
1
2
  export * from "./createAnimations";
2
3
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.tsx"],
4
- "sourcesContent": ["export * from './createAnimations'\n"],
5
- "mappings": "AAAA;",
4
+ "sourcesContent": ["import './polyfill'\n\nexport * from './createAnimations'\n"],
5
+ "mappings": "AAAA;AAEA;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,4 @@
1
+ if (typeof requestAnimationFrame === "undefined") {
2
+ globalThis["requestAnimationFrame"] = setImmediate;
3
+ }
4
+ //# sourceMappingURL=polyfill.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/polyfill.ts"],
4
+ "sourcesContent": ["// for SSR\nif (typeof requestAnimationFrame === 'undefined') {\n globalThis['requestAnimationFrame'] = setImmediate\n}\n"],
5
+ "mappings": "AACA,IAAI,OAAO,0BAA0B,aAAa;AAChD,aAAW,2BAA2B;AACxC;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/animations-react-native",
3
- "version": "1.0.1-beta.105",
3
+ "version": "1.0.1-beta.108",
4
4
  "source": "src/index.ts",
5
5
  "sideEffects": true,
6
6
  "license": "MIT",
@@ -14,11 +14,11 @@
14
14
  "dist"
15
15
  ],
16
16
  "dependencies": {
17
- "@tamagui/animate-presence": "^1.0.1-beta.105",
18
- "@tamagui/core": "^1.0.1-beta.105"
17
+ "@tamagui/animate-presence": "^1.0.1-beta.108",
18
+ "@tamagui/core": "^1.0.1-beta.108"
19
19
  },
20
20
  "devDependencies": {
21
- "@tamagui/build": "^1.0.1-beta.105",
21
+ "@tamagui/build": "^1.0.1-beta.108",
22
22
  "react": "*",
23
23
  "react-dom": "*",
24
24
  "react-native": "*"
@@ -1,6 +1,6 @@
1
1
  import { PresenceContext, usePresence } from '@tamagui/animate-presence'
2
- import { AnimationDriver, AnimationProp, isWeb } from '@tamagui/core'
3
- import { useCallback, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react'
2
+ import { AnimationDriver, AnimationProp, isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'
3
+ import { useContext, useMemo, useRef } from 'react'
4
4
  import { Animated } from 'react-native'
5
5
 
6
6
  type AnimationsConfig<A extends Object = any> = {
@@ -22,9 +22,6 @@ type AnimationConfig = Partial<
22
22
  | 'velocity'
23
23
  >
24
24
  >
25
- // | ({ type: 'timing'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithTimingConfig)
26
- // | ({ type: 'spring'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithSpringConfig)
27
- // | ({ type: 'decay'; loop?: number; repeat?: number; repeatReverse?: boolean } & WithDecayConfig)
28
25
 
29
26
  const animatedStyleKey = {
30
27
  transform: true,
@@ -44,20 +41,13 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
44
41
  View: AnimatedView,
45
42
  Text: AnimatedText,
46
43
  useAnimations: (props, helpers) => {
47
- const { pseudos, onDidAnimate, delay, getStyle, state, staticConfig } = helpers
44
+ const { onDidAnimate, delay, getStyle, state } = helpers
48
45
  const [isPresent, sendExitComplete] = usePresence()
49
46
  const presence = useContext(PresenceContext)
50
47
 
51
- const exitStyle = presence?.exitVariant
52
- ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle
53
- : pseudos.exitStyle
54
-
55
- const onDidAnimateCb = useCallback<NonNullable<typeof onDidAnimate>>(
56
- (...args) => {
57
- onDidAnimate?.(...args)
58
- },
59
- [onDidAnimate]
60
- )
48
+ // const exitStyle = presence?.exitVariant
49
+ // ? staticConfig.variantsParsed?.[presence.exitVariant]?.true || pseudos.exitStyle
50
+ // : pseudos.exitStyle
61
51
 
62
52
  const isExiting = isPresent === false
63
53
  const isEntering = !state.mounted
@@ -71,39 +61,65 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
71
61
 
72
62
  const animateStyles = useRef<Record<string, Animated.Value>>({})
73
63
  const animatedTranforms = useRef<{ [key: string]: Animated.Value }[]>([])
74
- const interpolations = new WeakMap<Animated.Value, string>()
64
+ const interpolations = useRef(new WeakMap<Animated.Value, Animated.AnimatedInterpolation>())
75
65
 
76
66
  // TODO loop and create values, run them if they change
77
67
 
78
68
  const runners: Function[] = []
69
+ const completions: Promise<void>[] = []
79
70
 
80
- function update(animated: Animated.Value | undefined, valIn: any) {
81
- let val = valIn
82
- let postfix = ''
83
- if (typeof val === 'string') {
84
- const [numbers, after] = val.split(/[0-9]+/)
85
- postfix = after
86
- val = +numbers
71
+ function update(key: string, animated: Animated.Value | undefined, valIn: string | number) {
72
+ const [val, type] = getValue(valIn)
73
+ const value = animated || new Animated.Value(val)
74
+ if (type) {
75
+ interpolations.current.set(value, getInterpolated(value, type, val))
87
76
  }
88
77
  if (animated) {
89
- const animationConfig = typeof props.animation === 'string' && animations[props.animation]
78
+ const animationConfig = getAnimationConfig(key, animations, props.animation)
79
+
80
+ let resolve
81
+ const promise = new Promise<void>((res) => {
82
+ resolve = res
83
+ })
84
+ completions.push(promise)
85
+
90
86
  runners.push(() => {
91
- // console.log('animate to', val, animationConfig)
92
87
  Animated.spring(animated, {
93
88
  toValue: val,
94
89
  useNativeDriver: !isWeb,
95
90
  ...animationConfig,
96
- }).start()
91
+ }).start(({ finished }) => {
92
+ if (finished) {
93
+ resolve()
94
+ }
95
+ })
97
96
  })
98
- return animated
99
- } else {
100
- const res = new Animated.Value(val)
101
- // console.log('set up', res, (val) =>
102
- // Animated.spring(res, { toValue: val, useNativeDriver: false }).start()
103
- // )
104
- interpolations.set(res, postfix)
105
- return res
106
97
  }
98
+ return value
99
+ }
100
+
101
+ function getValue(input: number | string) {
102
+ if (typeof input !== 'string') {
103
+ return [input] as const
104
+ }
105
+ const neg = input[0] === '-'
106
+ if (neg) input = input.slice(1)
107
+ const [_, number, after] = input.match(/([-0-9]+)(deg|%)/) ?? []
108
+ return [+number * (neg ? -1 : 1), after] as const
109
+ }
110
+
111
+ function getInterpolated(val: Animated.Value, postfix: string, next: number) {
112
+ const cur = val['_value'] as number
113
+ const inputRange = [cur, next]
114
+ const outputRange = [`${cur}deg`, `${next}deg`]
115
+ if (next < cur) {
116
+ inputRange.reverse()
117
+ outputRange.reverse()
118
+ }
119
+ return val.interpolate({
120
+ inputRange,
121
+ outputRange,
122
+ })
107
123
  }
108
124
 
109
125
  const nonAnimatedStyle = {}
@@ -116,14 +132,13 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
116
132
  for (const [index, transform] of val.entries()) {
117
133
  if (!transform) continue
118
134
  const tkey = Object.keys(transform)[0]
119
- // console.log('tkey', tkey)
120
135
  animatedTranforms.current[index] = {
121
- [tkey]: update(animatedTranforms.current[index]?.[tkey], transform[tkey]),
136
+ [tkey]: update(tkey, animatedTranforms.current[index]?.[tkey], transform[tkey]),
122
137
  }
123
138
  }
124
139
  }
125
140
  } else {
126
- animateStyles.current[key] = update(animateStyles.current[key], val)
141
+ animateStyles.current[key] = update(key, animateStyles.current[key], val)
127
142
  }
128
143
  } else {
129
144
  nonAnimatedStyle[key] = val
@@ -131,8 +146,16 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
131
146
  }
132
147
 
133
148
  const animatedStyle = {
134
- ...animateStyles.current,
135
- transform: animatedTranforms.current,
149
+ ...Object.fromEntries(
150
+ Object.entries({
151
+ ...animateStyles.current,
152
+ }).map(([k, v]) => [k, interpolations.current.get(v) || v])
153
+ ),
154
+ transform: animatedTranforms.current.map((r) => {
155
+ const key = Object.keys(r)[0]
156
+ const val = interpolations.current.get(r[key]) || r[key]
157
+ return { [key]: val }
158
+ }),
136
159
  }
137
160
 
138
161
  const args = [
@@ -145,40 +168,23 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
145
168
  delay,
146
169
  isPresent,
147
170
  onDidAnimate,
148
- onDidAnimateCb,
149
171
  presence?.exitVariant,
150
172
  presence?.enterVariant,
151
173
  ]
152
174
 
153
- useLayoutEffect(() => {
175
+ useIsomorphicLayoutEffect(() => {
154
176
  //
155
177
  for (const runner of runners) {
156
- console.log('gogo')
157
178
  runner()
158
179
  }
180
+ Promise.all(completions).then(() => {
181
+ onDidAnimate?.()
182
+ if (isExiting) {
183
+ sendExitComplete?.()
184
+ }
185
+ })
159
186
  }, args)
160
187
 
161
- // const callback = (
162
- // isExiting: boolean,
163
- // exitingStyleProps: Record<string, boolean>,
164
- // key: string,
165
- // value: any
166
- // ) => {
167
- // return (completed, current) => {
168
- // onDidAnimateCb(key, completed, current, {
169
- // attemptedValue: value,
170
- // })
171
- // if (isExiting) {
172
- // exitingStyleProps[key] = false
173
- // const areStylesExiting = Object.values(exitingStyleProps).some(Boolean)
174
- // // if this is true, then we've finished our exit animations
175
- // if (!areStylesExiting) {
176
- // sendExitComplete?.()
177
- // }
178
- // }
179
- // }
180
- // }
181
-
182
188
  return useMemo(() => {
183
189
  return {
184
190
  style: [nonAnimatedStyle, animatedStyle],
@@ -187,3 +193,35 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
187
193
  },
188
194
  }
189
195
  }
196
+
197
+ function getAnimationConfig(key: string, animations: AnimationsConfig, animation?: AnimationProp) {
198
+ if (typeof animation === 'string') {
199
+ return animations[animation]
200
+ }
201
+ let type = ''
202
+ let extraConf: any
203
+ if (Array.isArray(animation)) {
204
+ type = animation[0] as string
205
+ const conf = animation[1] && animation[1][key]
206
+ if (conf) {
207
+ if (typeof conf === 'string') {
208
+ type = conf
209
+ } else {
210
+ type = (conf as any).type || type
211
+ extraConf = conf
212
+ }
213
+ }
214
+ } else {
215
+ const val = animation?.[key]
216
+ type = val?.type
217
+ extraConf = val
218
+ }
219
+ const found = animations[type]
220
+ if (!found) {
221
+ throw new Error(`No animation of type "${type}" for key "${key}"`)
222
+ }
223
+ return {
224
+ ...found,
225
+ ...extraConf,
226
+ }
227
+ }
package/src/index.tsx CHANGED
@@ -1 +1,3 @@
1
+ import './polyfill'
2
+
1
3
  export * from './createAnimations'
@@ -0,0 +1,4 @@
1
+ // for SSR
2
+ if (typeof requestAnimationFrame === 'undefined') {
3
+ globalThis['requestAnimationFrame'] = setImmediate
4
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"createAnimations.d.ts","sourceRoot":"","sources":["../src/createAnimations.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAwB,MAAM,eAAe,CAAA;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,aAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,IAAI;KAC7C,GAAG,IAAI,MAAM,CAAC,GAAG,eAAe;CAClC,CAAA;AAED,aAAK,eAAe,GAAG,OAAO,CAC5B,IAAI,CACF,QAAQ,CAAC,qBAAqB,EAC5B,OAAO,GACP,YAAY,GACZ,SAAS,GACT,UAAU,GACV,MAAM,GACN,mBAAmB,GACnB,OAAO,GACP,WAAW,GACX,SAAS,GACT,UAAU,CACb,CACF,CAAA;AAUD,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EAAE,UAAU,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CA2J9F"}
1
+ {"version":3,"file":"createAnimations.d.ts","sourceRoot":"","sources":["../src/createAnimations.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAmD,MAAM,eAAe,CAAA;AAEhG,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,aAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,IAAI;KAC7C,GAAG,IAAI,MAAM,CAAC,GAAG,eAAe;CAClC,CAAA;AAED,aAAK,eAAe,GAAG,OAAO,CAC5B,IAAI,CACF,QAAQ,CAAC,qBAAqB,EAC5B,OAAO,GACP,YAAY,GACZ,SAAS,GACT,UAAU,GACV,MAAM,GACN,mBAAmB,GACnB,OAAO,GACP,WAAW,GACX,SAAS,GACT,UAAU,CACb,CACF,CAAA;AAOD,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EAAE,UAAU,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAoK9F"}
package/types/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ import './polyfill';
1
2
  export * from './createAnimations';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAA;AAEnB,cAAc,oBAAoB,CAAA"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=polyfill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polyfill.d.ts","sourceRoot":"","sources":["../src/polyfill.ts"],"names":[],"mappings":""}