@number10/jsx-core 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/LICENSE +667 -0
  2. package/README.md +38 -0
  3. package/dist/animation/animated-signal.cjs +19 -0
  4. package/dist/animation/animated-signal.cjs.map +1 -0
  5. package/dist/animation/animated-signal.d.ts +35 -0
  6. package/dist/animation/animated-signal.d.ts.map +1 -0
  7. package/dist/animation/animated-signal.js +19 -0
  8. package/dist/animation/animated-signal.js.map +1 -0
  9. package/dist/animation/create-spring.cjs +80 -0
  10. package/dist/animation/create-spring.cjs.map +1 -0
  11. package/dist/animation/create-spring.d.ts +56 -0
  12. package/dist/animation/create-spring.d.ts.map +1 -0
  13. package/dist/animation/create-spring.js +80 -0
  14. package/dist/animation/create-spring.js.map +1 -0
  15. package/dist/animation/easing.cjs +76 -0
  16. package/dist/animation/easing.cjs.map +1 -0
  17. package/dist/animation/easing.d.ts +45 -0
  18. package/dist/animation/easing.d.ts.map +1 -0
  19. package/dist/animation/easing.js +76 -0
  20. package/dist/animation/easing.js.map +1 -0
  21. package/dist/animation/effect-definitions.cjs +441 -0
  22. package/dist/animation/effect-definitions.cjs.map +1 -0
  23. package/dist/animation/effect-definitions.d.ts +60 -0
  24. package/dist/animation/effect-definitions.d.ts.map +1 -0
  25. package/dist/animation/effect-definitions.js +441 -0
  26. package/dist/animation/effect-definitions.js.map +1 -0
  27. package/dist/animation/effect-engine.cjs +189 -0
  28. package/dist/animation/effect-engine.cjs.map +1 -0
  29. package/dist/animation/effect-engine.d.ts +70 -0
  30. package/dist/animation/effect-engine.d.ts.map +1 -0
  31. package/dist/animation/effect-engine.js +189 -0
  32. package/dist/animation/effect-engine.js.map +1 -0
  33. package/dist/animation/index.d.ts +24 -0
  34. package/dist/animation/index.d.ts.map +1 -0
  35. package/dist/animation/spring-physics.cjs +94 -0
  36. package/dist/animation/spring-physics.cjs.map +1 -0
  37. package/dist/animation/spring-physics.d.ts +145 -0
  38. package/dist/animation/spring-physics.d.ts.map +1 -0
  39. package/dist/animation/spring-physics.js +94 -0
  40. package/dist/animation/spring-physics.js.map +1 -0
  41. package/dist/animation/tween.cjs +67 -0
  42. package/dist/animation/tween.cjs.map +1 -0
  43. package/dist/animation/tween.d.ts +60 -0
  44. package/dist/animation/tween.d.ts.map +1 -0
  45. package/dist/animation/tween.js +67 -0
  46. package/dist/animation/tween.js.map +1 -0
  47. package/dist/animation/types.d.ts +31 -0
  48. package/dist/animation/types.d.ts.map +1 -0
  49. package/dist/animation/useSpring.cjs +152 -0
  50. package/dist/animation/useSpring.cjs.map +1 -0
  51. package/dist/animation/useSpring.d.ts +55 -0
  52. package/dist/animation/useSpring.d.ts.map +1 -0
  53. package/dist/animation/useSpring.js +149 -0
  54. package/dist/animation/useSpring.js.map +1 -0
  55. package/dist/animation/useTween.cjs +208 -0
  56. package/dist/animation/useTween.cjs.map +1 -0
  57. package/dist/animation/useTween.d.ts +116 -0
  58. package/dist/animation/useTween.d.ts.map +1 -0
  59. package/dist/animation/useTween.js +208 -0
  60. package/dist/animation/useTween.js.map +1 -0
  61. package/dist/border-geometry.cjs +447 -0
  62. package/dist/border-geometry.cjs.map +1 -0
  63. package/dist/border-geometry.d.ts +114 -0
  64. package/dist/border-geometry.d.ts.map +1 -0
  65. package/dist/border-geometry.js +447 -0
  66. package/dist/border-geometry.js.map +1 -0
  67. package/dist/colors/color-presets.cjs +236 -0
  68. package/dist/colors/color-presets.cjs.map +1 -0
  69. package/dist/colors/color-presets.d.ts +89 -0
  70. package/dist/colors/color-presets.d.ts.map +1 -0
  71. package/dist/colors/color-presets.js +236 -0
  72. package/dist/colors/color-presets.js.map +1 -0
  73. package/dist/colors/color-theme-helpers.cjs +32 -0
  74. package/dist/colors/color-theme-helpers.cjs.map +1 -0
  75. package/dist/colors/color-theme-helpers.d.ts +65 -0
  76. package/dist/colors/color-theme-helpers.d.ts.map +1 -0
  77. package/dist/colors/color-theme-helpers.js +32 -0
  78. package/dist/colors/color-theme-helpers.js.map +1 -0
  79. package/dist/colors/color-types.cjs +38 -0
  80. package/dist/colors/color-types.cjs.map +1 -0
  81. package/dist/colors/color-types.d.ts +112 -0
  82. package/dist/colors/color-types.d.ts.map +1 -0
  83. package/dist/colors/color-types.js +38 -0
  84. package/dist/colors/color-types.js.map +1 -0
  85. package/dist/colors/color-utils.cjs +197 -0
  86. package/dist/colors/color-utils.cjs.map +1 -0
  87. package/dist/colors/color-utils.d.ts +216 -0
  88. package/dist/colors/color-utils.d.ts.map +1 -0
  89. package/dist/colors/color-utils.js +197 -0
  90. package/dist/colors/color-utils.js.map +1 -0
  91. package/dist/colors/contrast-contracts.cjs +265 -0
  92. package/dist/colors/contrast-contracts.cjs.map +1 -0
  93. package/dist/colors/contrast-contracts.d.ts +289 -0
  94. package/dist/colors/contrast-contracts.d.ts.map +1 -0
  95. package/dist/colors/contrast-contracts.js +265 -0
  96. package/dist/colors/contrast-contracts.js.map +1 -0
  97. package/dist/colors/index.cjs +55 -0
  98. package/dist/colors/index.cjs.map +1 -0
  99. package/dist/colors/index.d.ts +16 -0
  100. package/dist/colors/index.d.ts.map +1 -0
  101. package/dist/colors/index.js +55 -0
  102. package/dist/colors/index.js.map +1 -0
  103. package/dist/core-props.cjs +66 -0
  104. package/dist/core-props.cjs.map +1 -0
  105. package/dist/core-props.d.ts +395 -0
  106. package/dist/core-props.d.ts.map +1 -0
  107. package/dist/core-props.js +66 -0
  108. package/dist/core-props.js.map +1 -0
  109. package/dist/design-tokens/design-token-presets.cjs +91 -0
  110. package/dist/design-tokens/design-token-presets.cjs.map +1 -0
  111. package/dist/design-tokens/design-token-presets.d.ts +34 -0
  112. package/dist/design-tokens/design-token-presets.d.ts.map +1 -0
  113. package/dist/design-tokens/design-token-presets.js +91 -0
  114. package/dist/design-tokens/design-token-presets.js.map +1 -0
  115. package/dist/design-tokens/design-token-types.d.ts +97 -0
  116. package/dist/design-tokens/design-token-types.d.ts.map +1 -0
  117. package/dist/design-tokens/index.cjs +10 -0
  118. package/dist/design-tokens/index.cjs.map +1 -0
  119. package/dist/design-tokens/index.d.ts +9 -0
  120. package/dist/design-tokens/index.d.ts.map +1 -0
  121. package/dist/design-tokens/index.js +10 -0
  122. package/dist/design-tokens/index.js.map +1 -0
  123. package/dist/dev-config.cjs +296 -0
  124. package/dist/dev-config.cjs.map +1 -0
  125. package/dist/dev-config.d.ts +238 -0
  126. package/dist/dev-config.d.ts.map +1 -0
  127. package/dist/dev-config.js +296 -0
  128. package/dist/dev-config.js.map +1 -0
  129. package/dist/effects.cjs +69 -0
  130. package/dist/effects.cjs.map +1 -0
  131. package/dist/effects.d.ts +152 -0
  132. package/dist/effects.d.ts.map +1 -0
  133. package/dist/effects.js +69 -0
  134. package/dist/effects.js.map +1 -0
  135. package/dist/global-registry.cjs +25 -0
  136. package/dist/global-registry.cjs.map +1 -0
  137. package/dist/global-registry.d.ts +19 -0
  138. package/dist/global-registry.d.ts.map +1 -0
  139. package/dist/global-registry.js +25 -0
  140. package/dist/global-registry.js.map +1 -0
  141. package/dist/hooks.cjs +378 -0
  142. package/dist/hooks.cjs.map +1 -0
  143. package/dist/hooks.d.ts +322 -0
  144. package/dist/hooks.d.ts.map +1 -0
  145. package/dist/hooks.js +378 -0
  146. package/dist/hooks.js.map +1 -0
  147. package/dist/host-adapter.d.ts +414 -0
  148. package/dist/host-adapter.d.ts.map +1 -0
  149. package/dist/index.cjs +229 -0
  150. package/dist/index.cjs.map +1 -0
  151. package/dist/index.d.ts +32 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +226 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/jsx-dev-runtime.cjs +10 -0
  156. package/dist/jsx-dev-runtime.cjs.map +1 -0
  157. package/dist/jsx-dev-runtime.d.ts +5 -0
  158. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  159. package/dist/jsx-dev-runtime.js +11 -0
  160. package/dist/jsx-dev-runtime.js.map +1 -0
  161. package/dist/jsx-runtime.cjs +44 -0
  162. package/dist/jsx-runtime.cjs.map +1 -0
  163. package/dist/jsx-runtime.d.ts +24 -0
  164. package/dist/jsx-runtime.d.ts.map +1 -0
  165. package/dist/jsx-runtime.js +44 -0
  166. package/dist/jsx-runtime.js.map +1 -0
  167. package/dist/jsx-types.d.ts +25 -0
  168. package/dist/jsx-types.d.ts.map +1 -0
  169. package/dist/layout/appliers/container-applier.cjs +20 -0
  170. package/dist/layout/appliers/container-applier.cjs.map +1 -0
  171. package/dist/layout/appliers/container-applier.d.ts +9 -0
  172. package/dist/layout/appliers/container-applier.d.ts.map +1 -0
  173. package/dist/layout/appliers/container-applier.js +20 -0
  174. package/dist/layout/appliers/container-applier.js.map +1 -0
  175. package/dist/layout/appliers/position-applier.cjs +31 -0
  176. package/dist/layout/appliers/position-applier.cjs.map +1 -0
  177. package/dist/layout/appliers/position-applier.d.ts +8 -0
  178. package/dist/layout/appliers/position-applier.d.ts.map +1 -0
  179. package/dist/layout/appliers/position-applier.js +31 -0
  180. package/dist/layout/appliers/position-applier.js.map +1 -0
  181. package/dist/layout/layout-engine-test-utils.d.ts +26 -0
  182. package/dist/layout/layout-engine-test-utils.d.ts.map +1 -0
  183. package/dist/layout/layout-engine.cjs +628 -0
  184. package/dist/layout/layout-engine.cjs.map +1 -0
  185. package/dist/layout/layout-engine.d.ts +140 -0
  186. package/dist/layout/layout-engine.d.ts.map +1 -0
  187. package/dist/layout/layout-engine.js +628 -0
  188. package/dist/layout/layout-engine.js.map +1 -0
  189. package/dist/layout/strategies/base-strategy.cjs +31 -0
  190. package/dist/layout/strategies/base-strategy.cjs.map +1 -0
  191. package/dist/layout/strategies/base-strategy.d.ts +59 -0
  192. package/dist/layout/strategies/base-strategy.d.ts.map +1 -0
  193. package/dist/layout/strategies/base-strategy.js +31 -0
  194. package/dist/layout/strategies/base-strategy.js.map +1 -0
  195. package/dist/layout/strategies/column-layout.cjs +145 -0
  196. package/dist/layout/strategies/column-layout.cjs.map +1 -0
  197. package/dist/layout/strategies/column-layout.d.ts +38 -0
  198. package/dist/layout/strategies/column-layout.d.ts.map +1 -0
  199. package/dist/layout/strategies/column-layout.js +145 -0
  200. package/dist/layout/strategies/column-layout.js.map +1 -0
  201. package/dist/layout/strategies/row-layout.cjs +145 -0
  202. package/dist/layout/strategies/row-layout.cjs.map +1 -0
  203. package/dist/layout/strategies/row-layout.d.ts +38 -0
  204. package/dist/layout/strategies/row-layout.d.ts.map +1 -0
  205. package/dist/layout/strategies/row-layout.js +145 -0
  206. package/dist/layout/strategies/row-layout.js.map +1 -0
  207. package/dist/layout/strategies/stack-layout.cjs +94 -0
  208. package/dist/layout/strategies/stack-layout.cjs.map +1 -0
  209. package/dist/layout/strategies/stack-layout.d.ts +30 -0
  210. package/dist/layout/strategies/stack-layout.d.ts.map +1 -0
  211. package/dist/layout/strategies/stack-layout.js +94 -0
  212. package/dist/layout/strategies/stack-layout.js.map +1 -0
  213. package/dist/layout/types.d.ts +134 -0
  214. package/dist/layout/types.d.ts.map +1 -0
  215. package/dist/layout/utils/child-utils.cjs +129 -0
  216. package/dist/layout/utils/child-utils.cjs.map +1 -0
  217. package/dist/layout/utils/child-utils.d.ts +54 -0
  218. package/dist/layout/utils/child-utils.d.ts.map +1 -0
  219. package/dist/layout/utils/child-utils.js +129 -0
  220. package/dist/layout/utils/child-utils.js.map +1 -0
  221. package/dist/layout/utils/dimension-calculator.cjs +109 -0
  222. package/dist/layout/utils/dimension-calculator.cjs.map +1 -0
  223. package/dist/layout/utils/dimension-calculator.d.ts +59 -0
  224. package/dist/layout/utils/dimension-calculator.d.ts.map +1 -0
  225. package/dist/layout/utils/dimension-calculator.js +109 -0
  226. package/dist/layout/utils/dimension-calculator.js.map +1 -0
  227. package/dist/layout/utils/flex-distributor.cjs +173 -0
  228. package/dist/layout/utils/flex-distributor.cjs.map +1 -0
  229. package/dist/layout/utils/flex-distributor.d.ts +18 -0
  230. package/dist/layout/utils/flex-distributor.d.ts.map +1 -0
  231. package/dist/layout/utils/flex-distributor.js +173 -0
  232. package/dist/layout/utils/flex-distributor.js.map +1 -0
  233. package/dist/layout/utils/size-resolver.cjs +280 -0
  234. package/dist/layout/utils/size-resolver.cjs.map +1 -0
  235. package/dist/layout/utils/size-resolver.d.ts +84 -0
  236. package/dist/layout/utils/size-resolver.d.ts.map +1 -0
  237. package/dist/layout/utils/size-resolver.js +280 -0
  238. package/dist/layout/utils/size-resolver.js.map +1 -0
  239. package/dist/layout/utils/spacing-calculator.cjs +50 -0
  240. package/dist/layout/utils/spacing-calculator.cjs.map +1 -0
  241. package/dist/layout/utils/spacing-calculator.d.ts +27 -0
  242. package/dist/layout/utils/spacing-calculator.d.ts.map +1 -0
  243. package/dist/layout/utils/spacing-calculator.js +50 -0
  244. package/dist/layout/utils/spacing-calculator.js.map +1 -0
  245. package/dist/memo.cjs +18 -0
  246. package/dist/memo.cjs.map +1 -0
  247. package/dist/memo.d.ts +29 -0
  248. package/dist/memo.d.ts.map +1 -0
  249. package/dist/memo.js +18 -0
  250. package/dist/memo.js.map +1 -0
  251. package/dist/nineslice-contract.cjs +60 -0
  252. package/dist/nineslice-contract.cjs.map +1 -0
  253. package/dist/nineslice-contract.d.ts +107 -0
  254. package/dist/nineslice-contract.d.ts.map +1 -0
  255. package/dist/nineslice-contract.js +60 -0
  256. package/dist/nineslice-contract.js.map +1 -0
  257. package/dist/placeholder.cjs +12 -0
  258. package/dist/placeholder.cjs.map +1 -0
  259. package/dist/placeholder.d.ts +44 -0
  260. package/dist/placeholder.d.ts.map +1 -0
  261. package/dist/placeholder.js +12 -0
  262. package/dist/placeholder.js.map +1 -0
  263. package/dist/portal.cjs +89 -0
  264. package/dist/portal.cjs.map +1 -0
  265. package/dist/portal.d.ts +62 -0
  266. package/dist/portal.d.ts.map +1 -0
  267. package/dist/portal.js +89 -0
  268. package/dist/portal.js.map +1 -0
  269. package/dist/primitive-contracts.cjs +12 -0
  270. package/dist/primitive-contracts.cjs.map +1 -0
  271. package/dist/primitive-contracts.d.ts +186 -0
  272. package/dist/primitive-contracts.d.ts.map +1 -0
  273. package/dist/primitive-contracts.js +12 -0
  274. package/dist/primitive-contracts.js.map +1 -0
  275. package/dist/theme.cjs +332 -0
  276. package/dist/theme.cjs.map +1 -0
  277. package/dist/theme.d.ts +204 -0
  278. package/dist/theme.d.ts.map +1 -0
  279. package/dist/theme.js +332 -0
  280. package/dist/theme.js.map +1 -0
  281. package/dist/types.d.ts +86 -0
  282. package/dist/types.d.ts.map +1 -0
  283. package/dist/vdom/create-runtime.cjs +79 -0
  284. package/dist/vdom/create-runtime.cjs.map +1 -0
  285. package/dist/vdom/create-runtime.d.ts +7 -0
  286. package/dist/vdom/create-runtime.d.ts.map +1 -0
  287. package/dist/vdom/create-runtime.js +79 -0
  288. package/dist/vdom/create-runtime.js.map +1 -0
  289. package/dist/vdom/index.cjs +8 -0
  290. package/dist/vdom/index.cjs.map +1 -0
  291. package/dist/vdom/index.d.ts +4 -0
  292. package/dist/vdom/index.d.ts.map +1 -0
  293. package/dist/vdom/index.js +8 -0
  294. package/dist/vdom/index.js.map +1 -0
  295. package/dist/vdom/mount.cjs +161 -0
  296. package/dist/vdom/mount.cjs.map +1 -0
  297. package/dist/vdom/mount.d.ts +6 -0
  298. package/dist/vdom/mount.d.ts.map +1 -0
  299. package/dist/vdom/mount.js +161 -0
  300. package/dist/vdom/mount.js.map +1 -0
  301. package/dist/vdom/patch.cjs +163 -0
  302. package/dist/vdom/patch.cjs.map +1 -0
  303. package/dist/vdom/patch.d.ts +3 -0
  304. package/dist/vdom/patch.d.ts.map +1 -0
  305. package/dist/vdom/patch.js +163 -0
  306. package/dist/vdom/patch.js.map +1 -0
  307. package/dist/vdom/registry.cjs +85 -0
  308. package/dist/vdom/registry.cjs.map +1 -0
  309. package/dist/vdom/registry.d.ts +28 -0
  310. package/dist/vdom/registry.d.ts.map +1 -0
  311. package/dist/vdom/registry.js +85 -0
  312. package/dist/vdom/registry.js.map +1 -0
  313. package/dist/vdom/runtime-helpers.cjs +23 -0
  314. package/dist/vdom/runtime-helpers.cjs.map +1 -0
  315. package/dist/vdom/runtime-helpers.d.ts +8 -0
  316. package/dist/vdom/runtime-helpers.d.ts.map +1 -0
  317. package/dist/vdom/runtime-helpers.js +23 -0
  318. package/dist/vdom/runtime-helpers.js.map +1 -0
  319. package/dist/vdom/surface.cjs +107 -0
  320. package/dist/vdom/surface.cjs.map +1 -0
  321. package/dist/vdom/surface.d.ts +9 -0
  322. package/dist/vdom/surface.d.ts.map +1 -0
  323. package/dist/vdom/surface.js +107 -0
  324. package/dist/vdom/surface.js.map +1 -0
  325. package/dist/vdom/types.d.ts +104 -0
  326. package/dist/vdom/types.d.ts.map +1 -0
  327. package/dist/vdom/utils.cjs +146 -0
  328. package/dist/vdom/utils.cjs.map +1 -0
  329. package/dist/vdom/utils.d.ts +24 -0
  330. package/dist/vdom/utils.d.ts.map +1 -0
  331. package/dist/vdom/utils.js +146 -0
  332. package/dist/vdom/utils.js.map +1 -0
  333. package/dist/vdom.d.ts +4 -0
  334. package/dist/vdom.d.ts.map +1 -0
  335. package/dist/vector-draw-context.d.ts +63 -0
  336. package/dist/vector-draw-context.d.ts.map +1 -0
  337. package/package.json +161 -0
  338. package/vdom/index.cjs +1 -0
  339. package/vdom/index.d.ts +1 -0
  340. package/vdom/index.js +1 -0
@@ -0,0 +1,149 @@
1
+ import { computed } from "@preact/signals-core";
2
+ import { useRef, getCurrentCtx, useEffect } from "../hooks.js";
3
+ import { animatedSignal } from "./animated-signal.js";
4
+ import { SPRING_PRESETS, SpringPhysics } from "./spring-physics.js";
5
+ function useSpring(initialValue, config, onComplete) {
6
+ const resolvedConfig = typeof config === "string" ? SPRING_PRESETS[config] : config ?? SPRING_PRESETS.default;
7
+ const valueSignal = useRef(null);
8
+ if (valueSignal.current === null) {
9
+ valueSignal.current = animatedSignal(initialValue);
10
+ }
11
+ const ctx = getCurrentCtx();
12
+ const scheduler = ctx?.surface?.scheduler ?? null;
13
+ const state = useRef({ value: initialValue, velocity: 0 });
14
+ const target = useRef({ value: initialValue });
15
+ const physics = useRef(new SpringPhysics(resolvedConfig));
16
+ const schedulerRef = useRef(null);
17
+ const wasAtRest = useRef(true);
18
+ if (scheduler && schedulerRef.current !== scheduler) {
19
+ schedulerRef.current = scheduler;
20
+ }
21
+ const setValueRef = useRef(
22
+ null
23
+ );
24
+ if (!setValueRef.current) {
25
+ setValueRef.current = (newTarget) => {
26
+ const nextTarget = typeof newTarget === "function" ? newTarget(target.current.value) : newTarget;
27
+ target.current.value = nextTarget;
28
+ };
29
+ }
30
+ useEffect(() => {
31
+ const currentScheduler = schedulerRef.current;
32
+ if (!currentScheduler) {
33
+ console.warn("useSpring: HostScheduler not found in surface context");
34
+ return;
35
+ }
36
+ const updateListener = (delta) => {
37
+ const currentTarget = target.current.value;
38
+ const currentState = state.current;
39
+ const atRest = physics.current.isAtRest(currentState, currentTarget);
40
+ if (wasAtRest.current && !atRest) {
41
+ resolvedConfig.onStart?.();
42
+ }
43
+ if (atRest && !wasAtRest.current && onComplete) {
44
+ onComplete();
45
+ }
46
+ wasAtRest.current = atRest;
47
+ if (atRest) {
48
+ const snapped = physics.current.snapIfAtRest(currentState, currentTarget);
49
+ if (snapped.value !== currentState.value && valueSignal.current) {
50
+ state.current = snapped;
51
+ valueSignal.current.value = snapped.value;
52
+ }
53
+ return;
54
+ }
55
+ const deltaSeconds = delta / 1e3;
56
+ const newState = physics.current.step(currentState, currentTarget, deltaSeconds);
57
+ resolvedConfig.onUpdate?.(newState.value);
58
+ if (valueSignal.current) {
59
+ state.current = newState;
60
+ valueSignal.current.value = newState.value;
61
+ }
62
+ };
63
+ const handle = currentScheduler.onFrame(updateListener);
64
+ return () => {
65
+ handle.cancel();
66
+ };
67
+ }, []);
68
+ if (!valueSignal.current) {
69
+ throw new Error("useSpring: Failed to initialize animated signal");
70
+ }
71
+ return [
72
+ valueSignal.current,
73
+ setValueRef.current
74
+ ];
75
+ }
76
+ function useSprings(initialValues, config) {
77
+ const keys = Object.keys(initialValues);
78
+ const springsMap = useRef(/* @__PURE__ */ new Map());
79
+ const schedulerRef = useRef(null);
80
+ const resolvedConfig = typeof config === "string" ? SPRING_PRESETS[config] : config ?? SPRING_PRESETS.default;
81
+ keys.forEach((key) => {
82
+ if (!springsMap.current.has(key)) {
83
+ const initialValue = initialValues[key];
84
+ const signal = animatedSignal(initialValue);
85
+ const target = { value: initialValue };
86
+ const state = { value: initialValue, velocity: 0 };
87
+ const physics = new SpringPhysics(resolvedConfig);
88
+ springsMap.current.set(key, { signal, target, state, physics });
89
+ }
90
+ });
91
+ const ctx = getCurrentCtx();
92
+ const scheduler = ctx?.surface?.scheduler ?? null;
93
+ if (scheduler && schedulerRef.current !== scheduler) {
94
+ schedulerRef.current = scheduler;
95
+ }
96
+ useEffect(() => {
97
+ const currentScheduler = schedulerRef.current;
98
+ if (!currentScheduler) {
99
+ console.warn("useSprings: HostScheduler not found in surface context");
100
+ return;
101
+ }
102
+ const updateListener = (delta) => {
103
+ const deltaSeconds = delta / 1e3;
104
+ springsMap.current.forEach((spring) => {
105
+ const currentTarget = spring.target.value;
106
+ const currentState = spring.state;
107
+ if (spring.physics.isAtRest(currentState, currentTarget)) {
108
+ const snapped = spring.physics.snapIfAtRest(currentState, currentTarget);
109
+ if (snapped.value !== currentState.value) {
110
+ spring.state = snapped;
111
+ spring.signal.value = snapped.value;
112
+ }
113
+ return;
114
+ }
115
+ const newState = spring.physics.step(currentState, currentTarget, deltaSeconds);
116
+ spring.state = newState;
117
+ spring.signal.value = newState.value;
118
+ });
119
+ };
120
+ const handle = currentScheduler.onFrame(updateListener);
121
+ return () => {
122
+ handle.cancel();
123
+ };
124
+ }, []);
125
+ const signals = {};
126
+ keys.forEach((key) => {
127
+ const spring = springsMap.current.get(key);
128
+ if (spring) {
129
+ signals[key] = spring.signal;
130
+ }
131
+ });
132
+ const setValues = (values) => {
133
+ Object.entries(values).forEach(([key, value]) => {
134
+ const spring = springsMap.current.get(key);
135
+ if (spring) {
136
+ const nextTarget = typeof value === "function" ? value(spring.target.value) : value;
137
+ spring.target.value = nextTarget;
138
+ }
139
+ });
140
+ };
141
+ return [signals, setValues];
142
+ }
143
+ export {
144
+ SPRING_PRESETS,
145
+ computed,
146
+ useSpring,
147
+ useSprings
148
+ };
149
+ //# sourceMappingURL=useSpring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpring.js","sources":["../../src/animation/useSpring.ts"],"sourcesContent":["/**\n * Spring animation hook\n * Provides physics-based animations using signals for direct updates.\n * Uses HostScheduler.onFrame() — no renderer-specific tick source needed.\n *\n * @migration(audit:surface-access) Phase 7 — moved to @number10/jsx-core ✅\n */\nimport { computed, type Signal } from '@preact/signals-core'\nimport { getCurrentCtx, useEffect, useRef, type HookContext } from '../hooks'\nimport type { HostScheduler } from '../host-adapter'\nimport { animatedSignal, type AnimatedSignal } from './animated-signal'\nimport {\n SPRING_PRESETS,\n SpringPhysics,\n type SpringConfig,\n type SpringState,\n} from './spring-physics'\n\n/**\n * Spring animation hook\n * Creates an animated signal that smoothly transitions to target values\n *\n * @param initialValue - Initial value\n * @param config - Spring configuration or preset name\n * @param onComplete - Optional callback when spring reaches rest\n * @returns Tuple of [animated signal, setter function]\n *\n * @example\n * ```tsx\n * // ✓ SAFE - leaf node\n * const [x, setX] = useSpring(0, 'wobbly')\n * <View x={x} width={50} height={50} backgroundColor={0xff0000} />\n *\n * // ✓ SAFE - transform properties\n * const [scale, setScale] = useSpring(1, 'default')\n * <View scale={scale}><Text text=\"Hello\" /></View>\n *\n * // ✗ UNSAFE - container with percentage children\n * const [width, setWidth] = useSpring(200, 'wobbly')\n * <View width={width}><NineSlice width=\"100%\" /></View> // BREAKS!\n * ```\n */\nexport function useSpring(\n initialValue: number,\n config?: SpringConfig | keyof typeof SPRING_PRESETS,\n onComplete?: () => void\n): [AnimatedSignal, (target: number | ((prev: number) => number)) => void] {\n // Resolve config\n const resolvedConfig =\n typeof config === 'string' ? SPRING_PRESETS[config] : (config ?? SPRING_PRESETS.default)\n\n // Create animated signal\n const valueSignal = useRef<AnimatedSignal | null>(null)\n if (valueSignal.current === null) {\n valueSignal.current = animatedSignal(initialValue)\n }\n\n // Capture scheduler from surface context during render\n const ctx = getCurrentCtx() as HookContext | null\n const scheduler = ctx?.surface?.scheduler ?? null\n\n // Physics state\n const state = useRef<SpringState>({ value: initialValue, velocity: 0 })\n const target = useRef<Signal<number>>({ value: initialValue } as Signal<number>)\n const physics = useRef(new SpringPhysics(resolvedConfig))\n const schedulerRef = useRef<HostScheduler | null>(null)\n const wasAtRest = useRef<boolean>(true)\n\n // Update scheduler ref if it changes\n if (scheduler && schedulerRef.current !== scheduler) {\n schedulerRef.current = scheduler\n }\n\n // Setter function — stable reference via ref (avoids effect re-runs)\n const setValueRef = useRef<((newTarget: number | ((prev: number) => number)) => void) | null>(\n null\n )\n if (!setValueRef.current) {\n setValueRef.current = (newTarget: number | ((prev: number) => number)) => {\n const nextTarget =\n typeof newTarget === 'function' ? newTarget(target.current.value) : newTarget\n target.current.value = nextTarget\n }\n }\n\n useEffect(() => {\n const currentScheduler = schedulerRef.current\n if (!currentScheduler) {\n console.warn('useSpring: HostScheduler not found in surface context')\n return\n }\n\n // Physics update loop\n const updateListener = (delta: number) => {\n const currentTarget = target.current.value\n const currentState = state.current\n\n // Check if at rest\n const atRest = physics.current.isAtRest(currentState, currentTarget)\n\n // Fire onStart when transitioning from rest to active\n if (wasAtRest.current && !atRest) {\n ;(resolvedConfig as SpringConfig).onStart?.()\n }\n\n // Call onComplete if just reached rest\n if (atRest && !wasAtRest.current && onComplete) {\n onComplete()\n }\n wasAtRest.current = atRest\n\n // Skip if already at rest\n if (atRest) {\n // Snap to target\n const snapped = physics.current.snapIfAtRest(currentState, currentTarget)\n if (snapped.value !== currentState.value && valueSignal.current) {\n state.current = snapped\n valueSignal.current.value = snapped.value\n }\n return\n }\n\n // Perform physics step\n const deltaSeconds = delta / 1000\n const newState = physics.current.step(currentState, currentTarget, deltaSeconds)\n\n // Fire onUpdate with current value every frame while active\n ;(resolvedConfig as SpringConfig).onUpdate?.(newState.value)\n\n // Update state and signal\n if (valueSignal.current) {\n state.current = newState\n valueSignal.current.value = newState.value\n }\n }\n\n const handle = currentScheduler.onFrame(updateListener)\n return () => {\n handle.cancel()\n }\n }, [])\n\n if (!valueSignal.current) {\n throw new Error('useSpring: Failed to initialize animated signal')\n }\n\n return [\n valueSignal.current,\n setValueRef.current as (target: number | ((prev: number) => number)) => void,\n ]\n}\n\n/**\n * Multi-spring animation hook\n * Creates multiple animated signals that share the same configuration\n * @param initialValues - Object with initial values\n * @param config - Spring configuration or preset name\n * @returns Tuple of [animated signals object, setter function]\n *\n * @example\n * ```tsx\n * const [pos, setPos] = useSprings({ x: 0, y: 0 }, 'wobbly')\n * <View x={pos.x} y={pos.y} />\n * setPos({ x: 100, y: 200 })\n * ```\n */\nexport function useSprings<T extends Record<string, number>>(\n initialValues: T,\n config?: SpringConfig | keyof typeof SPRING_PRESETS\n): [\n { [K in keyof T]: AnimatedSignal },\n (values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>) => void,\n] {\n const keys = Object.keys(initialValues) as (keyof T)[]\n const springsMap = useRef<\n Map<\n keyof T,\n {\n signal: AnimatedSignal\n target: { value: number }\n state: SpringState\n physics: SpringPhysics\n }\n >\n >(new Map())\n const schedulerRef = useRef<HostScheduler | null>(null)\n\n // Resolve config\n const resolvedConfig =\n typeof config === 'string' ? SPRING_PRESETS[config] : (config ?? SPRING_PRESETS.default)\n\n // Initialize springs manually (can't use hooks in loops!)\n keys.forEach((key) => {\n if (!springsMap.current.has(key)) {\n const initialValue = initialValues[key] as number\n const signal = animatedSignal(initialValue)\n const target = { value: initialValue }\n const state = { value: initialValue, velocity: 0 }\n const physics = new SpringPhysics(resolvedConfig)\n springsMap.current.set(key, { signal, target, state, physics })\n }\n })\n\n // Capture scheduler from surface context during render\n const ctx = getCurrentCtx() as HookContext | null\n const scheduler = ctx?.surface?.scheduler ?? null\n\n if (scheduler && schedulerRef.current !== scheduler) {\n schedulerRef.current = scheduler\n }\n\n // Setup physics update loop\n useEffect(() => {\n const currentScheduler = schedulerRef.current\n if (!currentScheduler) {\n console.warn('useSprings: HostScheduler not found in surface context')\n return\n }\n\n const updateListener = (delta: number) => {\n const deltaSeconds = delta / 1000\n\n springsMap.current.forEach((spring) => {\n const currentTarget = spring.target.value\n const currentState = spring.state\n\n // Skip if already at rest\n if (spring.physics.isAtRest(currentState, currentTarget)) {\n const snapped = spring.physics.snapIfAtRest(currentState, currentTarget)\n if (snapped.value !== currentState.value) {\n spring.state = snapped\n spring.signal.value = snapped.value\n }\n return\n }\n\n // Perform physics step\n const newState = spring.physics.step(currentState, currentTarget, deltaSeconds)\n spring.state = newState\n spring.signal.value = newState.value\n })\n }\n\n const handle = currentScheduler.onFrame(updateListener)\n return () => {\n handle.cancel()\n }\n }, [])\n\n // Build result object\n const signals = {} as { [K in keyof T]: AnimatedSignal }\n keys.forEach((key) => {\n const spring = springsMap.current.get(key)\n if (spring) {\n signals[key] = spring.signal\n }\n })\n\n // Setter function\n const setValues = (values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>) => {\n Object.entries(values).forEach(([key, value]) => {\n const spring = springsMap.current.get(key as keyof T)\n if (spring) {\n const nextTarget = typeof value === 'function' ? value(spring.target.value) : value\n spring.target.value = nextTarget as number\n }\n })\n }\n\n return [signals, setValues]\n}\n\n/**\n * Export presets for convenience\n */\nexport { computed, SPRING_PRESETS }\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const hooks = require("../hooks.cjs");
4
+ const animatedSignal = require("./animated-signal.cjs");
5
+ const easing = require("./easing.cjs");
6
+ const tween = require("./tween.cjs");
7
+ const TWEEN_PRESETS = {
8
+ /** Standard transition (300ms, quadOut) */
9
+ default: { duration: 300, ease: easing.Easing.quadOut },
10
+ /** Quick transition (150ms, quadOut) */
11
+ fast: { duration: 150, ease: easing.Easing.quadOut },
12
+ /** Slow, deliberate transition (600ms, quadOut) */
13
+ slow: { duration: 600, ease: easing.Easing.quadOut },
14
+ /** Slightly bouncy quick transition (200ms, backOut) */
15
+ snappy: { duration: 200, ease: easing.Easing.backOut },
16
+ /** Elastic feel (400ms, elasticOut) */
17
+ elastic: { duration: 400, ease: easing.Easing.elasticOut },
18
+ /** Snap to value instantly (0ms) — useful for reset patterns */
19
+ instant: { duration: 0 }
20
+ };
21
+ function useTween(initialValue, config, onComplete) {
22
+ const resolvedBaseConfig = typeof config === "string" ? TWEEN_PRESETS[config] : config ?? TWEEN_PRESETS.default;
23
+ const resolvedTo = resolvedBaseConfig.to;
24
+ const isLooping = resolvedBaseConfig.loop !== void 0 && resolvedBaseConfig.loop !== false;
25
+ const valueSignal = hooks.useRef(null);
26
+ if (valueSignal.current === null) {
27
+ valueSignal.current = animatedSignal.animatedSignal(initialValue);
28
+ }
29
+ const ctx = hooks.getCurrentCtx();
30
+ const schedulerRef = hooks.useRef(ctx?.surface?.scheduler ?? null);
31
+ if (ctx?.surface?.scheduler && schedulerRef.current !== ctx.surface.scheduler) {
32
+ schedulerRef.current = ctx.surface.scheduler;
33
+ }
34
+ const currentTarget = hooks.useRef(resolvedTo ?? initialValue);
35
+ const tweenCleanupRef = hooks.useRef(null);
36
+ const setValueRef = hooks.useRef(
37
+ null
38
+ );
39
+ if (!setValueRef.current) {
40
+ setValueRef.current = (newTarget) => {
41
+ const resolved = typeof newTarget === "function" ? newTarget(currentTarget.current) : newTarget;
42
+ currentTarget.current = resolved;
43
+ startTween();
44
+ };
45
+ }
46
+ const startTween = () => {
47
+ const scheduler = schedulerRef.current;
48
+ if (!scheduler) {
49
+ if (valueSignal.current) {
50
+ valueSignal.current.value = currentTarget.current;
51
+ }
52
+ return;
53
+ }
54
+ tweenCleanupRef.current?.();
55
+ const signal = valueSignal.current;
56
+ if (!signal) return;
57
+ const resolvedConfig = resolvedBaseConfig;
58
+ const steps = resolvedConfig.steps ?? [
59
+ {
60
+ to: currentTarget.current,
61
+ duration: resolvedConfig.duration ?? 300,
62
+ ease: resolvedConfig.ease
63
+ }
64
+ ];
65
+ const onAllStepsComplete = () => {
66
+ if (isLooping && resolvedTo !== void 0) {
67
+ signal.value = initialValue;
68
+ currentTarget.current = resolvedTo;
69
+ startTween();
70
+ return;
71
+ }
72
+ onComplete?.();
73
+ };
74
+ let stepIndex = 0;
75
+ let currentHandle = null;
76
+ resolvedConfig.onStart?.();
77
+ const runNextStep = () => {
78
+ if (stepIndex >= steps.length) {
79
+ onAllStepsComplete();
80
+ return;
81
+ }
82
+ const step = steps[stepIndex];
83
+ if (!step) return;
84
+ const startValue = signal.value;
85
+ currentHandle = tween.createTween(
86
+ { value: startValue },
87
+ {
88
+ to: { value: step.to },
89
+ duration: step.duration,
90
+ ease: step.ease ?? easing.Easing.quadOut,
91
+ onUpdate: (t) => {
92
+ signal.value = t.value;
93
+ resolvedConfig.onUpdate?.(t.value);
94
+ },
95
+ onComplete: () => {
96
+ stepIndex++;
97
+ runNextStep();
98
+ }
99
+ },
100
+ scheduler
101
+ );
102
+ };
103
+ runNextStep();
104
+ tweenCleanupRef.current = () => {
105
+ currentHandle?.stop();
106
+ };
107
+ };
108
+ hooks.useEffect(() => {
109
+ if (currentTarget.current !== initialValue) {
110
+ startTween();
111
+ }
112
+ return () => {
113
+ tweenCleanupRef.current?.();
114
+ tweenCleanupRef.current = null;
115
+ };
116
+ }, []);
117
+ if (!valueSignal.current) {
118
+ throw new Error("useTween: Failed to initialize animated signal");
119
+ }
120
+ return [
121
+ valueSignal.current,
122
+ setValueRef.current
123
+ ];
124
+ }
125
+ function useTweens(initialValues, config, onComplete) {
126
+ const keys = Object.keys(initialValues);
127
+ const resolvedConfig = typeof config === "string" ? TWEEN_PRESETS[config] : config ?? TWEEN_PRESETS.default;
128
+ const tweenMap = hooks.useRef(
129
+ /* @__PURE__ */ new Map()
130
+ );
131
+ keys.forEach((key) => {
132
+ if (!tweenMap.current.has(key)) {
133
+ const initialValue = initialValues[key];
134
+ tweenMap.current.set(key, {
135
+ signal: animatedSignal.animatedSignal(initialValue),
136
+ target: { value: initialValue }
137
+ });
138
+ }
139
+ });
140
+ const ctx = hooks.getCurrentCtx();
141
+ const scheduler = ctx?.surface?.scheduler ?? null;
142
+ const schedulerRef = hooks.useRef(scheduler);
143
+ if (scheduler && schedulerRef.current !== scheduler) {
144
+ schedulerRef.current = scheduler;
145
+ }
146
+ const handlesRef = hooks.useRef([]);
147
+ const setValues = (values) => {
148
+ const currentScheduler = schedulerRef.current;
149
+ const entries = Object.entries(values).filter(([, v]) => v !== void 0);
150
+ if (!currentScheduler) {
151
+ entries.forEach(([key, val]) => {
152
+ const entry = tweenMap.current.get(key);
153
+ if (entry) {
154
+ entry.signal.value = typeof val === "function" ? val(entry.target.value) : val;
155
+ entry.target.value = entry.signal.value;
156
+ }
157
+ });
158
+ return;
159
+ }
160
+ handlesRef.current.forEach((h) => h.stop());
161
+ handlesRef.current = [];
162
+ let completedCount = 0;
163
+ const totalAnimations = entries.length;
164
+ entries.forEach(([key, val]) => {
165
+ const entry = tweenMap.current.get(key);
166
+ if (!entry) return;
167
+ const toValue = typeof val === "function" ? val(entry.target.value) : val;
168
+ entry.target.value = toValue;
169
+ const handle = tween.createTween(
170
+ { value: entry.signal.value },
171
+ {
172
+ to: { value: toValue },
173
+ duration: resolvedConfig.duration ?? 300,
174
+ ease: resolvedConfig.ease ?? easing.Easing.quadOut,
175
+ onUpdate: (t) => {
176
+ entry.signal.value = t.value;
177
+ },
178
+ onComplete: () => {
179
+ completedCount++;
180
+ if (completedCount >= totalAnimations) {
181
+ onComplete?.();
182
+ }
183
+ }
184
+ },
185
+ currentScheduler
186
+ );
187
+ handlesRef.current.push(handle);
188
+ });
189
+ };
190
+ hooks.useEffect(() => {
191
+ return () => {
192
+ handlesRef.current.forEach((h) => h.stop());
193
+ handlesRef.current = [];
194
+ };
195
+ }, []);
196
+ const signals = {};
197
+ keys.forEach((key) => {
198
+ const entry = tweenMap.current.get(key);
199
+ if (entry) {
200
+ signals[key] = entry.signal;
201
+ }
202
+ });
203
+ return [signals, setValues];
204
+ }
205
+ exports.TWEEN_PRESETS = TWEEN_PRESETS;
206
+ exports.useTween = useTween;
207
+ exports.useTweens = useTweens;
208
+ //# sourceMappingURL=useTween.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTween.cjs","sources":["../../src/animation/useTween.ts"],"sourcesContent":["/**\n * Tween animation hook — declarative time-based animations via signals.\n *\n * Counterpart to useSpring. Uses createTween internally, driven by\n * HostScheduler.onFrame(). Returns an AnimatedSignal that components\n * can bind to JSX props for direct VDOM-bypassing updates.\n *\n * @example\n * ```tsx\n * const [x, setX] = useTween(0, { duration: 500, ease: Easing.quadOut })\n * <View x={x} />\n * setX(200) // animates from current to 200 over 500ms\n *\n * // Multi-step:\n * const [scale, setScale] = useTween(1, {\n * steps: [\n * { to: 1.3, duration: 150, ease: Easing.quadOut },\n * { to: 1.0, duration: 150, ease: Easing.backOut },\n * ]\n * })\n * ```\n */\n\nimport { getCurrentCtx, useEffect, useRef, type HookContext } from '../hooks'\nimport type { HostScheduler } from '../host-adapter'\nimport { animatedSignal, type AnimatedSignal } from './animated-signal'\nimport { Easing, type EasingFn } from './easing'\nimport { createTween } from './tween'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Configuration for a single tween step in a multi-step animation */\nexport interface TweenAnimationStep {\n /** Target value */\n to: number\n /** Duration in ms */\n duration: number\n /** Easing function (default: quadOut) */\n ease?: EasingFn | undefined\n}\n\n/** Configuration for useTween */\nexport interface TweenConfig {\n /** Duration in ms (default: 300) */\n duration?: number | undefined\n /** Easing function (default: Easing.quadOut) */\n ease?: EasingFn | undefined\n /** Multi-step tween sequence (overrides duration/ease) */\n steps?: TweenAnimationStep[] | undefined\n /**\n * Target value — auto-starts the tween from initialValue to `to`.\n * No need to call the setter for the first animation.\n *\n * When combined with `loop`, the animation restarts from initialValue\n * to `to` on each completion.\n */\n to?: number | undefined\n /**\n * Loop the animation. When `true`, restarts from initialValue to `to`\n * each time the tween completes. Use with `to` for auto-starting loops.\n *\n * @example\n * ```tsx\n * // Continuous rotation — no effect, no ref, no onComplete needed\n * const [rotation] = useTween(0, { to: Math.PI * 2, duration: 8000, ease: Easing.linear, loop: true })\n * <View rotation={rotation} />\n * ```\n */\n loop?: boolean | { reverse?: boolean } | undefined\n /**\n * Called once when the tween starts (including on restart/loop).\n * Fires BEFORE the first frame is rendered.\n */\n onStart?: (() => void) | undefined\n /**\n * Called on every frame with the current interpolated value.\n * Useful for syncing non-signal state (logging, analytics).\n */\n onUpdate?: ((value: number) => void) | undefined\n}\n\n/**\n * Preset tween configurations for common animation durations.\n *\n * @example\n * ```tsx\n * const [x, setX] = useTween(0, TWEEN_PRESETS.snappy)\n * setX(200)\n * ```\n */\nexport const TWEEN_PRESETS = {\n /** Standard transition (300ms, quadOut) */\n default: { duration: 300, ease: Easing.quadOut } as TweenConfig,\n /** Quick transition (150ms, quadOut) */\n fast: { duration: 150, ease: Easing.quadOut } as TweenConfig,\n /** Slow, deliberate transition (600ms, quadOut) */\n slow: { duration: 600, ease: Easing.quadOut } as TweenConfig,\n /** Slightly bouncy quick transition (200ms, backOut) */\n snappy: { duration: 200, ease: Easing.backOut } as TweenConfig,\n /** Elastic feel (400ms, elasticOut) */\n elastic: { duration: 400, ease: Easing.elasticOut } as TweenConfig,\n /** Snap to value instantly (0ms) — useful for reset patterns */\n instant: { duration: 0 } as TweenConfig,\n} as const\n\n/**\n * Type for tween preset keys\n */\nexport type TweenPreset = keyof typeof TWEEN_PRESETS\n\n// ---------------------------------------------------------------------------\n// useTween\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an animated signal that transitions to target values\n * over a fixed duration with configurable easing.\n *\n * @param initialValue - Initial value\n * @param config - Duration, easing, or multi-step config\n * @param onComplete - Optional callback when animation completes\n * @returns Tuple of [animated signal, setter function]\n */\nexport function useTween(\n initialValue: number,\n config?: TweenConfig | TweenPreset,\n onComplete?: () => void\n): [AnimatedSignal, (target: number | ((prev: number) => number)) => void] {\n // Resolve config — supports preset names\n const resolvedBaseConfig: TweenConfig =\n typeof config === 'string' ? TWEEN_PRESETS[config] : (config ?? TWEEN_PRESETS.default)\n\n const resolvedTo = resolvedBaseConfig.to\n const isLooping = resolvedBaseConfig.loop !== undefined && resolvedBaseConfig.loop !== false\n\n const valueSignal = useRef<AnimatedSignal | null>(null)\n if (valueSignal.current === null) {\n valueSignal.current = animatedSignal(initialValue)\n }\n\n // Capture scheduler from surface context\n const ctx = getCurrentCtx() as HookContext | null\n const schedulerRef = useRef<HostScheduler | null>(ctx?.surface?.scheduler ?? null)\n\n // Update scheduler ref if it changes\n if (ctx?.surface?.scheduler && schedulerRef.current !== ctx.surface.scheduler) {\n schedulerRef.current = ctx.surface.scheduler\n }\n\n // Auto-start: if `to` is specified, use it as the initial target\n const currentTarget = useRef<number>(resolvedTo ?? initialValue)\n const tweenCleanupRef = useRef<(() => void) | null>(null)\n\n // Stable setter — avoids re-running effects that depend on it\n const setValueRef = useRef<((newTarget: number | ((prev: number) => number)) => void) | null>(\n null\n )\n if (!setValueRef.current) {\n setValueRef.current = (newTarget: number | ((prev: number) => number)): void => {\n const resolved =\n typeof newTarget === 'function' ? newTarget(currentTarget.current) : newTarget\n currentTarget.current = resolved\n startTween()\n }\n }\n\n const startTween = (): void => {\n const scheduler = schedulerRef.current\n if (!scheduler) {\n // Fallback: set value immediately\n if (valueSignal.current) {\n valueSignal.current.value = currentTarget.current\n }\n return\n }\n\n // Cleanup previous tween\n tweenCleanupRef.current?.()\n\n const signal = valueSignal.current\n if (!signal) return\n\n const resolvedConfig = resolvedBaseConfig\n\n // Build step array\n const steps: TweenAnimationStep[] = resolvedConfig.steps ?? [\n {\n to: currentTarget.current,\n duration: resolvedConfig.duration ?? 300,\n ease: resolvedConfig.ease,\n },\n ]\n\n // Completion handler — supports loop restart\n const onAllStepsComplete = (): void => {\n if (isLooping && resolvedTo !== undefined) {\n // Reset signal to initialValue and restart tween\n signal.value = initialValue\n currentTarget.current = resolvedTo\n startTween()\n return\n }\n onComplete?.()\n }\n\n let stepIndex = 0\n let currentHandle: ReturnType<typeof createTween> | null = null\n\n // Fire onStart when the first step begins\n resolvedConfig.onStart?.()\n\n const runNextStep = (): void => {\n if (stepIndex >= steps.length) {\n onAllStepsComplete()\n return\n }\n\n const step = steps[stepIndex]\n if (!step) return\n\n const startValue = signal.value\n\n currentHandle = createTween(\n { value: startValue },\n {\n to: { value: step.to },\n duration: step.duration,\n ease: step.ease ?? Easing.quadOut,\n onUpdate: (t) => {\n signal.value = t.value\n resolvedConfig.onUpdate?.(t.value)\n },\n onComplete: () => {\n stepIndex++\n runNextStep()\n },\n },\n scheduler\n )\n }\n\n runNextStep()\n\n tweenCleanupRef.current = () => {\n currentHandle?.stop()\n }\n }\n\n // Start initial animation if target differs from initial\n useEffect(() => {\n if (currentTarget.current !== initialValue) {\n startTween()\n }\n\n return () => {\n tweenCleanupRef.current?.()\n tweenCleanupRef.current = null\n }\n }, [])\n\n if (!valueSignal.current) {\n throw new Error('useTween: Failed to initialize animated signal')\n }\n\n return [\n valueSignal.current,\n setValueRef.current as (target: number | ((prev: number) => number)) => void,\n ]\n}\n\n// ---------------------------------------------------------------------------\n// useTweens — multi-value tween hook\n// ---------------------------------------------------------------------------\n\n/**\n * Multi-tween animation hook.\n *\n * Creates multiple animated signals that share the same tween configuration.\n * Counterpart to `useSprings`.\n *\n * @param initialValues - Object with initial numeric values\n * @param config - Tween config or preset name (shared across all properties)\n * @param onComplete - Called when ALL tweens complete (fires once per setValues call)\n * @returns Tuple of [animated signals object, setter function]\n *\n * @example\n * ```tsx\n * const [pos, setPos] = useTweens({ x: 0, y: 0 }, 'snappy')\n * <View x={pos.x} y={pos.y} />\n * setPos({ x: 100, y: 200 }) // both animate to target simultaneously\n * ```\n */\nexport function useTweens<T extends Record<string, number>>(\n initialValues: T,\n config?: TweenConfig | TweenPreset,\n onComplete?: () => void\n): [\n { [K in keyof T]: AnimatedSignal },\n (values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>) => void,\n] {\n const keys = Object.keys(initialValues) as (keyof T)[]\n\n // Resolve config — supports preset names\n const resolvedConfig: TweenConfig =\n typeof config === 'string' ? TWEEN_PRESETS[config] : (config ?? TWEEN_PRESETS.default)\n\n // Initialize signals and targets\n const tweenMap = useRef<Map<keyof T, { signal: AnimatedSignal; target: { value: number } }>>(\n new Map()\n )\n\n keys.forEach((key) => {\n if (!tweenMap.current.has(key)) {\n const initialValue = initialValues[key] as number\n tweenMap.current.set(key, {\n signal: animatedSignal(initialValue),\n target: { value: initialValue },\n })\n }\n })\n\n // Capture scheduler from surface context\n const ctx = getCurrentCtx() as HookContext | null\n const scheduler = ctx?.surface?.scheduler ?? null\n const schedulerRef = useRef<HostScheduler | null>(scheduler)\n if (scheduler && schedulerRef.current !== scheduler) {\n schedulerRef.current = scheduler\n }\n\n // Track active tween handles for cleanup\n const handlesRef = useRef<ReturnType<typeof createTween>[]>([])\n\n // Setter function\n const setValues = (\n values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>\n ): void => {\n const currentScheduler = schedulerRef.current\n\n // Filter out undefined values (Partial may include them)\n const entries = Object.entries(values).filter(([, v]) => v !== undefined) as [\n string,\n number | ((prev: number) => number),\n ][]\n\n if (!currentScheduler) {\n // Fallback: set values immediately\n entries.forEach(([key, val]) => {\n const entry = tweenMap.current.get(key as keyof T)\n if (entry) {\n entry.signal.value = typeof val === 'function' ? val(entry.target.value) : val\n entry.target.value = entry.signal.value\n }\n })\n return\n }\n\n // Cleanup previous tweens\n handlesRef.current.forEach((h) => h.stop())\n handlesRef.current = []\n\n let completedCount = 0\n const totalAnimations = entries.length\n\n entries.forEach(([key, val]) => {\n const entry = tweenMap.current.get(key as keyof T)\n if (!entry) return\n\n const toValue = typeof val === 'function' ? val(entry.target.value) : val\n entry.target.value = toValue\n\n const handle = createTween(\n { value: entry.signal.value },\n {\n to: { value: toValue },\n duration: resolvedConfig.duration ?? 300,\n ease: resolvedConfig.ease ?? Easing.quadOut,\n onUpdate: (t) => {\n entry.signal.value = t.value\n },\n onComplete: () => {\n completedCount++\n if (completedCount >= totalAnimations) {\n onComplete?.()\n }\n },\n },\n currentScheduler\n )\n\n handlesRef.current.push(handle)\n })\n }\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n handlesRef.current.forEach((h) => h.stop())\n handlesRef.current = []\n }\n }, [])\n\n // Build result object\n const signals = {} as { [K in keyof T]: AnimatedSignal }\n keys.forEach((key) => {\n const entry = tweenMap.current.get(key)\n if (entry) {\n signals[key] = entry.signal\n }\n })\n\n return [signals, setValues]\n}\n"],"names":["Easing","useRef","animatedSignal","getCurrentCtx","createTween","useEffect"],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import { AnimatedSignal } from './animated-signal';
2
+ import { EasingFn } from './easing';
3
+ /** Configuration for a single tween step in a multi-step animation */
4
+ export interface TweenAnimationStep {
5
+ /** Target value */
6
+ to: number;
7
+ /** Duration in ms */
8
+ duration: number;
9
+ /** Easing function (default: quadOut) */
10
+ ease?: EasingFn | undefined;
11
+ }
12
+ /** Configuration for useTween */
13
+ export interface TweenConfig {
14
+ /** Duration in ms (default: 300) */
15
+ duration?: number | undefined;
16
+ /** Easing function (default: Easing.quadOut) */
17
+ ease?: EasingFn | undefined;
18
+ /** Multi-step tween sequence (overrides duration/ease) */
19
+ steps?: TweenAnimationStep[] | undefined;
20
+ /**
21
+ * Target value — auto-starts the tween from initialValue to `to`.
22
+ * No need to call the setter for the first animation.
23
+ *
24
+ * When combined with `loop`, the animation restarts from initialValue
25
+ * to `to` on each completion.
26
+ */
27
+ to?: number | undefined;
28
+ /**
29
+ * Loop the animation. When `true`, restarts from initialValue to `to`
30
+ * each time the tween completes. Use with `to` for auto-starting loops.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * // Continuous rotation — no effect, no ref, no onComplete needed
35
+ * const [rotation] = useTween(0, { to: Math.PI * 2, duration: 8000, ease: Easing.linear, loop: true })
36
+ * <View rotation={rotation} />
37
+ * ```
38
+ */
39
+ loop?: boolean | {
40
+ reverse?: boolean;
41
+ } | undefined;
42
+ /**
43
+ * Called once when the tween starts (including on restart/loop).
44
+ * Fires BEFORE the first frame is rendered.
45
+ */
46
+ onStart?: (() => void) | undefined;
47
+ /**
48
+ * Called on every frame with the current interpolated value.
49
+ * Useful for syncing non-signal state (logging, analytics).
50
+ */
51
+ onUpdate?: ((value: number) => void) | undefined;
52
+ }
53
+ /**
54
+ * Preset tween configurations for common animation durations.
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * const [x, setX] = useTween(0, TWEEN_PRESETS.snappy)
59
+ * setX(200)
60
+ * ```
61
+ */
62
+ export declare const TWEEN_PRESETS: {
63
+ /** Standard transition (300ms, quadOut) */
64
+ readonly default: TweenConfig;
65
+ /** Quick transition (150ms, quadOut) */
66
+ readonly fast: TweenConfig;
67
+ /** Slow, deliberate transition (600ms, quadOut) */
68
+ readonly slow: TweenConfig;
69
+ /** Slightly bouncy quick transition (200ms, backOut) */
70
+ readonly snappy: TweenConfig;
71
+ /** Elastic feel (400ms, elasticOut) */
72
+ readonly elastic: TweenConfig;
73
+ /** Snap to value instantly (0ms) — useful for reset patterns */
74
+ readonly instant: TweenConfig;
75
+ };
76
+ /**
77
+ * Type for tween preset keys
78
+ */
79
+ export type TweenPreset = keyof typeof TWEEN_PRESETS;
80
+ /**
81
+ * Creates an animated signal that transitions to target values
82
+ * over a fixed duration with configurable easing.
83
+ *
84
+ * @param initialValue - Initial value
85
+ * @param config - Duration, easing, or multi-step config
86
+ * @param onComplete - Optional callback when animation completes
87
+ * @returns Tuple of [animated signal, setter function]
88
+ */
89
+ export declare function useTween(initialValue: number, config?: TweenConfig | TweenPreset, onComplete?: () => void): [AnimatedSignal, (target: number | ((prev: number) => number)) => void];
90
+ /**
91
+ * Multi-tween animation hook.
92
+ *
93
+ * Creates multiple animated signals that share the same tween configuration.
94
+ * Counterpart to `useSprings`.
95
+ *
96
+ * @param initialValues - Object with initial numeric values
97
+ * @param config - Tween config or preset name (shared across all properties)
98
+ * @param onComplete - Called when ALL tweens complete (fires once per setValues call)
99
+ * @returns Tuple of [animated signals object, setter function]
100
+ *
101
+ * @example
102
+ * ```tsx
103
+ * const [pos, setPos] = useTweens({ x: 0, y: 0 }, 'snappy')
104
+ * <View x={pos.x} y={pos.y} />
105
+ * setPos({ x: 100, y: 200 }) // both animate to target simultaneously
106
+ * ```
107
+ */
108
+ export declare function useTweens<T extends Record<string, number>>(initialValues: T, config?: TweenConfig | TweenPreset, onComplete?: () => void): [
109
+ {
110
+ [K in keyof T]: AnimatedSignal;
111
+ },
112
+ (values: Partial<{
113
+ [K in keyof T]: number | ((prev: number) => number);
114
+ }>) => void
115
+ ];
116
+ //# sourceMappingURL=useTween.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTween.d.ts","sourceRoot":"","sources":["../../src/animation/useTween.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAOhD,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAC5B;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,gDAAgD;IAChD,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC3B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAA;IACxC;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvB;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAA;IAClD;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACjD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;IACxB,2CAA2C;sBACS,WAAW;IAC/D,wCAAwC;mBACS,WAAW;IAC5D,mDAAmD;mBACF,WAAW;IAC5D,wDAAwD;qBACL,WAAW;IAC9D,uCAAuC;sBACgB,WAAW;IAClE,gEAAgE;sBACpC,WAAW;CAC/B,CAAA;AAEV;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,aAAa,CAAA;AAMpD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,EAClC,UAAU,CAAC,EAAE,MAAM,IAAI,GACtB,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,KAAK,IAAI,CAAC,CA6IzE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxD,aAAa,EAAE,CAAC,EAChB,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,EAClC,UAAU,CAAC,EAAE,MAAM,IAAI,GACtB;IACD;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,cAAc;KAAE;IAClC,CAAC,MAAM,EAAE,OAAO,CAAC;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;KAAE,CAAC,KAAK,IAAI;CACnF,CAgHA"}