@voila.dev/motion 0.0.0-stage → 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 (273) hide show
  1. package/README.md +105 -2
  2. package/dist/accessibility/reduced-motion.d.ts +13 -0
  3. package/dist/accessibility/reduced-motion.d.ts.map +1 -0
  4. package/dist/accessibility/reduced-motion.js +56 -0
  5. package/dist/accessibility/reduced-motion.js.map +7 -0
  6. package/dist/animate/animate.d.ts +21 -0
  7. package/dist/animate/animate.d.ts.map +1 -0
  8. package/dist/animate/animate.js +76 -0
  9. package/dist/animate/animate.js.map +7 -0
  10. package/dist/animate/controls.d.ts +16 -0
  11. package/dist/animate/controls.d.ts.map +1 -0
  12. package/dist/animate/controls.js +62 -0
  13. package/dist/animate/controls.js.map +7 -0
  14. package/dist/animate/dom.d.ts +11 -0
  15. package/dist/animate/dom.d.ts.map +1 -0
  16. package/dist/animate/dom.js +112 -0
  17. package/dist/animate/dom.js.map +7 -0
  18. package/dist/animate/js-animation.d.ts +25 -0
  19. package/dist/animate/js-animation.d.ts.map +1 -0
  20. package/dist/animate/js-animation.js +117 -0
  21. package/dist/animate/js-animation.js.map +7 -0
  22. package/dist/animate/plan.d.ts +17 -0
  23. package/dist/animate/plan.d.ts.map +1 -0
  24. package/dist/animate/plan.js +48 -0
  25. package/dist/animate/plan.js.map +7 -0
  26. package/dist/animate/style.d.ts +27 -0
  27. package/dist/animate/style.d.ts.map +1 -0
  28. package/dist/animate/style.js +96 -0
  29. package/dist/animate/style.js.map +7 -0
  30. package/dist/animate/types.d.ts +62 -0
  31. package/dist/animate/types.d.ts.map +1 -0
  32. package/dist/animate/types.js +1 -0
  33. package/dist/animate/types.js.map +7 -0
  34. package/dist/animate/value.d.ts +13 -0
  35. package/dist/animate/value.d.ts.map +1 -0
  36. package/dist/animate/value.js +71 -0
  37. package/dist/animate/value.js.map +7 -0
  38. package/dist/animate/waapi.d.ts +20 -0
  39. package/dist/animate/waapi.d.ts.map +1 -0
  40. package/dist/animate/waapi.js +152 -0
  41. package/dist/animate/waapi.js.map +7 -0
  42. package/dist/dom.d.ts +12 -0
  43. package/dist/dom.d.ts.map +1 -0
  44. package/dist/dom.js +17 -0
  45. package/dist/dom.js.map +7 -0
  46. package/dist/easing/cubic-bezier.d.ts +4 -0
  47. package/dist/easing/cubic-bezier.d.ts.map +1 -0
  48. package/dist/easing/cubic-bezier.js +54 -0
  49. package/dist/easing/cubic-bezier.js.map +7 -0
  50. package/dist/easing/linear-css.d.ts +9 -0
  51. package/dist/easing/linear-css.d.ts.map +1 -0
  52. package/dist/easing/linear-css.js +30 -0
  53. package/dist/easing/linear-css.js.map +7 -0
  54. package/dist/easing/named.d.ts +16 -0
  55. package/dist/easing/named.d.ts.map +1 -0
  56. package/dist/easing/named.js +82 -0
  57. package/dist/easing/named.js.map +7 -0
  58. package/dist/easing/spring.d.ts +11 -0
  59. package/dist/easing/spring.d.ts.map +1 -0
  60. package/dist/easing/spring.js +18 -0
  61. package/dist/easing/spring.js.map +7 -0
  62. package/dist/easing/steps.d.ts +4 -0
  63. package/dist/easing/steps.d.ts.map +1 -0
  64. package/dist/easing/steps.js +14 -0
  65. package/dist/easing/steps.js.map +7 -0
  66. package/dist/easing/types.d.ts +5 -0
  67. package/dist/easing/types.d.ts.map +1 -0
  68. package/dist/easing/types.js +1 -0
  69. package/dist/easing/types.js.map +7 -0
  70. package/dist/frame/driver.d.ts +13 -0
  71. package/dist/frame/driver.d.ts.map +1 -0
  72. package/dist/frame/driver.js +42 -0
  73. package/dist/frame/driver.js.map +7 -0
  74. package/dist/frame/frame.d.ts +20 -0
  75. package/dist/frame/frame.d.ts.map +1 -0
  76. package/dist/frame/frame.js +77 -0
  77. package/dist/frame/frame.js.map +7 -0
  78. package/dist/generators/inertia.d.ts +20 -0
  79. package/dist/generators/inertia.d.ts.map +1 -0
  80. package/dist/generators/inertia.js +59 -0
  81. package/dist/generators/inertia.js.map +7 -0
  82. package/dist/generators/spring.d.ts +17 -0
  83. package/dist/generators/spring.d.ts.map +1 -0
  84. package/dist/generators/spring.js +87 -0
  85. package/dist/generators/spring.js.map +7 -0
  86. package/dist/generators/tween.d.ts +15 -0
  87. package/dist/generators/tween.d.ts.map +1 -0
  88. package/dist/generators/tween.js +51 -0
  89. package/dist/generators/tween.js.map +7 -0
  90. package/dist/generators/types.d.ts +30 -0
  91. package/dist/generators/types.d.ts.map +1 -0
  92. package/dist/generators/types.js +1 -0
  93. package/dist/generators/types.js.map +7 -0
  94. package/dist/index.d.ts +26 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +97 -0
  97. package/dist/index.js.map +7 -0
  98. package/dist/interpolate/array.d.ts +3 -0
  99. package/dist/interpolate/array.d.ts.map +1 -0
  100. package/dist/interpolate/array.js +12 -0
  101. package/dist/interpolate/array.js.map +7 -0
  102. package/dist/interpolate/color-parse.d.ts +14 -0
  103. package/dist/interpolate/color-parse.d.ts.map +1 -0
  104. package/dist/interpolate/color-parse.js +111 -0
  105. package/dist/interpolate/color-parse.js.map +7 -0
  106. package/dist/interpolate/color.d.ts +11 -0
  107. package/dist/interpolate/color.d.ts.map +1 -0
  108. package/dist/interpolate/color.js +74 -0
  109. package/dist/interpolate/color.js.map +7 -0
  110. package/dist/interpolate/complex.d.ts +7 -0
  111. package/dist/interpolate/complex.d.ts.map +1 -0
  112. package/dist/interpolate/complex.js +56 -0
  113. package/dist/interpolate/complex.js.map +7 -0
  114. package/dist/interpolate/interpolate.d.ts +16 -0
  115. package/dist/interpolate/interpolate.d.ts.map +1 -0
  116. package/dist/interpolate/interpolate.js +39 -0
  117. package/dist/interpolate/interpolate.js.map +7 -0
  118. package/dist/interpolate/mix.d.ts +8 -0
  119. package/dist/interpolate/mix.d.ts.map +1 -0
  120. package/dist/interpolate/mix.js +48 -0
  121. package/dist/interpolate/mix.js.map +7 -0
  122. package/dist/interpolate/number.d.ts +2 -0
  123. package/dist/interpolate/number.d.ts.map +1 -0
  124. package/dist/interpolate/number.js +7 -0
  125. package/dist/interpolate/number.js.map +7 -0
  126. package/dist/interpolate/object.d.ts +5 -0
  127. package/dist/interpolate/object.d.ts.map +1 -0
  128. package/dist/interpolate/object.js +17 -0
  129. package/dist/interpolate/object.js.map +7 -0
  130. package/dist/interpolate/path/flatten.d.ts +10 -0
  131. package/dist/interpolate/path/flatten.d.ts.map +1 -0
  132. package/dist/interpolate/path/flatten.js +135 -0
  133. package/dist/interpolate/path/flatten.js.map +7 -0
  134. package/dist/interpolate/path/morph.d.ts +9 -0
  135. package/dist/interpolate/path/morph.d.ts.map +1 -0
  136. package/dist/interpolate/path/morph.js +72 -0
  137. package/dist/interpolate/path/morph.js.map +7 -0
  138. package/dist/interpolate/path/parse.d.ts +24 -0
  139. package/dist/interpolate/path/parse.d.ts.map +1 -0
  140. package/dist/interpolate/path/parse.js +125 -0
  141. package/dist/interpolate/path/parse.js.map +7 -0
  142. package/dist/interpolate/path/rings.d.ts +13 -0
  143. package/dist/interpolate/path/rings.d.ts.map +1 -0
  144. package/dist/interpolate/path/rings.js +117 -0
  145. package/dist/interpolate/path/rings.js.map +7 -0
  146. package/dist/react/index.d.ts +7 -0
  147. package/dist/react/index.d.ts.map +1 -0
  148. package/dist/react/index.js +19 -0
  149. package/dist/react/index.js.map +7 -0
  150. package/dist/react/presence.d.ts +27 -0
  151. package/dist/react/presence.d.ts.map +1 -0
  152. package/dist/react/presence.js +135 -0
  153. package/dist/react/presence.js.map +7 -0
  154. package/dist/react/use-animate.d.ts +17 -0
  155. package/dist/react/use-animate.d.ts.map +1 -0
  156. package/dist/react/use-animate.js +34 -0
  157. package/dist/react/use-animate.js.map +7 -0
  158. package/dist/react/use-motion-value.d.ts +4 -0
  159. package/dist/react/use-motion-value.d.ts.map +1 -0
  160. package/dist/react/use-motion-value.js +11 -0
  161. package/dist/react/use-motion-value.js.map +7 -0
  162. package/dist/react/use-reduced-motion.d.ts +7 -0
  163. package/dist/react/use-reduced-motion.d.ts.map +1 -0
  164. package/dist/react/use-reduced-motion.js +19 -0
  165. package/dist/react/use-reduced-motion.js.map +7 -0
  166. package/dist/react/use-spring.d.ts +9 -0
  167. package/dist/react/use-spring.d.ts.map +1 -0
  168. package/dist/react/use-spring.js +27 -0
  169. package/dist/react/use-spring.js.map +7 -0
  170. package/dist/react/use-transform.d.ts +13 -0
  171. package/dist/react/use-transform.d.ts.map +1 -0
  172. package/dist/react/use-transform.js +44 -0
  173. package/dist/react/use-transform.js.map +7 -0
  174. package/dist/sequence/sequence.d.ts +25 -0
  175. package/dist/sequence/sequence.d.ts.map +1 -0
  176. package/dist/sequence/sequence.js +68 -0
  177. package/dist/sequence/sequence.js.map +7 -0
  178. package/dist/stagger/stagger.d.ts +12 -0
  179. package/dist/stagger/stagger.d.ts.map +1 -0
  180. package/dist/stagger/stagger.js +21 -0
  181. package/dist/stagger/stagger.js.map +7 -0
  182. package/dist/testing/manual-frames.d.ts +11 -0
  183. package/dist/testing/manual-frames.d.ts.map +1 -0
  184. package/dist/testing/manual-frames.js +40 -0
  185. package/dist/testing/manual-frames.js.map +7 -0
  186. package/dist/value/motion-value.d.ts +27 -0
  187. package/dist/value/motion-value.d.ts.map +1 -0
  188. package/dist/value/motion-value.js +88 -0
  189. package/dist/value/motion-value.js.map +7 -0
  190. package/dist/value/transform.d.ts +16 -0
  191. package/dist/value/transform.d.ts.map +1 -0
  192. package/dist/value/transform.js +28 -0
  193. package/dist/value/transform.js.map +7 -0
  194. package/dist/view/in-view.d.ts +19 -0
  195. package/dist/view/in-view.d.ts.map +1 -0
  196. package/dist/view/in-view.js +46 -0
  197. package/dist/view/in-view.js.map +7 -0
  198. package/dist/view/resize.d.ts +13 -0
  199. package/dist/view/resize.d.ts.map +1 -0
  200. package/dist/view/resize.js +72 -0
  201. package/dist/view/resize.js.map +7 -0
  202. package/dist/view/resolve-elements.d.ts +3 -0
  203. package/dist/view/resolve-elements.d.ts.map +1 -0
  204. package/dist/view/resolve-elements.js +10 -0
  205. package/dist/view/resolve-elements.js.map +7 -0
  206. package/dist/view/scroll-measure.d.ts +16 -0
  207. package/dist/view/scroll-measure.d.ts.map +1 -0
  208. package/dist/view/scroll-measure.js +51 -0
  209. package/dist/view/scroll-measure.js.map +7 -0
  210. package/dist/view/scroll-offset.d.ts +28 -0
  211. package/dist/view/scroll-offset.d.ts.map +1 -0
  212. package/dist/view/scroll-offset.js +55 -0
  213. package/dist/view/scroll-offset.js.map +7 -0
  214. package/dist/view/scroll.d.ts +34 -0
  215. package/dist/view/scroll.d.ts.map +1 -0
  216. package/dist/view/scroll.js +83 -0
  217. package/dist/view/scroll.js.map +7 -0
  218. package/package.json +57 -5
  219. package/src/accessibility/reduced-motion.ts +75 -0
  220. package/src/animate/animate.ts +155 -0
  221. package/src/animate/controls.ts +76 -0
  222. package/src/animate/dom.ts +166 -0
  223. package/src/animate/js-animation.ts +151 -0
  224. package/src/animate/plan.ts +74 -0
  225. package/src/animate/style.ts +131 -0
  226. package/src/animate/types.ts +69 -0
  227. package/src/animate/value.ts +93 -0
  228. package/src/animate/waapi.ts +212 -0
  229. package/src/dom.ts +35 -0
  230. package/src/easing/cubic-bezier.ts +64 -0
  231. package/src/easing/linear-css.ts +41 -0
  232. package/src/easing/named.ts +88 -0
  233. package/src/easing/spring.ts +25 -0
  234. package/src/easing/steps.ts +16 -0
  235. package/src/easing/types.ts +18 -0
  236. package/src/frame/driver.ts +56 -0
  237. package/src/frame/frame.ts +102 -0
  238. package/src/generators/inertia.ts +88 -0
  239. package/src/generators/spring.ts +117 -0
  240. package/src/generators/tween.ts +74 -0
  241. package/src/generators/types.ts +31 -0
  242. package/src/index.ts +91 -0
  243. package/src/interpolate/array.ts +13 -0
  244. package/src/interpolate/color-parse.ts +136 -0
  245. package/src/interpolate/color.ts +97 -0
  246. package/src/interpolate/complex.ts +80 -0
  247. package/src/interpolate/interpolate.ts +60 -0
  248. package/src/interpolate/mix.ts +74 -0
  249. package/src/interpolate/number.ts +3 -0
  250. package/src/interpolate/object.ts +20 -0
  251. package/src/interpolate/path/flatten.ts +185 -0
  252. package/src/interpolate/path/morph.ts +100 -0
  253. package/src/interpolate/path/parse.ts +162 -0
  254. package/src/interpolate/path/rings.ts +151 -0
  255. package/src/react/index.ts +11 -0
  256. package/src/react/presence.tsx +194 -0
  257. package/src/react/use-animate.ts +46 -0
  258. package/src/react/use-motion-value.ts +9 -0
  259. package/src/react/use-reduced-motion.ts +22 -0
  260. package/src/react/use-spring.ts +35 -0
  261. package/src/react/use-transform.ts +73 -0
  262. package/src/sequence/sequence.ts +129 -0
  263. package/src/stagger/stagger.ts +36 -0
  264. package/src/testing/browser-commands.d.ts +11 -0
  265. package/src/testing/manual-frames.ts +49 -0
  266. package/src/value/motion-value.ts +131 -0
  267. package/src/value/transform.ts +61 -0
  268. package/src/view/in-view.ts +74 -0
  269. package/src/view/resize.ts +101 -0
  270. package/src/view/resolve-elements.ts +11 -0
  271. package/src/view/scroll-measure.ts +83 -0
  272. package/src/view/scroll-offset.ts +100 -0
  273. package/src/view/scroll.ts +143 -0
package/dist/index.js ADDED
@@ -0,0 +1,97 @@
1
+ import {
2
+ onReducedMotionChange,
3
+ prefersReducedMotion,
4
+ reducedMotionPolicy,
5
+ setReducedMotion,
6
+ shouldReduceMotion
7
+ } from "./accessibility/reduced-motion.js";
8
+ import { animate, createAnimate } from "./animate/animate.js";
9
+ import { cubicBezier } from "./easing/cubic-bezier.js";
10
+ import { linearEasing } from "./easing/linear-css.js";
11
+ import {
12
+ anticipate,
13
+ backIn,
14
+ backInOut,
15
+ backOut,
16
+ circIn,
17
+ circInOut,
18
+ circOut,
19
+ easeIn,
20
+ easeInOut,
21
+ easeOut,
22
+ linear,
23
+ resolveEasing
24
+ } from "./easing/named.js";
25
+ import { springEasing } from "./easing/spring.js";
26
+ import { steps } from "./easing/steps.js";
27
+ import {
28
+ cancelFrame,
29
+ frame,
30
+ frameData
31
+ } from "./frame/frame.js";
32
+ import { inertia } from "./generators/inertia.js";
33
+ import { spring, springPhysics } from "./generators/spring.js";
34
+ import { tween } from "./generators/tween.js";
35
+ import { mixColor } from "./interpolate/color.js";
36
+ import {
37
+ interpolate
38
+ } from "./interpolate/interpolate.js";
39
+ import { mix } from "./interpolate/mix.js";
40
+ import { mixPath } from "./interpolate/path/morph.js";
41
+ import { stagger } from "./stagger/stagger.js";
42
+ import {
43
+ isMotionValue,
44
+ motionValue
45
+ } from "./value/motion-value.js";
46
+ import { transformValue } from "./value/transform.js";
47
+ import {
48
+ inView
49
+ } from "./view/in-view.js";
50
+ import { resize } from "./view/resize.js";
51
+ import {
52
+ scroll
53
+ } from "./view/scroll.js";
54
+ export {
55
+ animate,
56
+ anticipate,
57
+ backIn,
58
+ backInOut,
59
+ backOut,
60
+ cancelFrame,
61
+ circIn,
62
+ circInOut,
63
+ circOut,
64
+ createAnimate,
65
+ cubicBezier,
66
+ easeIn,
67
+ easeInOut,
68
+ easeOut,
69
+ frame,
70
+ frameData,
71
+ inView,
72
+ inertia,
73
+ interpolate,
74
+ isMotionValue,
75
+ linear,
76
+ linearEasing,
77
+ mix,
78
+ mixColor,
79
+ mixPath,
80
+ motionValue,
81
+ onReducedMotionChange,
82
+ prefersReducedMotion,
83
+ reducedMotionPolicy,
84
+ resize,
85
+ resolveEasing,
86
+ scroll,
87
+ setReducedMotion,
88
+ shouldReduceMotion,
89
+ spring,
90
+ springEasing,
91
+ springPhysics,
92
+ stagger,
93
+ steps,
94
+ transformValue,
95
+ tween
96
+ };
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["export {\n\tonReducedMotionChange,\n\tprefersReducedMotion,\n\ttype ReducedMotionPolicy,\n\treducedMotionPolicy,\n\tsetReducedMotion,\n\tshouldReduceMotion,\n} from \"#/accessibility/reduced-motion.ts\";\nexport { type Animate, animate, createAnimate } from \"#/animate/animate.ts\";\nexport type {\n\tAnimationControls,\n\tAnimationOptions,\n\tAnimationState,\n\tDOMKeyframes,\n\tElementTarget,\n\tKeyframes,\n\tValueAnimationOptions,\n} from \"#/animate/types.ts\";\nexport { cubicBezier } from \"#/easing/cubic-bezier.ts\";\nexport { linearEasing } from \"#/easing/linear-css.ts\";\nexport {\n\tanticipate,\n\tbackIn,\n\tbackInOut,\n\tbackOut,\n\tcircIn,\n\tcircInOut,\n\tcircOut,\n\teaseIn,\n\teaseInOut,\n\teaseOut,\n\tlinear,\n\tresolveEasing,\n} from \"#/easing/named.ts\";\nexport { type SpringEasing, springEasing } from \"#/easing/spring.ts\";\nexport { steps } from \"#/easing/steps.ts\";\nexport type {\n\tCubicBezier,\n\tEasing,\n\tEasingDefinition,\n\tEasingName,\n} from \"#/easing/types.ts\";\nexport {\n\tcancelFrame,\n\ttype FrameCallback,\n\ttype FrameData,\n\tframe,\n\tframeData,\n} from \"#/frame/frame.ts\";\nexport { type InertiaOptions, inertia } from \"#/generators/inertia.ts\";\nexport { spring, springPhysics } from \"#/generators/spring.ts\";\nexport { type TweenOptions, tween } from \"#/generators/tween.ts\";\nexport type {\n\tGenerator,\n\tGeneratorState,\n\tSpringOptions,\n} from \"#/generators/types.ts\";\nexport { mixColor } from \"#/interpolate/color.ts\";\nexport {\n\ttype InterpolateOptions,\n\tinterpolate,\n} from \"#/interpolate/interpolate.ts\";\nexport { type Mixer, mix } from \"#/interpolate/mix.ts\";\nexport { mixPath } from \"#/interpolate/path/morph.ts\";\nexport type {\n\tSegment,\n\tSegmentOptions,\n\tSequenceAt,\n} from \"#/sequence/sequence.ts\";\nexport { type StaggerOptions, stagger } from \"#/stagger/stagger.ts\";\nexport {\n\tisMotionValue,\n\ttype MotionValue,\n\ttype MotionValueEvent,\n\tmotionValue,\n} from \"#/value/motion-value.ts\";\nexport { transformValue } from \"#/value/transform.ts\";\nexport {\n\ttype InViewOptions,\n\tinView,\n\ttype OnViewEnd,\n\ttype OnViewStart,\n} from \"#/view/in-view.ts\";\nexport { resize, type Size } from \"#/view/resize.ts\";\nexport {\n\ttype OnScroll,\n\ttype ScrollDrivable,\n\ttype ScrollInfo,\n\ttype ScrollOptions,\n\tscroll,\n} from \"#/view/scroll.ts\";\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAuB,SAAS,qBAAqB;AAUrD,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAA4B,oBAAoB;AAChD,SAAS,aAAa;AAOtB;AAAA,EACC;AAAA,EAGA;AAAA,EACA;AAAA,OACM;AACP,SAA8B,eAAe;AAC7C,SAAS,QAAQ,qBAAqB;AACtC,SAA4B,aAAa;AAMzC,SAAS,gBAAgB;AACzB;AAAA,EAEC;AAAA,OACM;AACP,SAAqB,WAAW;AAChC,SAAS,eAAe;AAMxB,SAA8B,eAAe;AAC7C;AAAA,EACC;AAAA,EAGA;AAAA,OACM;AACP,SAAS,sBAAsB;AAC/B;AAAA,EAEC;AAAA,OAGM;AACP,SAAS,cAAyB;AAClC;AAAA,EAKC;AAAA,OACM;",
6
+ "names": []
7
+ }
@@ -0,0 +1,3 @@
1
+ /** Element by element; arrays of different lengths have no midpoint, so they step. */
2
+ export declare function mixArray<T>(from: readonly T[], to: readonly T[]): ((progress: number) => T[]) | undefined;
3
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../../src/interpolate/array.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,CAAC,EACzB,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,EAAE,EAAE,SAAS,CAAC,EAAE,GACd,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC,GAAG,SAAS,CAMzC"}
@@ -0,0 +1,12 @@
1
+ import { mix } from "./mix.js";
2
+ function mixArray(from, to) {
3
+ if (from.length !== to.length) {
4
+ return void 0;
5
+ }
6
+ const mixers = from.map((value, index) => mix(value, to[index]));
7
+ return (progress) => mixers.map((mixer) => mixer(progress));
8
+ }
9
+ export {
10
+ mixArray
11
+ };
12
+ //# sourceMappingURL=array.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/array.ts"],
4
+ "sourcesContent": ["import { mix } from \"#/interpolate/mix.ts\";\n\n/** Element by element; arrays of different lengths have no midpoint, so they step. */\nexport function mixArray<T>(\n\tfrom: readonly T[],\n\tto: readonly T[],\n): ((progress: number) => T[]) | undefined {\n\tif (from.length !== to.length) {\n\t\treturn undefined;\n\t}\n\tconst mixers = from.map((value, index) => mix(value, to[index] as T));\n\treturn (progress) => mixers.map((mixer) => mixer(progress));\n}\n"],
5
+ "mappings": "AAAA,SAAS,WAAW;AAGb,SAAS,SACf,MACA,IAC0C;AAC1C,MAAI,KAAK,WAAW,GAAG,QAAQ;AAC9B,WAAO;AAAA,EACR;AACA,QAAM,SAAS,KAAK,IAAI,CAAC,OAAO,UAAU,IAAI,OAAO,GAAG,KAAK,CAAM,CAAC;AACpE,SAAO,CAAC,aAAa,OAAO,IAAI,CAAC,UAAU,MAAM,QAAQ,CAAC;AAC3D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ /** A colour in sRGB, every channel 0–1. */
2
+ export interface Rgba {
3
+ readonly r: number;
4
+ readonly g: number;
5
+ readonly b: number;
6
+ readonly alpha: number;
7
+ }
8
+ type Channels = readonly [number, number, number, number];
9
+ /** Oklab is mixed in, and also a syntax a page can write colours in. */
10
+ export declare function oklabToRgba([l, a, b, alpha]: Channels): Rgba;
11
+ /** A colour written out in full; `undefined` for what only the page can resolve (`var()`, names). */
12
+ export declare function parseColor(text: string): Rgba | undefined;
13
+ export {};
14
+ //# sourceMappingURL=color-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-parse.d.ts","sourceRoot":"","sources":["../../src/interpolate/color-parse.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAoC1D,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAa5D;AA6DD,qGAAqG;AACrG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAezD"}
@@ -0,0 +1,111 @@
1
+ const FUNCTION = /^(rgba?|hsla?|oklch|oklab)\(\s*([^()]*)\)$/i;
2
+ const HUE_UNITS = {
3
+ deg: 1,
4
+ grad: 0.9,
5
+ rad: 180 / Math.PI,
6
+ turn: 360
7
+ };
8
+ function channel(text, percentScale) {
9
+ if (text === void 0 || text === "none") {
10
+ return 0;
11
+ }
12
+ return text.endsWith("%") ? Number.parseFloat(text) / 100 * percentScale : Number.parseFloat(text);
13
+ }
14
+ function hue(text) {
15
+ const unit = text?.match(/[a-z]+$/i)?.[0].toLowerCase() ?? "deg";
16
+ return channel(text, 1) * (HUE_UNITS[unit] ?? 1);
17
+ }
18
+ function alphaOf(args) {
19
+ return args[3] === void 0 ? 1 : channel(args[3], 1);
20
+ }
21
+ function linearToSrgb(value) {
22
+ return value <= 31308e-7 ? 12.92 * value : 1.055 * value ** (1 / 2.4) - 0.055;
23
+ }
24
+ function oklabToRgba([l, a, b, alpha]) {
25
+ const lms = [
26
+ (l + 0.3963377774 * a + 0.2158037573 * b) ** 3,
27
+ (l - 0.1055613458 * a - 0.0638541728 * b) ** 3,
28
+ (l - 0.0894841775 * a - 1.291485548 * b) ** 3
29
+ ];
30
+ const [x, y, z] = lms;
31
+ return {
32
+ r: linearToSrgb(4.0767416621 * x - 3.3077115913 * y + 0.2309699292 * z),
33
+ g: linearToSrgb(-1.2684380046 * x + 2.6097574011 * y - 0.3413193965 * z),
34
+ b: linearToSrgb(-0.0041960863 * x - 0.7034186147 * y + 1.707614701 * z),
35
+ alpha
36
+ };
37
+ }
38
+ function hslToRgba(h, s, l, alpha) {
39
+ const amount = s * Math.min(l, 1 - l);
40
+ function f(n) {
41
+ const k = (n + h / 30) % 12;
42
+ return l - amount * Math.max(-1, Math.min(k - 3, 9 - k, 1));
43
+ }
44
+ return { r: f(0), g: f(8), b: f(4), alpha };
45
+ }
46
+ const PARSERS = {
47
+ rgb: (args) => ({
48
+ r: channel(args[0], 255) / 255,
49
+ g: channel(args[1], 255) / 255,
50
+ b: channel(args[2], 255) / 255,
51
+ alpha: alphaOf(args)
52
+ }),
53
+ hsl: (args) => hslToRgba(
54
+ (hue(args[0]) % 360 + 360) % 360,
55
+ channel(args[1], 100) / 100,
56
+ channel(args[2], 100) / 100,
57
+ alphaOf(args)
58
+ ),
59
+ oklab: (args) => oklabToRgba([
60
+ channel(args[0], 1),
61
+ channel(args[1], 0.4),
62
+ channel(args[2], 0.4),
63
+ alphaOf(args)
64
+ ]),
65
+ oklch: (args) => {
66
+ const chroma = channel(args[1], 0.4);
67
+ const angle = hue(args[2]) * Math.PI / 180;
68
+ return oklabToRgba([
69
+ channel(args[0], 1),
70
+ chroma * Math.cos(angle),
71
+ chroma * Math.sin(angle),
72
+ alphaOf(args)
73
+ ]);
74
+ }
75
+ };
76
+ function parseHex(hex) {
77
+ const digits = hex.length <= 4 ? [...hex].map((digit) => digit + digit).join("") : hex;
78
+ if (!/^[0-9a-f]{6}(?:[0-9a-f]{2})?$/i.test(digits)) {
79
+ return void 0;
80
+ }
81
+ function byte(index) {
82
+ return Number.parseInt(digits.slice(index, index + 2), 16) / 255;
83
+ }
84
+ return {
85
+ r: byte(0),
86
+ g: byte(2),
87
+ b: byte(4),
88
+ alpha: digits.length === 8 ? byte(6) : 1
89
+ };
90
+ }
91
+ function parseColor(text) {
92
+ const trimmed = text.trim();
93
+ if (trimmed.toLowerCase() === "transparent") {
94
+ return { r: 0, g: 0, b: 0, alpha: 0 };
95
+ }
96
+ if (trimmed.startsWith("#")) {
97
+ return parseHex(trimmed.slice(1));
98
+ }
99
+ const match = FUNCTION.exec(trimmed);
100
+ if (match === null) {
101
+ return void 0;
102
+ }
103
+ const name = match[1].toLowerCase().replace(/a$/, "");
104
+ const args = match[2].split(/[\s,/]+/).filter(Boolean);
105
+ return PARSERS[name]?.(args);
106
+ }
107
+ export {
108
+ oklabToRgba,
109
+ parseColor
110
+ };
111
+ //# sourceMappingURL=color-parse.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/color-parse.ts"],
4
+ "sourcesContent": ["/** A colour in sRGB, every channel 0\u20131. */\nexport interface Rgba {\n\treadonly r: number;\n\treadonly g: number;\n\treadonly b: number;\n\treadonly alpha: number;\n}\n\ntype Channels = readonly [number, number, number, number];\ntype Parser = (args: readonly string[]) => Rgba | undefined;\n\nconst FUNCTION = /^(rgba?|hsla?|oklch|oklab)\\(\\s*([^()]*)\\)$/i;\nconst HUE_UNITS: Readonly<Record<string, number>> = {\n\tdeg: 1,\n\tgrad: 0.9,\n\trad: 180 / Math.PI,\n\tturn: 360,\n};\n\n/** A number, a percentage of `percentScale`, or `none`. */\nfunction channel(text: string | undefined, percentScale: number): number {\n\tif (text === undefined || text === \"none\") {\n\t\treturn 0;\n\t}\n\treturn text.endsWith(\"%\")\n\t\t? (Number.parseFloat(text) / 100) * percentScale\n\t\t: Number.parseFloat(text);\n}\n\nfunction hue(text: string | undefined): number {\n\tconst unit = text?.match(/[a-z]+$/i)?.[0].toLowerCase() ?? \"deg\";\n\treturn channel(text, 1) * (HUE_UNITS[unit] ?? 1);\n}\n\nfunction alphaOf(args: readonly string[]): number {\n\treturn args[3] === undefined ? 1 : channel(args[3], 1);\n}\n\nfunction linearToSrgb(value: number): number {\n\treturn value <= 0.0031308\n\t\t? 12.92 * value\n\t\t: 1.055 * value ** (1 / 2.4) - 0.055;\n}\n\n/** Oklab is mixed in, and also a syntax a page can write colours in. */\nexport function oklabToRgba([l, a, b, alpha]: Channels): Rgba {\n\tconst lms = [\n\t\t(l + 0.3963377774 * a + 0.2158037573 * b) ** 3,\n\t\t(l - 0.1055613458 * a - 0.0638541728 * b) ** 3,\n\t\t(l - 0.0894841775 * a - 1.291485548 * b) ** 3,\n\t] as const;\n\tconst [x, y, z] = lms;\n\treturn {\n\t\tr: linearToSrgb(4.0767416621 * x - 3.3077115913 * y + 0.2309699292 * z),\n\t\tg: linearToSrgb(-1.2684380046 * x + 2.6097574011 * y - 0.3413193965 * z),\n\t\tb: linearToSrgb(-0.0041960863 * x - 0.7034186147 * y + 1.707614701 * z),\n\t\talpha,\n\t};\n}\n\nfunction hslToRgba(h: number, s: number, l: number, alpha: number): Rgba {\n\tconst amount = s * Math.min(l, 1 - l);\n\tfunction f(n: number) {\n\t\tconst k = (n + h / 30) % 12;\n\t\treturn l - amount * Math.max(-1, Math.min(k - 3, 9 - k, 1));\n\t}\n\treturn { r: f(0), g: f(8), b: f(4), alpha };\n}\n\nconst PARSERS: Readonly<Record<string, Parser>> = {\n\trgb: (args) => ({\n\t\tr: channel(args[0], 255) / 255,\n\t\tg: channel(args[1], 255) / 255,\n\t\tb: channel(args[2], 255) / 255,\n\t\talpha: alphaOf(args),\n\t}),\n\thsl: (args) =>\n\t\thslToRgba(\n\t\t\t((hue(args[0]) % 360) + 360) % 360,\n\t\t\tchannel(args[1], 100) / 100,\n\t\t\tchannel(args[2], 100) / 100,\n\t\t\talphaOf(args),\n\t\t),\n\toklab: (args) =>\n\t\toklabToRgba([\n\t\t\tchannel(args[0], 1),\n\t\t\tchannel(args[1], 0.4),\n\t\t\tchannel(args[2], 0.4),\n\t\t\talphaOf(args),\n\t\t]),\n\toklch: (args) => {\n\t\tconst chroma = channel(args[1], 0.4);\n\t\tconst angle = (hue(args[2]) * Math.PI) / 180;\n\t\treturn oklabToRgba([\n\t\t\tchannel(args[0], 1),\n\t\t\tchroma * Math.cos(angle),\n\t\t\tchroma * Math.sin(angle),\n\t\t\talphaOf(args),\n\t\t]);\n\t},\n};\n\nfunction parseHex(hex: string): Rgba | undefined {\n\tconst digits =\n\t\thex.length <= 4 ? [...hex].map((digit) => digit + digit).join(\"\") : hex;\n\tif (!/^[0-9a-f]{6}(?:[0-9a-f]{2})?$/i.test(digits)) {\n\t\treturn undefined;\n\t}\n\tfunction byte(index: number) {\n\t\treturn Number.parseInt(digits.slice(index, index + 2), 16) / 255;\n\t}\n\treturn {\n\t\tr: byte(0),\n\t\tg: byte(2),\n\t\tb: byte(4),\n\t\talpha: digits.length === 8 ? byte(6) : 1,\n\t};\n}\n\n/** A colour written out in full; `undefined` for what only the page can resolve (`var()`, names). */\nexport function parseColor(text: string): Rgba | undefined {\n\tconst trimmed = text.trim();\n\tif (trimmed.toLowerCase() === \"transparent\") {\n\t\treturn { r: 0, g: 0, b: 0, alpha: 0 };\n\t}\n\tif (trimmed.startsWith(\"#\")) {\n\t\treturn parseHex(trimmed.slice(1));\n\t}\n\tconst match = FUNCTION.exec(trimmed);\n\tif (match === null) {\n\t\treturn undefined;\n\t}\n\tconst name = (match[1] as string).toLowerCase().replace(/a$/, \"\");\n\tconst args = (match[2] as string).split(/[\\s,/]+/).filter(Boolean);\n\treturn PARSERS[name]?.(args);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ export { parseColor, type Rgba } from "./color-parse.js";
2
+ /** A string the page resolves to a colour: written out, a `var()`, a name, `currentColor`. */
3
+ export declare function isColorLike(text: string): boolean;
4
+ /**
5
+ * Two written-out colours mix in oklab here, premultiplied so a fade from
6
+ * `transparent` does not pass through grey. A `var()` or a name is only known
7
+ * to the page, so it mixes there: `color-mix()` with the share quantised to
8
+ * 2 %, which caps the strings a long animation mints at 51.
9
+ */
10
+ export declare function mixColor(from: string, to: string): (progress: number) => string;
11
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/interpolate/color.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAuCrE,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACvB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACR,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CA+B9B"}
@@ -0,0 +1,74 @@
1
+ import {
2
+ oklabToRgba,
3
+ parseColor
4
+ } from "./color-parse.js";
5
+ import { mixNumber } from "./number.js";
6
+ import { parseColor as parseColor2 } from "./color-parse.js";
7
+ const VARIABLE = /^var\(/i;
8
+ const IDENTIFIER = /^[a-z]+$/i;
9
+ function srgbToLinear(value) {
10
+ return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
11
+ }
12
+ function toOklab({ r, g, b, alpha }) {
13
+ const [lr, lg, lb] = [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];
14
+ const l = Math.cbrt(
15
+ 0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb
16
+ );
17
+ const m = Math.cbrt(
18
+ 0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb
19
+ );
20
+ const s = Math.cbrt(
21
+ 0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb
22
+ );
23
+ return [
24
+ 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
25
+ 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
26
+ 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
27
+ alpha
28
+ ];
29
+ }
30
+ function byte(value) {
31
+ return Math.round(Math.min(1, Math.max(0, value)) * 255);
32
+ }
33
+ function format({ r, g, b, alpha }) {
34
+ const a = Math.round(Math.min(1, Math.max(0, alpha)) * 1e3) / 1e3;
35
+ return `rgba(${byte(r)}, ${byte(g)}, ${byte(b)}, ${a})`;
36
+ }
37
+ function isColorLike(text) {
38
+ const trimmed = text.trim();
39
+ return parseColor(trimmed) !== void 0 || VARIABLE.test(trimmed) || IDENTIFIER.test(trimmed);
40
+ }
41
+ function mixColor(from, to) {
42
+ const start = parseColor(from);
43
+ const end = parseColor(to);
44
+ if (start === void 0 || end === void 0) {
45
+ return (progress) => {
46
+ const share = Math.round(progress * 50) * 2;
47
+ if (share <= 0) {
48
+ return from;
49
+ }
50
+ return share >= 100 ? to : `color-mix(in oklab, ${to} ${share}%, ${from})`;
51
+ };
52
+ }
53
+ const a = toOklab(start);
54
+ const b = toOklab(end);
55
+ return (progress) => {
56
+ if (progress === 0) {
57
+ return from;
58
+ }
59
+ if (progress === 1) {
60
+ return to;
61
+ }
62
+ const alpha = mixNumber(a[3], b[3], progress);
63
+ function channel(index) {
64
+ return alpha === 0 ? 0 : mixNumber(a[index] * a[3], b[index] * b[3], progress) / alpha;
65
+ }
66
+ return format(oklabToRgba([channel(0), channel(1), channel(2), alpha]));
67
+ };
68
+ }
69
+ export {
70
+ isColorLike,
71
+ mixColor,
72
+ parseColor2 as parseColor
73
+ };
74
+ //# sourceMappingURL=color.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/color.ts"],
4
+ "sourcesContent": ["import {\n\toklabToRgba,\n\tparseColor,\n\ttype Rgba,\n} from \"#/interpolate/color-parse.ts\";\nimport { mixNumber } from \"#/interpolate/number.ts\";\n\nexport { parseColor, type Rgba } from \"#/interpolate/color-parse.ts\";\n\ntype Oklab = readonly [number, number, number, number];\n\nconst VARIABLE = /^var\\(/i;\nconst IDENTIFIER = /^[a-z]+$/i;\n\nfunction srgbToLinear(value: number): number {\n\treturn value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n}\n\nfunction toOklab({ r, g, b, alpha }: Rgba): Oklab {\n\tconst [lr, lg, lb] = [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)];\n\tconst l = Math.cbrt(\n\t\t0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb,\n\t);\n\tconst m = Math.cbrt(\n\t\t0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb,\n\t);\n\tconst s = Math.cbrt(\n\t\t0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb,\n\t);\n\treturn [\n\t\t0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n\t\t1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n\t\t0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n\t\talpha,\n\t];\n}\n\nfunction byte(value: number): number {\n\treturn Math.round(Math.min(1, Math.max(0, value)) * 255);\n}\n\nfunction format({ r, g, b, alpha }: Rgba): string {\n\tconst a = Math.round(Math.min(1, Math.max(0, alpha)) * 1000) / 1000;\n\treturn `rgba(${byte(r)}, ${byte(g)}, ${byte(b)}, ${a})`;\n}\n\n/** A string the page resolves to a colour: written out, a `var()`, a name, `currentColor`. */\nexport function isColorLike(text: string): boolean {\n\tconst trimmed = text.trim();\n\treturn (\n\t\tparseColor(trimmed) !== undefined ||\n\t\tVARIABLE.test(trimmed) ||\n\t\tIDENTIFIER.test(trimmed)\n\t);\n}\n\n/**\n * Two written-out colours mix in oklab here, premultiplied so a fade from\n * `transparent` does not pass through grey. A `var()` or a name is only known\n * to the page, so it mixes there: `color-mix()` with the share quantised to\n * 2 %, which caps the strings a long animation mints at 51.\n */\nexport function mixColor(\n\tfrom: string,\n\tto: string,\n): (progress: number) => string {\n\tconst start = parseColor(from);\n\tconst end = parseColor(to);\n\tif (start === undefined || end === undefined) {\n\t\treturn (progress) => {\n\t\t\tconst share = Math.round(progress * 50) * 2;\n\t\t\tif (share <= 0) {\n\t\t\t\treturn from;\n\t\t\t}\n\t\t\treturn share >= 100\n\t\t\t\t? to\n\t\t\t\t: `color-mix(in oklab, ${to} ${share}%, ${from})`;\n\t\t};\n\t}\n\tconst a = toOklab(start);\n\tconst b = toOklab(end);\n\treturn (progress) => {\n\t\tif (progress === 0) {\n\t\t\treturn from;\n\t\t}\n\t\tif (progress === 1) {\n\t\t\treturn to;\n\t\t}\n\t\tconst alpha = mixNumber(a[3], b[3], progress);\n\t\tfunction channel(index: 0 | 1 | 2) {\n\t\t\treturn alpha === 0\n\t\t\t\t? 0\n\t\t\t\t: mixNumber(a[index] * a[3], b[index] * b[3], progress) / alpha;\n\t\t}\n\t\treturn format(oklabToRgba([channel(0), channel(1), channel(2), alpha]));\n\t};\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,OAEM;AACP,SAAS,iBAAiB;AAE1B,SAAS,cAAAA,mBAA6B;AAItC,MAAM,WAAW;AACjB,MAAM,aAAa;AAEnB,SAAS,aAAa,OAAuB;AAC5C,SAAO,SAAS,UAAU,QAAQ,UAAU,QAAQ,SAAS,UAAU;AACxE;AAEA,SAAS,QAAQ,EAAE,GAAG,GAAG,GAAG,MAAM,GAAgB;AACjD,QAAM,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,aAAa,CAAC,GAAG,aAAa,CAAC,CAAC;AACvE,QAAM,IAAI,KAAK;AAAA,IACd,eAAe,KAAK,eAAe,KAAK,eAAe;AAAA,EACxD;AACA,QAAM,IAAI,KAAK;AAAA,IACd,eAAe,KAAK,eAAe,KAAK,eAAe;AAAA,EACxD;AACA,QAAM,IAAI,KAAK;AAAA,IACd,eAAe,KAAK,eAAe,KAAK,eAAe;AAAA,EACxD;AACA,SAAO;AAAA,IACN,eAAe,IAAI,cAAc,IAAI,eAAe;AAAA,IACpD,eAAe,IAAI,cAAc,IAAI,eAAe;AAAA,IACpD,eAAe,IAAI,eAAe,IAAI,cAAc;AAAA,IACpD;AAAA,EACD;AACD;AAEA,SAAS,KAAK,OAAuB;AACpC,SAAO,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG;AACxD;AAEA,SAAS,OAAO,EAAE,GAAG,GAAG,GAAG,MAAM,GAAiB;AACjD,QAAM,IAAI,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,GAAI,IAAI;AAC/D,SAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC;AACrD;AAGO,SAAS,YAAY,MAAuB;AAClD,QAAM,UAAU,KAAK,KAAK;AAC1B,SACC,WAAW,OAAO,MAAM,UACxB,SAAS,KAAK,OAAO,KACrB,WAAW,KAAK,OAAO;AAEzB;AAQO,SAAS,SACf,MACA,IAC+B;AAC/B,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,MAAM,WAAW,EAAE;AACzB,MAAI,UAAU,UAAa,QAAQ,QAAW;AAC7C,WAAO,CAAC,aAAa;AACpB,YAAM,QAAQ,KAAK,MAAM,WAAW,EAAE,IAAI;AAC1C,UAAI,SAAS,GAAG;AACf,eAAO;AAAA,MACR;AACA,aAAO,SAAS,MACb,KACA,uBAAuB,EAAE,IAAI,KAAK,MAAM,IAAI;AAAA,IAChD;AAAA,EACD;AACA,QAAM,IAAI,QAAQ,KAAK;AACvB,QAAM,IAAI,QAAQ,GAAG;AACrB,SAAO,CAAC,aAAa;AACpB,QAAI,aAAa,GAAG;AACnB,aAAO;AAAA,IACR;AACA,QAAI,aAAa,GAAG;AACnB,aAAO;AAAA,IACR;AACA,UAAM,QAAQ,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,QAAQ;AAC5C,aAAS,QAAQ,OAAkB;AAClC,aAAO,UAAU,IACd,IACA,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,GAAG,QAAQ,IAAI;AAAA,IAC5D;AACA,WAAO,OAAO,YAAY,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EACvE;AACD;",
6
+ "names": ["parseColor"]
7
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Strings that differ only in their numbers and colours: `10px 20px`, a
3
+ * transform list, two paths with the same commands. Anything else has no
4
+ * midpoint here, and `undefined` says so.
5
+ */
6
+ export declare function mixComplex(from: string, to: string): ((progress: number) => string) | undefined;
7
+ //# sourceMappingURL=complex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complex.d.ts","sourceRoot":"","sources":["../../src/interpolate/complex.ts"],"names":[],"mappings":"AAqCA;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACR,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAkC5C"}
@@ -0,0 +1,56 @@
1
+ import { mixColor } from "./color.js";
2
+ import { mixNumber } from "./number.js";
3
+ const TOKEN = /(#[0-9a-f]{3,8}\b|(?:rgba?|hsla?|oklch|oklab)\([^()]*\))|(-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)/gi;
4
+ function parse(text) {
5
+ const skeleton = [];
6
+ const tokens = [];
7
+ let last = 0;
8
+ for (const match of text.matchAll(TOKEN)) {
9
+ skeleton.push(text.slice(last, match.index));
10
+ tokens.push(
11
+ match[1] === void 0 ? { kind: "number", value: Number(match[2]) } : { kind: "color", value: match[1] }
12
+ );
13
+ last = match.index + match[0].length;
14
+ }
15
+ skeleton.push(text.slice(last));
16
+ return { skeleton, tokens };
17
+ }
18
+ function round(value) {
19
+ return Math.round(value * 1e3) / 1e3;
20
+ }
21
+ function mixComplex(from, to) {
22
+ const start = parse(from);
23
+ const end = parse(to);
24
+ const sameShape = start.tokens.length === end.tokens.length && start.skeleton.every((part, index) => part === end.skeleton[index]) && start.tokens.every(
25
+ (token, index) => token.kind === end.tokens[index]?.kind
26
+ );
27
+ if (!sameShape || start.tokens.length === 0 && from !== to) {
28
+ return void 0;
29
+ }
30
+ const mixers = start.tokens.map((token, index) => {
31
+ const target = end.tokens[index];
32
+ if (token.kind === "color") {
33
+ return mixColor(token.value, target.value);
34
+ }
35
+ const a = token.value;
36
+ const b = target.value;
37
+ return (progress) => String(round(mixNumber(a, b, progress)));
38
+ });
39
+ return (progress) => {
40
+ if (progress === 0) {
41
+ return from;
42
+ }
43
+ if (progress === 1) {
44
+ return to;
45
+ }
46
+ let text = start.skeleton[0];
47
+ mixers.forEach((mixer, index) => {
48
+ text += mixer(progress) + start.skeleton[index + 1];
49
+ });
50
+ return text;
51
+ };
52
+ }
53
+ export {
54
+ mixComplex
55
+ };
56
+ //# sourceMappingURL=complex.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/complex.ts"],
4
+ "sourcesContent": ["import { mixColor } from \"#/interpolate/color.ts\";\nimport { mixNumber } from \"#/interpolate/number.ts\";\n\ntype Token =\n\t| { readonly kind: \"number\"; readonly value: number }\n\t| { readonly kind: \"color\"; readonly value: string };\n\ninterface Parsed {\n\treadonly skeleton: readonly string[];\n\treadonly tokens: readonly Token[];\n}\n\n/** Colours first, so a hex or an `rgb()` is one token rather than its digits. */\nconst TOKEN =\n\t/(#[0-9a-f]{3,8}\\b|(?:rgba?|hsla?|oklch|oklab)\\([^()]*\\))|(-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?)/gi;\n\nfunction parse(text: string): Parsed {\n\tconst skeleton: string[] = [];\n\tconst tokens: Token[] = [];\n\tlet last = 0;\n\tfor (const match of text.matchAll(TOKEN)) {\n\t\tskeleton.push(text.slice(last, match.index));\n\t\ttokens.push(\n\t\t\tmatch[1] === undefined\n\t\t\t\t? { kind: \"number\", value: Number(match[2]) }\n\t\t\t\t: { kind: \"color\", value: match[1] },\n\t\t);\n\t\tlast = match.index + match[0].length;\n\t}\n\tskeleton.push(text.slice(last));\n\treturn { skeleton, tokens };\n}\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000;\n}\n\n/**\n * Strings that differ only in their numbers and colours: `10px 20px`, a\n * transform list, two paths with the same commands. Anything else has no\n * midpoint here, and `undefined` says so.\n */\nexport function mixComplex(\n\tfrom: string,\n\tto: string,\n): ((progress: number) => string) | undefined {\n\tconst start = parse(from);\n\tconst end = parse(to);\n\tconst sameShape =\n\t\tstart.tokens.length === end.tokens.length &&\n\t\tstart.skeleton.every((part, index) => part === end.skeleton[index]) &&\n\t\tstart.tokens.every(\n\t\t\t(token, index) => token.kind === end.tokens[index]?.kind,\n\t\t);\n\tif (!sameShape || (start.tokens.length === 0 && from !== to)) {\n\t\treturn undefined;\n\t}\n\tconst mixers = start.tokens.map((token, index) => {\n\t\tconst target = end.tokens[index] as Token;\n\t\tif (token.kind === \"color\") {\n\t\t\treturn mixColor(token.value, target.value as string);\n\t\t}\n\t\tconst a = token.value;\n\t\tconst b = target.value as number;\n\t\treturn (progress: number) => String(round(mixNumber(a, b, progress)));\n\t});\n\treturn (progress) => {\n\t\tif (progress === 0) {\n\t\t\treturn from;\n\t\t}\n\t\tif (progress === 1) {\n\t\t\treturn to;\n\t\t}\n\t\tlet text = start.skeleton[0] as string;\n\t\tmixers.forEach((mixer, index) => {\n\t\t\ttext += mixer(progress) + (start.skeleton[index + 1] as string);\n\t\t});\n\t\treturn text;\n\t};\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAY1B,MAAM,QACL;AAED,SAAS,MAAM,MAAsB;AACpC,QAAM,WAAqB,CAAC;AAC5B,QAAM,SAAkB,CAAC;AACzB,MAAI,OAAO;AACX,aAAW,SAAS,KAAK,SAAS,KAAK,GAAG;AACzC,aAAS,KAAK,KAAK,MAAM,MAAM,MAAM,KAAK,CAAC;AAC3C,WAAO;AAAA,MACN,MAAM,CAAC,MAAM,SACV,EAAE,MAAM,UAAU,OAAO,OAAO,MAAM,CAAC,CAAC,EAAE,IAC1C,EAAE,MAAM,SAAS,OAAO,MAAM,CAAC,EAAE;AAAA,IACrC;AACA,WAAO,MAAM,QAAQ,MAAM,CAAC,EAAE;AAAA,EAC/B;AACA,WAAS,KAAK,KAAK,MAAM,IAAI,CAAC;AAC9B,SAAO,EAAE,UAAU,OAAO;AAC3B;AAEA,SAAS,MAAM,OAAuB;AACrC,SAAO,KAAK,MAAM,QAAQ,GAAI,IAAI;AACnC;AAOO,SAAS,WACf,MACA,IAC6C;AAC7C,QAAM,QAAQ,MAAM,IAAI;AACxB,QAAM,MAAM,MAAM,EAAE;AACpB,QAAM,YACL,MAAM,OAAO,WAAW,IAAI,OAAO,UACnC,MAAM,SAAS,MAAM,CAAC,MAAM,UAAU,SAAS,IAAI,SAAS,KAAK,CAAC,KAClE,MAAM,OAAO;AAAA,IACZ,CAAC,OAAO,UAAU,MAAM,SAAS,IAAI,OAAO,KAAK,GAAG;AAAA,EACrD;AACD,MAAI,CAAC,aAAc,MAAM,OAAO,WAAW,KAAK,SAAS,IAAK;AAC7D,WAAO;AAAA,EACR;AACA,QAAM,SAAS,MAAM,OAAO,IAAI,CAAC,OAAO,UAAU;AACjD,UAAM,SAAS,IAAI,OAAO,KAAK;AAC/B,QAAI,MAAM,SAAS,SAAS;AAC3B,aAAO,SAAS,MAAM,OAAO,OAAO,KAAe;AAAA,IACpD;AACA,UAAM,IAAI,MAAM;AAChB,UAAM,IAAI,OAAO;AACjB,WAAO,CAAC,aAAqB,OAAO,MAAM,UAAU,GAAG,GAAG,QAAQ,CAAC,CAAC;AAAA,EACrE,CAAC;AACD,SAAO,CAAC,aAAa;AACpB,QAAI,aAAa,GAAG;AACnB,aAAO;AAAA,IACR;AACA,QAAI,aAAa,GAAG;AACnB,aAAO;AAAA,IACR;AACA,QAAI,OAAO,MAAM,SAAS,CAAC;AAC3B,WAAO,QAAQ,CAAC,OAAO,UAAU;AAChC,cAAQ,MAAM,QAAQ,IAAK,MAAM,SAAS,QAAQ,CAAC;AAAA,IACpD,CAAC;AACD,WAAO;AAAA,EACR;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import type { EasingDefinition } from "../easing/types.js";
2
+ import { type Mixer } from "./mix.js";
3
+ export interface InterpolateOptions<T> {
4
+ /** Hold the output at its ends outside the input range. Default true. */
5
+ readonly clamp?: boolean;
6
+ /** One easing for every segment, or one per segment. */
7
+ readonly ease?: EasingDefinition | readonly EasingDefinition[];
8
+ readonly mixer?: (from: T, to: T) => Mixer<T>;
9
+ }
10
+ /**
11
+ * Maps a number through a piecewise range: `interpolate([0, 100], [1, 0])`
12
+ * turns a scroll offset into an opacity, `[0, 50, 100]` with three colours a
13
+ * progress into a gradient. The input may run either way.
14
+ */
15
+ export declare function interpolate<T>(input: readonly number[], output: readonly T[], options?: InterpolateOptions<T>): (value: number) => T;
16
+ //# sourceMappingURL=interpolate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../../src/interpolate/interpolate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,KAAK,KAAK,EAAO,MAAM,sBAAsB,CAAC;AAEvD,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,SAAS,gBAAgB,EAAE,CAAC;IAC/D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,OAAO,GAAE,kBAAkB,CAAC,CAAC,CAAM,GACjC,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,CAsCtB"}
@@ -0,0 +1,39 @@
1
+ import { resolveEasing } from "../easing/named.js";
2
+ import { mix } from "./mix.js";
3
+ function interpolate(input, output, options = {}) {
4
+ if (input.length !== output.length || input.length === 0) {
5
+ throw new RangeError(
6
+ "interpolate: input and output need the same, non-zero length"
7
+ );
8
+ }
9
+ if (input.length === 1) {
10
+ return () => output[0];
11
+ }
12
+ const direction = input[0] > input[input.length - 1] ? -1 : 1;
13
+ const makeMixer = options.mixer ?? mix;
14
+ const mixers = output.slice(1).map((value, index) => makeMixer(output[index], value));
15
+ const eases = mixers.map((_mixer, index) => {
16
+ const ease = options.ease;
17
+ const definition = Array.isArray(ease) ? ease[index] : ease;
18
+ return resolveEasing(definition ?? "linear");
19
+ });
20
+ const clamp = options.clamp ?? true;
21
+ const low = Math.min(input[0], input[input.length - 1]);
22
+ const high = Math.max(input[0], input[input.length - 1]);
23
+ return (value) => {
24
+ const at = clamp ? Math.min(high, Math.max(low, value)) : value;
25
+ let segment = 0;
26
+ while (segment < mixers.length - 1 && (at - input[segment + 1]) * direction > 0) {
27
+ segment += 1;
28
+ }
29
+ const start = input[segment];
30
+ const span = input[segment + 1] - start;
31
+ const progress = span === 0 ? 1 : (at - start) / span;
32
+ const eased = eases[segment](progress);
33
+ return mixers[segment](eased);
34
+ };
35
+ }
36
+ export {
37
+ interpolate
38
+ };
39
+ //# sourceMappingURL=interpolate.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/interpolate.ts"],
4
+ "sourcesContent": ["import { resolveEasing } from \"#/easing/named.ts\";\nimport type { EasingDefinition } from \"#/easing/types.ts\";\nimport { type Mixer, mix } from \"#/interpolate/mix.ts\";\n\nexport interface InterpolateOptions<T> {\n\t/** Hold the output at its ends outside the input range. Default true. */\n\treadonly clamp?: boolean;\n\t/** One easing for every segment, or one per segment. */\n\treadonly ease?: EasingDefinition | readonly EasingDefinition[];\n\treadonly mixer?: (from: T, to: T) => Mixer<T>;\n}\n\n/**\n * Maps a number through a piecewise range: `interpolate([0, 100], [1, 0])`\n * turns a scroll offset into an opacity, `[0, 50, 100]` with three colours a\n * progress into a gradient. The input may run either way.\n */\nexport function interpolate<T>(\n\tinput: readonly number[],\n\toutput: readonly T[],\n\toptions: InterpolateOptions<T> = {},\n): (value: number) => T {\n\tif (input.length !== output.length || input.length === 0) {\n\t\tthrow new RangeError(\n\t\t\t\"interpolate: input and output need the same, non-zero length\",\n\t\t);\n\t}\n\tif (input.length === 1) {\n\t\treturn () => output[0] as T;\n\t}\n\tconst direction =\n\t\t(input[0] as number) > (input[input.length - 1] as number) ? -1 : 1;\n\tconst makeMixer = options.mixer ?? mix;\n\tconst mixers = output\n\t\t.slice(1)\n\t\t.map((value, index) => makeMixer(output[index] as T, value));\n\tconst eases = mixers.map((_mixer, index) => {\n\t\tconst ease = options.ease;\n\t\tconst definition = Array.isArray(ease) ? ease[index] : ease;\n\t\treturn resolveEasing((definition ?? \"linear\") as EasingDefinition);\n\t});\n\tconst clamp = options.clamp ?? true;\n\tconst low = Math.min(input[0] as number, input[input.length - 1] as number);\n\tconst high = Math.max(input[0] as number, input[input.length - 1] as number);\n\treturn (value) => {\n\t\tconst at = clamp ? Math.min(high, Math.max(low, value)) : value;\n\t\tlet segment = 0;\n\t\twhile (\n\t\t\tsegment < mixers.length - 1 &&\n\t\t\t(at - (input[segment + 1] as number)) * direction > 0\n\t\t) {\n\t\t\tsegment += 1;\n\t\t}\n\t\tconst start = input[segment] as number;\n\t\tconst span = (input[segment + 1] as number) - start;\n\t\tconst progress = span === 0 ? 1 : (at - start) / span;\n\t\tconst eased = (eases[segment] as (progress: number) => number)(progress);\n\t\treturn (mixers[segment] as Mixer<T>)(eased);\n\t};\n}\n"],
5
+ "mappings": "AAAA,SAAS,qBAAqB;AAE9B,SAAqB,WAAW;AAezB,SAAS,YACf,OACA,QACA,UAAiC,CAAC,GACX;AACvB,MAAI,MAAM,WAAW,OAAO,UAAU,MAAM,WAAW,GAAG;AACzD,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,MAAI,MAAM,WAAW,GAAG;AACvB,WAAO,MAAM,OAAO,CAAC;AAAA,EACtB;AACA,QAAM,YACJ,MAAM,CAAC,IAAgB,MAAM,MAAM,SAAS,CAAC,IAAe,KAAK;AACnE,QAAM,YAAY,QAAQ,SAAS;AACnC,QAAM,SAAS,OACb,MAAM,CAAC,EACP,IAAI,CAAC,OAAO,UAAU,UAAU,OAAO,KAAK,GAAQ,KAAK,CAAC;AAC5D,QAAM,QAAQ,OAAO,IAAI,CAAC,QAAQ,UAAU;AAC3C,UAAM,OAAO,QAAQ;AACrB,UAAM,aAAa,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,IAAI;AACvD,WAAO,cAAe,cAAc,QAA6B;AAAA,EAClE,CAAC;AACD,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,MAAM,KAAK,IAAI,MAAM,CAAC,GAAa,MAAM,MAAM,SAAS,CAAC,CAAW;AAC1E,QAAM,OAAO,KAAK,IAAI,MAAM,CAAC,GAAa,MAAM,MAAM,SAAS,CAAC,CAAW;AAC3E,SAAO,CAAC,UAAU;AACjB,UAAM,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC,IAAI;AAC1D,QAAI,UAAU;AACd,WACC,UAAU,OAAO,SAAS,MACzB,KAAM,MAAM,UAAU,CAAC,KAAgB,YAAY,GACnD;AACD,iBAAW;AAAA,IACZ;AACA,UAAM,QAAQ,MAAM,OAAO;AAC3B,UAAM,OAAQ,MAAM,UAAU,CAAC,IAAe;AAC9C,UAAM,WAAW,SAAS,IAAI,KAAK,KAAK,SAAS;AACjD,UAAM,QAAS,MAAM,OAAO,EAAmC,QAAQ;AACvE,WAAQ,OAAO,OAAO,EAAe,KAAK;AAAA,EAC3C;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,8 @@
1
+ export type Mixer<T> = (progress: number) => T;
2
+ /**
3
+ * The value `progress` of the way from `from` to `to`, whatever they are:
4
+ * numbers, colours (in oklab), paths (morphed), strings of numbers, arrays,
5
+ * objects. What has no midpoint switches halfway.
6
+ */
7
+ export declare function mix<T>(from: T, to: T): Mixer<T>;
8
+ //# sourceMappingURL=mix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mix.d.ts","sourceRoot":"","sources":["../../src/interpolate/mix.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC;AAqD/C;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAQ/C"}
@@ -0,0 +1,48 @@
1
+ import { mixArray } from "./array.js";
2
+ import { isColorLike, mixColor, parseColor } from "./color.js";
3
+ import { mixComplex } from "./complex.js";
4
+ import { mixNumber } from "./number.js";
5
+ import { mixObject } from "./object.js";
6
+ import { mixPath } from "./path/morph.js";
7
+ const PATH = /^\s*[Mm]/;
8
+ function bothStrings(from, to) {
9
+ return typeof from === "string" && typeof to === "string" ? [from, to] : void 0;
10
+ }
11
+ function colors(from, to) {
12
+ const resolved = parseColor(from) !== void 0 || parseColor(to) !== void 0;
13
+ const variables = /^\s*var\(/i.test(from) && /^\s*var\(/i.test(to);
14
+ return isColorLike(from) && isColorLike(to) && (resolved || variables);
15
+ }
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+ const STRATEGIES = [
20
+ (from, to) => typeof from === "number" && typeof to === "number" ? (progress) => mixNumber(from, to, progress) : void 0,
21
+ (from, to) => {
22
+ const pair = bothStrings(from, to);
23
+ return pair && PATH.test(pair[0]) && PATH.test(pair[1]) ? mixPath(...pair) : void 0;
24
+ },
25
+ (from, to) => {
26
+ const pair = bothStrings(from, to);
27
+ return pair && colors(...pair) ? mixColor(...pair) : void 0;
28
+ },
29
+ (from, to) => {
30
+ const pair = bothStrings(from, to);
31
+ return pair && mixComplex(...pair);
32
+ },
33
+ (from, to) => Array.isArray(from) && Array.isArray(to) ? mixArray(from, to) : void 0,
34
+ (from, to) => isRecord(from) && isRecord(to) ? mixObject(from, to) : void 0
35
+ ];
36
+ function mix(from, to) {
37
+ for (const strategy of STRATEGIES) {
38
+ const mixer = strategy(from, to);
39
+ if (mixer !== void 0) {
40
+ return mixer;
41
+ }
42
+ }
43
+ return (progress) => progress < 0.5 ? from : to;
44
+ }
45
+ export {
46
+ mix
47
+ };
48
+ //# sourceMappingURL=mix.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/interpolate/mix.ts"],
4
+ "sourcesContent": ["import { mixArray } from \"#/interpolate/array.ts\";\nimport { isColorLike, mixColor, parseColor } from \"#/interpolate/color.ts\";\nimport { mixComplex } from \"#/interpolate/complex.ts\";\nimport { mixNumber } from \"#/interpolate/number.ts\";\nimport { mixObject } from \"#/interpolate/object.ts\";\nimport { mixPath } from \"#/interpolate/path/morph.ts\";\n\nexport type Mixer<T> = (progress: number) => T;\n\ntype Strategy = (from: unknown, to: unknown) => Mixer<unknown> | undefined;\n\nconst PATH = /^\\s*[Mm]/;\n\nfunction bothStrings(from: unknown, to: unknown): [string, string] | undefined {\n\treturn typeof from === \"string\" && typeof to === \"string\"\n\t\t? [from, to]\n\t\t: undefined;\n}\n\n/**\n * A colour pair needs one side written out, or both to be variables: two bare\n * words are as likely `auto` and `none` as `red` and `blue`.\n */\nfunction colors(from: string, to: string): boolean {\n\tconst resolved =\n\t\tparseColor(from) !== undefined || parseColor(to) !== undefined;\n\tconst variables = /^\\s*var\\(/i.test(from) && /^\\s*var\\(/i.test(to);\n\treturn isColorLike(from) && isColorLike(to) && (resolved || variables);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Tried in order; the first that knows the pair mixes it. */\nconst STRATEGIES: readonly Strategy[] = [\n\t(from, to) =>\n\t\ttypeof from === \"number\" && typeof to === \"number\"\n\t\t\t? (progress) => mixNumber(from, to, progress)\n\t\t\t: undefined,\n\t(from, to) => {\n\t\tconst pair = bothStrings(from, to);\n\t\treturn pair && PATH.test(pair[0]) && PATH.test(pair[1])\n\t\t\t? mixPath(...pair)\n\t\t\t: undefined;\n\t},\n\t(from, to) => {\n\t\tconst pair = bothStrings(from, to);\n\t\treturn pair && colors(...pair) ? mixColor(...pair) : undefined;\n\t},\n\t(from, to) => {\n\t\tconst pair = bothStrings(from, to);\n\t\treturn pair && mixComplex(...pair);\n\t},\n\t(from, to) =>\n\t\tArray.isArray(from) && Array.isArray(to) ? mixArray(from, to) : undefined,\n\t(from, to) =>\n\t\tisRecord(from) && isRecord(to) ? mixObject(from, to) : undefined,\n];\n\n/**\n * The value `progress` of the way from `from` to `to`, whatever they are:\n * numbers, colours (in oklab), paths (morphed), strings of numbers, arrays,\n * objects. What has no midpoint switches halfway.\n */\nexport function mix<T>(from: T, to: T): Mixer<T> {\n\tfor (const strategy of STRATEGIES) {\n\t\tconst mixer = strategy(from, to);\n\t\tif (mixer !== undefined) {\n\t\t\treturn mixer as Mixer<T>;\n\t\t}\n\t}\n\treturn (progress) => (progress < 0.5 ? from : to);\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,aAAa,UAAU,kBAAkB;AAClD,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AAMxB,MAAM,OAAO;AAEb,SAAS,YAAY,MAAe,IAA2C;AAC9E,SAAO,OAAO,SAAS,YAAY,OAAO,OAAO,WAC9C,CAAC,MAAM,EAAE,IACT;AACJ;AAMA,SAAS,OAAO,MAAc,IAAqB;AAClD,QAAM,WACL,WAAW,IAAI,MAAM,UAAa,WAAW,EAAE,MAAM;AACtD,QAAM,YAAY,aAAa,KAAK,IAAI,KAAK,aAAa,KAAK,EAAE;AACjE,SAAO,YAAY,IAAI,KAAK,YAAY,EAAE,MAAM,YAAY;AAC7D;AAEA,SAAS,SAAS,OAAkD;AACnE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC3E;AAGA,MAAM,aAAkC;AAAA,EACvC,CAAC,MAAM,OACN,OAAO,SAAS,YAAY,OAAO,OAAO,WACvC,CAAC,aAAa,UAAU,MAAM,IAAI,QAAQ,IAC1C;AAAA,EACJ,CAAC,MAAM,OAAO;AACb,UAAM,OAAO,YAAY,MAAM,EAAE;AACjC,WAAO,QAAQ,KAAK,KAAK,KAAK,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,CAAC,CAAC,IACnD,QAAQ,GAAG,IAAI,IACf;AAAA,EACJ;AAAA,EACA,CAAC,MAAM,OAAO;AACb,UAAM,OAAO,YAAY,MAAM,EAAE;AACjC,WAAO,QAAQ,OAAO,GAAG,IAAI,IAAI,SAAS,GAAG,IAAI,IAAI;AAAA,EACtD;AAAA,EACA,CAAC,MAAM,OAAO;AACb,UAAM,OAAO,YAAY,MAAM,EAAE;AACjC,WAAO,QAAQ,WAAW,GAAG,IAAI;AAAA,EAClC;AAAA,EACA,CAAC,MAAM,OACN,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,EAAE,IAAI,SAAS,MAAM,EAAE,IAAI;AAAA,EACjE,CAAC,MAAM,OACN,SAAS,IAAI,KAAK,SAAS,EAAE,IAAI,UAAU,MAAM,EAAE,IAAI;AACzD;AAOO,SAAS,IAAO,MAAS,IAAiB;AAChD,aAAW,YAAY,YAAY;AAClC,UAAM,QAAQ,SAAS,MAAM,EAAE;AAC/B,QAAI,UAAU,QAAW;AACxB,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO,CAAC,aAAc,WAAW,MAAM,OAAO;AAC/C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ export declare function mixNumber(from: number, to: number, progress: number): number;
2
+ //# sourceMappingURL=number.d.ts.map