@number10/jsx-core 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/LICENSE +667 -0
  2. package/README.md +38 -0
  3. package/dist/animation/animated-signal.cjs +19 -0
  4. package/dist/animation/animated-signal.cjs.map +1 -0
  5. package/dist/animation/animated-signal.d.ts +35 -0
  6. package/dist/animation/animated-signal.d.ts.map +1 -0
  7. package/dist/animation/animated-signal.js +19 -0
  8. package/dist/animation/animated-signal.js.map +1 -0
  9. package/dist/animation/create-spring.cjs +80 -0
  10. package/dist/animation/create-spring.cjs.map +1 -0
  11. package/dist/animation/create-spring.d.ts +56 -0
  12. package/dist/animation/create-spring.d.ts.map +1 -0
  13. package/dist/animation/create-spring.js +80 -0
  14. package/dist/animation/create-spring.js.map +1 -0
  15. package/dist/animation/easing.cjs +76 -0
  16. package/dist/animation/easing.cjs.map +1 -0
  17. package/dist/animation/easing.d.ts +45 -0
  18. package/dist/animation/easing.d.ts.map +1 -0
  19. package/dist/animation/easing.js +76 -0
  20. package/dist/animation/easing.js.map +1 -0
  21. package/dist/animation/effect-definitions.cjs +441 -0
  22. package/dist/animation/effect-definitions.cjs.map +1 -0
  23. package/dist/animation/effect-definitions.d.ts +60 -0
  24. package/dist/animation/effect-definitions.d.ts.map +1 -0
  25. package/dist/animation/effect-definitions.js +441 -0
  26. package/dist/animation/effect-definitions.js.map +1 -0
  27. package/dist/animation/effect-engine.cjs +189 -0
  28. package/dist/animation/effect-engine.cjs.map +1 -0
  29. package/dist/animation/effect-engine.d.ts +70 -0
  30. package/dist/animation/effect-engine.d.ts.map +1 -0
  31. package/dist/animation/effect-engine.js +189 -0
  32. package/dist/animation/effect-engine.js.map +1 -0
  33. package/dist/animation/index.d.ts +24 -0
  34. package/dist/animation/index.d.ts.map +1 -0
  35. package/dist/animation/spring-physics.cjs +94 -0
  36. package/dist/animation/spring-physics.cjs.map +1 -0
  37. package/dist/animation/spring-physics.d.ts +145 -0
  38. package/dist/animation/spring-physics.d.ts.map +1 -0
  39. package/dist/animation/spring-physics.js +94 -0
  40. package/dist/animation/spring-physics.js.map +1 -0
  41. package/dist/animation/tween.cjs +67 -0
  42. package/dist/animation/tween.cjs.map +1 -0
  43. package/dist/animation/tween.d.ts +60 -0
  44. package/dist/animation/tween.d.ts.map +1 -0
  45. package/dist/animation/tween.js +67 -0
  46. package/dist/animation/tween.js.map +1 -0
  47. package/dist/animation/types.d.ts +31 -0
  48. package/dist/animation/types.d.ts.map +1 -0
  49. package/dist/animation/useSpring.cjs +152 -0
  50. package/dist/animation/useSpring.cjs.map +1 -0
  51. package/dist/animation/useSpring.d.ts +55 -0
  52. package/dist/animation/useSpring.d.ts.map +1 -0
  53. package/dist/animation/useSpring.js +149 -0
  54. package/dist/animation/useSpring.js.map +1 -0
  55. package/dist/animation/useTween.cjs +208 -0
  56. package/dist/animation/useTween.cjs.map +1 -0
  57. package/dist/animation/useTween.d.ts +116 -0
  58. package/dist/animation/useTween.d.ts.map +1 -0
  59. package/dist/animation/useTween.js +208 -0
  60. package/dist/animation/useTween.js.map +1 -0
  61. package/dist/border-geometry.cjs +447 -0
  62. package/dist/border-geometry.cjs.map +1 -0
  63. package/dist/border-geometry.d.ts +114 -0
  64. package/dist/border-geometry.d.ts.map +1 -0
  65. package/dist/border-geometry.js +447 -0
  66. package/dist/border-geometry.js.map +1 -0
  67. package/dist/colors/color-presets.cjs +236 -0
  68. package/dist/colors/color-presets.cjs.map +1 -0
  69. package/dist/colors/color-presets.d.ts +89 -0
  70. package/dist/colors/color-presets.d.ts.map +1 -0
  71. package/dist/colors/color-presets.js +236 -0
  72. package/dist/colors/color-presets.js.map +1 -0
  73. package/dist/colors/color-theme-helpers.cjs +32 -0
  74. package/dist/colors/color-theme-helpers.cjs.map +1 -0
  75. package/dist/colors/color-theme-helpers.d.ts +65 -0
  76. package/dist/colors/color-theme-helpers.d.ts.map +1 -0
  77. package/dist/colors/color-theme-helpers.js +32 -0
  78. package/dist/colors/color-theme-helpers.js.map +1 -0
  79. package/dist/colors/color-types.cjs +38 -0
  80. package/dist/colors/color-types.cjs.map +1 -0
  81. package/dist/colors/color-types.d.ts +112 -0
  82. package/dist/colors/color-types.d.ts.map +1 -0
  83. package/dist/colors/color-types.js +38 -0
  84. package/dist/colors/color-types.js.map +1 -0
  85. package/dist/colors/color-utils.cjs +197 -0
  86. package/dist/colors/color-utils.cjs.map +1 -0
  87. package/dist/colors/color-utils.d.ts +216 -0
  88. package/dist/colors/color-utils.d.ts.map +1 -0
  89. package/dist/colors/color-utils.js +197 -0
  90. package/dist/colors/color-utils.js.map +1 -0
  91. package/dist/colors/contrast-contracts.cjs +265 -0
  92. package/dist/colors/contrast-contracts.cjs.map +1 -0
  93. package/dist/colors/contrast-contracts.d.ts +289 -0
  94. package/dist/colors/contrast-contracts.d.ts.map +1 -0
  95. package/dist/colors/contrast-contracts.js +265 -0
  96. package/dist/colors/contrast-contracts.js.map +1 -0
  97. package/dist/colors/index.cjs +55 -0
  98. package/dist/colors/index.cjs.map +1 -0
  99. package/dist/colors/index.d.ts +16 -0
  100. package/dist/colors/index.d.ts.map +1 -0
  101. package/dist/colors/index.js +55 -0
  102. package/dist/colors/index.js.map +1 -0
  103. package/dist/core-props.cjs +66 -0
  104. package/dist/core-props.cjs.map +1 -0
  105. package/dist/core-props.d.ts +395 -0
  106. package/dist/core-props.d.ts.map +1 -0
  107. package/dist/core-props.js +66 -0
  108. package/dist/core-props.js.map +1 -0
  109. package/dist/design-tokens/design-token-presets.cjs +91 -0
  110. package/dist/design-tokens/design-token-presets.cjs.map +1 -0
  111. package/dist/design-tokens/design-token-presets.d.ts +34 -0
  112. package/dist/design-tokens/design-token-presets.d.ts.map +1 -0
  113. package/dist/design-tokens/design-token-presets.js +91 -0
  114. package/dist/design-tokens/design-token-presets.js.map +1 -0
  115. package/dist/design-tokens/design-token-types.d.ts +97 -0
  116. package/dist/design-tokens/design-token-types.d.ts.map +1 -0
  117. package/dist/design-tokens/index.cjs +10 -0
  118. package/dist/design-tokens/index.cjs.map +1 -0
  119. package/dist/design-tokens/index.d.ts +9 -0
  120. package/dist/design-tokens/index.d.ts.map +1 -0
  121. package/dist/design-tokens/index.js +10 -0
  122. package/dist/design-tokens/index.js.map +1 -0
  123. package/dist/dev-config.cjs +296 -0
  124. package/dist/dev-config.cjs.map +1 -0
  125. package/dist/dev-config.d.ts +238 -0
  126. package/dist/dev-config.d.ts.map +1 -0
  127. package/dist/dev-config.js +296 -0
  128. package/dist/dev-config.js.map +1 -0
  129. package/dist/effects.cjs +69 -0
  130. package/dist/effects.cjs.map +1 -0
  131. package/dist/effects.d.ts +152 -0
  132. package/dist/effects.d.ts.map +1 -0
  133. package/dist/effects.js +69 -0
  134. package/dist/effects.js.map +1 -0
  135. package/dist/global-registry.cjs +25 -0
  136. package/dist/global-registry.cjs.map +1 -0
  137. package/dist/global-registry.d.ts +19 -0
  138. package/dist/global-registry.d.ts.map +1 -0
  139. package/dist/global-registry.js +25 -0
  140. package/dist/global-registry.js.map +1 -0
  141. package/dist/hooks.cjs +378 -0
  142. package/dist/hooks.cjs.map +1 -0
  143. package/dist/hooks.d.ts +322 -0
  144. package/dist/hooks.d.ts.map +1 -0
  145. package/dist/hooks.js +378 -0
  146. package/dist/hooks.js.map +1 -0
  147. package/dist/host-adapter.d.ts +414 -0
  148. package/dist/host-adapter.d.ts.map +1 -0
  149. package/dist/index.cjs +229 -0
  150. package/dist/index.cjs.map +1 -0
  151. package/dist/index.d.ts +32 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +226 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/jsx-dev-runtime.cjs +10 -0
  156. package/dist/jsx-dev-runtime.cjs.map +1 -0
  157. package/dist/jsx-dev-runtime.d.ts +5 -0
  158. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  159. package/dist/jsx-dev-runtime.js +11 -0
  160. package/dist/jsx-dev-runtime.js.map +1 -0
  161. package/dist/jsx-runtime.cjs +44 -0
  162. package/dist/jsx-runtime.cjs.map +1 -0
  163. package/dist/jsx-runtime.d.ts +24 -0
  164. package/dist/jsx-runtime.d.ts.map +1 -0
  165. package/dist/jsx-runtime.js +44 -0
  166. package/dist/jsx-runtime.js.map +1 -0
  167. package/dist/jsx-types.d.ts +25 -0
  168. package/dist/jsx-types.d.ts.map +1 -0
  169. package/dist/layout/appliers/container-applier.cjs +20 -0
  170. package/dist/layout/appliers/container-applier.cjs.map +1 -0
  171. package/dist/layout/appliers/container-applier.d.ts +9 -0
  172. package/dist/layout/appliers/container-applier.d.ts.map +1 -0
  173. package/dist/layout/appliers/container-applier.js +20 -0
  174. package/dist/layout/appliers/container-applier.js.map +1 -0
  175. package/dist/layout/appliers/position-applier.cjs +31 -0
  176. package/dist/layout/appliers/position-applier.cjs.map +1 -0
  177. package/dist/layout/appliers/position-applier.d.ts +8 -0
  178. package/dist/layout/appliers/position-applier.d.ts.map +1 -0
  179. package/dist/layout/appliers/position-applier.js +31 -0
  180. package/dist/layout/appliers/position-applier.js.map +1 -0
  181. package/dist/layout/layout-engine-test-utils.d.ts +26 -0
  182. package/dist/layout/layout-engine-test-utils.d.ts.map +1 -0
  183. package/dist/layout/layout-engine.cjs +628 -0
  184. package/dist/layout/layout-engine.cjs.map +1 -0
  185. package/dist/layout/layout-engine.d.ts +140 -0
  186. package/dist/layout/layout-engine.d.ts.map +1 -0
  187. package/dist/layout/layout-engine.js +628 -0
  188. package/dist/layout/layout-engine.js.map +1 -0
  189. package/dist/layout/strategies/base-strategy.cjs +31 -0
  190. package/dist/layout/strategies/base-strategy.cjs.map +1 -0
  191. package/dist/layout/strategies/base-strategy.d.ts +59 -0
  192. package/dist/layout/strategies/base-strategy.d.ts.map +1 -0
  193. package/dist/layout/strategies/base-strategy.js +31 -0
  194. package/dist/layout/strategies/base-strategy.js.map +1 -0
  195. package/dist/layout/strategies/column-layout.cjs +145 -0
  196. package/dist/layout/strategies/column-layout.cjs.map +1 -0
  197. package/dist/layout/strategies/column-layout.d.ts +38 -0
  198. package/dist/layout/strategies/column-layout.d.ts.map +1 -0
  199. package/dist/layout/strategies/column-layout.js +145 -0
  200. package/dist/layout/strategies/column-layout.js.map +1 -0
  201. package/dist/layout/strategies/row-layout.cjs +145 -0
  202. package/dist/layout/strategies/row-layout.cjs.map +1 -0
  203. package/dist/layout/strategies/row-layout.d.ts +38 -0
  204. package/dist/layout/strategies/row-layout.d.ts.map +1 -0
  205. package/dist/layout/strategies/row-layout.js +145 -0
  206. package/dist/layout/strategies/row-layout.js.map +1 -0
  207. package/dist/layout/strategies/stack-layout.cjs +94 -0
  208. package/dist/layout/strategies/stack-layout.cjs.map +1 -0
  209. package/dist/layout/strategies/stack-layout.d.ts +30 -0
  210. package/dist/layout/strategies/stack-layout.d.ts.map +1 -0
  211. package/dist/layout/strategies/stack-layout.js +94 -0
  212. package/dist/layout/strategies/stack-layout.js.map +1 -0
  213. package/dist/layout/types.d.ts +134 -0
  214. package/dist/layout/types.d.ts.map +1 -0
  215. package/dist/layout/utils/child-utils.cjs +129 -0
  216. package/dist/layout/utils/child-utils.cjs.map +1 -0
  217. package/dist/layout/utils/child-utils.d.ts +54 -0
  218. package/dist/layout/utils/child-utils.d.ts.map +1 -0
  219. package/dist/layout/utils/child-utils.js +129 -0
  220. package/dist/layout/utils/child-utils.js.map +1 -0
  221. package/dist/layout/utils/dimension-calculator.cjs +109 -0
  222. package/dist/layout/utils/dimension-calculator.cjs.map +1 -0
  223. package/dist/layout/utils/dimension-calculator.d.ts +59 -0
  224. package/dist/layout/utils/dimension-calculator.d.ts.map +1 -0
  225. package/dist/layout/utils/dimension-calculator.js +109 -0
  226. package/dist/layout/utils/dimension-calculator.js.map +1 -0
  227. package/dist/layout/utils/flex-distributor.cjs +173 -0
  228. package/dist/layout/utils/flex-distributor.cjs.map +1 -0
  229. package/dist/layout/utils/flex-distributor.d.ts +18 -0
  230. package/dist/layout/utils/flex-distributor.d.ts.map +1 -0
  231. package/dist/layout/utils/flex-distributor.js +173 -0
  232. package/dist/layout/utils/flex-distributor.js.map +1 -0
  233. package/dist/layout/utils/size-resolver.cjs +280 -0
  234. package/dist/layout/utils/size-resolver.cjs.map +1 -0
  235. package/dist/layout/utils/size-resolver.d.ts +84 -0
  236. package/dist/layout/utils/size-resolver.d.ts.map +1 -0
  237. package/dist/layout/utils/size-resolver.js +280 -0
  238. package/dist/layout/utils/size-resolver.js.map +1 -0
  239. package/dist/layout/utils/spacing-calculator.cjs +50 -0
  240. package/dist/layout/utils/spacing-calculator.cjs.map +1 -0
  241. package/dist/layout/utils/spacing-calculator.d.ts +27 -0
  242. package/dist/layout/utils/spacing-calculator.d.ts.map +1 -0
  243. package/dist/layout/utils/spacing-calculator.js +50 -0
  244. package/dist/layout/utils/spacing-calculator.js.map +1 -0
  245. package/dist/memo.cjs +18 -0
  246. package/dist/memo.cjs.map +1 -0
  247. package/dist/memo.d.ts +29 -0
  248. package/dist/memo.d.ts.map +1 -0
  249. package/dist/memo.js +18 -0
  250. package/dist/memo.js.map +1 -0
  251. package/dist/nineslice-contract.cjs +60 -0
  252. package/dist/nineslice-contract.cjs.map +1 -0
  253. package/dist/nineslice-contract.d.ts +107 -0
  254. package/dist/nineslice-contract.d.ts.map +1 -0
  255. package/dist/nineslice-contract.js +60 -0
  256. package/dist/nineslice-contract.js.map +1 -0
  257. package/dist/placeholder.cjs +12 -0
  258. package/dist/placeholder.cjs.map +1 -0
  259. package/dist/placeholder.d.ts +44 -0
  260. package/dist/placeholder.d.ts.map +1 -0
  261. package/dist/placeholder.js +12 -0
  262. package/dist/placeholder.js.map +1 -0
  263. package/dist/portal.cjs +89 -0
  264. package/dist/portal.cjs.map +1 -0
  265. package/dist/portal.d.ts +62 -0
  266. package/dist/portal.d.ts.map +1 -0
  267. package/dist/portal.js +89 -0
  268. package/dist/portal.js.map +1 -0
  269. package/dist/primitive-contracts.cjs +12 -0
  270. package/dist/primitive-contracts.cjs.map +1 -0
  271. package/dist/primitive-contracts.d.ts +186 -0
  272. package/dist/primitive-contracts.d.ts.map +1 -0
  273. package/dist/primitive-contracts.js +12 -0
  274. package/dist/primitive-contracts.js.map +1 -0
  275. package/dist/theme.cjs +332 -0
  276. package/dist/theme.cjs.map +1 -0
  277. package/dist/theme.d.ts +204 -0
  278. package/dist/theme.d.ts.map +1 -0
  279. package/dist/theme.js +332 -0
  280. package/dist/theme.js.map +1 -0
  281. package/dist/types.d.ts +86 -0
  282. package/dist/types.d.ts.map +1 -0
  283. package/dist/vdom/create-runtime.cjs +79 -0
  284. package/dist/vdom/create-runtime.cjs.map +1 -0
  285. package/dist/vdom/create-runtime.d.ts +7 -0
  286. package/dist/vdom/create-runtime.d.ts.map +1 -0
  287. package/dist/vdom/create-runtime.js +79 -0
  288. package/dist/vdom/create-runtime.js.map +1 -0
  289. package/dist/vdom/index.cjs +8 -0
  290. package/dist/vdom/index.cjs.map +1 -0
  291. package/dist/vdom/index.d.ts +4 -0
  292. package/dist/vdom/index.d.ts.map +1 -0
  293. package/dist/vdom/index.js +8 -0
  294. package/dist/vdom/index.js.map +1 -0
  295. package/dist/vdom/mount.cjs +161 -0
  296. package/dist/vdom/mount.cjs.map +1 -0
  297. package/dist/vdom/mount.d.ts +6 -0
  298. package/dist/vdom/mount.d.ts.map +1 -0
  299. package/dist/vdom/mount.js +161 -0
  300. package/dist/vdom/mount.js.map +1 -0
  301. package/dist/vdom/patch.cjs +163 -0
  302. package/dist/vdom/patch.cjs.map +1 -0
  303. package/dist/vdom/patch.d.ts +3 -0
  304. package/dist/vdom/patch.d.ts.map +1 -0
  305. package/dist/vdom/patch.js +163 -0
  306. package/dist/vdom/patch.js.map +1 -0
  307. package/dist/vdom/registry.cjs +85 -0
  308. package/dist/vdom/registry.cjs.map +1 -0
  309. package/dist/vdom/registry.d.ts +28 -0
  310. package/dist/vdom/registry.d.ts.map +1 -0
  311. package/dist/vdom/registry.js +85 -0
  312. package/dist/vdom/registry.js.map +1 -0
  313. package/dist/vdom/runtime-helpers.cjs +23 -0
  314. package/dist/vdom/runtime-helpers.cjs.map +1 -0
  315. package/dist/vdom/runtime-helpers.d.ts +8 -0
  316. package/dist/vdom/runtime-helpers.d.ts.map +1 -0
  317. package/dist/vdom/runtime-helpers.js +23 -0
  318. package/dist/vdom/runtime-helpers.js.map +1 -0
  319. package/dist/vdom/surface.cjs +107 -0
  320. package/dist/vdom/surface.cjs.map +1 -0
  321. package/dist/vdom/surface.d.ts +9 -0
  322. package/dist/vdom/surface.d.ts.map +1 -0
  323. package/dist/vdom/surface.js +107 -0
  324. package/dist/vdom/surface.js.map +1 -0
  325. package/dist/vdom/types.d.ts +104 -0
  326. package/dist/vdom/types.d.ts.map +1 -0
  327. package/dist/vdom/utils.cjs +146 -0
  328. package/dist/vdom/utils.cjs.map +1 -0
  329. package/dist/vdom/utils.d.ts +24 -0
  330. package/dist/vdom/utils.d.ts.map +1 -0
  331. package/dist/vdom/utils.js +146 -0
  332. package/dist/vdom/utils.js.map +1 -0
  333. package/dist/vdom.d.ts +4 -0
  334. package/dist/vdom.d.ts.map +1 -0
  335. package/dist/vector-draw-context.d.ts +63 -0
  336. package/dist/vector-draw-context.d.ts.map +1 -0
  337. package/package.json +161 -0
  338. package/vdom/index.cjs +1 -0
  339. package/vdom/index.d.ts +1 -0
  340. package/vdom/index.js +1 -0
@@ -0,0 +1,208 @@
1
+ import { useRef, getCurrentCtx, useEffect } from "../hooks.js";
2
+ import { animatedSignal } from "./animated-signal.js";
3
+ import { Easing } from "./easing.js";
4
+ import { createTween } from "./tween.js";
5
+ const TWEEN_PRESETS = {
6
+ /** Standard transition (300ms, quadOut) */
7
+ default: { duration: 300, ease: Easing.quadOut },
8
+ /** Quick transition (150ms, quadOut) */
9
+ fast: { duration: 150, ease: Easing.quadOut },
10
+ /** Slow, deliberate transition (600ms, quadOut) */
11
+ slow: { duration: 600, ease: Easing.quadOut },
12
+ /** Slightly bouncy quick transition (200ms, backOut) */
13
+ snappy: { duration: 200, ease: Easing.backOut },
14
+ /** Elastic feel (400ms, elasticOut) */
15
+ elastic: { duration: 400, ease: Easing.elasticOut },
16
+ /** Snap to value instantly (0ms) — useful for reset patterns */
17
+ instant: { duration: 0 }
18
+ };
19
+ function useTween(initialValue, config, onComplete) {
20
+ const resolvedBaseConfig = typeof config === "string" ? TWEEN_PRESETS[config] : config ?? TWEEN_PRESETS.default;
21
+ const resolvedTo = resolvedBaseConfig.to;
22
+ const isLooping = resolvedBaseConfig.loop !== void 0 && resolvedBaseConfig.loop !== false;
23
+ const valueSignal = useRef(null);
24
+ if (valueSignal.current === null) {
25
+ valueSignal.current = animatedSignal(initialValue);
26
+ }
27
+ const ctx = getCurrentCtx();
28
+ const schedulerRef = useRef(ctx?.surface?.scheduler ?? null);
29
+ if (ctx?.surface?.scheduler && schedulerRef.current !== ctx.surface.scheduler) {
30
+ schedulerRef.current = ctx.surface.scheduler;
31
+ }
32
+ const currentTarget = useRef(resolvedTo ?? initialValue);
33
+ const tweenCleanupRef = useRef(null);
34
+ const setValueRef = useRef(
35
+ null
36
+ );
37
+ if (!setValueRef.current) {
38
+ setValueRef.current = (newTarget) => {
39
+ const resolved = typeof newTarget === "function" ? newTarget(currentTarget.current) : newTarget;
40
+ currentTarget.current = resolved;
41
+ startTween();
42
+ };
43
+ }
44
+ const startTween = () => {
45
+ const scheduler = schedulerRef.current;
46
+ if (!scheduler) {
47
+ if (valueSignal.current) {
48
+ valueSignal.current.value = currentTarget.current;
49
+ }
50
+ return;
51
+ }
52
+ tweenCleanupRef.current?.();
53
+ const signal = valueSignal.current;
54
+ if (!signal) return;
55
+ const resolvedConfig = resolvedBaseConfig;
56
+ const steps = resolvedConfig.steps ?? [
57
+ {
58
+ to: currentTarget.current,
59
+ duration: resolvedConfig.duration ?? 300,
60
+ ease: resolvedConfig.ease
61
+ }
62
+ ];
63
+ const onAllStepsComplete = () => {
64
+ if (isLooping && resolvedTo !== void 0) {
65
+ signal.value = initialValue;
66
+ currentTarget.current = resolvedTo;
67
+ startTween();
68
+ return;
69
+ }
70
+ onComplete?.();
71
+ };
72
+ let stepIndex = 0;
73
+ let currentHandle = null;
74
+ resolvedConfig.onStart?.();
75
+ const runNextStep = () => {
76
+ if (stepIndex >= steps.length) {
77
+ onAllStepsComplete();
78
+ return;
79
+ }
80
+ const step = steps[stepIndex];
81
+ if (!step) return;
82
+ const startValue = signal.value;
83
+ currentHandle = createTween(
84
+ { value: startValue },
85
+ {
86
+ to: { value: step.to },
87
+ duration: step.duration,
88
+ ease: step.ease ?? Easing.quadOut,
89
+ onUpdate: (t) => {
90
+ signal.value = t.value;
91
+ resolvedConfig.onUpdate?.(t.value);
92
+ },
93
+ onComplete: () => {
94
+ stepIndex++;
95
+ runNextStep();
96
+ }
97
+ },
98
+ scheduler
99
+ );
100
+ };
101
+ runNextStep();
102
+ tweenCleanupRef.current = () => {
103
+ currentHandle?.stop();
104
+ };
105
+ };
106
+ useEffect(() => {
107
+ if (currentTarget.current !== initialValue) {
108
+ startTween();
109
+ }
110
+ return () => {
111
+ tweenCleanupRef.current?.();
112
+ tweenCleanupRef.current = null;
113
+ };
114
+ }, []);
115
+ if (!valueSignal.current) {
116
+ throw new Error("useTween: Failed to initialize animated signal");
117
+ }
118
+ return [
119
+ valueSignal.current,
120
+ setValueRef.current
121
+ ];
122
+ }
123
+ function useTweens(initialValues, config, onComplete) {
124
+ const keys = Object.keys(initialValues);
125
+ const resolvedConfig = typeof config === "string" ? TWEEN_PRESETS[config] : config ?? TWEEN_PRESETS.default;
126
+ const tweenMap = useRef(
127
+ /* @__PURE__ */ new Map()
128
+ );
129
+ keys.forEach((key) => {
130
+ if (!tweenMap.current.has(key)) {
131
+ const initialValue = initialValues[key];
132
+ tweenMap.current.set(key, {
133
+ signal: animatedSignal(initialValue),
134
+ target: { value: initialValue }
135
+ });
136
+ }
137
+ });
138
+ const ctx = getCurrentCtx();
139
+ const scheduler = ctx?.surface?.scheduler ?? null;
140
+ const schedulerRef = useRef(scheduler);
141
+ if (scheduler && schedulerRef.current !== scheduler) {
142
+ schedulerRef.current = scheduler;
143
+ }
144
+ const handlesRef = useRef([]);
145
+ const setValues = (values) => {
146
+ const currentScheduler = schedulerRef.current;
147
+ const entries = Object.entries(values).filter(([, v]) => v !== void 0);
148
+ if (!currentScheduler) {
149
+ entries.forEach(([key, val]) => {
150
+ const entry = tweenMap.current.get(key);
151
+ if (entry) {
152
+ entry.signal.value = typeof val === "function" ? val(entry.target.value) : val;
153
+ entry.target.value = entry.signal.value;
154
+ }
155
+ });
156
+ return;
157
+ }
158
+ handlesRef.current.forEach((h) => h.stop());
159
+ handlesRef.current = [];
160
+ let completedCount = 0;
161
+ const totalAnimations = entries.length;
162
+ entries.forEach(([key, val]) => {
163
+ const entry = tweenMap.current.get(key);
164
+ if (!entry) return;
165
+ const toValue = typeof val === "function" ? val(entry.target.value) : val;
166
+ entry.target.value = toValue;
167
+ const handle = createTween(
168
+ { value: entry.signal.value },
169
+ {
170
+ to: { value: toValue },
171
+ duration: resolvedConfig.duration ?? 300,
172
+ ease: resolvedConfig.ease ?? Easing.quadOut,
173
+ onUpdate: (t) => {
174
+ entry.signal.value = t.value;
175
+ },
176
+ onComplete: () => {
177
+ completedCount++;
178
+ if (completedCount >= totalAnimations) {
179
+ onComplete?.();
180
+ }
181
+ }
182
+ },
183
+ currentScheduler
184
+ );
185
+ handlesRef.current.push(handle);
186
+ });
187
+ };
188
+ useEffect(() => {
189
+ return () => {
190
+ handlesRef.current.forEach((h) => h.stop());
191
+ handlesRef.current = [];
192
+ };
193
+ }, []);
194
+ const signals = {};
195
+ keys.forEach((key) => {
196
+ const entry = tweenMap.current.get(key);
197
+ if (entry) {
198
+ signals[key] = entry.signal;
199
+ }
200
+ });
201
+ return [signals, setValues];
202
+ }
203
+ export {
204
+ TWEEN_PRESETS,
205
+ useTween,
206
+ useTweens
207
+ };
208
+ //# sourceMappingURL=useTween.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTween.js","sources":["../../src/animation/useTween.ts"],"sourcesContent":["/**\n * Tween animation hook — declarative time-based animations via signals.\n *\n * Counterpart to useSpring. Uses createTween internally, driven by\n * HostScheduler.onFrame(). Returns an AnimatedSignal that components\n * can bind to JSX props for direct VDOM-bypassing updates.\n *\n * @example\n * ```tsx\n * const [x, setX] = useTween(0, { duration: 500, ease: Easing.quadOut })\n * <View x={x} />\n * setX(200) // animates from current to 200 over 500ms\n *\n * // Multi-step:\n * const [scale, setScale] = useTween(1, {\n * steps: [\n * { to: 1.3, duration: 150, ease: Easing.quadOut },\n * { to: 1.0, duration: 150, ease: Easing.backOut },\n * ]\n * })\n * ```\n */\n\nimport { getCurrentCtx, useEffect, useRef, type HookContext } from '../hooks'\nimport type { HostScheduler } from '../host-adapter'\nimport { animatedSignal, type AnimatedSignal } from './animated-signal'\nimport { Easing, type EasingFn } from './easing'\nimport { createTween } from './tween'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Configuration for a single tween step in a multi-step animation */\nexport interface TweenAnimationStep {\n /** Target value */\n to: number\n /** Duration in ms */\n duration: number\n /** Easing function (default: quadOut) */\n ease?: EasingFn | undefined\n}\n\n/** Configuration for useTween */\nexport interface TweenConfig {\n /** Duration in ms (default: 300) */\n duration?: number | undefined\n /** Easing function (default: Easing.quadOut) */\n ease?: EasingFn | undefined\n /** Multi-step tween sequence (overrides duration/ease) */\n steps?: TweenAnimationStep[] | undefined\n /**\n * Target value — auto-starts the tween from initialValue to `to`.\n * No need to call the setter for the first animation.\n *\n * When combined with `loop`, the animation restarts from initialValue\n * to `to` on each completion.\n */\n to?: number | undefined\n /**\n * Loop the animation. When `true`, restarts from initialValue to `to`\n * each time the tween completes. Use with `to` for auto-starting loops.\n *\n * @example\n * ```tsx\n * // Continuous rotation — no effect, no ref, no onComplete needed\n * const [rotation] = useTween(0, { to: Math.PI * 2, duration: 8000, ease: Easing.linear, loop: true })\n * <View rotation={rotation} />\n * ```\n */\n loop?: boolean | { reverse?: boolean } | undefined\n /**\n * Called once when the tween starts (including on restart/loop).\n * Fires BEFORE the first frame is rendered.\n */\n onStart?: (() => void) | undefined\n /**\n * Called on every frame with the current interpolated value.\n * Useful for syncing non-signal state (logging, analytics).\n */\n onUpdate?: ((value: number) => void) | undefined\n}\n\n/**\n * Preset tween configurations for common animation durations.\n *\n * @example\n * ```tsx\n * const [x, setX] = useTween(0, TWEEN_PRESETS.snappy)\n * setX(200)\n * ```\n */\nexport const TWEEN_PRESETS = {\n /** Standard transition (300ms, quadOut) */\n default: { duration: 300, ease: Easing.quadOut } as TweenConfig,\n /** Quick transition (150ms, quadOut) */\n fast: { duration: 150, ease: Easing.quadOut } as TweenConfig,\n /** Slow, deliberate transition (600ms, quadOut) */\n slow: { duration: 600, ease: Easing.quadOut } as TweenConfig,\n /** Slightly bouncy quick transition (200ms, backOut) */\n snappy: { duration: 200, ease: Easing.backOut } as TweenConfig,\n /** Elastic feel (400ms, elasticOut) */\n elastic: { duration: 400, ease: Easing.elasticOut } as TweenConfig,\n /** Snap to value instantly (0ms) — useful for reset patterns */\n instant: { duration: 0 } as TweenConfig,\n} as const\n\n/**\n * Type for tween preset keys\n */\nexport type TweenPreset = keyof typeof TWEEN_PRESETS\n\n// ---------------------------------------------------------------------------\n// useTween\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an animated signal that transitions to target values\n * over a fixed duration with configurable easing.\n *\n * @param initialValue - Initial value\n * @param config - Duration, easing, or multi-step config\n * @param onComplete - Optional callback when animation completes\n * @returns Tuple of [animated signal, setter function]\n */\nexport function useTween(\n initialValue: number,\n config?: TweenConfig | TweenPreset,\n onComplete?: () => void\n): [AnimatedSignal, (target: number | ((prev: number) => number)) => void] {\n // Resolve config — supports preset names\n const resolvedBaseConfig: TweenConfig =\n typeof config === 'string' ? TWEEN_PRESETS[config] : (config ?? TWEEN_PRESETS.default)\n\n const resolvedTo = resolvedBaseConfig.to\n const isLooping = resolvedBaseConfig.loop !== undefined && resolvedBaseConfig.loop !== false\n\n const valueSignal = useRef<AnimatedSignal | null>(null)\n if (valueSignal.current === null) {\n valueSignal.current = animatedSignal(initialValue)\n }\n\n // Capture scheduler from surface context\n const ctx = getCurrentCtx() as HookContext | null\n const schedulerRef = useRef<HostScheduler | null>(ctx?.surface?.scheduler ?? null)\n\n // Update scheduler ref if it changes\n if (ctx?.surface?.scheduler && schedulerRef.current !== ctx.surface.scheduler) {\n schedulerRef.current = ctx.surface.scheduler\n }\n\n // Auto-start: if `to` is specified, use it as the initial target\n const currentTarget = useRef<number>(resolvedTo ?? initialValue)\n const tweenCleanupRef = useRef<(() => void) | null>(null)\n\n // Stable setter — avoids re-running effects that depend on it\n const setValueRef = useRef<((newTarget: number | ((prev: number) => number)) => void) | null>(\n null\n )\n if (!setValueRef.current) {\n setValueRef.current = (newTarget: number | ((prev: number) => number)): void => {\n const resolved =\n typeof newTarget === 'function' ? newTarget(currentTarget.current) : newTarget\n currentTarget.current = resolved\n startTween()\n }\n }\n\n const startTween = (): void => {\n const scheduler = schedulerRef.current\n if (!scheduler) {\n // Fallback: set value immediately\n if (valueSignal.current) {\n valueSignal.current.value = currentTarget.current\n }\n return\n }\n\n // Cleanup previous tween\n tweenCleanupRef.current?.()\n\n const signal = valueSignal.current\n if (!signal) return\n\n const resolvedConfig = resolvedBaseConfig\n\n // Build step array\n const steps: TweenAnimationStep[] = resolvedConfig.steps ?? [\n {\n to: currentTarget.current,\n duration: resolvedConfig.duration ?? 300,\n ease: resolvedConfig.ease,\n },\n ]\n\n // Completion handler — supports loop restart\n const onAllStepsComplete = (): void => {\n if (isLooping && resolvedTo !== undefined) {\n // Reset signal to initialValue and restart tween\n signal.value = initialValue\n currentTarget.current = resolvedTo\n startTween()\n return\n }\n onComplete?.()\n }\n\n let stepIndex = 0\n let currentHandle: ReturnType<typeof createTween> | null = null\n\n // Fire onStart when the first step begins\n resolvedConfig.onStart?.()\n\n const runNextStep = (): void => {\n if (stepIndex >= steps.length) {\n onAllStepsComplete()\n return\n }\n\n const step = steps[stepIndex]\n if (!step) return\n\n const startValue = signal.value\n\n currentHandle = createTween(\n { value: startValue },\n {\n to: { value: step.to },\n duration: step.duration,\n ease: step.ease ?? Easing.quadOut,\n onUpdate: (t) => {\n signal.value = t.value\n resolvedConfig.onUpdate?.(t.value)\n },\n onComplete: () => {\n stepIndex++\n runNextStep()\n },\n },\n scheduler\n )\n }\n\n runNextStep()\n\n tweenCleanupRef.current = () => {\n currentHandle?.stop()\n }\n }\n\n // Start initial animation if target differs from initial\n useEffect(() => {\n if (currentTarget.current !== initialValue) {\n startTween()\n }\n\n return () => {\n tweenCleanupRef.current?.()\n tweenCleanupRef.current = null\n }\n }, [])\n\n if (!valueSignal.current) {\n throw new Error('useTween: Failed to initialize animated signal')\n }\n\n return [\n valueSignal.current,\n setValueRef.current as (target: number | ((prev: number) => number)) => void,\n ]\n}\n\n// ---------------------------------------------------------------------------\n// useTweens — multi-value tween hook\n// ---------------------------------------------------------------------------\n\n/**\n * Multi-tween animation hook.\n *\n * Creates multiple animated signals that share the same tween configuration.\n * Counterpart to `useSprings`.\n *\n * @param initialValues - Object with initial numeric values\n * @param config - Tween config or preset name (shared across all properties)\n * @param onComplete - Called when ALL tweens complete (fires once per setValues call)\n * @returns Tuple of [animated signals object, setter function]\n *\n * @example\n * ```tsx\n * const [pos, setPos] = useTweens({ x: 0, y: 0 }, 'snappy')\n * <View x={pos.x} y={pos.y} />\n * setPos({ x: 100, y: 200 }) // both animate to target simultaneously\n * ```\n */\nexport function useTweens<T extends Record<string, number>>(\n initialValues: T,\n config?: TweenConfig | TweenPreset,\n onComplete?: () => void\n): [\n { [K in keyof T]: AnimatedSignal },\n (values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>) => void,\n] {\n const keys = Object.keys(initialValues) as (keyof T)[]\n\n // Resolve config — supports preset names\n const resolvedConfig: TweenConfig =\n typeof config === 'string' ? TWEEN_PRESETS[config] : (config ?? TWEEN_PRESETS.default)\n\n // Initialize signals and targets\n const tweenMap = useRef<Map<keyof T, { signal: AnimatedSignal; target: { value: number } }>>(\n new Map()\n )\n\n keys.forEach((key) => {\n if (!tweenMap.current.has(key)) {\n const initialValue = initialValues[key] as number\n tweenMap.current.set(key, {\n signal: animatedSignal(initialValue),\n target: { value: initialValue },\n })\n }\n })\n\n // Capture scheduler from surface context\n const ctx = getCurrentCtx() as HookContext | null\n const scheduler = ctx?.surface?.scheduler ?? null\n const schedulerRef = useRef<HostScheduler | null>(scheduler)\n if (scheduler && schedulerRef.current !== scheduler) {\n schedulerRef.current = scheduler\n }\n\n // Track active tween handles for cleanup\n const handlesRef = useRef<ReturnType<typeof createTween>[]>([])\n\n // Setter function\n const setValues = (\n values: Partial<{ [K in keyof T]: number | ((prev: number) => number) }>\n ): void => {\n const currentScheduler = schedulerRef.current\n\n // Filter out undefined values (Partial may include them)\n const entries = Object.entries(values).filter(([, v]) => v !== undefined) as [\n string,\n number | ((prev: number) => number),\n ][]\n\n if (!currentScheduler) {\n // Fallback: set values immediately\n entries.forEach(([key, val]) => {\n const entry = tweenMap.current.get(key as keyof T)\n if (entry) {\n entry.signal.value = typeof val === 'function' ? val(entry.target.value) : val\n entry.target.value = entry.signal.value\n }\n })\n return\n }\n\n // Cleanup previous tweens\n handlesRef.current.forEach((h) => h.stop())\n handlesRef.current = []\n\n let completedCount = 0\n const totalAnimations = entries.length\n\n entries.forEach(([key, val]) => {\n const entry = tweenMap.current.get(key as keyof T)\n if (!entry) return\n\n const toValue = typeof val === 'function' ? val(entry.target.value) : val\n entry.target.value = toValue\n\n const handle = createTween(\n { value: entry.signal.value },\n {\n to: { value: toValue },\n duration: resolvedConfig.duration ?? 300,\n ease: resolvedConfig.ease ?? Easing.quadOut,\n onUpdate: (t) => {\n entry.signal.value = t.value\n },\n onComplete: () => {\n completedCount++\n if (completedCount >= totalAnimations) {\n onComplete?.()\n }\n },\n },\n currentScheduler\n )\n\n handlesRef.current.push(handle)\n })\n }\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n handlesRef.current.forEach((h) => h.stop())\n handlesRef.current = []\n }\n }, [])\n\n // Build result object\n const signals = {} as { [K in keyof T]: AnimatedSignal }\n keys.forEach((key) => {\n const entry = tweenMap.current.get(key)\n if (entry) {\n signals[key] = entry.signal\n }\n })\n\n return [signals, setValues]\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,447 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function resolveBorderSides(width) {
4
+ if (width === void 0) return { top: 0, right: 0, bottom: 0, left: 0 };
5
+ if (typeof width === "number") {
6
+ const w = Math.max(0, width);
7
+ return { top: w, right: w, bottom: w, left: w };
8
+ }
9
+ return {
10
+ top: Math.max(0, width.top ?? 0),
11
+ right: Math.max(0, width.right ?? 0),
12
+ bottom: Math.max(0, width.bottom ?? 0),
13
+ left: Math.max(0, width.left ?? 0)
14
+ };
15
+ }
16
+ function isUniformBorder(sides) {
17
+ return sides.top === sides.right && sides.right === sides.bottom && sides.bottom === sides.left;
18
+ }
19
+ function resolveCornerRadii(cr) {
20
+ if (typeof cr === "number") {
21
+ const r = Math.max(0, cr);
22
+ return { tl: r, tr: r, bl: r, br: r };
23
+ }
24
+ if (cr) {
25
+ return {
26
+ tl: Math.max(0, cr.tl ?? 0),
27
+ tr: Math.max(0, cr.tr ?? 0),
28
+ bl: Math.max(0, cr.bl ?? 0),
29
+ br: Math.max(0, cr.br ?? 0)
30
+ };
31
+ }
32
+ return { tl: 0, tr: 0, bl: 0, br: 0 };
33
+ }
34
+ function hasAnyCornerRadius(corners) {
35
+ return corners.tl > 0 || corners.tr > 0 || corners.bl > 0 || corners.br > 0;
36
+ }
37
+ function shouldUseCoreBorderGeometry(border, rendererIssues) {
38
+ const sides = resolveBorderSides(border.width);
39
+ const asymmetric = !isUniformBorder(sides);
40
+ if (asymmetric) return true;
41
+ if (rendererIssues && rendererIssues.length > 0) {
42
+ if (rendererIssues.includes("all")) return true;
43
+ if (rendererIssues.includes("rounded-dotted") && border.style === "dotted") {
44
+ return true;
45
+ }
46
+ if (rendererIssues.includes("rounded-dashed-cap") && border.style === "dashed") {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+ function pushPerimeterPoint(points, pt, width) {
53
+ const last = points[points.length - 1];
54
+ if (!last || Math.abs(last.x - pt.x) > 1e-3 || Math.abs(last.y - pt.y) > 1e-3) {
55
+ points.push({ x: pt.x, y: pt.y, width });
56
+ return;
57
+ }
58
+ last.width = width;
59
+ }
60
+ function appendPerimeterArcPoints(points, corner, startAngle, endAngle, widthStart, widthEnd) {
61
+ const start = pointOnEllipse(corner, startAngle);
62
+ pushPerimeterPoint(points, start, widthStart);
63
+ if (corner.rx <= 0 || corner.ry <= 0) {
64
+ pushPerimeterPoint(points, pointOnEllipse(corner, endAngle), widthEnd);
65
+ return;
66
+ }
67
+ const span = endAngle - startAngle;
68
+ const maxR = Math.max(corner.rx, corner.ry);
69
+ const steps = Math.max(1, Math.min(24, Math.ceil(Math.abs(span) * maxR / 8)));
70
+ for (let i = 1; i <= steps; i++) {
71
+ const t = i / steps;
72
+ const angle = startAngle + span * t;
73
+ const width = widthStart + (widthEnd - widthStart) * t;
74
+ pushPerimeterPoint(points, pointOnEllipse(corner, angle), width);
75
+ }
76
+ }
77
+ function buildPerimeterPoints(w, h, sides, corners, align) {
78
+ const offsets = resolveBorderOffsets(sides, align);
79
+ const outer = buildOuterContour(w, h, corners, offsets.outer);
80
+ const inner = buildInnerContour(w, h, corners, offsets.inner);
81
+ const mid = averageContours(outer, inner);
82
+ const points = [];
83
+ pushPerimeterPoint(points, { x: mid.tl.cx, y: mid.top }, sides.top);
84
+ pushPerimeterPoint(points, { x: mid.tr.cx, y: mid.top }, sides.top);
85
+ appendPerimeterArcPoints(points, mid.tr, -Math.PI / 2, 0, sides.top, sides.right);
86
+ pushPerimeterPoint(points, { x: mid.right, y: mid.br.cy }, sides.right);
87
+ appendPerimeterArcPoints(points, mid.br, 0, Math.PI / 2, sides.right, sides.bottom);
88
+ pushPerimeterPoint(points, { x: mid.bl.cx, y: mid.bottom }, sides.bottom);
89
+ appendPerimeterArcPoints(points, mid.bl, Math.PI / 2, Math.PI, sides.bottom, sides.left);
90
+ pushPerimeterPoint(points, { x: mid.left, y: mid.tl.cy }, sides.left);
91
+ appendPerimeterArcPoints(points, mid.tl, Math.PI, Math.PI * 1.5, sides.left, sides.top);
92
+ if (points.length > 1) {
93
+ const first = points[0] ?? { x: 0, y: 0 };
94
+ const last = points[points.length - 1] ?? { x: 0, y: 0 };
95
+ if (Math.abs(first.x - last.x) <= 1e-3 && Math.abs(first.y - last.y) <= 1e-3) {
96
+ points.pop();
97
+ }
98
+ }
99
+ return points;
100
+ }
101
+ function buildPerimeterSegments(points) {
102
+ if (points.length < 2) return [];
103
+ const segs = [];
104
+ for (let i = 0; i < points.length; i++) {
105
+ const p1 = points[i] ?? { x: 0, y: 0, width: 0 };
106
+ const p2 = points[(i + 1) % points.length] ?? { x: 0, y: 0, width: 0 };
107
+ const dx = p2.x - p1.x;
108
+ const dy = p2.y - p1.y;
109
+ const length = Math.sqrt(dx * dx + dy * dy);
110
+ if (length <= 1e-3) continue;
111
+ segs.push({
112
+ x1: p1.x,
113
+ y1: p1.y,
114
+ x2: p2.x,
115
+ y2: p2.y,
116
+ width1: p1.width,
117
+ width2: p2.width,
118
+ length
119
+ });
120
+ }
121
+ return segs;
122
+ }
123
+ function pointAtDistance(seg, t) {
124
+ const frac = seg.length > 0 ? t / seg.length : 0;
125
+ return {
126
+ x: seg.x1 + (seg.x2 - seg.x1) * frac,
127
+ y: seg.y1 + (seg.y2 - seg.y1) * frac,
128
+ width: seg.width1 + (seg.width2 - seg.width1) * frac
129
+ };
130
+ }
131
+ function resolveBorderOffsets(sides, align) {
132
+ if (align === "inside") {
133
+ return {
134
+ outer: { top: 0, right: 0, bottom: 0, left: 0 },
135
+ inner: { ...sides }
136
+ };
137
+ }
138
+ if (align === "outside") {
139
+ return {
140
+ outer: { ...sides },
141
+ inner: { top: 0, right: 0, bottom: 0, left: 0 }
142
+ };
143
+ }
144
+ return {
145
+ outer: {
146
+ top: sides.top / 2,
147
+ right: sides.right / 2,
148
+ bottom: sides.bottom / 2,
149
+ left: sides.left / 2
150
+ },
151
+ inner: {
152
+ top: sides.top / 2,
153
+ right: sides.right / 2,
154
+ bottom: sides.bottom / 2,
155
+ left: sides.left / 2
156
+ }
157
+ };
158
+ }
159
+ function buildOuterContour(w, h, corners, offsets) {
160
+ const left = -offsets.left;
161
+ const top = -offsets.top;
162
+ const right = w + offsets.right;
163
+ const bottom = h + offsets.bottom;
164
+ return {
165
+ left,
166
+ top,
167
+ right,
168
+ bottom,
169
+ tl: {
170
+ cx: corners.tl,
171
+ cy: corners.tl,
172
+ rx: corners.tl + offsets.left,
173
+ ry: corners.tl + offsets.top
174
+ },
175
+ tr: {
176
+ cx: w - corners.tr,
177
+ cy: corners.tr,
178
+ rx: corners.tr + offsets.right,
179
+ ry: corners.tr + offsets.top
180
+ },
181
+ br: {
182
+ cx: w - corners.br,
183
+ cy: h - corners.br,
184
+ rx: corners.br + offsets.right,
185
+ ry: corners.br + offsets.bottom
186
+ },
187
+ bl: {
188
+ cx: corners.bl,
189
+ cy: h - corners.bl,
190
+ rx: corners.bl + offsets.left,
191
+ ry: corners.bl + offsets.bottom
192
+ }
193
+ };
194
+ }
195
+ function buildInnerContour(w, h, corners, offsets) {
196
+ const left = offsets.left;
197
+ const top = offsets.top;
198
+ const right = w - offsets.right;
199
+ const bottom = h - offsets.bottom;
200
+ const tlRx = Math.max(0, corners.tl - offsets.left);
201
+ const tlRy = Math.max(0, corners.tl - offsets.top);
202
+ const trRx = Math.max(0, corners.tr - offsets.right);
203
+ const trRy = Math.max(0, corners.tr - offsets.top);
204
+ const brRx = Math.max(0, corners.br - offsets.right);
205
+ const brRy = Math.max(0, corners.br - offsets.bottom);
206
+ const blRx = Math.max(0, corners.bl - offsets.left);
207
+ const blRy = Math.max(0, corners.bl - offsets.bottom);
208
+ return {
209
+ left,
210
+ top,
211
+ right,
212
+ bottom,
213
+ tl: { cx: left + tlRx, cy: top + tlRy, rx: tlRx, ry: tlRy },
214
+ tr: { cx: right - trRx, cy: top + trRy, rx: trRx, ry: trRy },
215
+ br: { cx: right - brRx, cy: bottom - brRy, rx: brRx, ry: brRy },
216
+ bl: { cx: left + blRx, cy: bottom - blRy, rx: blRx, ry: blRy }
217
+ };
218
+ }
219
+ function averageContours(a, b) {
220
+ const avgCorner = (ca, cb, sideX, sideY, right = false, bottom = false) => {
221
+ const rx = (ca.rx + cb.rx) / 2;
222
+ const ry = (ca.ry + cb.ry) / 2;
223
+ return {
224
+ cx: right ? sideX - rx : sideX + rx,
225
+ cy: bottom ? sideY - ry : sideY + ry,
226
+ rx,
227
+ ry
228
+ };
229
+ };
230
+ return {
231
+ left: (a.left + b.left) / 2,
232
+ top: (a.top + b.top) / 2,
233
+ right: (a.right + b.right) / 2,
234
+ bottom: (a.bottom + b.bottom) / 2,
235
+ tl: avgCorner(a.tl, b.tl, (a.left + b.left) / 2, (a.top + b.top) / 2),
236
+ tr: avgCorner(a.tr, b.tr, (a.right + b.right) / 2, (a.top + b.top) / 2, true, false),
237
+ br: avgCorner(a.br, b.br, (a.right + b.right) / 2, (a.bottom + b.bottom) / 2, true, true),
238
+ bl: avgCorner(a.bl, b.bl, (a.left + b.left) / 2, (a.bottom + b.bottom) / 2, false, true)
239
+ };
240
+ }
241
+ function pointOnEllipse(corner, angle) {
242
+ return {
243
+ x: corner.cx + corner.rx * Math.cos(angle),
244
+ y: corner.cy + corner.ry * Math.sin(angle)
245
+ };
246
+ }
247
+ function pushPoint(points, pt) {
248
+ const last = points[points.length - 1];
249
+ if (!last || Math.abs(last.x - pt.x) > 1e-3 || Math.abs(last.y - pt.y) > 1e-3) {
250
+ points.push(pt);
251
+ }
252
+ }
253
+ function appendEllipseArcPoints(points, corner, startAngle, endAngle) {
254
+ const start = pointOnEllipse(corner, startAngle);
255
+ const end = pointOnEllipse(corner, endAngle);
256
+ pushPoint(points, start);
257
+ if (corner.rx <= 0 || corner.ry <= 0) {
258
+ pushPoint(points, end);
259
+ return;
260
+ }
261
+ const span = endAngle - startAngle;
262
+ const maxR = Math.max(corner.rx, corner.ry);
263
+ const steps = Math.max(1, Math.min(24, Math.ceil(Math.abs(span) * maxR / 8)));
264
+ for (let i = 1; i <= steps; i++) {
265
+ const t = i / steps;
266
+ const angle = startAngle + span * t;
267
+ pushPoint(points, pointOnEllipse(corner, angle));
268
+ }
269
+ }
270
+ function buildContourPoints(contour) {
271
+ const points = [];
272
+ pushPoint(points, { x: contour.tl.cx, y: contour.top });
273
+ pushPoint(points, { x: contour.tr.cx, y: contour.top });
274
+ appendEllipseArcPoints(points, contour.tr, -Math.PI / 2, 0);
275
+ pushPoint(points, { x: contour.right, y: contour.br.cy });
276
+ appendEllipseArcPoints(points, contour.br, 0, Math.PI / 2);
277
+ pushPoint(points, { x: contour.bl.cx, y: contour.bottom });
278
+ appendEllipseArcPoints(points, contour.bl, Math.PI / 2, Math.PI);
279
+ pushPoint(points, { x: contour.left, y: contour.tl.cy });
280
+ appendEllipseArcPoints(points, contour.tl, Math.PI, Math.PI * 1.5);
281
+ return points;
282
+ }
283
+ function traceClosedPath(ctx, points) {
284
+ if (points.length === 0) return;
285
+ if (points[0] === void 0) return;
286
+ ctx.moveTo(points[0].x, points[0].y);
287
+ for (let i = 1; i < points.length; i++) {
288
+ const pt = points[i] ?? { x: 0, y: 0 };
289
+ ctx.lineTo(pt.x, pt.y);
290
+ }
291
+ ctx.closePath();
292
+ }
293
+ function drawSolidBorder(ctx, w, h, sides, corners, color, alpha, align) {
294
+ const offsets = resolveBorderOffsets(sides, align);
295
+ const outer = buildOuterContour(w, h, corners, offsets.outer);
296
+ const inner = buildInnerContour(w, h, corners, offsets.inner);
297
+ const outerPoints = buildContourPoints(outer);
298
+ const innerPoints = buildContourPoints(inner);
299
+ if (outerPoints.length < 3) return;
300
+ ctx.fillStyle(color, alpha);
301
+ ctx.beginPath();
302
+ traceClosedPath(ctx, outerPoints);
303
+ traceClosedPath(ctx, [...innerPoints].reverse());
304
+ ctx.fillPath();
305
+ }
306
+ function appendDashPoint(points, pt) {
307
+ const last = points[points.length - 1];
308
+ if (!last || Math.abs(last.x - pt.x) > 1e-3 || Math.abs(last.y - pt.y) > 1e-3) {
309
+ points.push(pt);
310
+ }
311
+ }
312
+ function strokeDashedPath(ctx, points, widths, color, alpha) {
313
+ if (points.length < 2 || widths.length === 0) return;
314
+ const width = widths.reduce((sum, value) => sum + value, 0) / widths.length;
315
+ if (width <= 0) return;
316
+ ctx.lineStyle(width, color, alpha);
317
+ ctx.beginPath();
318
+ if (points[0] === void 0) return;
319
+ ctx.moveTo(points[0].x, points[0].y);
320
+ for (let i = 1; i < points.length; i++) {
321
+ const pt = points[i];
322
+ if (pt === void 0) continue;
323
+ ctx.lineTo(pt.x, pt.y);
324
+ }
325
+ ctx.strokePath();
326
+ }
327
+ function drawDashedBorder(ctx, w, h, sides, corners, border, color, alpha, align) {
328
+ const segs = buildPerimeterSegments(buildPerimeterPoints(w, h, sides, corners, align));
329
+ if (segs.length === 0) return;
330
+ const maxWidth = Math.max(sides.top, sides.right, sides.bottom, sides.left);
331
+ const dashArray = border.dash ?? [maxWidth * 3, maxWidth * 2];
332
+ const dashOffset = border.dashOffset ?? 0;
333
+ const pattern = dashArray.length % 2 === 0 ? dashArray : [...dashArray, ...dashArray];
334
+ const patternSum = pattern.reduce((a, b) => a + b, 0);
335
+ if (patternSum <= 0) return;
336
+ let patIdx = 0;
337
+ let drawing = true;
338
+ let accumulated = pattern[0] ?? 0;
339
+ let offset = dashOffset % patternSum;
340
+ if (offset < 0) offset += patternSum;
341
+ while (offset > 1e-3) {
342
+ const consume = Math.min(offset, accumulated);
343
+ offset -= consume;
344
+ accumulated -= consume;
345
+ if (accumulated <= 1e-3) {
346
+ patIdx = (patIdx + 1) % pattern.length;
347
+ drawing = !drawing;
348
+ accumulated = pattern[patIdx] ?? 0;
349
+ }
350
+ }
351
+ let dashPoints = [];
352
+ let dashWidths = [];
353
+ const flushDash = () => {
354
+ if (dashPoints.length > 1) {
355
+ strokeDashedPath(ctx, dashPoints, dashWidths, color, alpha);
356
+ }
357
+ dashPoints = [];
358
+ dashWidths = [];
359
+ };
360
+ for (const seg of segs) {
361
+ const sLen = seg.length;
362
+ if (sLen <= 0) continue;
363
+ let t = 0;
364
+ while (t < sLen) {
365
+ const consume = Math.min(accumulated, sLen - t);
366
+ const end = t + consume;
367
+ if (drawing && consume > 0) {
368
+ const p1 = pointAtDistance(seg, t);
369
+ const p2 = pointAtDistance(seg, end);
370
+ if (dashPoints.length === 0) {
371
+ appendDashPoint(dashPoints, p1);
372
+ dashWidths.push(p1.width);
373
+ }
374
+ appendDashPoint(dashPoints, p2);
375
+ dashWidths.push((p1.width + p2.width) / 2);
376
+ }
377
+ t += consume;
378
+ accumulated -= consume;
379
+ if (accumulated <= 1e-3) {
380
+ if (drawing) flushDash();
381
+ patIdx = (patIdx + 1) % pattern.length;
382
+ drawing = !drawing;
383
+ accumulated = pattern[patIdx] ?? 0;
384
+ }
385
+ }
386
+ }
387
+ if (drawing) flushDash();
388
+ }
389
+ function drawDottedBorder(ctx, w, h, sides, corners, border, color, alpha, align) {
390
+ const segs = buildPerimeterSegments(buildPerimeterPoints(w, h, sides, corners, align));
391
+ if (segs.length === 0) return;
392
+ const dotGap = border.dash?.[0] ?? Math.max(sides.top, sides.right, sides.bottom, sides.left);
393
+ const dotDiameterOverride = border.dash?.[1];
394
+ const totalLength = segs.reduce((sum, seg) => sum + seg.length, 0);
395
+ if (totalLength <= 0) return;
396
+ const fallbackDiameter = Math.max(sides.top, sides.right, sides.bottom, sides.left);
397
+ const baseDiameter = dotDiameterOverride ?? fallbackDiameter;
398
+ const step = baseDiameter + dotGap;
399
+ if (step <= 0) return;
400
+ let distance = step / 2 + (border.dashOffset ?? 0);
401
+ while (distance < 0) distance += step;
402
+ for (; distance < totalLength; distance += step) {
403
+ let remaining = distance;
404
+ for (const seg of segs) {
405
+ if (remaining <= seg.length) {
406
+ const pt = pointAtDistance(seg, remaining);
407
+ const dotDiameter = dotDiameterOverride ?? pt.width;
408
+ const dotRadius = dotDiameter / 2;
409
+ if (dotRadius > 0) {
410
+ ctx.fillCircleStyled(pt.x, pt.y, dotRadius, color, alpha);
411
+ }
412
+ break;
413
+ }
414
+ remaining -= seg.length;
415
+ }
416
+ }
417
+ }
418
+ function drawBorderGeometry(ctx, input, border) {
419
+ const { box, sides, corners } = input;
420
+ const { w, h } = box;
421
+ const color = border.color ?? 16777215;
422
+ const alpha = typeof border.alpha === "number" ? border.alpha : 1;
423
+ const maxSw = Math.max(sides.top, sides.right, sides.bottom, sides.left);
424
+ if (maxSw <= 0) return;
425
+ if (w <= 0 || h <= 0) return;
426
+ const align = border.align ?? "center";
427
+ const style = border.style ?? "solid";
428
+ switch (style) {
429
+ case "dotted":
430
+ drawDottedBorder(ctx, w, h, sides, corners, border, color, alpha, align);
431
+ break;
432
+ case "dashed":
433
+ drawDashedBorder(ctx, w, h, sides, corners, border, color, alpha, align);
434
+ break;
435
+ case "solid":
436
+ default:
437
+ drawSolidBorder(ctx, w, h, sides, corners, color, alpha, align);
438
+ break;
439
+ }
440
+ }
441
+ exports.drawBorderGeometry = drawBorderGeometry;
442
+ exports.hasAnyCornerRadius = hasAnyCornerRadius;
443
+ exports.isUniformBorder = isUniformBorder;
444
+ exports.resolveBorderSides = resolveBorderSides;
445
+ exports.resolveCornerRadii = resolveCornerRadii;
446
+ exports.shouldUseCoreBorderGeometry = shouldUseCoreBorderGeometry;
447
+ //# sourceMappingURL=border-geometry.cjs.map