@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,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.motionMix = motionMix;
4
+ // The public Motion `mix` utility. Pin: motion-dom/src/utils/mix/{index,complex,immediate,number}
5
+ // and value/types/color. H1 (REQ-VALUETYPE-016): arm SELECTION is the pin's `getMixer`, dispatching
6
+ // on the ORIGIN alone, and the arms the pin owns outright — array, object, color object,
7
+ // CSS-variable token, and the non-mixable fallback — run the pin's own algorithms, output-reference
8
+ // reuse included. The remaining string arm still executes through core's ONE value seam
9
+ // (parseValue → mix → transformValue): its per-family laws are unchanged here, and its recorded
10
+ // divergences from the pin — REQ-VALUETYPE-004/007/008 value-seam strictness and
11
+ // REQ-VALUETYPE-005/006 color-syntax capability — stay owned by those requirements and by their own
12
+ // doctrine-census rows, never by this file. REQ-VALUETYPE-015's both-visible discrete pair is no
13
+ // longer among them: H3 closed it, and the seam publishes the pin's zero-slot constant.
14
+ //
15
+ // Exported publicly as `mix` by the PRODUCT entries only — the core-root `mix` name stays the
16
+ // SPEC-VALUE-TYPES typed seam.
17
+ const value_types_1 = require("./value-types/index.cjs");
18
+ const color_1 = require("./value-types/color.cjs");
19
+ // pin mix/number.ts: unclamped linear interpolation through raw JavaScript arithmetic — a
20
+ // non-numeric operand yields NaN, it does not refuse.
21
+ function mixNumber(from, to, progress) {
22
+ return from + (to - from) * progress;
23
+ }
24
+ function numberMixer(from, to) {
25
+ return (p) => mixNumber(from, to, p);
26
+ }
27
+ // pin mix/immediate.ts: the origin until progress passes zero, then the target.
28
+ function mixImmediate(from, to) {
29
+ return (p) => (p > 0 ? to : from);
30
+ }
31
+ // pin animation/utils/is-css-variable.ts, reproduced verbatim (prefix guard + comment-stripped
32
+ // single-variable pattern). Native has no CSS custom properties to resolve, so the pin's immediate
33
+ // arm IS the faithful behavior — a refusal here would be a stricter native policy.
34
+ const SINGLE_CSS_VARIABLE_RE = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
35
+ function isCssVariableToken(value) {
36
+ if (!value.startsWith('var(--'))
37
+ return false;
38
+ return SINGLE_CSS_VARIABLE_RE.test((value.split('/*')[0] ?? '').trim());
39
+ }
40
+ // pin value/types/utils/single-color-regex.ts, reproduced verbatim (flags included) — the pin's
41
+ // colour RECOGNIZER. Core's own `isColor` is deliberately WIDER (a named-colour table,
42
+ // whitespace-padded channels — `motion.color-syntax-capability`), so this replica exists to answer
43
+ // the one question `colorMixer`'s degrade path cannot answer with core's recognizer: which PIN arm
44
+ // would own the pair. The reproduced stringification fault depends on it (LOOP Decision 53), and
45
+ // the differential's boundary rows pin both sides.
46
+ const SINGLE_COLOR_REGEX = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
47
+ // pin value/types/color/index.ts `color.test` for the OBJECT arm: an own `red` property is an RGBA
48
+ // record, an own `hue` property an HSLA record. `Object.hasOwn` is the modern spelling of the pin's
49
+ // `Object.prototype.hasOwnProperty.call` and answers identically.
50
+ function isColorObject(value) {
51
+ return Object.hasOwn(value, 'red') || Object.hasOwn(value, 'hue');
52
+ }
53
+ const NOT_A_COLOR = { kind: 'not-a-color' };
54
+ function asRgba(value) {
55
+ if (typeof value === 'string') {
56
+ if (!(0, color_1.isColor)(value))
57
+ return NOT_A_COLOR;
58
+ const verdict = (0, color_1.parseColorVerdict)(value);
59
+ return verdict.refusal === null
60
+ ? { kind: 'rgba', value: verdict.parsed }
61
+ : { kind: 'unparseable', refusal: verdict.refusal };
62
+ }
63
+ if (typeof value !== 'object' || value === null)
64
+ return NOT_A_COLOR;
65
+ if (Object.hasOwn(value, 'red'))
66
+ return { kind: 'rgba', value: value };
67
+ if (Object.hasOwn(value, 'hue')) {
68
+ const hsla = value;
69
+ return {
70
+ kind: 'rgba',
71
+ value: (0, color_1.hslaToRgba)(hsla.hue, hsla.saturation, hsla.lightness, hsla.alpha),
72
+ };
73
+ }
74
+ return NOT_A_COLOR;
75
+ }
76
+ // The pin's factory-time stringification of the endpoint that failed `asRgba`, reproduced so the
77
+ // same TypeError escapes at the same moment (LOOP Decision 53). Which pin arm would own the pair
78
+ // decides which operation the pin would fault on:
79
+ // - a `singleColorRegex` string origin, or a colour RECORD (the pin's object branch sends
80
+ // red/hue records to `mixColor` too): `mixColor`'s `asRGBA` interpolates the endpoint into its
81
+ // `warning()` template literal BEFORE returning false — throwing on a `Symbol`, an object with
82
+ // no `toString`, or a throwing `toString`; a nullish target stringifies fine there.
83
+ // - any other string origin core recognizes (a named colour, whitespace-padded rgb — the pairs
84
+ // core's WIDER recognizer routes here): `mixComplex`'s `analyseComplexValue`
85
+ // (value/types/complex/index.ts:21-22) opens with `const originalValue = value.toString()` and
86
+ // immediately parses the result with `.replace(complexRegex, …)` — throwing on a nullish
87
+ // target, on a target with no `toString`, AND on a `toString` that returns a non-string
88
+ // (`originalValue.replace is not a function`); tolerating a `Symbol` (its `toString` returns
89
+ // a string).
90
+ // For every pair the pin tolerates the operation is inert and the caller's step stands. `from` is
91
+ // never the failing endpoint here: `getMixer` only routes origins `asRgba` resolves.
92
+ function pinStringification(from, to) {
93
+ if (typeof from === 'string' && !SINGLE_COLOR_REGEX.test(from)) {
94
+ return pinComplexStringification(to);
95
+ }
96
+ return `${to}`;
97
+ }
98
+ // pin value/types/complex/index.ts `analyseComplexValue`'s fault surface, operation for operation:
99
+ // `const originalValue = value.toString()` then `originalValue.replace(complexRegex, …)`. The
100
+ // parameter is NAMED `value` because V8 quotes the receiver's source text in the TypeError, so the
101
+ // pin's message escapes byte-identically only under the pin's own identifier (the precedent is
102
+ // `arrayMixer`'s `blendValue`). The parse that follows the replace is the pin's semantics, not
103
+ // its fault surface, and is not reproduced. One acknowledged tail: the pin's `tokenised.split(...)`
104
+ // on the replace RESULT can still throw there (a `toString` returning a non-primitive object with
105
+ // a hostile `replace`) and is not reproduced — a contract-breaking constructed input, recorded by
106
+ // the confirming review as a non-blocking minor.
107
+ function pinComplexStringification(value) {
108
+ const originalValue = value.toString();
109
+ return originalValue.replace(/$/, '');
110
+ }
111
+ function colorMixer(from, to) {
112
+ const fromColor = asRgba(from);
113
+ const toColor = asRgba(to);
114
+ if (fromColor.kind === 'unparseable')
115
+ throw new Error(fromColor.refusal);
116
+ if (toColor.kind === 'unparseable')
117
+ throw new Error(toColor.refusal);
118
+ if (fromColor.kind === 'not-a-color' || toColor.kind === 'not-a-color') {
119
+ pinStringification(from, to);
120
+ return mixImmediate(from, to);
121
+ }
122
+ const fromRgba = fromColor.value;
123
+ const toRgba = toColor.value;
124
+ return (p) => (0, color_1.transformColor)((0, color_1.mixColor)(fromRgba, toRgba, p));
125
+ }
126
+ // The one core value seam (SPEC-VALUE-TYPES §3) — the pin's `mixComplex` position in the dispatch
127
+ // table. A non-string target has no decomposition here, so it stays the seam's own loud
128
+ // cross-family refusal (REQ-VALUETYPE-008, `motion.value-seam-strictness`).
129
+ function seamMixer(from, to) {
130
+ if (typeof to !== 'string') {
131
+ throw new Error(`mix: cannot mix ${JSON.stringify(from)} with ${JSON.stringify(to)} — a value-seam origin ` +
132
+ 'needs a string target of one value family (REQ-VALUETYPE-008)');
133
+ }
134
+ const fromTyped = (0, value_types_1.parseValue)(from);
135
+ const toTyped = (0, value_types_1.parseValue)(to);
136
+ return (p) => {
137
+ const committed = (0, value_types_1.transformValue)((0, value_types_1.mix)(fromTyped, toTyped, p));
138
+ return typeof committed === 'number' ? String(committed) : committed;
139
+ };
140
+ }
141
+ // pin mix/complex.ts `mixArray`: the ORIGIN governs length and arm choice, and ONE output array is
142
+ // mutated in place and handed back on every call.
143
+ function arrayMixer(from, to) {
144
+ const origin = from;
145
+ const target = to;
146
+ const output = [...origin];
147
+ const numValues = output.length;
148
+ // Named `blendValue` to match the pin's own local: `Array#map` SKIPS holes, so a sparse origin
149
+ // leaves a hole here and the call below raises the pin's `blendValue[i] is not a function`
150
+ // TypeError — byte-identical only if the identifier is. Guarding the hole instead would suppress
151
+ // a pin fault of exactly the class LOOP Decision 25 keeps.
152
+ const blendValue = origin.map((value, i) => getMixer(value)(value, target[i]));
153
+ return (p) => {
154
+ for (let i = 0; i < numValues; i++) {
155
+ output[i] = blendValue[i](p);
156
+ }
157
+ return output;
158
+ };
159
+ }
160
+ // pin mix/complex.ts `mixObject`: a UNION snapshot of both sides, only both-defined keys blended,
161
+ // and ONE output object mutated in place and handed back on every call. `for…in` and the direct
162
+ // `origin[key]` read are the pin's own operations — a null origin against a populated target
163
+ // raises the pin's `TypeError` here, which the fidelity presumption keeps rather than guarding.
164
+ function objectMixer(from, to) {
165
+ const origin = from;
166
+ const target = to;
167
+ const output = { ...origin, ...target };
168
+ const blendValue = {};
169
+ for (const key in output) {
170
+ if (origin[key] !== undefined && target[key] !== undefined) {
171
+ blendValue[key] = getMixer(origin[key])(origin[key], target[key]);
172
+ }
173
+ }
174
+ return (p) => {
175
+ for (const key in blendValue) {
176
+ output[key] = blendValue[key](p);
177
+ }
178
+ return output;
179
+ };
180
+ }
181
+ // pin mix/complex.ts `getMixer`, branch for branch. `typeof from === 'object'` deliberately
182
+ // includes `null`, exactly as the pin's does.
183
+ function getMixer(from) {
184
+ if (typeof from === 'number')
185
+ return numberMixer;
186
+ if (typeof from === 'string') {
187
+ if (isCssVariableToken(from))
188
+ return mixImmediate;
189
+ return (0, color_1.isColor)(from) ? colorMixer : seamMixer;
190
+ }
191
+ if (Array.isArray(from))
192
+ return arrayMixer;
193
+ if (typeof from === 'object') {
194
+ return from !== null && isColorObject(from) ? colorMixer : objectMixer;
195
+ }
196
+ return mixImmediate;
197
+ }
198
+ function motionMix(from, to, p) {
199
+ // pin mix/index.ts: the immediate form requires all THREE arguments to be numbers; otherwise the
200
+ // third is ignored and the factory is returned.
201
+ if (typeof from === 'number' && typeof to === 'number' && typeof p === 'number') {
202
+ return mixNumber(from, to, p);
203
+ }
204
+ return getMixer(from)(from, to);
205
+ }
@@ -0,0 +1,3 @@
1
+ export type MotionMixer<T> = (p: number) => T;
2
+ export declare function motionMix(from: number, to: number, p: number): number;
3
+ export declare function motionMix<T>(from: T, to: T): MotionMixer<T>;
@@ -0,0 +1,3 @@
1
+ export type MotionMixer<T> = (p: number) => T;
2
+ export declare function motionMix(from: number, to: number, p: number): number;
3
+ export declare function motionMix<T>(from: T, to: T): MotionMixer<T>;
@@ -0,0 +1,202 @@
1
+ // The public Motion `mix` utility. Pin: motion-dom/src/utils/mix/{index,complex,immediate,number}
2
+ // and value/types/color. H1 (REQ-VALUETYPE-016): arm SELECTION is the pin's `getMixer`, dispatching
3
+ // on the ORIGIN alone, and the arms the pin owns outright — array, object, color object,
4
+ // CSS-variable token, and the non-mixable fallback — run the pin's own algorithms, output-reference
5
+ // reuse included. The remaining string arm still executes through core's ONE value seam
6
+ // (parseValue → mix → transformValue): its per-family laws are unchanged here, and its recorded
7
+ // divergences from the pin — REQ-VALUETYPE-004/007/008 value-seam strictness and
8
+ // REQ-VALUETYPE-005/006 color-syntax capability — stay owned by those requirements and by their own
9
+ // doctrine-census rows, never by this file. REQ-VALUETYPE-015's both-visible discrete pair is no
10
+ // longer among them: H3 closed it, and the seam publishes the pin's zero-slot constant.
11
+ //
12
+ // Exported publicly as `mix` by the PRODUCT entries only — the core-root `mix` name stays the
13
+ // SPEC-VALUE-TYPES typed seam.
14
+ import { mix as mixTyped, parseValue, transformValue } from "./value-types/index.js";
15
+ import { hslaToRgba, isColor, mixColor, parseColorVerdict, transformColor, } from "./value-types/color.js";
16
+ // pin mix/number.ts: unclamped linear interpolation through raw JavaScript arithmetic — a
17
+ // non-numeric operand yields NaN, it does not refuse.
18
+ function mixNumber(from, to, progress) {
19
+ return from + (to - from) * progress;
20
+ }
21
+ function numberMixer(from, to) {
22
+ return (p) => mixNumber(from, to, p);
23
+ }
24
+ // pin mix/immediate.ts: the origin until progress passes zero, then the target.
25
+ function mixImmediate(from, to) {
26
+ return (p) => (p > 0 ? to : from);
27
+ }
28
+ // pin animation/utils/is-css-variable.ts, reproduced verbatim (prefix guard + comment-stripped
29
+ // single-variable pattern). Native has no CSS custom properties to resolve, so the pin's immediate
30
+ // arm IS the faithful behavior — a refusal here would be a stricter native policy.
31
+ const SINGLE_CSS_VARIABLE_RE = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
32
+ function isCssVariableToken(value) {
33
+ if (!value.startsWith('var(--'))
34
+ return false;
35
+ return SINGLE_CSS_VARIABLE_RE.test((value.split('/*')[0] ?? '').trim());
36
+ }
37
+ // pin value/types/utils/single-color-regex.ts, reproduced verbatim (flags included) — the pin's
38
+ // colour RECOGNIZER. Core's own `isColor` is deliberately WIDER (a named-colour table,
39
+ // whitespace-padded channels — `motion.color-syntax-capability`), so this replica exists to answer
40
+ // the one question `colorMixer`'s degrade path cannot answer with core's recognizer: which PIN arm
41
+ // would own the pair. The reproduced stringification fault depends on it (LOOP Decision 53), and
42
+ // the differential's boundary rows pin both sides.
43
+ const SINGLE_COLOR_REGEX = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
44
+ // pin value/types/color/index.ts `color.test` for the OBJECT arm: an own `red` property is an RGBA
45
+ // record, an own `hue` property an HSLA record. `Object.hasOwn` is the modern spelling of the pin's
46
+ // `Object.prototype.hasOwnProperty.call` and answers identically.
47
+ function isColorObject(value) {
48
+ return Object.hasOwn(value, 'red') || Object.hasOwn(value, 'hue');
49
+ }
50
+ const NOT_A_COLOR = { kind: 'not-a-color' };
51
+ function asRgba(value) {
52
+ if (typeof value === 'string') {
53
+ if (!isColor(value))
54
+ return NOT_A_COLOR;
55
+ const verdict = parseColorVerdict(value);
56
+ return verdict.refusal === null
57
+ ? { kind: 'rgba', value: verdict.parsed }
58
+ : { kind: 'unparseable', refusal: verdict.refusal };
59
+ }
60
+ if (typeof value !== 'object' || value === null)
61
+ return NOT_A_COLOR;
62
+ if (Object.hasOwn(value, 'red'))
63
+ return { kind: 'rgba', value: value };
64
+ if (Object.hasOwn(value, 'hue')) {
65
+ const hsla = value;
66
+ return {
67
+ kind: 'rgba',
68
+ value: hslaToRgba(hsla.hue, hsla.saturation, hsla.lightness, hsla.alpha),
69
+ };
70
+ }
71
+ return NOT_A_COLOR;
72
+ }
73
+ // The pin's factory-time stringification of the endpoint that failed `asRgba`, reproduced so the
74
+ // same TypeError escapes at the same moment (LOOP Decision 53). Which pin arm would own the pair
75
+ // decides which operation the pin would fault on:
76
+ // - a `singleColorRegex` string origin, or a colour RECORD (the pin's object branch sends
77
+ // red/hue records to `mixColor` too): `mixColor`'s `asRGBA` interpolates the endpoint into its
78
+ // `warning()` template literal BEFORE returning false — throwing on a `Symbol`, an object with
79
+ // no `toString`, or a throwing `toString`; a nullish target stringifies fine there.
80
+ // - any other string origin core recognizes (a named colour, whitespace-padded rgb — the pairs
81
+ // core's WIDER recognizer routes here): `mixComplex`'s `analyseComplexValue`
82
+ // (value/types/complex/index.ts:21-22) opens with `const originalValue = value.toString()` and
83
+ // immediately parses the result with `.replace(complexRegex, …)` — throwing on a nullish
84
+ // target, on a target with no `toString`, AND on a `toString` that returns a non-string
85
+ // (`originalValue.replace is not a function`); tolerating a `Symbol` (its `toString` returns
86
+ // a string).
87
+ // For every pair the pin tolerates the operation is inert and the caller's step stands. `from` is
88
+ // never the failing endpoint here: `getMixer` only routes origins `asRgba` resolves.
89
+ function pinStringification(from, to) {
90
+ if (typeof from === 'string' && !SINGLE_COLOR_REGEX.test(from)) {
91
+ return pinComplexStringification(to);
92
+ }
93
+ return `${to}`;
94
+ }
95
+ // pin value/types/complex/index.ts `analyseComplexValue`'s fault surface, operation for operation:
96
+ // `const originalValue = value.toString()` then `originalValue.replace(complexRegex, …)`. The
97
+ // parameter is NAMED `value` because V8 quotes the receiver's source text in the TypeError, so the
98
+ // pin's message escapes byte-identically only under the pin's own identifier (the precedent is
99
+ // `arrayMixer`'s `blendValue`). The parse that follows the replace is the pin's semantics, not
100
+ // its fault surface, and is not reproduced. One acknowledged tail: the pin's `tokenised.split(...)`
101
+ // on the replace RESULT can still throw there (a `toString` returning a non-primitive object with
102
+ // a hostile `replace`) and is not reproduced — a contract-breaking constructed input, recorded by
103
+ // the confirming review as a non-blocking minor.
104
+ function pinComplexStringification(value) {
105
+ const originalValue = value.toString();
106
+ return originalValue.replace(/$/, '');
107
+ }
108
+ function colorMixer(from, to) {
109
+ const fromColor = asRgba(from);
110
+ const toColor = asRgba(to);
111
+ if (fromColor.kind === 'unparseable')
112
+ throw new Error(fromColor.refusal);
113
+ if (toColor.kind === 'unparseable')
114
+ throw new Error(toColor.refusal);
115
+ if (fromColor.kind === 'not-a-color' || toColor.kind === 'not-a-color') {
116
+ pinStringification(from, to);
117
+ return mixImmediate(from, to);
118
+ }
119
+ const fromRgba = fromColor.value;
120
+ const toRgba = toColor.value;
121
+ return (p) => transformColor(mixColor(fromRgba, toRgba, p));
122
+ }
123
+ // The one core value seam (SPEC-VALUE-TYPES §3) — the pin's `mixComplex` position in the dispatch
124
+ // table. A non-string target has no decomposition here, so it stays the seam's own loud
125
+ // cross-family refusal (REQ-VALUETYPE-008, `motion.value-seam-strictness`).
126
+ function seamMixer(from, to) {
127
+ if (typeof to !== 'string') {
128
+ throw new Error(`mix: cannot mix ${JSON.stringify(from)} with ${JSON.stringify(to)} — a value-seam origin ` +
129
+ 'needs a string target of one value family (REQ-VALUETYPE-008)');
130
+ }
131
+ const fromTyped = parseValue(from);
132
+ const toTyped = parseValue(to);
133
+ return (p) => {
134
+ const committed = transformValue(mixTyped(fromTyped, toTyped, p));
135
+ return typeof committed === 'number' ? String(committed) : committed;
136
+ };
137
+ }
138
+ // pin mix/complex.ts `mixArray`: the ORIGIN governs length and arm choice, and ONE output array is
139
+ // mutated in place and handed back on every call.
140
+ function arrayMixer(from, to) {
141
+ const origin = from;
142
+ const target = to;
143
+ const output = [...origin];
144
+ const numValues = output.length;
145
+ // Named `blendValue` to match the pin's own local: `Array#map` SKIPS holes, so a sparse origin
146
+ // leaves a hole here and the call below raises the pin's `blendValue[i] is not a function`
147
+ // TypeError — byte-identical only if the identifier is. Guarding the hole instead would suppress
148
+ // a pin fault of exactly the class LOOP Decision 25 keeps.
149
+ const blendValue = origin.map((value, i) => getMixer(value)(value, target[i]));
150
+ return (p) => {
151
+ for (let i = 0; i < numValues; i++) {
152
+ output[i] = blendValue[i](p);
153
+ }
154
+ return output;
155
+ };
156
+ }
157
+ // pin mix/complex.ts `mixObject`: a UNION snapshot of both sides, only both-defined keys blended,
158
+ // and ONE output object mutated in place and handed back on every call. `for…in` and the direct
159
+ // `origin[key]` read are the pin's own operations — a null origin against a populated target
160
+ // raises the pin's `TypeError` here, which the fidelity presumption keeps rather than guarding.
161
+ function objectMixer(from, to) {
162
+ const origin = from;
163
+ const target = to;
164
+ const output = { ...origin, ...target };
165
+ const blendValue = {};
166
+ for (const key in output) {
167
+ if (origin[key] !== undefined && target[key] !== undefined) {
168
+ blendValue[key] = getMixer(origin[key])(origin[key], target[key]);
169
+ }
170
+ }
171
+ return (p) => {
172
+ for (const key in blendValue) {
173
+ output[key] = blendValue[key](p);
174
+ }
175
+ return output;
176
+ };
177
+ }
178
+ // pin mix/complex.ts `getMixer`, branch for branch. `typeof from === 'object'` deliberately
179
+ // includes `null`, exactly as the pin's does.
180
+ function getMixer(from) {
181
+ if (typeof from === 'number')
182
+ return numberMixer;
183
+ if (typeof from === 'string') {
184
+ if (isCssVariableToken(from))
185
+ return mixImmediate;
186
+ return isColor(from) ? colorMixer : seamMixer;
187
+ }
188
+ if (Array.isArray(from))
189
+ return arrayMixer;
190
+ if (typeof from === 'object') {
191
+ return from !== null && isColorObject(from) ? colorMixer : objectMixer;
192
+ }
193
+ return mixImmediate;
194
+ }
195
+ export function motionMix(from, to, p) {
196
+ // pin mix/index.ts: the immediate form requires all THREE arguments to be numbers; otherwise the
197
+ // third is ignored and the factory is returned.
198
+ if (typeof from === 'number' && typeof to === 'number' && typeof p === 'number') {
199
+ return mixNumber(from, to, p);
200
+ }
201
+ return getMixer(from)(from, to);
202
+ }