@unrulysystems/native-motion-core 0.1.0-alpha.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 (326) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -0
  4. package/dist/clock.cjs +71 -0
  5. package/dist/clock.d.cts +23 -0
  6. package/dist/clock.d.ts +23 -0
  7. package/dist/clock.js +66 -0
  8. package/dist/collect-reads.cjs +68 -0
  9. package/dist/collect-reads.d.cts +23 -0
  10. package/dist/collect-reads.d.ts +23 -0
  11. package/dist/collect-reads.js +62 -0
  12. package/dist/component/boundedArray.cjs +74 -0
  13. package/dist/component/boundedArray.d.cts +25 -0
  14. package/dist/component/boundedArray.d.ts +25 -0
  15. package/dist/component/boundedArray.js +68 -0
  16. package/dist/component/index.cjs +57 -0
  17. package/dist/component/index.d.cts +12 -0
  18. package/dist/component/index.d.ts +12 -0
  19. package/dist/component/index.js +22 -0
  20. package/dist/component/orchestration.cjs +129 -0
  21. package/dist/component/orchestration.d.cts +66 -0
  22. package/dist/component/orchestration.d.ts +66 -0
  23. package/dist/component/orchestration.js +124 -0
  24. package/dist/component/resolve.cjs +104 -0
  25. package/dist/component/resolve.d.cts +11 -0
  26. package/dist/component/resolve.d.ts +11 -0
  27. package/dist/component/resolve.js +97 -0
  28. package/dist/component/transition.cjs +352 -0
  29. package/dist/component/transition.d.cts +33 -0
  30. package/dist/component/transition.d.ts +33 -0
  31. package/dist/component/transition.js +339 -0
  32. package/dist/component/types.cjs +114 -0
  33. package/dist/component/types.d.cts +60 -0
  34. package/dist/component/types.d.ts +60 -0
  35. package/dist/component/types.js +111 -0
  36. package/dist/component/validate.cjs +1015 -0
  37. package/dist/component/validate.d.cts +37 -0
  38. package/dist/component/validate.d.ts +37 -0
  39. package/dist/component/validate.js +1002 -0
  40. package/dist/component/variants.cjs +333 -0
  41. package/dist/component/variants.d.cts +106 -0
  42. package/dist/component/variants.d.ts +106 -0
  43. package/dist/component/variants.js +321 -0
  44. package/dist/config/constants.cjs +41 -0
  45. package/dist/config/constants.d.cts +29 -0
  46. package/dist/config/constants.d.ts +29 -0
  47. package/dist/config/constants.js +38 -0
  48. package/dist/delay.cjs +72 -0
  49. package/dist/delay.d.cts +26 -0
  50. package/dist/delay.d.ts +26 -0
  51. package/dist/delay.js +70 -0
  52. package/dist/derived.cjs +143 -0
  53. package/dist/derived.d.cts +41 -0
  54. package/dist/derived.d.ts +41 -0
  55. package/dist/derived.js +139 -0
  56. package/dist/driver/index.cjs +22 -0
  57. package/dist/driver/index.d.cts +7 -0
  58. package/dist/driver/index.d.ts +7 -0
  59. package/dist/driver/index.js +14 -0
  60. package/dist/driver/keyframeTiming.cjs +130 -0
  61. package/dist/driver/keyframeTiming.d.cts +18 -0
  62. package/dist/driver/keyframeTiming.d.ts +18 -0
  63. package/dist/driver/keyframeTiming.js +124 -0
  64. package/dist/driver/keyframeTimingConfig.cjs +24 -0
  65. package/dist/driver/keyframeTimingConfig.d.cts +5 -0
  66. package/dist/driver/keyframeTimingConfig.d.ts +5 -0
  67. package/dist/driver/keyframeTimingConfig.js +22 -0
  68. package/dist/driver/prepare.cjs +459 -0
  69. package/dist/driver/prepare.d.cts +4 -0
  70. package/dist/driver/prepare.d.ts +4 -0
  71. package/dist/driver/prepare.js +454 -0
  72. package/dist/driver/reference.cjs +762 -0
  73. package/dist/driver/reference.d.cts +53 -0
  74. package/dist/driver/reference.d.ts +53 -0
  75. package/dist/driver/reference.js +757 -0
  76. package/dist/driver/step.cjs +55 -0
  77. package/dist/driver/step.d.cts +9 -0
  78. package/dist/driver/step.d.ts +9 -0
  79. package/dist/driver/step.js +52 -0
  80. package/dist/driver/tiers.cjs +40 -0
  81. package/dist/driver/tiers.d.cts +2 -0
  82. package/dist/driver/tiers.d.ts +2 -0
  83. package/dist/driver/tiers.js +37 -0
  84. package/dist/driver/types.cjs +9 -0
  85. package/dist/driver/types.d.cts +68 -0
  86. package/dist/driver/types.d.ts +68 -0
  87. package/dist/driver/types.js +8 -0
  88. package/dist/external-animation-ledger.cjs +1250 -0
  89. package/dist/external-animation-ledger.d.cts +416 -0
  90. package/dist/external-animation-ledger.d.ts +416 -0
  91. package/dist/external-animation-ledger.js +1243 -0
  92. package/dist/gesture/directionLock.cjs +25 -0
  93. package/dist/gesture/directionLock.d.cts +8 -0
  94. package/dist/gesture/directionLock.d.ts +8 -0
  95. package/dist/gesture/directionLock.js +21 -0
  96. package/dist/gesture/dragConfig.cjs +634 -0
  97. package/dist/gesture/dragConfig.d.cts +298 -0
  98. package/dist/gesture/dragConfig.d.ts +298 -0
  99. package/dist/gesture/dragConfig.js +624 -0
  100. package/dist/gesture/elastic.cjs +44 -0
  101. package/dist/gesture/elastic.d.cts +4 -0
  102. package/dist/gesture/elastic.d.ts +4 -0
  103. package/dist/gesture/elastic.js +39 -0
  104. package/dist/gesture/handoffSession.cjs +161 -0
  105. package/dist/gesture/handoffSession.d.cts +35 -0
  106. package/dist/gesture/handoffSession.d.ts +35 -0
  107. package/dist/gesture/handoffSession.js +158 -0
  108. package/dist/gesture/index.cjs +37 -0
  109. package/dist/gesture/index.d.cts +12 -0
  110. package/dist/gesture/index.d.ts +12 -0
  111. package/dist/gesture/index.js +11 -0
  112. package/dist/gesture/projection.cjs +95 -0
  113. package/dist/gesture/projection.d.cts +7 -0
  114. package/dist/gesture/projection.d.ts +7 -0
  115. package/dist/gesture/projection.js +87 -0
  116. package/dist/gesture/session.cjs +162 -0
  117. package/dist/gesture/session.d.cts +29 -0
  118. package/dist/gesture/session.d.ts +29 -0
  119. package/dist/gesture/session.js +158 -0
  120. package/dist/gesture/types.cjs +5 -0
  121. package/dist/gesture/types.d.cts +13 -0
  122. package/dist/gesture/types.d.ts +13 -0
  123. package/dist/gesture/types.js +4 -0
  124. package/dist/gesture/viewportConstraints.cjs +38 -0
  125. package/dist/gesture/viewportConstraints.d.cts +6 -0
  126. package/dist/gesture/viewportConstraints.d.ts +6 -0
  127. package/dist/gesture/viewportConstraints.js +34 -0
  128. package/dist/graph.cjs +226 -0
  129. package/dist/graph.d.cts +2 -0
  130. package/dist/graph.d.ts +2 -0
  131. package/dist/graph.js +223 -0
  132. package/dist/index.cjs +140 -0
  133. package/dist/index.d.cts +33 -0
  134. package/dist/index.d.ts +33 -0
  135. package/dist/index.js +70 -0
  136. package/dist/inertia.cjs +214 -0
  137. package/dist/inertia.d.cts +53 -0
  138. package/dist/inertia.d.ts +53 -0
  139. package/dist/inertia.js +212 -0
  140. package/dist/instant.cjs +66 -0
  141. package/dist/instant.d.cts +16 -0
  142. package/dist/instant.d.ts +16 -0
  143. package/dist/instant.js +63 -0
  144. package/dist/internal-driver.cjs +81 -0
  145. package/dist/internal-driver.d.cts +19 -0
  146. package/dist/internal-driver.d.ts +19 -0
  147. package/dist/internal-driver.js +35 -0
  148. package/dist/keyframes.cjs +191 -0
  149. package/dist/keyframes.d.cts +13 -0
  150. package/dist/keyframes.d.ts +13 -0
  151. package/dist/keyframes.js +188 -0
  152. package/dist/layout/commitDetector.cjs +67 -0
  153. package/dist/layout/commitDetector.d.cts +21 -0
  154. package/dist/layout/commitDetector.d.ts +21 -0
  155. package/dist/layout/commitDetector.js +64 -0
  156. package/dist/layout/compose.cjs +67 -0
  157. package/dist/layout/compose.d.cts +30 -0
  158. package/dist/layout/compose.d.ts +30 -0
  159. package/dist/layout/compose.js +65 -0
  160. package/dist/layout/constants.cjs +13 -0
  161. package/dist/layout/constants.d.cts +6 -0
  162. package/dist/layout/constants.d.ts +6 -0
  163. package/dist/layout/constants.js +10 -0
  164. package/dist/layout/identity.cjs +700 -0
  165. package/dist/layout/identity.d.cts +67 -0
  166. package/dist/layout/identity.d.ts +67 -0
  167. package/dist/layout/identity.js +698 -0
  168. package/dist/layout/index.cjs +36 -0
  169. package/dist/layout/index.d.cts +18 -0
  170. package/dist/layout/index.d.ts +18 -0
  171. package/dist/layout/index.js +13 -0
  172. package/dist/layout/measure.cjs +81 -0
  173. package/dist/layout/measure.d.cts +43 -0
  174. package/dist/layout/measure.d.ts +43 -0
  175. package/dist/layout/measure.js +78 -0
  176. package/dist/layout/projection.cjs +99 -0
  177. package/dist/layout/projection.d.cts +23 -0
  178. package/dist/layout/projection.d.ts +23 -0
  179. package/dist/layout/projection.js +97 -0
  180. package/dist/layout/scroll.cjs +27 -0
  181. package/dist/layout/scroll.d.cts +13 -0
  182. package/dist/layout/scroll.d.ts +13 -0
  183. package/dist/layout/scroll.js +24 -0
  184. package/dist/layout/session.cjs +207 -0
  185. package/dist/layout/session.d.cts +73 -0
  186. package/dist/layout/session.d.ts +73 -0
  187. package/dist/layout/session.js +205 -0
  188. package/dist/layout/tree.cjs +826 -0
  189. package/dist/layout/tree.d.cts +70 -0
  190. package/dist/layout/tree.d.ts +70 -0
  191. package/dist/layout/tree.js +823 -0
  192. package/dist/layout/types.cjs +36 -0
  193. package/dist/layout/types.d.cts +31 -0
  194. package/dist/layout/types.d.ts +31 -0
  195. package/dist/layout/types.js +35 -0
  196. package/dist/motion-arc.cjs +184 -0
  197. package/dist/motion-arc.d.cts +78 -0
  198. package/dist/motion-arc.d.ts +78 -0
  199. package/dist/motion-arc.js +183 -0
  200. package/dist/motion-mix.cjs +205 -0
  201. package/dist/motion-mix.d.cts +3 -0
  202. package/dist/motion-mix.d.ts +3 -0
  203. package/dist/motion-mix.js +202 -0
  204. package/dist/motion-value-driver-port.cjs +636 -0
  205. package/dist/motion-value-driver-port.d.cts +406 -0
  206. package/dist/motion-value-driver-port.d.ts +406 -0
  207. package/dist/motion-value-driver-port.js +627 -0
  208. package/dist/motion-value.cjs +189 -0
  209. package/dist/motion-value.d.cts +51 -0
  210. package/dist/motion-value.d.ts +51 -0
  211. package/dist/motion-value.js +185 -0
  212. package/dist/presence/controller.cjs +657 -0
  213. package/dist/presence/controller.d.cts +6 -0
  214. package/dist/presence/controller.d.ts +6 -0
  215. package/dist/presence/controller.js +652 -0
  216. package/dist/presence/index.cjs +19 -0
  217. package/dist/presence/index.d.cts +4 -0
  218. package/dist/presence/index.d.ts +4 -0
  219. package/dist/presence/index.js +12 -0
  220. package/dist/presence/machine.cjs +50 -0
  221. package/dist/presence/machine.d.cts +10 -0
  222. package/dist/presence/machine.d.ts +10 -0
  223. package/dist/presence/machine.js +46 -0
  224. package/dist/presence/types.cjs +6 -0
  225. package/dist/presence/types.d.cts +32 -0
  226. package/dist/presence/types.d.ts +32 -0
  227. package/dist/presence/types.js +5 -0
  228. package/dist/repeat.cjs +311 -0
  229. package/dist/repeat.d.cts +174 -0
  230. package/dist/repeat.d.ts +174 -0
  231. package/dist/repeat.js +300 -0
  232. package/dist/spring.cjs +128 -0
  233. package/dist/spring.d.cts +18 -0
  234. package/dist/spring.d.ts +18 -0
  235. package/dist/spring.js +125 -0
  236. package/dist/subscriptions.cjs +74 -0
  237. package/dist/subscriptions.d.cts +19 -0
  238. package/dist/subscriptions.d.ts +19 -0
  239. package/dist/subscriptions.js +69 -0
  240. package/dist/subset/index.cjs +23 -0
  241. package/dist/subset/index.d.cts +6 -0
  242. package/dist/subset/index.d.ts +6 -0
  243. package/dist/subset/index.js +13 -0
  244. package/dist/subset/normalize.cjs +90 -0
  245. package/dist/subset/normalize.d.cts +10 -0
  246. package/dist/subset/normalize.d.ts +10 -0
  247. package/dist/subset/normalize.js +85 -0
  248. package/dist/subset/registry.cjs +259 -0
  249. package/dist/subset/registry.d.cts +25 -0
  250. package/dist/subset/registry.d.ts +25 -0
  251. package/dist/subset/registry.js +256 -0
  252. package/dist/subset/resolve.cjs +98 -0
  253. package/dist/subset/resolve.d.cts +24 -0
  254. package/dist/subset/resolve.d.ts +24 -0
  255. package/dist/subset/resolve.js +90 -0
  256. package/dist/timing.cjs +206 -0
  257. package/dist/timing.d.cts +17 -0
  258. package/dist/timing.d.ts +17 -0
  259. package/dist/timing.js +201 -0
  260. package/dist/transformTemplate.cjs +219 -0
  261. package/dist/transformTemplate.d.cts +29 -0
  262. package/dist/transformTemplate.d.ts +29 -0
  263. package/dist/transformTemplate.js +215 -0
  264. package/dist/transition.cjs +231 -0
  265. package/dist/transition.d.cts +89 -0
  266. package/dist/transition.d.ts +89 -0
  267. package/dist/transition.js +223 -0
  268. package/dist/types.cjs +4 -0
  269. package/dist/types.d.cts +175 -0
  270. package/dist/types.d.ts +175 -0
  271. package/dist/types.js +3 -0
  272. package/dist/value-types/color.cjs +220 -0
  273. package/dist/value-types/color.d.cts +19 -0
  274. package/dist/value-types/color.d.ts +19 -0
  275. package/dist/value-types/color.js +218 -0
  276. package/dist/value-types/complex.cjs +160 -0
  277. package/dist/value-types/complex.d.cts +19 -0
  278. package/dist/value-types/complex.d.ts +19 -0
  279. package/dist/value-types/complex.js +155 -0
  280. package/dist/value-types/constants.cjs +15 -0
  281. package/dist/value-types/constants.d.cts +6 -0
  282. package/dist/value-types/constants.d.ts +6 -0
  283. package/dist/value-types/constants.js +12 -0
  284. package/dist/value-types/discrete.cjs +62 -0
  285. package/dist/value-types/discrete.d.cts +4 -0
  286. package/dist/value-types/discrete.d.ts +4 -0
  287. package/dist/value-types/discrete.js +56 -0
  288. package/dist/value-types/index.cjs +59 -0
  289. package/dist/value-types/index.d.cts +14 -0
  290. package/dist/value-types/index.d.ts +14 -0
  291. package/dist/value-types/index.js +24 -0
  292. package/dist/value-types/measure-resolve.cjs +325 -0
  293. package/dist/value-types/measure-resolve.d.cts +91 -0
  294. package/dist/value-types/measure-resolve.d.ts +91 -0
  295. package/dist/value-types/measure-resolve.js +313 -0
  296. package/dist/value-types/mix.cjs +90 -0
  297. package/dist/value-types/mix.d.cts +27 -0
  298. package/dist/value-types/mix.d.ts +27 -0
  299. package/dist/value-types/mix.js +85 -0
  300. package/dist/value-types/named-colors.cjs +61 -0
  301. package/dist/value-types/named-colors.d.cts +2 -0
  302. package/dist/value-types/named-colors.d.ts +2 -0
  303. package/dist/value-types/named-colors.js +58 -0
  304. package/dist/value-types/numeric.cjs +86 -0
  305. package/dist/value-types/numeric.d.cts +16 -0
  306. package/dist/value-types/numeric.d.ts +16 -0
  307. package/dist/value-types/numeric.js +79 -0
  308. package/dist/worklet-layout/config/constants.js +39 -0
  309. package/dist/worklet-layout/layout/constants.js +11 -0
  310. package/dist/worklet-layout/layout/identity.js +699 -0
  311. package/dist/worklet-layout/layout/projection.js +98 -0
  312. package/dist/worklet-layout/layout/session.js +206 -0
  313. package/dist/worklet-layout/layout/tree.js +824 -0
  314. package/dist/worklet-layout/layout/types.js +36 -0
  315. package/dist/worklet-layout/spring.js +125 -0
  316. package/dist/worklet-layout/timing.js +201 -0
  317. package/dist/worklet-layout/transition.js +223 -0
  318. package/dist/worklet-layout.cjs +47 -0
  319. package/dist/worklet-layout.d.cts +15 -0
  320. package/dist/worklet-layout.d.ts +15 -0
  321. package/dist/worklet-layout.js +28 -0
  322. package/dist/wrap.cjs +7 -0
  323. package/dist/wrap.d.cts +1 -0
  324. package/dist/wrap.d.ts +1 -0
  325. package/dist/wrap.js +4 -0
  326. package/package.json +45 -0
@@ -0,0 +1,97 @@
1
+ // SPEC-COMPONENT §2 — the pure target-merge + base-resolution functions (REQ-API-002/010/011/012/017).
2
+ // Two responsibilities, two pure functions on the verifier seam:
3
+ // • resolveTarget(base, target) — REQ-API-012 overlay: apply a partial target onto the live value set.
4
+ // Keys in the target retarget; keys absent from the target retain their live value; a target NEVER
5
+ // resets an unlisted property. There is no "full visual state" the author must restate.
6
+ // • resolveStartValue / hostBaseValue — REQ-API-011 base resolution: the STARTING value of a property
7
+ // appearing in a target with no prior live value — the resolved `style` value if present, else the
8
+ // documented host base. Identical across engines (the base derives from the registry value type, not
9
+ // from any host), so no engine supplies a divergent implicit default.
10
+ // Both are pure and deterministic: same inputs → same result, independent of clock or host (REQ-API-017).
11
+ // Host-agnostic (REQ-CORE-003) — reads only the SUBSET registry (relative import).
12
+ import { UNIVERSAL_SUBSET } from "../subset/index.js";
13
+ import { captureBoundedArray, capturedArrayDescription } from "./boundedArray.js";
14
+ import { InvalidTargetError } from "./validate.js";
15
+ // Overlay `target` onto the live `base` value set (REQ-API-012). Returns a fresh, complete value set: every
16
+ // key present in either input appears once; a key in `target` takes the target value (retarget), a key only
17
+ // in `base` retains its live value (hold). Never mutates its inputs; never resets a property the target did
18
+ // not mention. A target value may be a keyframe array (ResolvedTargetValue), so the merge is typed to carry it.
19
+ export function resolveTarget(base, target) {
20
+ // Hold every unlisted base key, then overlay the target. A keyframe ARRAY value is CLONED (and frozen)
21
+ // as it is captured — a resolved snapshot (a presence exit target, a retarget origin) is resolved-once
22
+ // and held-immutable, so it must not alias a caller-owned array whose later mutation would change it in
23
+ // place (REQ-API-017; review major c8d4e61a705b). Keyframe elements are scalars, so a shallow clone is a
24
+ // full copy. A fresh object each call — the inputs stay immutable.
25
+ const merged = {};
26
+ for (const key of Object.keys(base))
27
+ merged[key] = captureValue(key, base[key]);
28
+ for (const key of Object.keys(target))
29
+ merged[key] = captureValue(key, target[key]);
30
+ return merged;
31
+ }
32
+ // Capture a resolved value independently of its caller: a keyframe array is cloned + frozen (so a later
33
+ // source mutation cannot reach the snapshot, and the snapshot itself cannot be mutated downstream); a
34
+ // scalar is already immutable and passes through.
35
+ function captureValue(key, value) {
36
+ if (!Array.isArray(value))
37
+ return value;
38
+ const capture = captureBoundedArray(value);
39
+ if (capture.kind !== 'captured') {
40
+ throw new InvalidTargetError(undefined, key, capturedArrayDescription(capture), 'keyframe arrays must have a safe bounded length (REQ-API-033)');
41
+ }
42
+ if (capture.values.length < 2) {
43
+ throw new InvalidTargetError(undefined, key, capture.values, 'a keyframe array must have at least two keyframes (REQ-API-033)');
44
+ }
45
+ for (let index = 0; index < capture.values.length; index++) {
46
+ if (!Object.hasOwn(capture.values, index)) {
47
+ throw new InvalidTargetError(undefined, key, capture.values, `keyframe array is missing index ${index} (REQ-API-033)`);
48
+ }
49
+ }
50
+ return capture.values;
51
+ }
52
+ // REQ-API-011: the STARTING (from) value of a property that appears in a target with no prior live value.
53
+ // The resolved `style` value if the style prop specifies it, else the documented host base. Pure.
54
+ export function resolveStartValue(key, resolution) {
55
+ const styled = resolution?.style?.[key];
56
+ return styled !== undefined ? styled : hostBaseValue(key);
57
+ }
58
+ // T23 B2a2: the discrete-start refusal is TYPED so the component boundary can apply the
59
+ // severity law to exactly this case (production report + refuse the key) without message
60
+ // sniffing; unknown/complex host-base refusals stay plain loud errors on every severity.
61
+ export class DiscreteHostBaseError extends Error {
62
+ constructor(key) {
63
+ super(`no documented host base value for discrete '${key}': the host default diverges across ` +
64
+ 'engines — provide the starting keyword via initial/style/variants.');
65
+ this.name = 'DiscreteHostBaseError';
66
+ }
67
+ }
68
+ // The documented host base value for a universal property (REQ-API-011) — the value it animates FROM when
69
+ // neither a live value nor a `style` value exists. Derived from the registry value type so it is a SINGLE
70
+ // source of truth and identical across engines (no host parameter, no engine-divergent default): scale and
71
+ // opacity rest at 1; translations, dimensions, spacing, radii, border widths, and angles rest at 0; colors
72
+ // rest at fully-transparent black. complex/gesture capabilities have no scalar base and fail loud, as does
73
+ // an unknown property.
74
+ export function hostBaseValue(key) {
75
+ const entry = UNIVERSAL_SUBSET.get(key);
76
+ if (entry === undefined) {
77
+ throw new Error(`no documented host base value for unknown property '${key}': it is not a universal-subset property.`);
78
+ }
79
+ switch (entry.valueType) {
80
+ case 'unitless':
81
+ // opacity and scale/scaleX/scaleY are the only unitless universal properties; all rest at 1.
82
+ return 1;
83
+ case 'length':
84
+ case 'angle':
85
+ return 0;
86
+ case 'rgba':
87
+ return 'rgba(0, 0, 0, 0)';
88
+ case 'discrete':
89
+ // T23 B: the host default for a discrete keyword DIVERGES across engines (web block vs RN
90
+ // flex for display) — there is no engine-identical documented base, so the start value must
91
+ // come from `initial`/`style`/a variant, never a silent host default.
92
+ throw new DiscreteHostBaseError(key);
93
+ case 'complex':
94
+ case 'gesture':
95
+ throw new Error(`no documented host base value for '${key}' (valueType '${entry.valueType}'): it is not an animatable scalar/color property.`);
96
+ }
97
+ }
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ // SPEC-COMPONENT §2 — the transition unit boundary (REQ-API-001). The public `Transition` (in ./types)
3
+ // speaks Motion's SECONDS convention; the internal SPRING (`SpringConfig`) and TIMING (`TimingConfig`)
4
+ // resolvers consume MILLISECONDS. These pure converters are the SINGLE crossing point, so the internal
5
+ // millisecond unit never leaks into the authored public surface and a Motion-idiomatic transition config
6
+ // resolves identically here. Host-agnostic (REQ-CORE-003) — relative imports only.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.resolveTransitionForKey = resolveTransitionForKey;
9
+ exports.toSpringConfig = toSpringConfig;
10
+ exports.effectiveTransitionEase = effectiveTransitionEase;
11
+ exports.normalizeTransitionEaseAlias = normalizeTransitionEaseAlias;
12
+ exports.toRepeatFoldOptions = toRepeatFoldOptions;
13
+ exports.toDelayMs = toDelayMs;
14
+ exports.toTimingConfig = toTimingConfig;
15
+ exports.isTimingLaneTransition = isTimingLaneTransition;
16
+ exports.isDurationZeroInstantTransition = isDurationZeroInstantTransition;
17
+ exports.toTimingLaneConfig = toTimingLaneConfig;
18
+ exports.toKeyframesConfig = toKeyframesConfig;
19
+ const timing_1 = require("../timing.cjs");
20
+ const types_1 = require("./types.cjs");
21
+ // Motion authors durations in seconds; the SPRING/TIMING generators are seeded in milliseconds. This is the
22
+ // only conversion factor, named rather than inlined so the seconds↔ms boundary is explicit.
23
+ const MS_PER_SECOND = 1000;
24
+ const TRANSITION_MAP_KEYS = new Set(['default', 'layout', ...types_1.TARGET_PROPERTY_KEYS]);
25
+ function isTransitionMapKey(key) {
26
+ return TRANSITION_MAP_KEYS.has(key);
27
+ }
28
+ function flatTransitionSnapshot(source) {
29
+ const out = Object.create(null);
30
+ for (const key of Reflect.ownKeys(source)) {
31
+ if (typeof key !== 'string' || key === 'inherit' || isTransitionMapKey(key))
32
+ continue;
33
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
34
+ if (descriptor === undefined)
35
+ continue;
36
+ Object.defineProperty(out, key, {
37
+ value: source[key],
38
+ enumerable: descriptor.enumerable === true,
39
+ configurable: true,
40
+ writable: true,
41
+ });
42
+ }
43
+ return Object.freeze(out);
44
+ }
45
+ /**
46
+ * Resolve one Motion consumer against an authored transition map. The result is a detached flat
47
+ * bag: map entries never cross into a generator, and nested maps never recurse. Validation/capture
48
+ * owns malformed-shape refusal; this selector assumes that boundary has passed and preserves the
49
+ * pin's key → default → root precedence.
50
+ */
51
+ function resolveTransitionForKey(transition, key) {
52
+ const source = transition;
53
+ const named = isTransitionMapKey(key) ? source[key] : undefined;
54
+ const fallback = source['default'];
55
+ const selected = named !== undefined && named !== null
56
+ ? named
57
+ : fallback !== undefined && fallback !== null
58
+ ? fallback
59
+ : transition;
60
+ if (selected === transition)
61
+ return flatTransitionSnapshot(source);
62
+ const root = flatTransitionSnapshot(source);
63
+ const nested = selected;
64
+ if (nested['inherit'] !== true) {
65
+ // Motion's getValueTransition returns a replacing child bag unchanged. The separate delay
66
+ // rebase in animateTarget supplies only its orchestration delay before spreading this bag, so
67
+ // an ordinary selected bag does not inherit the root transition's delay (motion-dom@12.42.2).
68
+ return flatTransitionSnapshot(nested);
69
+ }
70
+ const merged = Object.create(null);
71
+ for (const key of Reflect.ownKeys(root)) {
72
+ const descriptor = Object.getOwnPropertyDescriptor(root, key);
73
+ if (descriptor !== undefined)
74
+ Object.defineProperty(merged, key, { ...descriptor, configurable: true, writable: true });
75
+ }
76
+ const child = flatTransitionSnapshot(nested);
77
+ for (const key of Reflect.ownKeys(child)) {
78
+ const descriptor = Object.getOwnPropertyDescriptor(child, key);
79
+ if (descriptor !== undefined)
80
+ Object.defineProperty(merged, key, { ...descriptor, configurable: true, writable: true });
81
+ }
82
+ return Object.freeze(merged);
83
+ }
84
+ // Bridge the public `Transition` to the internal spring `SpringConfig`. `duration` crosses seconds→ms;
85
+ // `visualDuration` is already seconds in both surfaces (passthrough); the physics options are unit-
86
+ // consistent with Motion. Absent fields are omitted entirely (not written as `undefined`) so the result
87
+ // satisfies `exactOptionalPropertyTypes`.
88
+ function toSpringConfig(transition) {
89
+ const config = {};
90
+ if (transition.stiffness !== undefined)
91
+ config.stiffness = transition.stiffness;
92
+ if (transition.damping !== undefined)
93
+ config.damping = transition.damping;
94
+ if (transition.mass !== undefined)
95
+ config.mass = transition.mass;
96
+ if (transition.bounce !== undefined)
97
+ config.bounce = transition.bounce;
98
+ if (transition.velocity !== undefined)
99
+ config.velocity = transition.velocity;
100
+ // U7c (REQ-SPRING-014): the authored settle thresholds cross verbatim — unit-free passthroughs
101
+ // (the velocity precedent). An explicit 0 is forwarded as PRESENT; the `||=` quirk (0 ≡ absent,
102
+ // motion-dom@12.42.2 spring.ts:275-280) resolves in the solver's `||` read, never here.
103
+ if (transition.restDelta !== undefined)
104
+ config.restDelta = transition.restDelta;
105
+ if (transition.restSpeed !== undefined)
106
+ config.restSpeed = transition.restSpeed;
107
+ if (transition.visualDuration !== undefined)
108
+ config.visualDuration = transition.visualDuration;
109
+ if (transition.duration !== undefined)
110
+ config.duration = transition.duration * MS_PER_SECOND;
111
+ return config;
112
+ }
113
+ // Bridge the public `Transition` to the internal `TimingConfig` (tween path). `duration` crosses
114
+ // seconds→ms; `ease` passes through. Absent fields omitted (exactOptionalPropertyTypes).
115
+ // Family-2 / T20: `easings` and `easing` are Motion catalog aliases of `ease`.
116
+ // Dual authorship is refused at validate.
117
+ function effectiveTransitionEase(transition) {
118
+ if (transition.ease !== undefined)
119
+ return transition.ease;
120
+ if (transition.easings !== undefined)
121
+ return transition.easings;
122
+ return transition.easing;
123
+ }
124
+ // Rewrite `easings` → `ease` for host pass-through (web motion.div speaks `ease`). Identity when
125
+ // only `ease` is authored. Dual authorship never reaches here (validate refuses first).
126
+ // Preserve null-prototype + freeze + own descriptors from captureTransition (G-INV-8): object
127
+ // spread would re-open prototype pollution and drop non-enumerable own keys.
128
+ // Explicit `ease: undefined` / `easings: undefined` are ABSENT (same law, 00i0nt) — strip those
129
+ // own keys so nested config merge cannot treat them as present values that clobber a parent.
130
+ const EASE_ALIAS_KEYS = ['easings', 'easing'];
131
+ function normalizeFlatTransitionEaseAlias(transition) {
132
+ const source = transition;
133
+ const hasOwnEase = Object.hasOwn(transition, 'ease');
134
+ const easeIsExplicitUndefined = hasOwnEase && source['ease'] === undefined;
135
+ let aliasKey;
136
+ let aliasValue;
137
+ let aliasExplicitUndefined = false;
138
+ for (const key of EASE_ALIAS_KEYS) {
139
+ if (!Object.hasOwn(transition, key))
140
+ continue;
141
+ const value = source[key];
142
+ if (value === undefined) {
143
+ aliasExplicitUndefined = true;
144
+ continue;
145
+ }
146
+ if (aliasKey === undefined) {
147
+ aliasKey = key;
148
+ aliasValue = value;
149
+ }
150
+ }
151
+ if (aliasKey === undefined) {
152
+ if (!easeIsExplicitUndefined && !aliasExplicitUndefined)
153
+ return transition;
154
+ const stripped = Object.create(null);
155
+ let changed = false;
156
+ for (const key of Reflect.ownKeys(transition)) {
157
+ if (key === 'ease' && source[key] === undefined) {
158
+ changed = true;
159
+ continue;
160
+ }
161
+ if ((key === 'easings' || key === 'easing') && source[key] === undefined) {
162
+ changed = true;
163
+ continue;
164
+ }
165
+ const descriptor = Object.getOwnPropertyDescriptor(transition, key);
166
+ if (descriptor === undefined)
167
+ continue;
168
+ Object.defineProperty(stripped, key, {
169
+ value: descriptor.value,
170
+ enumerable: descriptor.enumerable === true,
171
+ configurable: true,
172
+ writable: true,
173
+ });
174
+ }
175
+ return changed ? Object.freeze(stripped) : transition;
176
+ }
177
+ const captured = Object.create(null);
178
+ for (const key of Reflect.ownKeys(transition)) {
179
+ if (key === 'easings' || key === 'easing')
180
+ continue;
181
+ if (key === 'ease' && source[key] === undefined)
182
+ continue;
183
+ const descriptor = Object.getOwnPropertyDescriptor(transition, key);
184
+ if (descriptor === undefined)
185
+ continue;
186
+ Object.defineProperty(captured, key, {
187
+ value: descriptor.value,
188
+ enumerable: descriptor.enumerable === true,
189
+ configurable: true,
190
+ writable: true,
191
+ });
192
+ }
193
+ Object.defineProperty(captured, 'ease', {
194
+ value: aliasValue,
195
+ enumerable: true,
196
+ configurable: true,
197
+ writable: true,
198
+ });
199
+ return Object.freeze(captured);
200
+ }
201
+ const TRANSITION_MAP_KEYS_FOR_ALIAS = new Set([
202
+ 'default',
203
+ 'layout',
204
+ ...types_1.TARGET_PROPERTY_KEYS,
205
+ ]);
206
+ /**
207
+ * Canonicalize the public `easings` alias at both legal transition levels. The pin-facing web/native
208
+ * consumers never receive nested bags directly, but MotionConfig and variant inheritance can carry a
209
+ * captured map through several handoff boundaries before the consumer selector runs. Normalize exactly
210
+ * one nested bag level; recursive maps are a validation error, not an invitation to walk unbounded data.
211
+ */
212
+ function normalizeTransitionEaseAlias(transition) {
213
+ const root = normalizeFlatTransitionEaseAlias(transition);
214
+ const source = transition;
215
+ let changed = root !== transition;
216
+ const replacements = new Map();
217
+ for (const key of Reflect.ownKeys(transition)) {
218
+ if (typeof key !== 'string' || !TRANSITION_MAP_KEYS_FOR_ALIAS.has(key))
219
+ continue;
220
+ const nested = source[key];
221
+ if (typeof nested !== 'object' ||
222
+ nested === null ||
223
+ Array.isArray(nested) ||
224
+ (Object.getPrototypeOf(nested) !== Object.prototype && Object.getPrototypeOf(nested) !== null))
225
+ continue;
226
+ const normalized = normalizeFlatTransitionEaseAlias(nested);
227
+ if (normalized !== nested) {
228
+ changed = true;
229
+ replacements.set(key, normalized);
230
+ }
231
+ }
232
+ if (!changed)
233
+ return root;
234
+ const out = Object.create(null);
235
+ for (const key of Reflect.ownKeys(root)) {
236
+ const descriptor = Object.getOwnPropertyDescriptor(root, key);
237
+ if (descriptor === undefined)
238
+ continue;
239
+ Object.defineProperty(out, key, {
240
+ value: replacements.get(key) ?? descriptor.value,
241
+ enumerable: descriptor.enumerable === true,
242
+ configurable: true,
243
+ writable: true,
244
+ });
245
+ }
246
+ return Object.freeze(out);
247
+ }
248
+ function toRepeatFoldOptions(transition) {
249
+ const repeat = transition.repeat;
250
+ if (repeat === undefined || repeat <= 0)
251
+ return null;
252
+ return {
253
+ repeat,
254
+ repeatType: transition.repeatType ?? 'loop',
255
+ repeatDelayMs: (transition.repeatDelay ?? 0) * MS_PER_SECOND,
256
+ };
257
+ }
258
+ // T18-b (REQ-TIMING-004 / REQ-API-050): the public `delay` crosses seconds→ms HERE, at the same
259
+ // boundary as every other public time (duration in toTimingConfig/toKeyframesConfig, repeatDelay
260
+ // above) — the rebase consumes milliseconds. Absent reads as 0, the pin's default.
261
+ function toDelayMs(transition) {
262
+ return (transition.delay ?? 0) * MS_PER_SECOND;
263
+ }
264
+ function toTimingConfig(transition) {
265
+ const config = {};
266
+ if (transition.duration !== undefined)
267
+ config.duration = transition.duration * MS_PER_SECOND;
268
+ // The scalar TWEEN path takes a SINGLE easing only. A per-segment `ease` LIST (R8 M2-B) is a
269
+ // keyframe-array param carried exclusively by `toKeyframesConfig`; passing a list here would break
270
+ // `resolveEasing` (it expects one easing). A list on a scalar target is a cross-field error caught
271
+ // by `keyframeTimingRefusal`, so dropping it here is safe and keeps the tween path total.
272
+ const ease = effectiveTransitionEase(transition);
273
+ if (ease !== undefined && !(0, timing_1.isEasingList)(ease))
274
+ config.ease = ease;
275
+ return config;
276
+ }
277
+ // transition-default-selection F6: the pin's timing LANE predicate, and the ONE rule both drivers
278
+ // and validation read. `isTransitionDefined` counts an authored duration AND the ease spellings
279
+ // (only the orchestration keys are exempt, is-transition-defined.ts:4-29), and a DEFINED-but-
280
+ // typeless bag resolves through the keyframes/timing generator at the 300ms default
281
+ // (motion-dom@12.42.2 JSAnimation.ts:106-116 `type = keyframesGenerator`,
282
+ // generators/keyframes.ts:25 `duration = 300`) — never the spring backstop. The lane is therefore:
283
+ // type omitted AND (an authored duration OR an authored ease spelling — `ease`/`easings`/`easing`,
284
+ // the 00i0nt alias law). Inertia narrows off by its literal `type`.
285
+ //
286
+ // The duration arm is REQ-TIMING-006's: the pin's `isTransitionDefined({ duration })` is TRUE, so
287
+ // `animateMotionValue` SKIPS the per-key `getDefaultTransition` (the spring, REQ-SPRING-012) and
288
+ // `JSAnimation.initAnimation` falls through `type = keyframesGenerator` (motion-value.ts:68-71,
289
+ // JSAnimation.ts:104,115-116) — an authored scalar transition with `duration` and no `type` runs
290
+ // the keyframes/timing generator, monotone, NEVER a duration-spring. This predicate SUBSUMES that
291
+ // arm; the narrower `isDurationOnlyTransition` it superseded at every call site was removed rather
292
+ // than left as dead exported surface, so do not reintroduce a duration-only predicate here.
293
+ //
294
+ // The ease-only arm is the F6 addition and is why an absent `duration` does NOT imply the spring
295
+ // backstop: `{ ease: 'linear' }` matches. It keeps its authored ease verbatim —
296
+ // `toTimingLaneConfig` injects easeOut ONLY when no spelling is authored, so no injection fires
297
+ // here. An orchestration-only bag matches NEITHER arm and keeps the spring backstop: unreachable
298
+ // on the component path (the controller's flat arm already merged the per-key default under it,
299
+ // REQ-SPRING-012) but held as the defensive default.
300
+ function isTimingLaneTransition(transition) {
301
+ if (transition.type !== undefined)
302
+ return false;
303
+ if (transition.duration !== undefined)
304
+ return true;
305
+ return effectiveTransitionEase(transition) !== undefined;
306
+ }
307
+ // transition-default-selection F5: the duration-zero half of the pin's `makeAnimationInstant`
308
+ // guard (motion-dom@12.42.2 animation/interfaces/motion-value.ts:89-98 —
309
+ // `(options as any).type === false || (options.duration === 0 && !options.repeatDelay)`; the
310
+ // `type === false` half is the U7a lane, which the drivers check beside this one). The routing is
311
+ // TYPE-INDEPENDENT — a typed spring with `duration: 0` instants too — and honors the pin's
312
+ // truthiness: an authored `repeatDelay: 0` reads as absent. A repeatDelay-bearing bag is EXEMPT:
313
+ // it keeps its normal generator (the pin builds a real animation whose zero-length plays are
314
+ // separated by the repeatDelay gaps).
315
+ function isDurationZeroInstantTransition(transition) {
316
+ if (transition.type === 'inertia')
317
+ return false;
318
+ return transition.duration === 0 && !transition.repeatDelay;
319
+ }
320
+ // REQ-TIMING-006 + transition-default-selection F1: the timing LANE's config — the ONE builder
321
+ // every timing-lane consumer reads (both drivers' scalar arms, the presence exit lane). The pin's
322
+ // `animateMotionValue` options base is `{ keyframes: [null, target], ease: "easeOut", ...valueTransition }`
323
+ // (motion-dom@12.42.2 motion-value.ts:45-49), so only an AUTHORED ease spelling overrides:
324
+ // whenever the timing lane is selected — a typed tween OR a duration-only untyped bag — and no
325
+ // ease spelling is authored, the ease is [0, 0, 0.58, 1], never the generator default
326
+ // [0.25, 0.1, 0.35, 1] (REQ-TIMING-002, whose default now governs only the pin's per-key default
327
+ // tween, default-transitions.ts:35-48). Any authored spelling (`ease`/`easings`/`easing`, the
328
+ // 00i0nt alias law) suppresses the injection. Mirrors the sealed layout-lane law (REQ-LAYOUT-023
329
+ // a, 7htzcf).
330
+ function toTimingLaneConfig(transition) {
331
+ const config = toTimingConfig(transition);
332
+ if (effectiveTransitionEase(transition) === undefined)
333
+ config.ease = 'easeOut';
334
+ return config;
335
+ }
336
+ // Bridge the public `Transition` to the internal `KeyframesConfig` (the multi-keyframe timing path,
337
+ // REQ-API-033). `duration` crosses seconds→ms; `ease` passes through — a single easing (applied to
338
+ // every segment) OR a per-SEGMENT list (R8 M2-B, law d); `times` (custom 0–1 offsets) passes through
339
+ // as-is (offsets are unitless, no seconds→ms crossing). Absent fields omitted
340
+ // (exactOptionalPropertyTypes). Shape validation happens before this bridge; target-count fallback is
341
+ // owned by the shared core/UI keyframe normalization seam.
342
+ function toKeyframesConfig(transition) {
343
+ const config = {};
344
+ if (transition.duration !== undefined)
345
+ config.duration = transition.duration * MS_PER_SECOND;
346
+ const ease = effectiveTransitionEase(transition);
347
+ if (ease !== undefined)
348
+ config.ease = ease;
349
+ if (transition.times !== undefined)
350
+ config.times = transition.times;
351
+ return config;
352
+ }
@@ -0,0 +1,33 @@
1
+ import type { KeyframesConfig } from "../keyframes.cjs";
2
+ import type { RepeatType } from "../repeat.cjs";
3
+ import { type TimingConfig } from "../timing.cjs";
4
+ import type { InertiaTransition, SpringConfig } from "../transition.cjs";
5
+ import { type Transition } from "./types.cjs";
6
+ /**
7
+ * Resolve one Motion consumer against an authored transition map. The result is a detached flat
8
+ * bag: map entries never cross into a generator, and nested maps never recurse. Validation/capture
9
+ * owns malformed-shape refusal; this selector assumes that boundary has passed and preserves the
10
+ * pin's key → default → root precedence.
11
+ */
12
+ export declare function resolveTransitionForKey(transition: Transition, key: string): Transition;
13
+ export declare function toSpringConfig(transition: Transition): SpringConfig;
14
+ export declare function effectiveTransitionEase(transition: Transition): Transition['ease'] | Transition['easings'] | Transition['easing'];
15
+ /**
16
+ * Canonicalize the public `easings` alias at both legal transition levels. The pin-facing web/native
17
+ * consumers never receive nested bags directly, but MotionConfig and variant inheritance can carry a
18
+ * captured map through several handoff boundaries before the consumer selector runs. Normalize exactly
19
+ * one nested bag level; recursive maps are a validation error, not an invitation to walk unbounded data.
20
+ */
21
+ export declare function normalizeTransitionEaseAlias(transition: Transition): Transition;
22
+ export interface RepeatFoldOptions {
23
+ readonly repeat: number;
24
+ readonly repeatType: RepeatType;
25
+ readonly repeatDelayMs: number;
26
+ }
27
+ export declare function toRepeatFoldOptions(transition: Transition): RepeatFoldOptions | null;
28
+ export declare function toDelayMs(transition: Transition): number;
29
+ export declare function toTimingConfig(transition: Transition): TimingConfig;
30
+ export declare function isTimingLaneTransition(transition: Transition | InertiaTransition): boolean;
31
+ export declare function isDurationZeroInstantTransition(transition: Transition | InertiaTransition): boolean;
32
+ export declare function toTimingLaneConfig(transition: Transition): TimingConfig;
33
+ export declare function toKeyframesConfig(transition: Transition): KeyframesConfig;
@@ -0,0 +1,33 @@
1
+ import type { KeyframesConfig } from "../keyframes.js";
2
+ import type { RepeatType } from "../repeat.js";
3
+ import { type TimingConfig } from "../timing.js";
4
+ import type { InertiaTransition, SpringConfig } from "../transition.js";
5
+ import { type Transition } from "./types.js";
6
+ /**
7
+ * Resolve one Motion consumer against an authored transition map. The result is a detached flat
8
+ * bag: map entries never cross into a generator, and nested maps never recurse. Validation/capture
9
+ * owns malformed-shape refusal; this selector assumes that boundary has passed and preserves the
10
+ * pin's key → default → root precedence.
11
+ */
12
+ export declare function resolveTransitionForKey(transition: Transition, key: string): Transition;
13
+ export declare function toSpringConfig(transition: Transition): SpringConfig;
14
+ export declare function effectiveTransitionEase(transition: Transition): Transition['ease'] | Transition['easings'] | Transition['easing'];
15
+ /**
16
+ * Canonicalize the public `easings` alias at both legal transition levels. The pin-facing web/native
17
+ * consumers never receive nested bags directly, but MotionConfig and variant inheritance can carry a
18
+ * captured map through several handoff boundaries before the consumer selector runs. Normalize exactly
19
+ * one nested bag level; recursive maps are a validation error, not an invitation to walk unbounded data.
20
+ */
21
+ export declare function normalizeTransitionEaseAlias(transition: Transition): Transition;
22
+ export interface RepeatFoldOptions {
23
+ readonly repeat: number;
24
+ readonly repeatType: RepeatType;
25
+ readonly repeatDelayMs: number;
26
+ }
27
+ export declare function toRepeatFoldOptions(transition: Transition): RepeatFoldOptions | null;
28
+ export declare function toDelayMs(transition: Transition): number;
29
+ export declare function toTimingConfig(transition: Transition): TimingConfig;
30
+ export declare function isTimingLaneTransition(transition: Transition | InertiaTransition): boolean;
31
+ export declare function isDurationZeroInstantTransition(transition: Transition | InertiaTransition): boolean;
32
+ export declare function toTimingLaneConfig(transition: Transition): TimingConfig;
33
+ export declare function toKeyframesConfig(transition: Transition): KeyframesConfig;