@tamagui/animations-react-native 1.0.1-beta.106 → 1.0.1-beta.107

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({
@@ -76,22 +72,29 @@ function createAnimations(animations) {
76
72
  const animatedTranforms = (0, import_react.useRef)([]);
77
73
  const interpolations = (0, import_react.useRef)(/* @__PURE__ */ new WeakMap());
78
74
  const runners = [];
79
- function update(animated, valIn) {
80
- if (typeof props.animation !== "string") {
81
- return new import_react_native.Animated.Value(0);
82
- }
75
+ const completions = [];
76
+ function update(key, animated, valIn) {
83
77
  const [val, type] = getValue(valIn);
84
78
  const value = animated || new import_react_native.Animated.Value(val);
85
79
  if (type) {
86
80
  interpolations.current.set(value, getInterpolated(value, type, val));
87
81
  }
88
82
  if (animated) {
89
- const animationConfig = 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);
90
89
  runners.push(() => {
91
90
  import_react_native.Animated.spring(animated, __spreadValues({
92
91
  toValue: val,
93
92
  useNativeDriver: !import_core.isWeb
94
- }, animationConfig)).start();
93
+ }, animationConfig)).start(({ finished }) => {
94
+ if (finished) {
95
+ resolve();
96
+ }
97
+ });
95
98
  });
96
99
  }
97
100
  return value;
@@ -130,12 +133,12 @@ function createAnimations(animations) {
130
133
  continue;
131
134
  const tkey = Object.keys(transform)[0];
132
135
  animatedTranforms.current[index] = {
133
- [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])
134
137
  };
135
138
  }
136
139
  }
137
140
  } else {
138
- animateStyles.current[key] = update(animateStyles.current[key], val);
141
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
139
142
  }
140
143
  } else {
141
144
  nonAnimatedStyle[key] = val;
@@ -158,14 +161,19 @@ function createAnimations(animations) {
158
161
  delay,
159
162
  isPresent,
160
163
  onDidAnimate,
161
- onDidAnimateCb,
162
164
  presence == null ? void 0 : presence.exitVariant,
163
165
  presence == null ? void 0 : presence.enterVariant
164
166
  ];
165
- (0, import_react.useLayoutEffect)(() => {
167
+ (0, import_core.useIsomorphicLayoutEffect)(() => {
166
168
  for (const runner of runners) {
167
169
  runner();
168
170
  }
171
+ Promise.all(completions).then(() => {
172
+ onDidAnimate == null ? void 0 : onDidAnimate();
173
+ if (isExiting) {
174
+ sendExitComplete == null ? void 0 : sendExitComplete();
175
+ }
176
+ });
169
177
  }, args);
170
178
  return (0, import_react.useMemo)(() => {
171
179
  return {
@@ -175,6 +183,34 @@ function createAnimations(animations) {
175
183
  }
176
184
  };
177
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
+ }
178
214
  // Annotate the CommonJS export names for ESM import in node:
179
215
  0 && (module.exports = {
180
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 = 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\n function update(animated: Animated.Value | undefined, valIn: string | number) {\n if (typeof props.animation !== 'string') {\n return new Animated.Value(0)\n }\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 = animations[props.animation]\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\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(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 ...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 onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BAA6C;AAC7C,kBAAiF;AACjF,mBAA4C;AAC5C,0BAAyB;AAsBzB,MAAM,mBAAmB;AAAA,EACvB,WAAW;AAAA,EACX,SAAS;AACX;AAEO,0BAAsD,YAAmC;AAC9F,QAAM,eAAe,6BAAS;AAC9B,QAAM,eAAe,6BAAS;AAE9B,eAAa,iBAAiB;AAC9B,eAAa,iBAAiB;AAE9B,SAAO;AAAA,IACL,cAAc;AAAA,IACd;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe,CAAC,OAAO,YAAY;AA1CvC;AA2CM,YAAM,EAAE,cAAc,OAAO,UAAU,UAAU;AACjD,YAAM,CAAC,WAAW,oBAAoB,yCAAY;AAClD,YAAM,WAAW,6BAAW,uCAAe;AAM3C,YAAM,YAAY,cAAc;AAChC,YAAM,aAAa,CAAC,MAAM;AAE1B,YAAM,MAAM,SAAS;AAAA,QACnB;AAAA,QACA;AAAA,QACA,aAAa,qCAAU;AAAA,QACvB,cAAc,qCAAU;AAAA,MAC1B,CAAC;AAED,YAAM,gBAAgB,yBAAuC,CAAC,CAAC;AAC/D,YAAM,oBAAoB,yBAA4C,CAAC,CAAC;AACxE,YAAM,iBAAiB,yBAAO,oBAAI,QAAwD,CAAC;AAI3F,YAAM,UAAsB,CAAC;AAC7B,YAAM,cAA+B,CAAC;AAEtC,sBAAgB,KAAa,UAAsC,OAAwB;AACzF,cAAM,CAAC,KAAK,QAAQ,SAAS,KAAK;AAClC,cAAM,QAAQ,YAAY,IAAI,6BAAS,MAAM,GAAG;AAChD,YAAI,MAAM;AACR,yBAAe,QAAQ,IAAI,OAAO,gBAAgB,OAAO,MAAM,GAAG,CAAC;AAAA,QACrE;AACA,YAAI,UAAU;AACZ,gBAAM,kBAAkB,mBAAmB,KAAK,YAAY,MAAM,SAAS;AAE3E,cAAI;AACJ,gBAAM,UAAU,IAAI,QAAc,CAAC,QAAQ;AACzC,sBAAU;AAAA,UACZ,CAAC;AACD,sBAAY,KAAK,OAAO;AAExB,kBAAQ,KAAK,MAAM;AACjB,yCAAS,OAAO,UAAU;AAAA,cACxB,SAAS;AAAA,cACT,iBAAiB,CAAC;AAAA,eACf,gBACJ,EAAE,MAAM,CAAC,EAAE,eAAe;AACzB,kBAAI,UAAU;AACZ,wBAAQ;AAAA,cACV;AAAA,YACF,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT;AAEA,wBAAkB,OAAwB;AACxC,YAAI,OAAO,UAAU,UAAU;AAC7B,iBAAO,CAAC,KAAK;AAAA,QACf;AACA,cAAM,MAAM,MAAM,OAAO;AACzB,YAAI;AAAK,kBAAQ,MAAM,MAAM,CAAC;AAC9B,cAAM,CAAC,GAAG,QAAQ,SAAS,MAAM,MAAM,kBAAkB,KAAK,CAAC;AAC/D,eAAO,CAAC,CAAC,SAAU,OAAM,KAAK,IAAI,KAAK;AAAA,MACzC;AAEA,+BAAyB,KAAqB,SAAiB,MAAc;AAC3E,cAAM,MAAM,IAAI;AAChB,cAAM,aAAa,CAAC,KAAK,IAAI;AAC7B,cAAM,cAAc,CAAC,GAAG,UAAU,GAAG,SAAS;AAC9C,YAAI,OAAO,KAAK;AACd,qBAAW,QAAQ;AACnB,sBAAY,QAAQ;AAAA,QACtB;AACA,eAAO,IAAI,YAAY;AAAA,UACrB;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,mBAAmB,CAAC;AAC1B,iBAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,cAAM,MAAM,IAAI;AAChB,YAAI,iBAAiB,MAAM;AACzB,cAAI,QAAQ,aAAa;AAEvB,gBAAI,KAAK;AACP,yBAAW,CAAC,OAAO,cAAc,IAAI,QAAQ,GAAG;AAC9C,oBAAI,CAAC;AAAW;AAChB,sBAAM,OAAO,OAAO,KAAK,SAAS,EAAE;AACpC,kCAAkB,QAAQ,SAAS;AAAA,kBACjC,CAAC,OAAO,OAAO,MAAM,wBAAkB,QAAQ,WAA1B,mBAAmC,OAAO,UAAU,KAAK;AAAA,gBAChF;AAAA,cACF;AAAA,YACF;AAAA,UACF,OAAO;AACL,0BAAc,QAAQ,OAAO,OAAO,KAAK,cAAc,QAAQ,MAAM,GAAG;AAAA,UAC1E;AAAA,QACF,OAAO;AACL,2BAAiB,OAAO;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,gBAAgB,iCACjB,OAAO,YACR,OAAO,QAAQ,mBACV,cAAc,QAClB,EAAE,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,eAAe,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5D,IALoB;AAAA,QAMpB,WAAW,kBAAkB,QAAQ,IAAI,CAAC,MAAM;AAC9C,gBAAM,MAAM,OAAO,KAAK,CAAC,EAAE;AAC3B,gBAAM,MAAM,eAAe,QAAQ,IAAI,EAAE,IAAI,KAAK,EAAE;AACpD,iBAAO,EAAE,CAAC,MAAM,IAAI;AAAA,QACtB,CAAC;AAAA,MACH;AAEA,YAAM,OAAO;AAAA,QACX,KAAK,UAAU,GAAG;AAAA,QAClB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,qCAAU;AAAA,QACV,qCAAU;AAAA,MACZ;AAEA,iDAA0B,MAAM;AAE9B,mBAAW,UAAU,SAAS;AAC5B,iBAAO;AAAA,QACT;AACA,gBAAQ,IAAI,WAAW,EAAE,KAAK,MAAM;AAClC;AACA,cAAI,WAAW;AACb;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,GAAG,IAAI;AAEP,aAAO,0BAAQ,MAAM;AACnB,eAAO;AAAA,UACL,OAAO,CAAC,kBAAkB,aAAa;AAAA,QACzC;AAAA,MACF,GAAG,IAAI;AAAA,IACT;AAAA,EACF;AACF;AAEA,4BAA4B,KAAa,YAA8B,WAA2B;AAChG,MAAI,OAAO,cAAc,UAAU;AACjC,WAAO,WAAW;AAAA,EACpB;AACA,MAAI,OAAO;AACX,MAAI;AACJ,MAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,WAAO,UAAU;AACjB,UAAM,OAAO,UAAU,MAAM,UAAU,GAAG;AAC1C,QAAI,MAAM;AACR,UAAI,OAAO,SAAS,UAAU;AAC5B,eAAO;AAAA,MACT,OAAO;AACL,eAAQ,KAAa,QAAQ;AAC7B,oBAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAM,MAAM,uCAAY;AACxB,WAAO,2BAAK;AACZ,gBAAY;AAAA,EACd;AACA,QAAM,QAAQ,WAAW;AACzB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,yBAAyB,kBAAkB,MAAM;AAAA,EACnE;AACA,SAAO,kCACF,QACA;AAEP;",
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({
@@ -56,22 +52,29 @@ function createAnimations(animations) {
56
52
  const animatedTranforms = useRef([]);
57
53
  const interpolations = useRef(/* @__PURE__ */ new WeakMap());
58
54
  const runners = [];
59
- function update(animated, valIn) {
60
- if (typeof props.animation !== "string") {
61
- return new Animated.Value(0);
62
- }
55
+ const completions = [];
56
+ function update(key, animated, valIn) {
63
57
  const [val, type] = getValue(valIn);
64
58
  const value = animated || new Animated.Value(val);
65
59
  if (type) {
66
60
  interpolations.current.set(value, getInterpolated(value, type, val));
67
61
  }
68
62
  if (animated) {
69
- const animationConfig = 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);
70
69
  runners.push(() => {
71
70
  Animated.spring(animated, __spreadValues({
72
71
  toValue: val,
73
72
  useNativeDriver: !isWeb
74
- }, animationConfig)).start();
73
+ }, animationConfig)).start(({ finished }) => {
74
+ if (finished) {
75
+ resolve();
76
+ }
77
+ });
75
78
  });
76
79
  }
77
80
  return value;
@@ -110,12 +113,12 @@ function createAnimations(animations) {
110
113
  continue;
111
114
  const tkey = Object.keys(transform)[0];
112
115
  animatedTranforms.current[index] = {
113
- [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])
114
117
  };
115
118
  }
116
119
  }
117
120
  } else {
118
- animateStyles.current[key] = update(animateStyles.current[key], val);
121
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
119
122
  }
120
123
  } else {
121
124
  nonAnimatedStyle[key] = val;
@@ -138,14 +141,19 @@ function createAnimations(animations) {
138
141
  delay,
139
142
  isPresent,
140
143
  onDidAnimate,
141
- onDidAnimateCb,
142
144
  presence == null ? void 0 : presence.exitVariant,
143
145
  presence == null ? void 0 : presence.enterVariant
144
146
  ];
145
- useLayoutEffect(() => {
147
+ useIsomorphicLayoutEffect(() => {
146
148
  for (const runner of runners) {
147
149
  runner();
148
150
  }
151
+ Promise.all(completions).then(() => {
152
+ onDidAnimate == null ? void 0 : onDidAnimate();
153
+ if (isExiting) {
154
+ sendExitComplete == null ? void 0 : sendExitComplete();
155
+ }
156
+ });
149
157
  }, args);
150
158
  return useMemo(() => {
151
159
  return {
@@ -155,6 +163,34 @@ function createAnimations(animations) {
155
163
  }
156
164
  };
157
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
+ }
158
194
  export {
159
195
  createAnimations
160
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 = 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\n function update(animated: Animated.Value | undefined, valIn: string | number) {\n if (typeof props.animation !== 'string') {\n return new Animated.Value(0)\n }\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 = animations[props.animation]\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\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(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 ...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 onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\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": ";;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AAyBA,MAAM,mBAAmB;AAAA,EACvB,WAAW;AAAA,EACX,SAAS;AACX;AAEO,0BAAsD,YAAmC;AAC9F,QAAM,eAAe,SAAS;AAC9B,QAAM,eAAe,SAAS;AAE9B,eAAa,iBAAiB;AAC9B,eAAa,iBAAiB;AAE9B,SAAO;AAAA,IACL,cAAc;AAAA,IACd;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe,CAAC,OAAO,YAAY;AA7CvC;AA8CM,YAAM,EAAE,SAAS,cAAc,OAAO,UAAU,OAAO,iBAAiB;AACxE,YAAM,CAAC,WAAW,oBAAoB,YAAY;AAClD,YAAM,WAAW,WAAW,eAAe;AAE3C,YAAM,YAAY,sCAAU,eACxB,0BAAa,mBAAb,mBAA8B,SAAS,iBAAvC,mBAAqD,SAAQ,QAAQ,YACrE,QAAQ;AAEZ,YAAM,iBAAiB,YACrB,IAAI,UAAS;AACX,qDAAe,GAAG;AAAA,MACpB,GACA,CAAC,YAAY,CACf;AAEA,YAAM,YAAY,cAAc;AAChC,YAAM,aAAa,CAAC,MAAM;AAE1B,YAAM,MAAM,SAAS;AAAA,QACnB;AAAA,QACA;AAAA,QACA,aAAa,qCAAU;AAAA,QACvB,cAAc,qCAAU;AAAA,MAC1B,CAAC;AAED,YAAM,gBAAgB,OAAuC,CAAC,CAAC;AAC/D,YAAM,oBAAoB,OAA4C,CAAC,CAAC;AACxE,YAAM,iBAAiB,OAAO,oBAAI,QAAwD,CAAC;AAI3F,YAAM,UAAsB,CAAC;AAE7B,sBAAgB,UAAsC,OAAwB;AAC5E,YAAI,OAAO,MAAM,cAAc,UAAU;AACvC,iBAAO,IAAI,SAAS,MAAM,CAAC;AAAA,QAC7B;AACA,cAAM,CAAC,KAAK,QAAQ,SAAS,KAAK;AAClC,cAAM,QAAQ,YAAY,IAAI,SAAS,MAAM,GAAG;AAChD,YAAI,MAAM;AACR,yBAAe,QAAQ,IAAI,OAAO,gBAAgB,OAAO,MAAM,GAAG,CAAC;AAAA,QACrE;AACA,YAAI,UAAU;AACZ,gBAAM,kBAAkB,WAAW,MAAM;AACzC,kBAAQ,KAAK,MAAM;AACjB,qBAAS,OAAO,UAAU;AAAA,cACxB,SAAS;AAAA,cACT,iBAAiB,CAAC;AAAA,eACf,gBACJ,EAAE,MAAM;AAAA,UACX,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT;AAEA,wBAAkB,OAAwB;AACxC,YAAI,OAAO,UAAU,UAAU;AAC7B,iBAAO,CAAC,KAAK;AAAA,QACf;AACA,cAAM,MAAM,MAAM,OAAO;AACzB,YAAI;AAAK,kBAAQ,MAAM,MAAM,CAAC;AAC9B,cAAM,CAAC,GAAG,QAAQ,SAAS,MAAM,MAAM,kBAAkB,KAAK,CAAC;AAC/D,eAAO,CAAC,CAAC,SAAU,OAAM,KAAK,IAAI,KAAK;AAAA,MACzC;AAEA,+BAAyB,KAAqB,SAAiB,MAAc;AAC3E,cAAM,MAAM,IAAI;AAChB,cAAM,aAAa,CAAC,KAAK,IAAI;AAC7B,cAAM,cAAc,CAAC,GAAG,UAAU,GAAG,SAAS;AAC9C,YAAI,OAAO,KAAK;AACd,qBAAW,QAAQ;AACnB,sBAAY,QAAQ;AAAA,QACtB;AACA,eAAO,IAAI,YAAY;AAAA,UACrB;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,mBAAmB,CAAC;AAC1B,iBAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,cAAM,MAAM,IAAI;AAChB,YAAI,iBAAiB,MAAM;AACzB,cAAI,QAAQ,aAAa;AAEvB,gBAAI,KAAK;AACP,yBAAW,CAAC,OAAO,cAAc,IAAI,QAAQ,GAAG;AAC9C,oBAAI,CAAC;AAAW;AAChB,sBAAM,OAAO,OAAO,KAAK,SAAS,EAAE;AACpC,kCAAkB,QAAQ,SAAS;AAAA,kBACjC,CAAC,OAAO,OAAO,wBAAkB,QAAQ,WAA1B,mBAAmC,OAAO,UAAU,KAAK;AAAA,gBAC1E;AAAA,cACF;AAAA,YACF;AAAA,UACF,OAAO;AACL,0BAAc,QAAQ,OAAO,OAAO,cAAc,QAAQ,MAAM,GAAG;AAAA,UACrE;AAAA,QACF,OAAO;AACL,2BAAiB,OAAO;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,gBAAgB,iCACjB,OAAO,YACR,OAAO,QAAQ,mBACV,cAAc,QAClB,EAAE,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,eAAe,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5D,IALoB;AAAA,QAMpB,WAAW,kBAAkB,QAAQ,IAAI,CAAC,MAAM;AAC9C,gBAAM,MAAM,OAAO,KAAK,CAAC,EAAE;AAC3B,gBAAM,MAAM,eAAe,QAAQ,IAAI,EAAE,IAAI,KAAK,EAAE;AACpD,iBAAO,EAAE,CAAC,MAAM,IAAI;AAAA,QACtB,CAAC;AAAA,MACH;AAEA,YAAM,OAAO;AAAA,QACX,KAAK,UAAU,GAAG;AAAA,QAClB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,qCAAU;AAAA,QACV,qCAAU;AAAA,MACZ;AAEA,sBAAgB,MAAM;AAEpB,mBAAW,UAAU,SAAS;AAC5B,iBAAO;AAAA,QACT;AAAA,MACF,GAAG,IAAI;AAuBP,aAAO,QAAQ,MAAM;AACnB,eAAO;AAAA,UACL,OAAO,CAAC,kBAAkB,aAAa;AAAA,QACzC;AAAA,MACF,GAAG,IAAI;AAAA,IACT;AAAA,EACF;AACF;",
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({
@@ -37,23 +33,30 @@ function createAnimations(animations) {
37
33
  const animatedTranforms = useRef([]);
38
34
  const interpolations = useRef(/* @__PURE__ */ new WeakMap());
39
35
  const runners = [];
40
- function update(animated, valIn) {
41
- if (typeof props.animation !== "string") {
42
- return new Animated.Value(0);
43
- }
36
+ const completions = [];
37
+ function update(key, animated, valIn) {
44
38
  const [val, type] = getValue(valIn);
45
39
  const value = animated || new Animated.Value(val);
46
40
  if (type) {
47
41
  interpolations.current.set(value, getInterpolated(value, type, val));
48
42
  }
49
43
  if (animated) {
50
- const animationConfig = 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);
51
50
  runners.push(() => {
52
51
  Animated.spring(animated, {
53
52
  toValue: val,
54
53
  useNativeDriver: !isWeb,
55
54
  ...animationConfig
56
- }).start();
55
+ }).start(({ finished }) => {
56
+ if (finished) {
57
+ resolve();
58
+ }
59
+ });
57
60
  });
58
61
  }
59
62
  return value;
@@ -93,12 +96,12 @@ function createAnimations(animations) {
93
96
  continue;
94
97
  const tkey = Object.keys(transform)[0];
95
98
  animatedTranforms.current[index] = {
96
- [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])
97
100
  };
98
101
  }
99
102
  }
100
103
  } else {
101
- animateStyles.current[key] = update(animateStyles.current[key], val);
104
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
102
105
  }
103
106
  } else {
104
107
  nonAnimatedStyle[key] = val;
@@ -124,14 +127,19 @@ function createAnimations(animations) {
124
127
  delay,
125
128
  isPresent,
126
129
  onDidAnimate,
127
- onDidAnimateCb,
128
130
  presence == null ? void 0 : presence.exitVariant,
129
131
  presence == null ? void 0 : presence.enterVariant
130
132
  ];
131
- useLayoutEffect(() => {
133
+ useIsomorphicLayoutEffect(() => {
132
134
  for (const runner of runners) {
133
135
  runner();
134
136
  }
137
+ Promise.all(completions).then(() => {
138
+ onDidAnimate == null ? void 0 : onDidAnimate();
139
+ if (isExiting) {
140
+ sendExitComplete == null ? void 0 : sendExitComplete();
141
+ }
142
+ });
135
143
  }, args);
136
144
  return useMemo(() => {
137
145
  return {
@@ -141,6 +149,37 @@ function createAnimations(animations) {
141
149
  }
142
150
  };
143
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
+ }
144
183
  export {
145
184
  createAnimations
146
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 = 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\n function update(animated: Animated.Value | undefined, valIn: string | number) {\n if (typeof props.animation !== 'string') {\n return new Animated.Value(0)\n }\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 = animations[props.animation]\n runners.push(() => {\n Animated.spring(animated, {\n toValue: val,\n useNativeDriver: !isWeb,\n ...animationConfig,\n }).start()\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(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 ...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 onDidAnimateCb,\n presence?.exitVariant,\n presence?.enterVariant,\n ]\n\n useLayoutEffect(() => {\n //\n for (const runner of runners) {\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.106",
3
+ "version": "1.0.1-beta.107",
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.106",
18
- "@tamagui/core": "^1.0.1-beta.106"
17
+ "@tamagui/animate-presence": "^1.0.1-beta.107",
18
+ "@tamagui/core": "^1.0.1-beta.107"
19
19
  },
20
20
  "devDependencies": {
21
- "@tamagui/build": "^1.0.1-beta.106",
21
+ "@tamagui/build": "^1.0.1-beta.107",
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
@@ -76,24 +66,33 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
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: string | number) {
81
- if (typeof props.animation !== 'string') {
82
- return new Animated.Value(0)
83
- }
71
+ function update(key: string, animated: Animated.Value | undefined, valIn: string | number) {
84
72
  const [val, type] = getValue(valIn)
85
73
  const value = animated || new Animated.Value(val)
86
74
  if (type) {
87
75
  interpolations.current.set(value, getInterpolated(value, type, val))
88
76
  }
89
77
  if (animated) {
90
- const animationConfig = 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
+
91
86
  runners.push(() => {
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
97
  }
99
98
  return value
@@ -134,12 +133,12 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
134
133
  if (!transform) continue
135
134
  const tkey = Object.keys(transform)[0]
136
135
  animatedTranforms.current[index] = {
137
- [tkey]: update(animatedTranforms.current[index]?.[tkey], transform[tkey]),
136
+ [tkey]: update(tkey, animatedTranforms.current[index]?.[tkey], transform[tkey]),
138
137
  }
139
138
  }
140
139
  }
141
140
  } else {
142
- animateStyles.current[key] = update(animateStyles.current[key], val)
141
+ animateStyles.current[key] = update(key, animateStyles.current[key], val)
143
142
  }
144
143
  } else {
145
144
  nonAnimatedStyle[key] = val
@@ -169,39 +168,23 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
169
168
  delay,
170
169
  isPresent,
171
170
  onDidAnimate,
172
- onDidAnimateCb,
173
171
  presence?.exitVariant,
174
172
  presence?.enterVariant,
175
173
  ]
176
174
 
177
- useLayoutEffect(() => {
175
+ useIsomorphicLayoutEffect(() => {
178
176
  //
179
177
  for (const runner of runners) {
180
178
  runner()
181
179
  }
180
+ Promise.all(completions).then(() => {
181
+ onDidAnimate?.()
182
+ if (isExiting) {
183
+ sendExitComplete?.()
184
+ }
185
+ })
182
186
  }, args)
183
187
 
184
- // const callback = (
185
- // isExiting: boolean,
186
- // exitingStyleProps: Record<string, boolean>,
187
- // key: string,
188
- // value: any
189
- // ) => {
190
- // return (completed, current) => {
191
- // onDidAnimateCb(key, completed, current, {
192
- // attemptedValue: value,
193
- // })
194
- // if (isExiting) {
195
- // exitingStyleProps[key] = false
196
- // const areStylesExiting = Object.values(exitingStyleProps).some(Boolean)
197
- // // if this is true, then we've finished our exit animations
198
- // if (!areStylesExiting) {
199
- // sendExitComplete?.()
200
- // }
201
- // }
202
- // }
203
- // }
204
-
205
188
  return useMemo(() => {
206
189
  return {
207
190
  style: [nonAnimatedStyle, animatedStyle],
@@ -210,3 +193,35 @@ export function createAnimations<A extends AnimationsConfig>(animations: A): Ani
210
193
  },
211
194
  }
212
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,CAkL9F"}
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":""}