@wardic/solid 0.0.0-stage → 1.0.0-rc.2

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 (994) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -2
  3. package/THIRD_PARTY_NOTICES.md +145 -0
  4. package/dist/browser/animation-controls.js +150 -0
  5. package/dist/browser/animation-controls.js.map +1 -0
  6. package/dist/browser/animation-frame.js +29 -0
  7. package/dist/browser/animation-frame.js.map +1 -0
  8. package/dist/browser/appear.js +727 -0
  9. package/dist/browser/appear.js.map +1 -0
  10. package/dist/browser/arc.js +21 -0
  11. package/dist/browser/arc.js.map +1 -0
  12. package/dist/browser/bridge.js +69 -0
  13. package/dist/browser/bridge.js.map +1 -0
  14. package/dist/browser/complete.js +30 -0
  15. package/dist/browser/complete.js.map +1 -0
  16. package/dist/browser/config.js +2 -0
  17. package/dist/browser/config.js.map +1 -0
  18. package/dist/browser/create-animate.js +41 -0
  19. package/dist/browser/create-animate.js.map +1 -0
  20. package/dist/browser/create-ward.js +1001 -0
  21. package/dist/browser/create-ward.js.map +1 -0
  22. package/dist/browser/cycle-index.js +17 -0
  23. package/dist/browser/cycle-index.js.map +1 -0
  24. package/dist/browser/cycle.js +31 -0
  25. package/dist/browser/cycle.js.map +1 -0
  26. package/dist/browser/directive.js +80 -0
  27. package/dist/browser/directive.js.map +1 -0
  28. package/dist/browser/drag-constraints.js +76 -0
  29. package/dist/browser/drag-constraints.js.map +1 -0
  30. package/dist/browser/drag-controls.js +51 -0
  31. package/dist/browser/drag-controls.js.map +1 -0
  32. package/dist/browser/drag-samples.js +40 -0
  33. package/dist/browser/drag-samples.js.map +1 -0
  34. package/dist/browser/drag-sensor.js +35 -0
  35. package/dist/browser/drag-sensor.js.map +1 -0
  36. package/dist/browser/drag-track.js +817 -0
  37. package/dist/browser/drag-track.js.map +1 -0
  38. package/dist/browser/drag-transition.js +56 -0
  39. package/dist/browser/drag-transition.js.map +1 -0
  40. package/dist/browser/drag.js +44 -0
  41. package/dist/browser/drag.js.map +1 -0
  42. package/dist/browser/element-style.js +67 -0
  43. package/dist/browser/element-style.js.map +1 -0
  44. package/dist/browser/element.js +353 -0
  45. package/dist/browser/element.js.map +1 -0
  46. package/dist/browser/feature-section.js +17 -0
  47. package/dist/browser/feature-section.js.map +1 -0
  48. package/dist/browser/feature.js +261 -0
  49. package/dist/browser/feature.js.map +1 -0
  50. package/dist/browser/features/all.js +10 -0
  51. package/dist/browser/features/all.js.map +1 -0
  52. package/dist/browser/features/colors.js +33 -0
  53. package/dist/browser/features/colors.js.map +1 -0
  54. package/dist/browser/features/dom-animation.js +7 -0
  55. package/dist/browser/features/dom-animation.js.map +1 -0
  56. package/dist/browser/features/dom-max.js +4 -0
  57. package/dist/browser/features/dom-max.js.map +1 -0
  58. package/dist/browser/features/drag.js +28 -0
  59. package/dist/browser/features/drag.js.map +1 -0
  60. package/dist/browser/features/focus.js +18 -0
  61. package/dist/browser/features/focus.js.map +1 -0
  62. package/dist/browser/features/hover.js +18 -0
  63. package/dist/browser/features/hover.js.map +1 -0
  64. package/dist/browser/features/in-view.js +18 -0
  65. package/dist/browser/features/in-view.js.map +1 -0
  66. package/dist/browser/features/input.js +30 -0
  67. package/dist/browser/features/input.js.map +1 -0
  68. package/dist/browser/features/keys.js +19 -0
  69. package/dist/browser/features/keys.js.map +1 -0
  70. package/dist/browser/features/layout.js +33 -0
  71. package/dist/browser/features/layout.js.map +1 -0
  72. package/dist/browser/features/pan.js +18 -0
  73. package/dist/browser/features/pan.js.map +1 -0
  74. package/dist/browser/features/press.js +12 -0
  75. package/dist/browser/features/press.js.map +1 -0
  76. package/dist/browser/focus-sensor.js +23 -0
  77. package/dist/browser/focus-sensor.js.map +1 -0
  78. package/dist/browser/frame-time.js +40 -0
  79. package/dist/browser/frame-time.js.map +1 -0
  80. package/dist/browser/gesture-callbacks.js +172 -0
  81. package/dist/browser/gesture-callbacks.js.map +1 -0
  82. package/dist/browser/gesture-features.js +29 -0
  83. package/dist/browser/gesture-features.js.map +1 -0
  84. package/dist/browser/gesture-info.js +43 -0
  85. package/dist/browser/gesture-info.js.map +1 -0
  86. package/dist/browser/hover-sensor.js +29 -0
  87. package/dist/browser/hover-sensor.js.map +1 -0
  88. package/dist/browser/imperative.js +614 -0
  89. package/dist/browser/imperative.js.map +1 -0
  90. package/dist/browser/index.js +165 -0
  91. package/dist/browser/index.js.map +1 -0
  92. package/dist/browser/instant.js +51 -0
  93. package/dist/browser/instant.js.map +1 -0
  94. package/dist/browser/layout-group.js +27 -0
  95. package/dist/browser/layout-group.js.map +1 -0
  96. package/dist/browser/layout-member.js +362 -0
  97. package/dist/browser/layout-member.js.map +1 -0
  98. package/dist/browser/layout-projection.js +19 -0
  99. package/dist/browser/layout-projection.js.map +1 -0
  100. package/dist/browser/layout.js +91 -0
  101. package/dist/browser/layout.js.map +1 -0
  102. package/dist/browser/live-style.js +313 -0
  103. package/dist/browser/live-style.js.map +1 -0
  104. package/dist/browser/live-value.js +252 -0
  105. package/dist/browser/live-value.js.map +1 -0
  106. package/dist/browser/motion-props.js +172 -0
  107. package/dist/browser/motion-props.js.map +1 -0
  108. package/dist/browser/owner-scope.js +29 -0
  109. package/dist/browser/owner-scope.js.map +1 -0
  110. package/dist/browser/page-point.js +92 -0
  111. package/dist/browser/page-point.js.map +1 -0
  112. package/dist/browser/presence-controller.js +1324 -0
  113. package/dist/browser/presence-controller.js.map +1 -0
  114. package/dist/browser/presence-record.js +27 -0
  115. package/dist/browser/presence-record.js.map +1 -0
  116. package/dist/browser/presence.js +207 -0
  117. package/dist/browser/presence.js.map +1 -0
  118. package/dist/browser/press-sensor.js +30 -0
  119. package/dist/browser/press-sensor.js.map +1 -0
  120. package/dist/browser/press.js +24 -0
  121. package/dist/browser/press.js.map +1 -0
  122. package/dist/browser/provider.js +445 -0
  123. package/dist/browser/provider.js.map +1 -0
  124. package/dist/browser/reactivity.js +9 -0
  125. package/dist/browser/reactivity.js.map +1 -0
  126. package/dist/browser/reorder-input.js +46 -0
  127. package/dist/browser/reorder-input.js.map +1 -0
  128. package/dist/browser/reorder.js +543 -0
  129. package/dist/browser/reorder.js.map +1 -0
  130. package/dist/browser/retarget-legs.js +1019 -0
  131. package/dist/browser/retarget-legs.js.map +1 -0
  132. package/dist/browser/runtime.js +249 -0
  133. package/dist/browser/runtime.js.map +1 -0
  134. package/dist/browser/sensors.js +172 -0
  135. package/dist/browser/sensors.js.map +1 -0
  136. package/dist/browser/server-interpolators.js +20 -0
  137. package/dist/browser/server-interpolators.js.map +1 -0
  138. package/dist/browser/server.js +20 -0
  139. package/dist/browser/server.js.map +1 -0
  140. package/dist/browser/solid-reactivity.js +26 -0
  141. package/dist/browser/solid-reactivity.js.map +1 -0
  142. package/dist/browser/spine.js +2939 -0
  143. package/dist/browser/spine.js.map +1 -0
  144. package/dist/browser/stagger.js +13 -0
  145. package/dist/browser/stagger.js.map +1 -0
  146. package/dist/browser/unstable/v2/bridge.js +76 -0
  147. package/dist/browser/unstable/v2/bridge.js.map +1 -0
  148. package/dist/browser/unstable/v2/complete.js +29 -0
  149. package/dist/browser/unstable/v2/complete.js.map +1 -0
  150. package/dist/browser/unstable/v2/config-view.js +111 -0
  151. package/dist/browser/unstable/v2/config-view.js.map +1 -0
  152. package/dist/browser/unstable/v2/create-animate.js +102 -0
  153. package/dist/browser/unstable/v2/create-animate.js.map +1 -0
  154. package/dist/browser/unstable/v2/cycle.js +30 -0
  155. package/dist/browser/unstable/v2/cycle.js.map +1 -0
  156. package/dist/browser/unstable/v2/drag-sensor.js +34 -0
  157. package/dist/browser/unstable/v2/drag-sensor.js.map +1 -0
  158. package/dist/browser/unstable/v2/element.js +393 -0
  159. package/dist/browser/unstable/v2/element.js.map +1 -0
  160. package/dist/browser/unstable/v2/feature-section.js +27 -0
  161. package/dist/browser/unstable/v2/feature-section.js.map +1 -0
  162. package/dist/browser/unstable/v2/focus-sensor.js +23 -0
  163. package/dist/browser/unstable/v2/focus-sensor.js.map +1 -0
  164. package/dist/browser/unstable/v2/hover-sensor.js +28 -0
  165. package/dist/browser/unstable/v2/hover-sensor.js.map +1 -0
  166. package/dist/browser/unstable/v2/index.js +114 -0
  167. package/dist/browser/unstable/v2/index.js.map +1 -0
  168. package/dist/browser/unstable/v2/layout-projection.js +18 -0
  169. package/dist/browser/unstable/v2/layout-projection.js.map +1 -0
  170. package/dist/browser/unstable/v2/layout.js +71 -0
  171. package/dist/browser/unstable/v2/layout.js.map +1 -0
  172. package/dist/browser/unstable/v2/lifecycle.js +455 -0
  173. package/dist/browser/unstable/v2/lifecycle.js.map +1 -0
  174. package/dist/browser/unstable/v2/live-value.js +264 -0
  175. package/dist/browser/unstable/v2/live-value.js.map +1 -0
  176. package/dist/browser/unstable/v2/presence-handle.js +146 -0
  177. package/dist/browser/unstable/v2/presence-handle.js.map +1 -0
  178. package/dist/browser/unstable/v2/presence-hooks.js +142 -0
  179. package/dist/browser/unstable/v2/presence-hooks.js.map +1 -0
  180. package/dist/browser/unstable/v2/presence.js +124 -0
  181. package/dist/browser/unstable/v2/presence.js.map +1 -0
  182. package/dist/browser/unstable/v2/press-sensor.js +29 -0
  183. package/dist/browser/unstable/v2/press-sensor.js.map +1 -0
  184. package/dist/browser/unstable/v2/provider.js +457 -0
  185. package/dist/browser/unstable/v2/provider.js.map +1 -0
  186. package/dist/browser/unstable/v2/reorder.js +663 -0
  187. package/dist/browser/unstable/v2/reorder.js.map +1 -0
  188. package/dist/browser/unstable/v2/sensors.js +138 -0
  189. package/dist/browser/unstable/v2/sensors.js.map +1 -0
  190. package/dist/browser/unstable/v2/solid-reactivity.js +82 -0
  191. package/dist/browser/unstable/v2/solid-reactivity.js.map +1 -0
  192. package/dist/browser/unstable/v2/variant-node.js +395 -0
  193. package/dist/browser/unstable/v2/variant-node.js.map +1 -0
  194. package/dist/browser/unstable/v2/w.js +23 -0
  195. package/dist/browser/unstable/v2/w.js.map +1 -0
  196. package/dist/browser/unstable/v2/waiters.js +185 -0
  197. package/dist/browser/unstable/v2/waiters.js.map +1 -0
  198. package/dist/browser/unstable/v2/ward.js +1620 -0
  199. package/dist/browser/unstable/v2/ward.js.map +1 -0
  200. package/dist/browser/unstable/v2/wardic-config.js +40 -0
  201. package/dist/browser/unstable/v2/wardic-config.js.map +1 -0
  202. package/dist/browser/unstable/v2/wardic.js +16 -0
  203. package/dist/browser/unstable/v2/wardic.js.map +1 -0
  204. package/dist/browser/variant-node.js +308 -0
  205. package/dist/browser/variant-node.js.map +1 -0
  206. package/dist/browser/variant-target.js +224 -0
  207. package/dist/browser/variant-target.js.map +1 -0
  208. package/dist/browser/variant-tree.js +394 -0
  209. package/dist/browser/variant-tree.js.map +1 -0
  210. package/dist/browser/variants.js +43 -0
  211. package/dist/browser/variants.js.map +1 -0
  212. package/dist/browser/w.js +25 -0
  213. package/dist/browser/w.js.map +1 -0
  214. package/dist/browser/ward-keys.js +2 -0
  215. package/dist/browser/ward-keys.js.map +1 -0
  216. package/dist/browser/wardic-component.js +74 -0
  217. package/dist/browser/wardic-component.js.map +1 -0
  218. package/dist/browser/wardic-config-value.js +91 -0
  219. package/dist/browser/wardic-config-value.js.map +1 -0
  220. package/dist/browser/wardic-config.js +42 -0
  221. package/dist/browser/wardic-config.js.map +1 -0
  222. package/dist/browser/wardic.js +31 -0
  223. package/dist/browser/wardic.js.map +1 -0
  224. package/dist/server/animation-controls.js +150 -0
  225. package/dist/server/animation-controls.js.map +1 -0
  226. package/dist/server/animation-frame.js +29 -0
  227. package/dist/server/animation-frame.js.map +1 -0
  228. package/dist/server/appear.js +727 -0
  229. package/dist/server/appear.js.map +1 -0
  230. package/dist/server/arc.js +21 -0
  231. package/dist/server/arc.js.map +1 -0
  232. package/dist/server/bridge.js +69 -0
  233. package/dist/server/bridge.js.map +1 -0
  234. package/dist/server/complete.js +30 -0
  235. package/dist/server/complete.js.map +1 -0
  236. package/dist/server/config.js +2 -0
  237. package/dist/server/config.js.map +1 -0
  238. package/dist/server/create-animate.js +41 -0
  239. package/dist/server/create-animate.js.map +1 -0
  240. package/dist/server/create-ward.js +1001 -0
  241. package/dist/server/create-ward.js.map +1 -0
  242. package/dist/server/cycle-index.js +17 -0
  243. package/dist/server/cycle-index.js.map +1 -0
  244. package/dist/server/cycle.js +31 -0
  245. package/dist/server/cycle.js.map +1 -0
  246. package/dist/server/directive.js +80 -0
  247. package/dist/server/directive.js.map +1 -0
  248. package/dist/server/drag-constraints.js +76 -0
  249. package/dist/server/drag-constraints.js.map +1 -0
  250. package/dist/server/drag-controls.js +51 -0
  251. package/dist/server/drag-controls.js.map +1 -0
  252. package/dist/server/drag-samples.js +40 -0
  253. package/dist/server/drag-samples.js.map +1 -0
  254. package/dist/server/drag-sensor.js +35 -0
  255. package/dist/server/drag-sensor.js.map +1 -0
  256. package/dist/server/drag-track.js +817 -0
  257. package/dist/server/drag-track.js.map +1 -0
  258. package/dist/server/drag-transition.js +56 -0
  259. package/dist/server/drag-transition.js.map +1 -0
  260. package/dist/server/drag.js +44 -0
  261. package/dist/server/drag.js.map +1 -0
  262. package/dist/server/element-style.js +67 -0
  263. package/dist/server/element-style.js.map +1 -0
  264. package/dist/server/element.js +353 -0
  265. package/dist/server/element.js.map +1 -0
  266. package/dist/server/feature-section.js +17 -0
  267. package/dist/server/feature-section.js.map +1 -0
  268. package/dist/server/feature.js +261 -0
  269. package/dist/server/feature.js.map +1 -0
  270. package/dist/server/features/all.js +10 -0
  271. package/dist/server/features/all.js.map +1 -0
  272. package/dist/server/features/colors.js +33 -0
  273. package/dist/server/features/colors.js.map +1 -0
  274. package/dist/server/features/dom-animation.js +7 -0
  275. package/dist/server/features/dom-animation.js.map +1 -0
  276. package/dist/server/features/dom-max.js +4 -0
  277. package/dist/server/features/dom-max.js.map +1 -0
  278. package/dist/server/features/drag.js +28 -0
  279. package/dist/server/features/drag.js.map +1 -0
  280. package/dist/server/features/focus.js +18 -0
  281. package/dist/server/features/focus.js.map +1 -0
  282. package/dist/server/features/hover.js +18 -0
  283. package/dist/server/features/hover.js.map +1 -0
  284. package/dist/server/features/in-view.js +18 -0
  285. package/dist/server/features/in-view.js.map +1 -0
  286. package/dist/server/features/input.js +30 -0
  287. package/dist/server/features/input.js.map +1 -0
  288. package/dist/server/features/keys.js +19 -0
  289. package/dist/server/features/keys.js.map +1 -0
  290. package/dist/server/features/layout.js +33 -0
  291. package/dist/server/features/layout.js.map +1 -0
  292. package/dist/server/features/pan.js +18 -0
  293. package/dist/server/features/pan.js.map +1 -0
  294. package/dist/server/features/press.js +12 -0
  295. package/dist/server/features/press.js.map +1 -0
  296. package/dist/server/focus-sensor.js +23 -0
  297. package/dist/server/focus-sensor.js.map +1 -0
  298. package/dist/server/frame-time.js +40 -0
  299. package/dist/server/frame-time.js.map +1 -0
  300. package/dist/server/gesture-callbacks.js +172 -0
  301. package/dist/server/gesture-callbacks.js.map +1 -0
  302. package/dist/server/gesture-features.js +29 -0
  303. package/dist/server/gesture-features.js.map +1 -0
  304. package/dist/server/gesture-info.js +43 -0
  305. package/dist/server/gesture-info.js.map +1 -0
  306. package/dist/server/hover-sensor.js +29 -0
  307. package/dist/server/hover-sensor.js.map +1 -0
  308. package/dist/server/imperative.js +614 -0
  309. package/dist/server/imperative.js.map +1 -0
  310. package/dist/server/index.js +165 -0
  311. package/dist/server/index.js.map +1 -0
  312. package/dist/server/instant.js +51 -0
  313. package/dist/server/instant.js.map +1 -0
  314. package/dist/server/layout-group.js +27 -0
  315. package/dist/server/layout-group.js.map +1 -0
  316. package/dist/server/layout-member.js +362 -0
  317. package/dist/server/layout-member.js.map +1 -0
  318. package/dist/server/layout-projection.js +19 -0
  319. package/dist/server/layout-projection.js.map +1 -0
  320. package/dist/server/layout.js +90 -0
  321. package/dist/server/layout.js.map +1 -0
  322. package/dist/server/live-style.js +313 -0
  323. package/dist/server/live-style.js.map +1 -0
  324. package/dist/server/live-value.js +252 -0
  325. package/dist/server/live-value.js.map +1 -0
  326. package/dist/server/motion-props.js +172 -0
  327. package/dist/server/motion-props.js.map +1 -0
  328. package/dist/server/owner-scope.js +29 -0
  329. package/dist/server/owner-scope.js.map +1 -0
  330. package/dist/server/page-point.js +92 -0
  331. package/dist/server/page-point.js.map +1 -0
  332. package/dist/server/presence-controller.js +1324 -0
  333. package/dist/server/presence-controller.js.map +1 -0
  334. package/dist/server/presence-record.js +27 -0
  335. package/dist/server/presence-record.js.map +1 -0
  336. package/dist/server/presence.js +207 -0
  337. package/dist/server/presence.js.map +1 -0
  338. package/dist/server/press-sensor.js +30 -0
  339. package/dist/server/press-sensor.js.map +1 -0
  340. package/dist/server/press.js +24 -0
  341. package/dist/server/press.js.map +1 -0
  342. package/dist/server/provider.js +439 -0
  343. package/dist/server/provider.js.map +1 -0
  344. package/dist/server/reactivity.js +9 -0
  345. package/dist/server/reactivity.js.map +1 -0
  346. package/dist/server/reorder-input.js +46 -0
  347. package/dist/server/reorder-input.js.map +1 -0
  348. package/dist/server/reorder.js +543 -0
  349. package/dist/server/reorder.js.map +1 -0
  350. package/dist/server/retarget-legs.js +1019 -0
  351. package/dist/server/retarget-legs.js.map +1 -0
  352. package/dist/server/runtime.js +249 -0
  353. package/dist/server/runtime.js.map +1 -0
  354. package/dist/server/sensors.js +172 -0
  355. package/dist/server/sensors.js.map +1 -0
  356. package/dist/server/server-interpolators.js +20 -0
  357. package/dist/server/server-interpolators.js.map +1 -0
  358. package/dist/server/server.js +20 -0
  359. package/dist/server/server.js.map +1 -0
  360. package/dist/server/solid-reactivity.js +26 -0
  361. package/dist/server/solid-reactivity.js.map +1 -0
  362. package/dist/server/spine.js +2939 -0
  363. package/dist/server/spine.js.map +1 -0
  364. package/dist/server/stagger.js +13 -0
  365. package/dist/server/stagger.js.map +1 -0
  366. package/dist/server/unstable/v2/bridge.js +76 -0
  367. package/dist/server/unstable/v2/bridge.js.map +1 -0
  368. package/dist/server/unstable/v2/complete.js +29 -0
  369. package/dist/server/unstable/v2/complete.js.map +1 -0
  370. package/dist/server/unstable/v2/config-view.js +111 -0
  371. package/dist/server/unstable/v2/config-view.js.map +1 -0
  372. package/dist/server/unstable/v2/create-animate.js +102 -0
  373. package/dist/server/unstable/v2/create-animate.js.map +1 -0
  374. package/dist/server/unstable/v2/cycle.js +30 -0
  375. package/dist/server/unstable/v2/cycle.js.map +1 -0
  376. package/dist/server/unstable/v2/drag-sensor.js +34 -0
  377. package/dist/server/unstable/v2/drag-sensor.js.map +1 -0
  378. package/dist/server/unstable/v2/element.js +402 -0
  379. package/dist/server/unstable/v2/element.js.map +1 -0
  380. package/dist/server/unstable/v2/feature-section.js +27 -0
  381. package/dist/server/unstable/v2/feature-section.js.map +1 -0
  382. package/dist/server/unstable/v2/focus-sensor.js +23 -0
  383. package/dist/server/unstable/v2/focus-sensor.js.map +1 -0
  384. package/dist/server/unstable/v2/hover-sensor.js +28 -0
  385. package/dist/server/unstable/v2/hover-sensor.js.map +1 -0
  386. package/dist/server/unstable/v2/index.js +114 -0
  387. package/dist/server/unstable/v2/index.js.map +1 -0
  388. package/dist/server/unstable/v2/layout-projection.js +18 -0
  389. package/dist/server/unstable/v2/layout-projection.js.map +1 -0
  390. package/dist/server/unstable/v2/layout.js +88 -0
  391. package/dist/server/unstable/v2/layout.js.map +1 -0
  392. package/dist/server/unstable/v2/lifecycle.js +455 -0
  393. package/dist/server/unstable/v2/lifecycle.js.map +1 -0
  394. package/dist/server/unstable/v2/live-value.js +264 -0
  395. package/dist/server/unstable/v2/live-value.js.map +1 -0
  396. package/dist/server/unstable/v2/presence-handle.js +146 -0
  397. package/dist/server/unstable/v2/presence-handle.js.map +1 -0
  398. package/dist/server/unstable/v2/presence-hooks.js +142 -0
  399. package/dist/server/unstable/v2/presence-hooks.js.map +1 -0
  400. package/dist/server/unstable/v2/presence.js +142 -0
  401. package/dist/server/unstable/v2/presence.js.map +1 -0
  402. package/dist/server/unstable/v2/press-sensor.js +29 -0
  403. package/dist/server/unstable/v2/press-sensor.js.map +1 -0
  404. package/dist/server/unstable/v2/provider.js +475 -0
  405. package/dist/server/unstable/v2/provider.js.map +1 -0
  406. package/dist/server/unstable/v2/reorder.js +733 -0
  407. package/dist/server/unstable/v2/reorder.js.map +1 -0
  408. package/dist/server/unstable/v2/sensors.js +138 -0
  409. package/dist/server/unstable/v2/sensors.js.map +1 -0
  410. package/dist/server/unstable/v2/solid-reactivity.js +82 -0
  411. package/dist/server/unstable/v2/solid-reactivity.js.map +1 -0
  412. package/dist/server/unstable/v2/variant-node.js +395 -0
  413. package/dist/server/unstable/v2/variant-node.js.map +1 -0
  414. package/dist/server/unstable/v2/w.js +23 -0
  415. package/dist/server/unstable/v2/w.js.map +1 -0
  416. package/dist/server/unstable/v2/waiters.js +185 -0
  417. package/dist/server/unstable/v2/waiters.js.map +1 -0
  418. package/dist/server/unstable/v2/ward.js +1653 -0
  419. package/dist/server/unstable/v2/ward.js.map +1 -0
  420. package/dist/server/unstable/v2/wardic-config.js +49 -0
  421. package/dist/server/unstable/v2/wardic-config.js.map +1 -0
  422. package/dist/server/unstable/v2/wardic.js +16 -0
  423. package/dist/server/unstable/v2/wardic.js.map +1 -0
  424. package/dist/server/variant-node.js +308 -0
  425. package/dist/server/variant-node.js.map +1 -0
  426. package/dist/server/variant-target.js +224 -0
  427. package/dist/server/variant-target.js.map +1 -0
  428. package/dist/server/variant-tree.js +394 -0
  429. package/dist/server/variant-tree.js.map +1 -0
  430. package/dist/server/variants.js +43 -0
  431. package/dist/server/variants.js.map +1 -0
  432. package/dist/server/w.js +25 -0
  433. package/dist/server/w.js.map +1 -0
  434. package/dist/server/ward-keys.js +2 -0
  435. package/dist/server/ward-keys.js.map +1 -0
  436. package/dist/server/wardic-component.js +74 -0
  437. package/dist/server/wardic-component.js.map +1 -0
  438. package/dist/server/wardic-config-value.js +91 -0
  439. package/dist/server/wardic-config-value.js.map +1 -0
  440. package/dist/server/wardic-config.js +42 -0
  441. package/dist/server/wardic-config.js.map +1 -0
  442. package/dist/server/wardic.js +31 -0
  443. package/dist/server/wardic.js.map +1 -0
  444. package/dist/solid/animation-controls.d.ts +104 -0
  445. package/dist/solid/animation-controls.d.ts.map +1 -0
  446. package/dist/solid/animation-controls.js +129 -0
  447. package/dist/solid/animation-controls.js.map +1 -0
  448. package/dist/solid/animation-frame.d.ts +11 -0
  449. package/dist/solid/animation-frame.d.ts.map +1 -0
  450. package/dist/solid/animation-frame.js +31 -0
  451. package/dist/solid/animation-frame.js.map +1 -0
  452. package/dist/solid/appear.d.ts +205 -0
  453. package/dist/solid/appear.d.ts.map +1 -0
  454. package/dist/solid/appear.js +519 -0
  455. package/dist/solid/appear.js.map +1 -0
  456. package/dist/solid/arc.d.ts +25 -0
  457. package/dist/solid/arc.d.ts.map +1 -0
  458. package/dist/solid/arc.js +21 -0
  459. package/dist/solid/arc.js.map +1 -0
  460. package/dist/solid/bridge.d.ts +53 -0
  461. package/dist/solid/bridge.d.ts.map +1 -0
  462. package/dist/solid/bridge.js +66 -0
  463. package/dist/solid/bridge.js.map +1 -0
  464. package/dist/solid/complete.d.ts +31 -0
  465. package/dist/solid/complete.d.ts.map +1 -0
  466. package/dist/solid/complete.js +27 -0
  467. package/dist/solid/complete.js.map +1 -0
  468. package/dist/solid/config.d.ts +693 -0
  469. package/dist/solid/config.d.ts.map +1 -0
  470. package/dist/solid/config.js +2 -0
  471. package/dist/solid/config.js.map +1 -0
  472. package/dist/solid/create-animate.d.ts +17 -0
  473. package/dist/solid/create-animate.d.ts.map +1 -0
  474. package/dist/solid/create-animate.js +42 -0
  475. package/dist/solid/create-animate.js.map +1 -0
  476. package/dist/solid/create-ward.d.ts +278 -0
  477. package/dist/solid/create-ward.d.ts.map +1 -0
  478. package/dist/solid/create-ward.jsx +874 -0
  479. package/dist/solid/create-ward.jsx.map +1 -0
  480. package/dist/solid/cycle-index.d.ts +7 -0
  481. package/dist/solid/cycle-index.d.ts.map +1 -0
  482. package/dist/solid/cycle-index.js +17 -0
  483. package/dist/solid/cycle-index.js.map +1 -0
  484. package/dist/solid/cycle.d.ts +21 -0
  485. package/dist/solid/cycle.d.ts.map +1 -0
  486. package/dist/solid/cycle.js +31 -0
  487. package/dist/solid/cycle.js.map +1 -0
  488. package/dist/solid/directive.d.ts +21 -0
  489. package/dist/solid/directive.d.ts.map +1 -0
  490. package/dist/solid/directive.js +76 -0
  491. package/dist/solid/directive.js.map +1 -0
  492. package/dist/solid/drag-constraints.d.ts +46 -0
  493. package/dist/solid/drag-constraints.d.ts.map +1 -0
  494. package/dist/solid/drag-constraints.js +49 -0
  495. package/dist/solid/drag-constraints.js.map +1 -0
  496. package/dist/solid/drag-controls.d.ts +50 -0
  497. package/dist/solid/drag-controls.d.ts.map +1 -0
  498. package/dist/solid/drag-controls.js +51 -0
  499. package/dist/solid/drag-controls.js.map +1 -0
  500. package/dist/solid/drag-samples.d.ts +34 -0
  501. package/dist/solid/drag-samples.d.ts.map +1 -0
  502. package/dist/solid/drag-samples.js +28 -0
  503. package/dist/solid/drag-samples.js.map +1 -0
  504. package/dist/solid/drag-sensor.d.ts +23 -0
  505. package/dist/solid/drag-sensor.d.ts.map +1 -0
  506. package/dist/solid/drag-sensor.js +33 -0
  507. package/dist/solid/drag-sensor.js.map +1 -0
  508. package/dist/solid/drag-track.d.ts +227 -0
  509. package/dist/solid/drag-track.d.ts.map +1 -0
  510. package/dist/solid/drag-track.js +631 -0
  511. package/dist/solid/drag-track.js.map +1 -0
  512. package/dist/solid/drag-transition.d.ts +20 -0
  513. package/dist/solid/drag-transition.d.ts.map +1 -0
  514. package/dist/solid/drag-transition.js +31 -0
  515. package/dist/solid/drag-transition.js.map +1 -0
  516. package/dist/solid/drag.d.ts +23 -0
  517. package/dist/solid/drag.d.ts.map +1 -0
  518. package/dist/solid/drag.js +44 -0
  519. package/dist/solid/drag.js.map +1 -0
  520. package/dist/solid/element-style.d.ts +60 -0
  521. package/dist/solid/element-style.d.ts.map +1 -0
  522. package/dist/solid/element-style.js +50 -0
  523. package/dist/solid/element-style.js.map +1 -0
  524. package/dist/solid/element.d.ts +73 -0
  525. package/dist/solid/element.d.ts.map +1 -0
  526. package/dist/solid/element.jsx +326 -0
  527. package/dist/solid/element.jsx.map +1 -0
  528. package/dist/solid/feature-section.d.ts +18 -0
  529. package/dist/solid/feature-section.d.ts.map +1 -0
  530. package/dist/solid/feature-section.js +13 -0
  531. package/dist/solid/feature-section.js.map +1 -0
  532. package/dist/solid/feature.d.ts +114 -0
  533. package/dist/solid/feature.d.ts.map +1 -0
  534. package/dist/solid/feature.js +248 -0
  535. package/dist/solid/feature.js.map +1 -0
  536. package/dist/solid/features/all.d.ts +10 -0
  537. package/dist/solid/features/all.d.ts.map +1 -0
  538. package/dist/solid/features/all.js +10 -0
  539. package/dist/solid/features/all.js.map +1 -0
  540. package/dist/solid/features/colors.d.ts +12 -0
  541. package/dist/solid/features/colors.d.ts.map +1 -0
  542. package/dist/solid/features/colors.js +34 -0
  543. package/dist/solid/features/colors.js.map +1 -0
  544. package/dist/solid/features/dom-animation.d.ts +11 -0
  545. package/dist/solid/features/dom-animation.d.ts.map +1 -0
  546. package/dist/solid/features/dom-animation.js +7 -0
  547. package/dist/solid/features/dom-animation.js.map +1 -0
  548. package/dist/solid/features/dom-max.d.ts +10 -0
  549. package/dist/solid/features/dom-max.d.ts.map +1 -0
  550. package/dist/solid/features/dom-max.js +4 -0
  551. package/dist/solid/features/dom-max.js.map +1 -0
  552. package/dist/solid/features/drag.d.ts +5 -0
  553. package/dist/solid/features/drag.d.ts.map +1 -0
  554. package/dist/solid/features/drag.js +28 -0
  555. package/dist/solid/features/drag.js.map +1 -0
  556. package/dist/solid/features/focus.d.ts +5 -0
  557. package/dist/solid/features/focus.d.ts.map +1 -0
  558. package/dist/solid/features/focus.js +16 -0
  559. package/dist/solid/features/focus.js.map +1 -0
  560. package/dist/solid/features/hover.d.ts +5 -0
  561. package/dist/solid/features/hover.d.ts.map +1 -0
  562. package/dist/solid/features/hover.js +16 -0
  563. package/dist/solid/features/hover.js.map +1 -0
  564. package/dist/solid/features/in-view.d.ts +5 -0
  565. package/dist/solid/features/in-view.d.ts.map +1 -0
  566. package/dist/solid/features/in-view.js +16 -0
  567. package/dist/solid/features/in-view.js.map +1 -0
  568. package/dist/solid/features/input.d.ts +26 -0
  569. package/dist/solid/features/input.d.ts.map +1 -0
  570. package/dist/solid/features/input.js +31 -0
  571. package/dist/solid/features/input.js.map +1 -0
  572. package/dist/solid/features/keys.d.ts +70 -0
  573. package/dist/solid/features/keys.d.ts.map +1 -0
  574. package/dist/solid/features/keys.js +26 -0
  575. package/dist/solid/features/keys.js.map +1 -0
  576. package/dist/solid/features/layout.d.ts +32 -0
  577. package/dist/solid/features/layout.d.ts.map +1 -0
  578. package/dist/solid/features/layout.js +34 -0
  579. package/dist/solid/features/layout.js.map +1 -0
  580. package/dist/solid/features/pan.d.ts +5 -0
  581. package/dist/solid/features/pan.d.ts.map +1 -0
  582. package/dist/solid/features/pan.js +16 -0
  583. package/dist/solid/features/pan.js.map +1 -0
  584. package/dist/solid/features/press.d.ts +11 -0
  585. package/dist/solid/features/press.d.ts.map +1 -0
  586. package/dist/solid/features/press.js +10 -0
  587. package/dist/solid/features/press.js.map +1 -0
  588. package/dist/solid/focus-sensor.d.ts +19 -0
  589. package/dist/solid/focus-sensor.d.ts.map +1 -0
  590. package/dist/solid/focus-sensor.js +23 -0
  591. package/dist/solid/focus-sensor.js.map +1 -0
  592. package/dist/solid/frame-time.d.ts +21 -0
  593. package/dist/solid/frame-time.d.ts.map +1 -0
  594. package/dist/solid/frame-time.js +41 -0
  595. package/dist/solid/frame-time.js.map +1 -0
  596. package/dist/solid/gesture-callbacks.d.ts +53 -0
  597. package/dist/solid/gesture-callbacks.d.ts.map +1 -0
  598. package/dist/solid/gesture-callbacks.js +184 -0
  599. package/dist/solid/gesture-callbacks.js.map +1 -0
  600. package/dist/solid/gesture-features.d.ts +28 -0
  601. package/dist/solid/gesture-features.d.ts.map +1 -0
  602. package/dist/solid/gesture-features.js +29 -0
  603. package/dist/solid/gesture-features.js.map +1 -0
  604. package/dist/solid/gesture-info.d.ts +59 -0
  605. package/dist/solid/gesture-info.d.ts.map +1 -0
  606. package/dist/solid/gesture-info.js +23 -0
  607. package/dist/solid/gesture-info.js.map +1 -0
  608. package/dist/solid/hover-sensor.d.ts +19 -0
  609. package/dist/solid/hover-sensor.d.ts.map +1 -0
  610. package/dist/solid/hover-sensor.js +23 -0
  611. package/dist/solid/hover-sensor.js.map +1 -0
  612. package/dist/solid/imperative.d.ts +195 -0
  613. package/dist/solid/imperative.d.ts.map +1 -0
  614. package/dist/solid/imperative.js +536 -0
  615. package/dist/solid/imperative.js.map +1 -0
  616. package/dist/solid/index.d.ts +180 -0
  617. package/dist/solid/index.d.ts.map +1 -0
  618. package/dist/solid/index.js +165 -0
  619. package/dist/solid/index.js.map +1 -0
  620. package/dist/solid/instant.d.ts +44 -0
  621. package/dist/solid/instant.d.ts.map +1 -0
  622. package/dist/solid/instant.js +49 -0
  623. package/dist/solid/instant.js.map +1 -0
  624. package/dist/solid/layout-group.d.ts +14 -0
  625. package/dist/solid/layout-group.d.ts.map +1 -0
  626. package/dist/solid/layout-group.js +27 -0
  627. package/dist/solid/layout-group.js.map +1 -0
  628. package/dist/solid/layout-member.d.ts +117 -0
  629. package/dist/solid/layout-member.d.ts.map +1 -0
  630. package/dist/solid/layout-member.js +164 -0
  631. package/dist/solid/layout-member.js.map +1 -0
  632. package/dist/solid/layout-projection.d.ts +22 -0
  633. package/dist/solid/layout-projection.d.ts.map +1 -0
  634. package/dist/solid/layout-projection.js +19 -0
  635. package/dist/solid/layout-projection.js.map +1 -0
  636. package/dist/solid/layout.d.ts +76 -0
  637. package/dist/solid/layout.d.ts.map +1 -0
  638. package/dist/solid/layout.jsx +80 -0
  639. package/dist/solid/layout.jsx.map +1 -0
  640. package/dist/solid/live-style.d.ts +147 -0
  641. package/dist/solid/live-style.d.ts.map +1 -0
  642. package/dist/solid/live-style.js +304 -0
  643. package/dist/solid/live-style.js.map +1 -0
  644. package/dist/solid/live-value.d.ts +144 -0
  645. package/dist/solid/live-value.d.ts.map +1 -0
  646. package/dist/solid/live-value.js +223 -0
  647. package/dist/solid/live-value.js.map +1 -0
  648. package/dist/solid/motion-props.d.ts +75 -0
  649. package/dist/solid/motion-props.d.ts.map +1 -0
  650. package/dist/solid/motion-props.js +314 -0
  651. package/dist/solid/motion-props.js.map +1 -0
  652. package/dist/solid/owner-scope.d.ts +16 -0
  653. package/dist/solid/owner-scope.d.ts.map +1 -0
  654. package/dist/solid/owner-scope.js +31 -0
  655. package/dist/solid/owner-scope.js.map +1 -0
  656. package/dist/solid/page-point.d.ts +35 -0
  657. package/dist/solid/page-point.d.ts.map +1 -0
  658. package/dist/solid/page-point.js +87 -0
  659. package/dist/solid/page-point.js.map +1 -0
  660. package/dist/solid/presence-controller.d.ts +122 -0
  661. package/dist/solid/presence-controller.d.ts.map +1 -0
  662. package/dist/solid/presence-controller.js +1207 -0
  663. package/dist/solid/presence-controller.js.map +1 -0
  664. package/dist/solid/presence-record.d.ts +167 -0
  665. package/dist/solid/presence-record.d.ts.map +1 -0
  666. package/dist/solid/presence-record.js +26 -0
  667. package/dist/solid/presence-record.js.map +1 -0
  668. package/dist/solid/presence.d.ts +95 -0
  669. package/dist/solid/presence.d.ts.map +1 -0
  670. package/dist/solid/presence.jsx +195 -0
  671. package/dist/solid/presence.jsx.map +1 -0
  672. package/dist/solid/press-sensor.d.ts +20 -0
  673. package/dist/solid/press-sensor.d.ts.map +1 -0
  674. package/dist/solid/press-sensor.js +24 -0
  675. package/dist/solid/press-sensor.js.map +1 -0
  676. package/dist/solid/press.d.ts +24 -0
  677. package/dist/solid/press.d.ts.map +1 -0
  678. package/dist/solid/press.js +19 -0
  679. package/dist/solid/press.js.map +1 -0
  680. package/dist/solid/provider.d.ts +263 -0
  681. package/dist/solid/provider.d.ts.map +1 -0
  682. package/dist/solid/provider.jsx +411 -0
  683. package/dist/solid/provider.jsx.map +1 -0
  684. package/dist/solid/reactivity.d.ts +27 -0
  685. package/dist/solid/reactivity.d.ts.map +1 -0
  686. package/dist/solid/reactivity.js +9 -0
  687. package/dist/solid/reactivity.js.map +1 -0
  688. package/dist/solid/reorder-input.d.ts +22 -0
  689. package/dist/solid/reorder-input.d.ts.map +1 -0
  690. package/dist/solid/reorder-input.js +45 -0
  691. package/dist/solid/reorder-input.js.map +1 -0
  692. package/dist/solid/reorder.d.ts +241 -0
  693. package/dist/solid/reorder.d.ts.map +1 -0
  694. package/dist/solid/reorder.jsx +427 -0
  695. package/dist/solid/reorder.jsx.map +1 -0
  696. package/dist/solid/retarget-legs.d.ts +189 -0
  697. package/dist/solid/retarget-legs.d.ts.map +1 -0
  698. package/dist/solid/retarget-legs.js +825 -0
  699. package/dist/solid/retarget-legs.js.map +1 -0
  700. package/dist/solid/runtime.d.ts +179 -0
  701. package/dist/solid/runtime.d.ts.map +1 -0
  702. package/dist/solid/runtime.js +237 -0
  703. package/dist/solid/runtime.js.map +1 -0
  704. package/dist/solid/sensors.d.ts +95 -0
  705. package/dist/solid/sensors.d.ts.map +1 -0
  706. package/dist/solid/sensors.js +154 -0
  707. package/dist/solid/sensors.js.map +1 -0
  708. package/dist/solid/server-interpolators.d.ts +13 -0
  709. package/dist/solid/server-interpolators.d.ts.map +1 -0
  710. package/dist/solid/server-interpolators.js +20 -0
  711. package/dist/solid/server-interpolators.js.map +1 -0
  712. package/dist/solid/server.d.ts +9 -0
  713. package/dist/solid/server.d.ts.map +1 -0
  714. package/dist/solid/server.js +20 -0
  715. package/dist/solid/server.js.map +1 -0
  716. package/dist/solid/solid-reactivity.d.ts +3 -0
  717. package/dist/solid/solid-reactivity.d.ts.map +1 -0
  718. package/dist/solid/solid-reactivity.js +19 -0
  719. package/dist/solid/solid-reactivity.js.map +1 -0
  720. package/dist/solid/spine.d.ts +597 -0
  721. package/dist/solid/spine.d.ts.map +1 -0
  722. package/dist/solid/spine.js +2761 -0
  723. package/dist/solid/spine.js.map +1 -0
  724. package/dist/solid/stagger.d.ts +29 -0
  725. package/dist/solid/stagger.d.ts.map +1 -0
  726. package/dist/solid/stagger.js +13 -0
  727. package/dist/solid/stagger.js.map +1 -0
  728. package/dist/solid/unstable/v2/bridge.d.ts +33 -0
  729. package/dist/solid/unstable/v2/bridge.d.ts.map +1 -0
  730. package/dist/solid/unstable/v2/bridge.js +76 -0
  731. package/dist/solid/unstable/v2/bridge.js.map +1 -0
  732. package/dist/solid/unstable/v2/complete.d.ts +21 -0
  733. package/dist/solid/unstable/v2/complete.d.ts.map +1 -0
  734. package/dist/solid/unstable/v2/complete.js +27 -0
  735. package/dist/solid/unstable/v2/complete.js.map +1 -0
  736. package/dist/solid/unstable/v2/config-view.d.ts +49 -0
  737. package/dist/solid/unstable/v2/config-view.d.ts.map +1 -0
  738. package/dist/solid/unstable/v2/config-view.js +114 -0
  739. package/dist/solid/unstable/v2/config-view.js.map +1 -0
  740. package/dist/solid/unstable/v2/create-animate.d.ts +31 -0
  741. package/dist/solid/unstable/v2/create-animate.d.ts.map +1 -0
  742. package/dist/solid/unstable/v2/create-animate.js +102 -0
  743. package/dist/solid/unstable/v2/create-animate.js.map +1 -0
  744. package/dist/solid/unstable/v2/cycle.d.ts +20 -0
  745. package/dist/solid/unstable/v2/cycle.d.ts.map +1 -0
  746. package/dist/solid/unstable/v2/cycle.js +30 -0
  747. package/dist/solid/unstable/v2/cycle.js.map +1 -0
  748. package/dist/solid/unstable/v2/drag-sensor.d.ts +23 -0
  749. package/dist/solid/unstable/v2/drag-sensor.d.ts.map +1 -0
  750. package/dist/solid/unstable/v2/drag-sensor.js +32 -0
  751. package/dist/solid/unstable/v2/drag-sensor.js.map +1 -0
  752. package/dist/solid/unstable/v2/element.d.ts +178 -0
  753. package/dist/solid/unstable/v2/element.d.ts.map +1 -0
  754. package/dist/solid/unstable/v2/element.jsx +325 -0
  755. package/dist/solid/unstable/v2/element.jsx.map +1 -0
  756. package/dist/solid/unstable/v2/feature-section.d.ts +12 -0
  757. package/dist/solid/unstable/v2/feature-section.d.ts.map +1 -0
  758. package/dist/solid/unstable/v2/feature-section.js +23 -0
  759. package/dist/solid/unstable/v2/feature-section.js.map +1 -0
  760. package/dist/solid/unstable/v2/focus-sensor.d.ts +13 -0
  761. package/dist/solid/unstable/v2/focus-sensor.d.ts.map +1 -0
  762. package/dist/solid/unstable/v2/focus-sensor.js +23 -0
  763. package/dist/solid/unstable/v2/focus-sensor.js.map +1 -0
  764. package/dist/solid/unstable/v2/hover-sensor.d.ts +12 -0
  765. package/dist/solid/unstable/v2/hover-sensor.d.ts.map +1 -0
  766. package/dist/solid/unstable/v2/hover-sensor.js +22 -0
  767. package/dist/solid/unstable/v2/hover-sensor.js.map +1 -0
  768. package/dist/solid/unstable/v2/index.d.ts +131 -0
  769. package/dist/solid/unstable/v2/index.d.ts.map +1 -0
  770. package/dist/solid/unstable/v2/index.js +114 -0
  771. package/dist/solid/unstable/v2/index.js.map +1 -0
  772. package/dist/solid/unstable/v2/layout-projection.d.ts +21 -0
  773. package/dist/solid/unstable/v2/layout-projection.d.ts.map +1 -0
  774. package/dist/solid/unstable/v2/layout-projection.js +18 -0
  775. package/dist/solid/unstable/v2/layout-projection.js.map +1 -0
  776. package/dist/solid/unstable/v2/layout.d.ts +47 -0
  777. package/dist/solid/unstable/v2/layout.d.ts.map +1 -0
  778. package/dist/solid/unstable/v2/layout.jsx +62 -0
  779. package/dist/solid/unstable/v2/layout.jsx.map +1 -0
  780. package/dist/solid/unstable/v2/lifecycle.d.ts +267 -0
  781. package/dist/solid/unstable/v2/lifecycle.d.ts.map +1 -0
  782. package/dist/solid/unstable/v2/lifecycle.js +457 -0
  783. package/dist/solid/unstable/v2/lifecycle.js.map +1 -0
  784. package/dist/solid/unstable/v2/live-value.d.ts +146 -0
  785. package/dist/solid/unstable/v2/live-value.d.ts.map +1 -0
  786. package/dist/solid/unstable/v2/live-value.js +235 -0
  787. package/dist/solid/unstable/v2/live-value.js.map +1 -0
  788. package/dist/solid/unstable/v2/presence-handle.d.ts +55 -0
  789. package/dist/solid/unstable/v2/presence-handle.d.ts.map +1 -0
  790. package/dist/solid/unstable/v2/presence-handle.js +119 -0
  791. package/dist/solid/unstable/v2/presence-handle.js.map +1 -0
  792. package/dist/solid/unstable/v2/presence-hooks.d.ts +51 -0
  793. package/dist/solid/unstable/v2/presence-hooks.d.ts.map +1 -0
  794. package/dist/solid/unstable/v2/presence-hooks.js +115 -0
  795. package/dist/solid/unstable/v2/presence-hooks.js.map +1 -0
  796. package/dist/solid/unstable/v2/presence.d.ts +89 -0
  797. package/dist/solid/unstable/v2/presence.d.ts.map +1 -0
  798. package/dist/solid/unstable/v2/presence.jsx +107 -0
  799. package/dist/solid/unstable/v2/presence.jsx.map +1 -0
  800. package/dist/solid/unstable/v2/press-sensor.d.ts +13 -0
  801. package/dist/solid/unstable/v2/press-sensor.d.ts.map +1 -0
  802. package/dist/solid/unstable/v2/press-sensor.js +23 -0
  803. package/dist/solid/unstable/v2/press-sensor.js.map +1 -0
  804. package/dist/solid/unstable/v2/provider.d.ts +239 -0
  805. package/dist/solid/unstable/v2/provider.d.ts.map +1 -0
  806. package/dist/solid/unstable/v2/provider.jsx +423 -0
  807. package/dist/solid/unstable/v2/provider.jsx.map +1 -0
  808. package/dist/solid/unstable/v2/reorder.d.ts +292 -0
  809. package/dist/solid/unstable/v2/reorder.d.ts.map +1 -0
  810. package/dist/solid/unstable/v2/reorder.jsx +525 -0
  811. package/dist/solid/unstable/v2/reorder.jsx.map +1 -0
  812. package/dist/solid/unstable/v2/sensors.d.ts +91 -0
  813. package/dist/solid/unstable/v2/sensors.d.ts.map +1 -0
  814. package/dist/solid/unstable/v2/sensors.js +124 -0
  815. package/dist/solid/unstable/v2/sensors.js.map +1 -0
  816. package/dist/solid/unstable/v2/solid-reactivity.d.ts +61 -0
  817. package/dist/solid/unstable/v2/solid-reactivity.d.ts.map +1 -0
  818. package/dist/solid/unstable/v2/solid-reactivity.js +62 -0
  819. package/dist/solid/unstable/v2/solid-reactivity.js.map +1 -0
  820. package/dist/solid/unstable/v2/variant-node.d.ts +51 -0
  821. package/dist/solid/unstable/v2/variant-node.d.ts.map +1 -0
  822. package/dist/solid/unstable/v2/variant-node.js +336 -0
  823. package/dist/solid/unstable/v2/variant-node.js.map +1 -0
  824. package/dist/solid/unstable/v2/w.d.ts +42 -0
  825. package/dist/solid/unstable/v2/w.d.ts.map +1 -0
  826. package/dist/solid/unstable/v2/w.jsx +22 -0
  827. package/dist/solid/unstable/v2/w.jsx.map +1 -0
  828. package/dist/solid/unstable/v2/waiters.d.ts +72 -0
  829. package/dist/solid/unstable/v2/waiters.d.ts.map +1 -0
  830. package/dist/solid/unstable/v2/waiters.js +175 -0
  831. package/dist/solid/unstable/v2/waiters.js.map +1 -0
  832. package/dist/solid/unstable/v2/ward.d.ts +393 -0
  833. package/dist/solid/unstable/v2/ward.d.ts.map +1 -0
  834. package/dist/solid/unstable/v2/ward.jsx +1475 -0
  835. package/dist/solid/unstable/v2/ward.jsx.map +1 -0
  836. package/dist/solid/unstable/v2/wardic-config.d.ts +68 -0
  837. package/dist/solid/unstable/v2/wardic-config.d.ts.map +1 -0
  838. package/dist/solid/unstable/v2/wardic-config.jsx +28 -0
  839. package/dist/solid/unstable/v2/wardic-config.jsx.map +1 -0
  840. package/dist/solid/unstable/v2/wardic.d.ts +28 -0
  841. package/dist/solid/unstable/v2/wardic.d.ts.map +1 -0
  842. package/dist/solid/unstable/v2/wardic.jsx +16 -0
  843. package/dist/solid/unstable/v2/wardic.jsx.map +1 -0
  844. package/dist/solid/variant-node.d.ts +32 -0
  845. package/dist/solid/variant-node.d.ts.map +1 -0
  846. package/dist/solid/variant-node.js +257 -0
  847. package/dist/solid/variant-node.js.map +1 -0
  848. package/dist/solid/variant-target.d.ts +102 -0
  849. package/dist/solid/variant-target.d.ts.map +1 -0
  850. package/dist/solid/variant-target.js +180 -0
  851. package/dist/solid/variant-target.js.map +1 -0
  852. package/dist/solid/variant-tree.d.ts +349 -0
  853. package/dist/solid/variant-tree.d.ts.map +1 -0
  854. package/dist/solid/variant-tree.js +358 -0
  855. package/dist/solid/variant-tree.js.map +1 -0
  856. package/dist/solid/variants.d.ts +21 -0
  857. package/dist/solid/variants.d.ts.map +1 -0
  858. package/dist/solid/variants.js +43 -0
  859. package/dist/solid/variants.js.map +1 -0
  860. package/dist/solid/w.d.ts +42 -0
  861. package/dist/solid/w.d.ts.map +1 -0
  862. package/dist/solid/w.jsx +23 -0
  863. package/dist/solid/w.jsx.map +1 -0
  864. package/dist/solid/ward-keys.d.ts +236 -0
  865. package/dist/solid/ward-keys.d.ts.map +1 -0
  866. package/dist/solid/ward-keys.js +2 -0
  867. package/dist/solid/ward-keys.js.map +1 -0
  868. package/dist/solid/wardic-component.d.ts +50 -0
  869. package/dist/solid/wardic-component.d.ts.map +1 -0
  870. package/dist/solid/wardic-component.js +74 -0
  871. package/dist/solid/wardic-component.js.map +1 -0
  872. package/dist/solid/wardic-config-value.d.ts +87 -0
  873. package/dist/solid/wardic-config-value.d.ts.map +1 -0
  874. package/dist/solid/wardic-config-value.js +106 -0
  875. package/dist/solid/wardic-config-value.js.map +1 -0
  876. package/dist/solid/wardic-config.d.ts +69 -0
  877. package/dist/solid/wardic-config.d.ts.map +1 -0
  878. package/dist/solid/wardic-config.jsx +30 -0
  879. package/dist/solid/wardic-config.jsx.map +1 -0
  880. package/dist/solid/wardic.d.ts +45 -0
  881. package/dist/solid/wardic.d.ts.map +1 -0
  882. package/dist/solid/wardic.jsx +31 -0
  883. package/dist/solid/wardic.jsx.map +1 -0
  884. package/package.json +98 -4
  885. package/src/animation-controls.ts +204 -0
  886. package/src/animation-frame.ts +32 -0
  887. package/src/appear.ts +804 -0
  888. package/src/arc.ts +34 -0
  889. package/src/bridge.ts +98 -0
  890. package/src/complete.ts +45 -0
  891. package/src/config.ts +805 -0
  892. package/src/create-animate.ts +41 -0
  893. package/src/create-ward.tsx +1271 -0
  894. package/src/cycle-index.ts +18 -0
  895. package/src/cycle.ts +34 -0
  896. package/src/directive.ts +87 -0
  897. package/src/drag-constraints.ts +103 -0
  898. package/src/drag-controls.ts +94 -0
  899. package/src/drag-samples.ts +54 -0
  900. package/src/drag-sensor.ts +46 -0
  901. package/src/drag-track.ts +937 -0
  902. package/src/drag-transition.ts +43 -0
  903. package/src/drag.ts +58 -0
  904. package/src/element-style.ts +112 -0
  905. package/src/element.tsx +400 -0
  906. package/src/feature-section.ts +33 -0
  907. package/src/feature.ts +342 -0
  908. package/src/features/all.ts +18 -0
  909. package/src/features/colors.ts +36 -0
  910. package/src/features/dom-animation.ts +15 -0
  911. package/src/features/dom-max.ts +11 -0
  912. package/src/features/drag.ts +30 -0
  913. package/src/features/focus.ts +17 -0
  914. package/src/features/hover.ts +17 -0
  915. package/src/features/in-view.ts +17 -0
  916. package/src/features/input.ts +42 -0
  917. package/src/features/keys.ts +89 -0
  918. package/src/features/layout.ts +54 -0
  919. package/src/features/pan.ts +17 -0
  920. package/src/features/press.ts +17 -0
  921. package/src/focus-sensor.ts +32 -0
  922. package/src/frame-time.ts +45 -0
  923. package/src/gesture-callbacks.ts +212 -0
  924. package/src/gesture-features.ts +35 -0
  925. package/src/gesture-info.ts +81 -0
  926. package/src/hover-sensor.ts +32 -0
  927. package/src/imperative.ts +782 -0
  928. package/src/index.ts +334 -0
  929. package/src/instant.ts +90 -0
  930. package/src/layout-group.ts +32 -0
  931. package/src/layout-member.ts +300 -0
  932. package/src/layout-projection.ts +28 -0
  933. package/src/layout.tsx +127 -0
  934. package/src/live-style.ts +449 -0
  935. package/src/live-value.ts +378 -0
  936. package/src/motion-props.ts +325 -0
  937. package/src/owner-scope.ts +31 -0
  938. package/src/page-point.ts +98 -0
  939. package/src/presence-controller.ts +1483 -0
  940. package/src/presence-record.ts +189 -0
  941. package/src/presence.tsx +269 -0
  942. package/src/press-sensor.ts +33 -0
  943. package/src/press.ts +40 -0
  944. package/src/provider.tsx +526 -0
  945. package/src/reactivity.ts +29 -0
  946. package/src/reorder-input.ts +53 -0
  947. package/src/reorder.tsx +703 -0
  948. package/src/retarget-legs.ts +1048 -0
  949. package/src/runtime.ts +388 -0
  950. package/src/sensors.ts +189 -0
  951. package/src/server-interpolators.ts +33 -0
  952. package/src/server.ts +21 -0
  953. package/src/solid-reactivity.ts +21 -0
  954. package/src/spine.ts +3385 -0
  955. package/src/stagger.ts +31 -0
  956. package/src/unstable/v2/bridge.ts +79 -0
  957. package/src/unstable/v2/complete.ts +47 -0
  958. package/src/unstable/v2/config-view.ts +156 -0
  959. package/src/unstable/v2/create-animate.ts +123 -0
  960. package/src/unstable/v2/cycle.ts +33 -0
  961. package/src/unstable/v2/drag-sensor.ts +44 -0
  962. package/src/unstable/v2/element.tsx +478 -0
  963. package/src/unstable/v2/feature-section.ts +32 -0
  964. package/src/unstable/v2/focus-sensor.ts +31 -0
  965. package/src/unstable/v2/hover-sensor.ts +30 -0
  966. package/src/unstable/v2/index.ts +270 -0
  967. package/src/unstable/v2/layout-projection.ts +27 -0
  968. package/src/unstable/v2/layout.tsx +89 -0
  969. package/src/unstable/v2/lifecycle.ts +612 -0
  970. package/src/unstable/v2/live-value.ts +414 -0
  971. package/src/unstable/v2/presence-handle.ts +159 -0
  972. package/src/unstable/v2/presence-hooks.ts +157 -0
  973. package/src/unstable/v2/presence.tsx +174 -0
  974. package/src/unstable/v2/press-sensor.ts +31 -0
  975. package/src/unstable/v2/provider.tsx +524 -0
  976. package/src/unstable/v2/reorder.tsx +880 -0
  977. package/src/unstable/v2/sensors.ts +169 -0
  978. package/src/unstable/v2/solid-reactivity.ts +69 -0
  979. package/src/unstable/v2/variant-node.ts +446 -0
  980. package/src/unstable/v2/w.tsx +49 -0
  981. package/src/unstable/v2/waiters.ts +212 -0
  982. package/src/unstable/v2/ward.tsx +2068 -0
  983. package/src/unstable/v2/wardic-config.tsx +84 -0
  984. package/src/unstable/v2/wardic.tsx +41 -0
  985. package/src/variant-node.ts +368 -0
  986. package/src/variant-target.ts +234 -0
  987. package/src/variant-tree.ts +638 -0
  988. package/src/variants.ts +47 -0
  989. package/src/w.tsx +59 -0
  990. package/src/ward-keys.ts +343 -0
  991. package/src/wardic-component.ts +96 -0
  992. package/src/wardic-config-value.ts +150 -0
  993. package/src/wardic-config.tsx +78 -0
  994. package/src/wardic.tsx +59 -0
package/src/spine.ts ADDED
@@ -0,0 +1,3385 @@
1
+ /**
2
+ * The motion spine's Retarget (ADR-0005), Solid-free (#209): what an element does from its mount on
3
+ * when its target changes, for the Solid 1 binding (`create-ward.tsx`'s `runSpine`) and the Solid 2
4
+ * one (`unstable/v2/ward.tsx`) alike. A binding mounts the element, resolves its Override stack
5
+ * reactively ({@link resolutionOf}), and calls {@link ElementSpine.retarget} on each change, read
6
+ * where its Solid doesn't track; everything a Retarget does is here:
7
+ *
8
+ * end the running legs -> carry the keys no entry sets back to their Base values (ADR-0022) ->
9
+ * start each key from its Snapshot (ADR-0024) -> take over an Appear animation (ADR-0044) ->
10
+ * build the legs (`retarget-legs.ts`) and run each into the gate -> `gate.write`.
11
+ *
12
+ * With it, the helpers both bindings' Wards share: the Starting values, the Base values' start links,
13
+ * the sink wrappers, and what a server render reads.
14
+ *
15
+ * @module
16
+ */
17
+ import * as BaseValue from "@wardic/core/BaseValue"
18
+ import type * as DefaultTransition from "@wardic/core/DefaultTransition"
19
+ import type * as Frame from "@wardic/core/Frame"
20
+ import type * as FrameLoop from "@wardic/core/FrameLoop"
21
+ import * as InterpolatorRegistry from "@wardic/core/InterpolatorRegistry"
22
+ import * as Machine from "@wardic/core/Machine"
23
+ import * as Override from "@wardic/core/Override"
24
+ import * as Playback from "@wardic/core/Playback"
25
+ import * as Projection from "@wardic/core/Projection"
26
+ import type * as ReducedMotion from "@wardic/core/ReducedMotion"
27
+ import type * as Renderer from "@wardic/core/Renderer"
28
+ import * as Supersede from "@wardic/core/Supersede"
29
+ import * as Values from "@wardic/core/Values"
30
+ import * as Appear from "@wardic/dom/Appear"
31
+ import * as DomRenderer from "@wardic/dom/DomRenderer"
32
+ import type * as FlushGate from "@wardic/dom/FlushGate"
33
+ import * as OwnValues from "@wardic/dom/OwnValues"
34
+ import * as Report from "@wardic/dom/Report"
35
+ import * as MeasuredPair from "@wardic/dom/MeasuredPair"
36
+ import * as Style from "@wardic/dom/Style"
37
+ import * as Variables from "@wardic/dom/Variables"
38
+ import * as Arr from "effect/Array"
39
+ import * as Bool from "effect/Boolean"
40
+ import * as Cause from "effect/Cause"
41
+ import * as Effect from "effect/Effect"
42
+ import * as Equivalence from "effect/Equivalence"
43
+ import * as Exit from "effect/Exit"
44
+ import * as Fiber from "effect/Fiber"
45
+ import { constFalse, constUndefined, constVoid, identity } from "effect/Function"
46
+ import * as Iter from "effect/Iterable"
47
+ import * as Match from "effect/Match"
48
+ import * as Option from "effect/Option"
49
+ import * as Predicate from "effect/Predicate"
50
+ import * as Rec from "effect/Record"
51
+ import { AtomRegistry } from "effect/reactivity"
52
+ import * as UndefinedOr from "effect/UndefinedOr"
53
+ import { enterServer, type Handoff, keyOf, type MountAnimation, repeatsForever, type ServerAppear, skippedField, startAtOf } from "./appear.ts"
54
+ import type {
55
+ WardConfig,
56
+ WardicAnimationDefinition,
57
+ WardicTransition,
58
+ WardicVariant,
59
+ WardicVariantLabels,
60
+ WardicVariants,
61
+ WardicVariantTransition,
62
+ } from "./config.ts"
63
+ import { type ControlsChange, join, leave } from "./animation-controls.ts"
64
+ import { clockNowOf, frameNow, MAX_VELOCITY_DELTA, NOMINAL_FRAME } from "./frame-time.ts"
65
+ import { type LiveStyle, serverRegistryOf, turnsWillChangeOn, valuesOf } from "./live-style.ts"
66
+ import { type ExitGroup, type PresenceContextValue, type PresenceExit, presenceMade, type PresenceRecord, type PresenceSeed, type PresenceTree } from "./presence-record.ts"
67
+ import type { DragTrack } from "./drag-track.ts"
68
+ import type { Accessor, Reactivity } from "./reactivity.ts"
69
+ import { delayedBy, type Follows, hasManyStops, keyframesFrom, type Leg, legsOf, mapMachine, type MeasuredPairs, startingAt, type StopsByKey, transitionForKey, type Velocities, withPathAxes } from "./retarget-legs.ts"
70
+ import type { WardicRuntime, WardicServices } from "./runtime.ts"
71
+ import {
72
+ changesContext,
73
+ hasOwnVariants,
74
+ GESTURE_LAYERS,
75
+ type GestureLayer,
76
+ type GestureNames,
77
+ type NameOrchestration,
78
+ activeNamesOf,
79
+ type GestureHandDown,
80
+ gesturesOn,
81
+ type GestureStates,
82
+ handDownFrom,
83
+ handDownOf,
84
+ NO_GESTURE_STATES,
85
+ NO_HAND_DOWN,
86
+ isVariantChild,
87
+ nameOf,
88
+ NO_GESTURE_NAMES,
89
+ ownOrInherited,
90
+ sameGestureNames,
91
+ type ServerVariantNode,
92
+ startingValuesOf,
93
+ startsAtAnimate,
94
+ startsQuiet,
95
+ type WardicVariantContextValue,
96
+ } from "./variant-tree.ts"
97
+ import { type Entry, type Keyframes, mergedOf, type NamedTarget, NO_VARIANT_STATE, resolveTarget, resolveTargets, sameLabels, type Target, transitionOfTarget, type VariantState } from "./variant-target.ts"
98
+
99
+ export { NO_VARIANT_STATE, resolveTarget, type Target, transitionOfTarget, type VariantState } from "./variant-target.ts"
100
+
101
+ /** What an element's exit is resolved from (#277): its last config, kept current while it's alive. */
102
+ export interface ExitConfig {
103
+ readonly exit: WardicVariant | WardicVariantLabels | undefined
104
+ readonly variants: WardicVariants | undefined
105
+ readonly custom: unknown
106
+ /** Its `transition`, or the one it inherits. */
107
+ readonly transition: WardicTransition | undefined
108
+ }
109
+
110
+ /** No exit: an element outside a presence never resolves one. */
111
+ export const NO_EXIT_CONFIG: ExitConfig = { exit: undefined, variants: undefined, custom: undefined, transition: undefined }
112
+
113
+ /** A record's place in the variant tree (#290), from its config at setup. */
114
+ export const presenceTreeOf = (c: WardConfig): PresenceTree => ({
115
+ joins: isVariantChild(c),
116
+ provides: changesContext(c),
117
+ twin: Predicate.isNotUndefined(c.layoutId),
118
+ })
119
+
120
+ /**
121
+ * An element's ref that tells its presence it was made (#286, ADR-0048): its `key`, read once, and
122
+ * whether it's a twin. With no presence, `set` itself: nothing is made per element.
123
+ */
124
+ export const madeWith = <E extends Element>(presence: PresenceContextValue | undefined, set: (el: E) => void, c: WardConfig): ((el: E) => void) => {
125
+ if (Predicate.isUndefined(presence)) return set
126
+ const key = c.key
127
+ const twin = Predicate.isNotUndefined(c.layoutId)
128
+ return (el) => {
129
+ presenceMade(presence, el, key, twin)
130
+ set(el)
131
+ }
132
+ }
133
+
134
+ /** An element's {@link ExitConfig} from its config now. */
135
+ export const exitConfigOf = (c: WardConfig, parent: WardicVariantContextValue | undefined): ExitConfig => ({
136
+ exit: c.exit,
137
+ variants: c.variants,
138
+ custom: c.custom,
139
+ transition: ownOrInherited(c.transition, parent),
140
+ })
141
+
142
+ /** An exit resolved (#277): its values, and the transition it runs on. */
143
+ export type ExitTarget = PresenceExit
144
+
145
+ /**
146
+ * Resolve an element's exit as it leaves (#277): with its `<AnimatePresence custom>` when that's
147
+ * given (Motion's: the leaving element's own props can't change any more), else its own `custom`; on
148
+ * its own transition, else the element's.
149
+ */
150
+ export const exitTargetOf = (config: ExitConfig, presenceCustom: unknown, state: VariantState, inherited: WardicVariantLabels | undefined): ExitTarget => {
151
+ const custom = UndefinedOr.match(presenceCustom, { onUndefined: () => config.custom, onDefined: identity })
152
+ // Its own `exit` wins; a Variant child with none exits on the name its provider hands down (#290).
153
+ const entry: Entry = UndefinedOr.match(config.exit, { onDefined: identity, onUndefined: (): Entry => inherited })
154
+ const name = UndefinedOr.match(nameOf(config.exit), { onDefined: identity, onUndefined: () => inherited })
155
+ if (Arr.isArray(entry)) {
156
+ // A list (#297): merged, and each name's own keys on its own transition.
157
+ const targets = resolveTargets(entry, config.variants, custom, state)
158
+ const merged = mergedOf(targets)
159
+ return {
160
+ values: merged.values,
161
+ transition: transitionOfTarget(merged.transition, config.transition),
162
+ name,
163
+ groups: exitGroupsOf(targets, config.transition),
164
+ keyframes: merged.keyframes,
165
+ }
166
+ }
167
+ const target = resolveTarget(entry, config.variants, custom, state)
168
+ return { values: target.values, transition: transitionOfTarget(target.transition, config.transition), name, keyframes: target.keyframes }
169
+ }
170
+
171
+ /** A list's exit groups (#297): each name, with the keys it's the last to set, on its own transition else `element`. */
172
+ const exitGroupsOf = (targets: ReadonlyArray<NamedTarget>, element: WardicTransition | undefined): ReadonlyArray<ExitGroup> =>
173
+ Arr.map(targets, (target, i) => ({
174
+ name: target.name as string,
175
+ values: Rec.filter(target.values, (_, key) => Bool.not(Arr.some(Arr.drop(targets, i + 1), (later) => Object.hasOwn(later.values, key)))),
176
+ transition: transitionOfTarget(target.transition, element),
177
+ }))
178
+
179
+ /** A config given as a value or as an accessor, as an accessor. A config is always an object, so a function is the accessor. */
180
+ export const accessorOf = <A extends object>(config: A | Accessor<A>): Accessor<A> =>
181
+ Bool.match(Predicate.isFunction(config), { onTrue: () => config as Accessor<A>, onFalse: () => () => config as A })
182
+
183
+ /**
184
+ * `transition` with a stagger delay folded into its own and its entries' (ADR-0007, #301), reused
185
+ * while its fields are (#66).
186
+ */
187
+ const staggeredOf = (
188
+ transition: WardicTransition | undefined,
189
+ extra: number,
190
+ reuse: (transition: WardicTransition) => WardicTransition,
191
+ ): WardicTransition | undefined => UndefinedOr.map(delayedBy(transition, extra), reuse)
192
+
193
+ /**
194
+ * A Retarget's keys by the entry that drives each (#291), when an active entry (the base's included)
195
+ * has its own transition: the highest active entry that sets it, and the base for a key none sets (a
196
+ * return). `undefined` when none has: one transition for every key.
197
+ */
198
+ const keysByLayerOf = (
199
+ t: Values.Values,
200
+ layers: ReadonlyArray<OverrideEntry>,
201
+ extraDelay: ((name: string | undefined) => number) | undefined,
202
+ extra: number,
203
+ listed: boolean,
204
+ shut: ReadonlyArray<boolean> | undefined,
205
+ ): ReadonlyArray<ReadonlySet<string>> | undefined => {
206
+ // Per Retarget (#460): statements.
207
+ if (!Arr.some(layers, hasOwnTransition) && !delaysDiffer(layers, extraDelay, extra) && !anyShutOf(shut)) return undefined
208
+ // A list's returns in a group of their own, after its entries' (#297).
209
+ let returnsAt = 0
210
+ if (listed) returnsAt = layers.length
211
+ const groups = Arr.makeBy(Math.max(layers.length, returnsAt + 1), () => new Set<string>())
212
+ Arr.forEach(Rec.keys(t), (key) => {
213
+ // A key only a Transition end sets (#428) is in its entry's group too, as the entry's own.
214
+ const at = Option.getOrElse(Arr.findLastIndex(layers, (layer) => Bool.and(layer.active, Bool.or(Object.hasOwn(layer.values, key), Object.hasOwn(layer.ends, key)))), () => returnsAt)
215
+ UndefinedOr.map(groups[at], (group) => group.add(key))
216
+ })
217
+ return groups
218
+ }
219
+
220
+ /**
221
+ * The transition `key` animates on in a Retarget: its group's (#277, #297), else the Retarget's one,
222
+ * with no stagger (#448 reads its fields, not its delay).
223
+ */
224
+ const keyTransitionOf = (
225
+ resolution: Resolution,
226
+ groups: ReadonlyArray<ReadonlySet<string>> | undefined,
227
+ key: string,
228
+ transition: WardicTransition | undefined,
229
+ element: WardicTransition | undefined,
230
+ ): WardicTransition | undefined => {
231
+ if (Predicate.isUndefined(groups)) return transition
232
+ return groupTransitionOf(resolution, groups, Option.getOrElse(Arr.findFirstIndex(groups, (group) => group.has(key)), () => -1), transition, element, undefined, identity)
233
+ }
234
+
235
+ /** Whether `given` gives `key` a velocity (#448, Motion's `valueTransition.velocity`): it kicks the key, so it animates though at its target. */
236
+ const givesVelocity = (given: WardicTransition | undefined, key: string): boolean => {
237
+ const own = transitionForKey(given, key) as { readonly velocity?: unknown } | undefined
238
+ if (Predicate.isUndefined(own)) return false
239
+ return Bool.and(Predicate.isNumber(own.velocity), own.velocity !== 0)
240
+ }
241
+
242
+ /** A key's velocity in the Snapshot, 0 with none (#448). Per key, per Retarget: a guard. */
243
+ const velocityOf = (snapshot: { readonly velocities: Readonly<Record<string, number>> }, key: string): number => {
244
+ const velocity = snapshot.velocities[key]
245
+ if (Predicate.isUndefined(velocity)) return 0
246
+ return velocity
247
+ }
248
+
249
+ /** `t`'s keys in the `i`th group, or all of them when there are no groups. */
250
+ const pickKeys = (t: Values.Values, groups: ReadonlyArray<ReadonlySet<string>> | undefined, i: number): Values.Values => {
251
+ if (Predicate.isUndefined(groups)) return t
252
+ const group = groups[i]
253
+ if (Predicate.isUndefined(group)) return {}
254
+ return Rec.filter(t, (_, key) => group.has(key))
255
+ }
256
+
257
+ /** A transition's `delay`, 0 without one. */
258
+ export const delayOf = (transition: WardicTransition | undefined): number =>
259
+ UndefinedOr.match(transition, { onUndefined: () => 0, onDefined: ({ delay = 0 }) => delay })
260
+
261
+ /** No keys: what a drag moves on a projected element, or one with no drag. */
262
+ const NO_KEYS: ReadonlyArray<string> = []
263
+
264
+ /** The keys a drag of `axis` moves directly. Built once, at module load. */
265
+ const dragMovesOf: (axis: boolean | "x" | "y") => ReadonlyArray<string> = Match.type<boolean | "x" | "y">().pipe(
266
+ Match.when("x", (): ReadonlyArray<string> => ["x"]),
267
+ Match.when("y", (): ReadonlyArray<string> => ["y"]),
268
+ Match.orElse((): ReadonlyArray<string> => ["x", "y"]),
269
+ )
270
+
271
+ /** Whether a start link's value takes its target's shape: both numbers, or both strings. */
272
+ const isSameKind = (value: number | string, like: number | string): boolean => Predicate.isNumber(value) === Predicate.isNumber(like)
273
+
274
+ /** The keys a drag direct-sets (ADR-0004). */
275
+ const TRANSLATE_KEYS: ReadonlySet<string> = new Set(["x", "y", "translateX", "translateY"])
276
+ const TRANSLATE_KEY_LIST: ReadonlyArray<string> = Arr.fromIterable(TRANSLATE_KEYS)
277
+
278
+ /** Whether a value map has any key. */
279
+ const hasKeys: Predicate.Predicate<Values.Values> = Predicate.not(Rec.isEmptyRecord)
280
+
281
+ /**
282
+ * Whether two transitions have the same keys, each holding the same value (`===`), an entry the
283
+ * same fields (#301: a stagger makes each entry anew).
284
+ */
285
+ const sameFields = (a: object, b: object): boolean => {
286
+ const ra = a as Readonly<Record<string, unknown>>
287
+ const rb = b as Readonly<Record<string, unknown>>
288
+ const keys = Rec.keys(ra)
289
+ return Bool.and(keys.length === Rec.keys(rb).length, Arr.every(keys, (key) => Bool.and(key in rb, sameField(ra[key], rb[key]))))
290
+ }
291
+
292
+ /** Whether two fields are the same: `===`, or two entries with the same fields (#301). */
293
+ const sameField = (a: unknown, b: unknown): boolean => {
294
+ if (a === b) return true
295
+ if (Bool.and(Predicate.isObject(a), Predicate.isObject(b))) return sameFields(a as object, b as object)
296
+ return false
297
+ }
298
+
299
+ /** The Override stack resolved: a Retarget's input. */
300
+ export interface Resolution {
301
+ /** Each key's value from the highest active entry. */
302
+ readonly resolved: Values.Values
303
+ /** The base entry, the first link of a key's Base value (ADR-0022). */
304
+ readonly base: Values.Values
305
+ /** Whether a drag holds the translate keys (ADR-0004's strip). */
306
+ readonly dragging: boolean
307
+ /** The variant name (or list, #297) the base entry resolved: its own `animate`'s, else the one it inherits; none for a values map. */
308
+ readonly variant: WardicVariantLabels | undefined
309
+ /** The entries it was resolved with (#257): a landing's gestures are the ones its Retarget started with. */
310
+ readonly active: Active
311
+ /** The base target's own transition (#277): the keys the base entry drives animate on it. */
312
+ readonly transition: WardicVariantTransition | undefined
313
+ /**
314
+ * The Override stack's entries (#291): the base, then each gesture's, lowest first. A Retarget runs
315
+ * each key on the own transition of the highest active entry that sets it.
316
+ */
317
+ readonly layers: ReadonlyArray<OverrideEntry>
318
+ /** The names its active gesture layers resolved (#291): its own `while*` names, else those it took. */
319
+ readonly names: GestureNames
320
+ /**
321
+ * Which gesture layers are on and set values or a Transition end (#470); a named one is in `names`.
322
+ * One turning on or off is a new target, whatever it resolves, as a Motion type turning active
323
+ * animates (`animation-state.ts`).
324
+ */
325
+ readonly layersOn: GestureStates
326
+ /** Its entries' **Transition ends** (#428), when any active one has one. */
327
+ readonly ends: Ends | undefined
328
+ /** Each key's **Keyframes**, as the entry that drives it gives them (#429), when any active entry has some. */
329
+ readonly keyframes: KeyframesNow | undefined
330
+ /**
331
+ * The **Controls change** in effect (#433): its own controls' latest, else the one its provider is
332
+ * in, for a Variant child. A new one is a Retarget, whatever it resolves to.
333
+ */
334
+ readonly change: ControlsChange | undefined
335
+ }
336
+
337
+ /**
338
+ * A key's **Keyframes** as a Retarget resolves them (#429): their stops, and the entry that drives the
339
+ * key, by its place in the Override stack and the variant name it resolved. Two are the same when all
340
+ * three are, Motion's rule for when Keyframes play again (`animation-state.ts`): an equal list, stop by
341
+ * stop, that a re-render makes runs on, where new stops, another entry driving the key (a hover over it
342
+ * ending) or a new name for its entry (`variantDidChange`) plays them again from their first stop.
343
+ */
344
+ export interface KeyframesAt {
345
+ readonly stops: Style.Stops
346
+ readonly layer: number
347
+ readonly name: string | undefined
348
+ }
349
+
350
+ /** Each key's {@link KeyframesAt}. */
351
+ export type KeyframesNow = Readonly<Record<string, KeyframesAt>>
352
+
353
+ /**
354
+ * A resolution's **Transition ends** (#428): each key only an entry's Transition end sets, with the
355
+ * entry that drives it (the highest active one that sets it, as for any key), and each entry's end
356
+ * values for the keys it drives, a key it also animates among them.
357
+ */
358
+ export interface Ends {
359
+ readonly endOnly: ReadonlyMap<string, number>
360
+ readonly byLayer: ReadonlyArray<Values.Values | undefined>
361
+ }
362
+
363
+ /**
364
+ * One entry of the Override stack (#291): whether it's on, its values, its target's own transition,
365
+ * and the variant name it resolved (#297), `undefined` for a values map. A list of names is an entry
366
+ * a name, in order.
367
+ */
368
+ export interface OverrideEntry {
369
+ readonly active: boolean
370
+ readonly values: Values.Values
371
+ readonly transition: WardicVariantTransition | undefined
372
+ readonly name: string | undefined
373
+ /** Its target's **Transition end** (#428): its keys are the entry's, set once its animated keys land. */
374
+ readonly ends: Values.Values
375
+ /** Its target's **Keyframes** (#429): each such key's stops, its value in `values` their last. */
376
+ readonly keyframes: Keyframes | undefined
377
+ }
378
+
379
+ /** A gesture layer that's off: nothing is resolved for it. */
380
+ const OFF: OverrideEntry = { active: false, values: {}, transition: undefined, name: undefined, ends: {}, keyframes: undefined }
381
+
382
+ /**
383
+ * A gesture layer (#291), while it's on (its own, or its provider's): its own `while*` (a target, or
384
+ * a variant name), else the label its provider hands down. Off, or with neither, nothing is resolved.
385
+ * Whether it set values or a Transition end (#470).
386
+ */
387
+ const gestureLayersInto = (
388
+ layers: Array<OverrideEntry>,
389
+ own: Entry,
390
+ on: boolean,
391
+ label: WardicVariantLabels | undefined,
392
+ variants: WardicVariants | undefined,
393
+ custom: unknown,
394
+ state: VariantState,
395
+ ): boolean => {
396
+ if (Bool.not(on)) {
397
+ layers.push(OFF)
398
+ return false
399
+ }
400
+ const entry = UndefinedOr.match(own, { onDefined: identity, onUndefined: (): Entry => label })
401
+ if (Predicate.isUndefined(entry)) {
402
+ layers.push(OFF)
403
+ return false
404
+ }
405
+ // A list is an entry a name, in order (#297): the last name that sets a key drives it.
406
+ if (Arr.isArray(entry)) {
407
+ let sets = false
408
+ Arr.forEach(resolveTargets(entry, variants, custom, state), (target) => {
409
+ const layer = namedLayerOf(target)
410
+ layers.push(layer)
411
+ if (setsValues(layer)) sets = true
412
+ })
413
+ return sets
414
+ }
415
+ const layer = layerOf(resolveTarget(entry, variants, custom, state), labelOrUndefined(entry))
416
+ layers.push(layer)
417
+ return setsValues(layer)
418
+ }
419
+
420
+ /**
421
+ * Whether a gesture layer sets values or a Transition end (#470). A values map with none sets
422
+ * nothing; a name that resolves none is told by its name (`names`), as Motion animates it.
423
+ */
424
+ const setsValues = (layer: OverrideEntry): boolean => {
425
+ if (hasKeys(layer.values)) return true
426
+ return hasKeys(layer.ends)
427
+ }
428
+
429
+ /** A single entry's name: itself, if a name; `undefined` for a values map. */
430
+ const labelOrUndefined = (entry: Entry): string | undefined => Bool.match(Predicate.isString(entry), { onTrue: () => entry as string, onFalse: constUndefined })
431
+
432
+ /** Each gesture on: the element's own, or its provider's too when it has one handing any down. */
433
+ const gesturesOnOf = (active: Active, above: GestureHandDown): GestureStates => {
434
+ if (above === NO_HAND_DOWN) return active
435
+ return gesturesOn(active, above.on)
436
+ }
437
+
438
+ /**
439
+ * The name each gesture layer resolves while it's on (#291): its own `while*`, if a name, else the
440
+ * label it took. With none on, the shared empty one: nothing made.
441
+ */
442
+ const activeNamesFor = (c: WardConfig, on: GestureStates, labels: GestureNames): GestureNames => {
443
+ if (Bool.not(anyOn(on))) return NO_GESTURE_NAMES
444
+ return activeNamesOf(handDownOf(c, on, { on: NO_GESTURE_STATES, names: labels }))
445
+ }
446
+
447
+ /** Whether any gesture is on: per Retarget, so no closure. */
448
+ const anyOn = (on: GestureStates): boolean => on.inView || on.focused || on.hovered || on.pressed || on.dragged
449
+
450
+ /**
451
+ * Whether an active entry's name delays its keys otherwise than the first entry's (#297): a Variant
452
+ * child's names each take their own stagger slot. Never for an element that joins none, nor for one
453
+ * entry.
454
+ */
455
+ const delaysDiffer = (layers: ReadonlyArray<OverrideEntry>, extraDelay: ((name: string | undefined) => number) | undefined, extra: number): boolean => {
456
+ if (Bool.or(Predicate.isUndefined(extraDelay), layers.length < 2)) return false
457
+ return Arr.some(layers, (layer) => Bool.and(layer.active, extraOf(extraDelay, layer) !== extra))
458
+ }
459
+
460
+ /** An entry's stagger delay (ADR-0007, #297): its name's, for a Variant child; 0 for any other element. */
461
+ const extraOf = (extraDelay: ((name: string | undefined) => number) | undefined, layer: OverrideEntry | undefined): number => {
462
+ if (Predicate.isUndefined(extraDelay)) return 0
463
+ if (Predicate.isUndefined(layer)) return extraDelay(undefined)
464
+ return extraDelay(layer.name)
465
+ }
466
+
467
+ /**
468
+ * The transition a key group runs on (#291, #297): unsplit, the base's (`transition`, its delay
469
+ * folded in); split, its entry's own, else the element's, at its name's delay. A list's first
470
+ * group carries its returns too, which run on the element's transition, as a list's base has no one
471
+ * transition of its own.
472
+ */
473
+ const groupTransitionOf = (
474
+ resolution: Resolution,
475
+ groups: ReadonlyArray<ReadonlySet<string>> | undefined,
476
+ i: number,
477
+ transition: WardicTransition | undefined,
478
+ element: WardicTransition | undefined,
479
+ extraDelay: ((name: string | undefined) => number) | undefined,
480
+ reuse: (transition: WardicTransition) => WardicTransition,
481
+ ): WardicTransition | undefined => {
482
+ if (Predicate.isUndefined(groups)) return transition
483
+ if (Bool.and(i === 0, Bool.not(Arr.isArray(resolution.variant)))) return transition
484
+ const layer = resolution.layers[i]
485
+ // A list's returns: the element's, at its whole orchestration's delay.
486
+ if (Predicate.isUndefined(layer)) return staggeredOf(element, extraOf(extraDelay, undefined), reuse)
487
+ return staggeredOf(transitionOfTarget(layer.transition, element), extraOf(extraDelay, layer), reuse)
488
+ }
489
+
490
+ /** No names. */
491
+ const NO_NAMES: ReadonlyArray<string> = []
492
+
493
+ /** No legs. */
494
+ const NO_LEGS: ReadonlyArray<Leg> = []
495
+
496
+ /**
497
+ * Where a Retarget's legs land (#257, #325): what each running leg's frames and end are told to.
498
+ * The last Retarget's, which every running leg counts toward, the ones it carried included.
499
+ */
500
+ interface Landing {
501
+ /** A leg drew a frame: its last, when `done`. */
502
+ readonly report: (done: boolean) => void
503
+ /** A leg settled. */
504
+ readonly settled: () => void
505
+ /** A leg failed (#257 item 4). */
506
+ readonly failed: (cause: Cause.Cause<unknown>) => void
507
+ }
508
+
509
+ /**
510
+ * A gated Retarget's landing (ADR-0007 `when`, #325): the legs it carries report the element
511
+ * unsettled, as it still owes an animation, and land nothing; the Retarget once the gate opens
512
+ * counts them.
513
+ */
514
+ const gatedLandingOf = (onFrame: ((done: boolean) => void) | undefined): Landing => ({
515
+ report: () => {
516
+ if (Predicate.isNotUndefined(onFrame)) onFrame(false)
517
+ },
518
+ settled: constVoid,
519
+ failed: constVoid,
520
+ })
521
+
522
+ /**
523
+ * A running leg (#325): the keys it draws, each with the target its Retarget resolved, and the
524
+ * landing its frames and end count toward. It's its machines' run options, with its own token
525
+ * (#200): a later Retarget that resolves a key to the same target leaves the leg that key, every
526
+ * other key is given up, and a leg left with none is ended.
527
+ */
528
+ interface Running extends Machine.RunOptions {
529
+ /** Each key it animates, with the target its Retarget gave it. */
530
+ readonly targets: Values.Values
531
+ /** The resolution of the Retarget that started it: a `when` gate holds that change's legs. */
532
+ readonly resolution: Resolution
533
+ /** How many of its keys it still draws. */
534
+ count: number
535
+ /** A frame's values for the keys it still draws: the frame's own while it draws all of them. */
536
+ values: (value: Values.Values) => Values.Values
537
+ /** The same, for a frame's velocities. */
538
+ velocities: (velocity: Readonly<Record<string, number>>) => Readonly<Record<string, number>>
539
+ /** It drew its last frame: its keys landed. */
540
+ done: boolean
541
+ /** It gave up a key in this Retarget: what it still draws is worked out at the Retarget's end. */
542
+ losing: boolean
543
+ fiber: Fiber.Fiber<void> | undefined
544
+ /** The landing it counts toward: its Retarget's, then the one of each Retarget that carried it. */
545
+ landing: Landing
546
+ /** A list's names its end is told to (#297), for the Retarget it counts toward. */
547
+ names: ((end: unknown) => void) | undefined
548
+ /** Its kind (#464): a Blend leg's keys' velocities are its frames', a Snap's none, the rest write their own. */
549
+ readonly kind: Leg["_tag"]
550
+ /** The frames it has drawn (#464). */
551
+ frames: number
552
+ /** When it drew its last frame, on {@link frameNow}'s clock; -Infinity before its first (#464). */
553
+ lastAt: number
554
+ /** A Blend leg's last frame's values, and the ones before them (the Snapshot's, before its first) and when (#464). */
555
+ last: Values.Values | undefined
556
+ before: Values.Values | undefined
557
+ beforeAt: number
558
+ }
559
+
560
+ /** No running legs. */
561
+ const NO_RUNNING: ReadonlyArray<Running> = []
562
+
563
+ /**
564
+ * An entry's Transition end waiting for its keys to land (#428, #508): no fiber of its own. Its `running`
565
+ * holds the keys only it sets, counts toward its landing and is given up as any leg's; the landing of
566
+ * its keys' last leg makes it due, and it's written at the next flush.
567
+ */
568
+ interface PendingEnd {
569
+ readonly running: Running
570
+ /** The keys its entry animates, each held by the leg drawing it. */
571
+ readonly animated: ReadonlyArray<string>
572
+ /** Its Transition end, the keys it also animates among them. */
573
+ readonly writes: Values.Values
574
+ /**
575
+ * An end that owns no key, its values all keys its entry animates: the leg drawing each of
576
+ * `animated` as it was made. Nothing gives such an end up, so a key's leg given up or replaced
577
+ * before it lands, the target interrupted, drops it (ADR-0057 Q1). Undefined for one that owns keys,
578
+ * which an interrupt gives up.
579
+ */
580
+ readonly legs: ReadonlyArray<Running | undefined> | undefined
581
+ state: "waiting" | "due" | "written" | "dropped"
582
+ }
583
+
584
+ /** An element's waiting Transition ends (#508). */
585
+ interface WaitingEnds {
586
+ /** An entry's end, waiting for its keys, or due already when they've landed. */
587
+ readonly add: (end: PendingEnd) => void
588
+ /** A leg landed: each end whose keys now all have is due, written at the next flush. */
589
+ readonly land: () => void
590
+ /** The end `running` is, dropped, whether it waits or is due: given up, stopped or ended. */
591
+ readonly drop: (running: Running) => void
592
+ /** The element is gone: none is written. */
593
+ readonly dispose: () => void
594
+ }
595
+
596
+ /**
597
+ * The waiting Transition ends of element `id` (#508): made at its first end, so an element with none,
598
+ * nearly every one, pays nothing for them. `owners` holds the leg drawing each key.
599
+ */
600
+ const waitingEndsOf = (owners: Owners, snapshot: Snapshot, gate: FlushGate.Shape, id: string, recordFrame: (value: Values.Values) => void): WaitingEnds => {
601
+ const pending: Array<PendingEnd> = []
602
+ let disposed = false
603
+ /** Whether `key`'s leg has landed: it drew its last frame, or none draws it. */
604
+ const keyLanded = (key: string): boolean => ownerLanded(owners.get(key))
605
+ /** `end` off the list. */
606
+ const remove = (end: PendingEnd): void => {
607
+ const at = pending.indexOf(end)
608
+ if (at >= 0) pending.splice(at, 1)
609
+ }
610
+ /**
611
+ * An end written, at the flush after its keys landed: the frame its leg's write would have drawn in,
612
+ * and Motion's (`frame.update` once its animations resolve). It counts toward its landing as that leg
613
+ * did, so the landing's settle, told after the next flush, sees it (ADR-0057 Q4).
614
+ */
615
+ const write = (end: PendingEnd): void => {
616
+ if (Bool.or(disposed, end.state !== "due")) return
617
+ end.state = "written"
618
+ remove(end)
619
+ const running = end.running
620
+ const value = running.values(end.writes)
621
+ snapshot.values = { ...snapshot.values, ...value }
622
+ gate.write(id, value)
623
+ recordFrame(value)
624
+ drew(running, true, snapshot.now())
625
+ running.landing.settled()
626
+ const tell = running.names
627
+ if (Predicate.isNotUndefined(tell)) tell(undefined)
628
+ }
629
+ /** Whether a key-less end's target was interrupted: a leg it waits for given up or replaced before it landed. */
630
+ const interrupted = (end: PendingEnd): boolean => {
631
+ const legs = end.legs
632
+ if (Predicate.isUndefined(legs)) return false
633
+ return Arr.some(end.animated, (key, i) => {
634
+ const leg = legs[i]
635
+ if (Predicate.isUndefined(leg)) return false
636
+ if (leg.done) return false
637
+ return owners.get(key) !== leg
638
+ })
639
+ }
640
+ /** An end due once every key it waits for has landed, written at the next flush; dropped when its target was interrupted. */
641
+ const landOne = (end: PendingEnd): void => {
642
+ if (end.state !== "waiting") return
643
+ if (interrupted(end)) {
644
+ end.state = "dropped"
645
+ return
646
+ }
647
+ if (Bool.not(Arr.every(end.animated, keyLanded))) return
648
+ end.state = "due"
649
+ gate.afterFlush(() => write(end))
650
+ }
651
+ const dropped = (end: PendingEnd): boolean => end.state === "dropped"
652
+ const land = (): void => {
653
+ Arr.forEach(pending, landOne)
654
+ if (Arr.some(pending, dropped)) {
655
+ const kept = Arr.filter(pending, Predicate.not(dropped))
656
+ pending.length = 0
657
+ pending.push(...kept)
658
+ }
659
+ }
660
+ return {
661
+ add: (end) => {
662
+ pending.push(end)
663
+ land()
664
+ },
665
+ land,
666
+ drop: (running) =>
667
+ Option.match(Arr.findFirst(pending, (end) => end.running === running), {
668
+ onNone: constVoid,
669
+ onSome: (end) => {
670
+ end.state = "dropped"
671
+ remove(end)
672
+ },
673
+ }),
674
+ dispose: () => {
675
+ disposed = true
676
+ pending.length = 0
677
+ },
678
+ }
679
+ }
680
+
681
+ /** A leg's last frame lands the Transition ends waiting on it (#508); an element with none has nothing to ask. */
682
+ const landEndsOf = (waiting: WaitingEnds | undefined): void => {
683
+ if (Predicate.isNotUndefined(waiting)) waiting.land()
684
+ }
685
+
686
+ /**
687
+ * The resolution an **Imperative animation**'s legs run under (#433): none of the Override stack's,
688
+ * so a Retarget that takes a key back never carries one as its own Keyframes or names.
689
+ */
690
+ const IMPERATIVE: Resolution = {
691
+ resolved: {},
692
+ base: {},
693
+ dragging: false,
694
+ variant: undefined,
695
+ active: { inView: false, focused: false, hovered: false, pressed: false, dragged: false, dragging: false },
696
+ transition: undefined,
697
+ layers: [],
698
+ names: NO_GESTURE_NAMES,
699
+ layersOn: NO_GESTURE_STATES,
700
+ ends: undefined,
701
+ keyframes: undefined,
702
+ change: undefined,
703
+ }
704
+
705
+ /** No values: what a spine's Retarget keys are before its first. */
706
+ const NO_VALUES: Values.Values = {}
707
+
708
+ /** Whether a key's Keyframes stops hold a Variable value (#55). Built once (#460). */
709
+ const stopsHoldVariable = (stops: ReadonlyArray<number | string>): boolean => Arr.some(stops, Variables.isValue)
710
+
711
+ /**
712
+ * Whether a change's starts, targets or Keyframes stops hold a Variable value (#542): only then can
713
+ * the element's Key rule, its Variable values (#55), take a pair, so only then is a leg's machine
714
+ * built under it. It declines every pair with no `var()` at either end.
715
+ */
716
+ const holdsVariable = (from: Values.Values, to: Values.Values, stops: StopsByKey | undefined): boolean => {
717
+ // Per Retarget (#460): statements, Effect's calls data-first.
718
+ if (Rec.some(from, Variables.isValue)) return true
719
+ if (Rec.some(to, Variables.isValue)) return true
720
+ if (Predicate.isUndefined(stops)) return false
721
+ return Rec.some(stops, stopsHoldVariable)
722
+ }
723
+
724
+ /** A Path's turn (#438, ADR-0065): the reserved key the dom transform adds onto `rotate`. */
725
+ const PATH_ROTATION = "pathRotation"
726
+
727
+ /** The turn back at 0, written once no leg draws it (#460). */
728
+ const TURNED_BACK: Values.Values = { [PATH_ROTATION]: 0 }
729
+
730
+ /**
731
+ * Each key's Leg (#325): the one that draws it, or the last one that did, landed; `undefined` once
732
+ * none does. A key's entry is cleared in place, never deleted: a Retarget that gives up and restarts
733
+ * every key would otherwise leave the Map a hole a key each time, and rehash it.
734
+ */
735
+ type Owners = Map<string, Running | undefined>
736
+
737
+ /** A leg over the keys of `to` (#325), counting toward `landing`: the spine gives it the keys. */
738
+ const runningOf = (to: Values.Values, resolution: Resolution, landing: Landing, kind: Leg["_tag"]): Running => ({
739
+ supersede: Supersede.make(),
740
+ targets: to,
741
+ resolution,
742
+ count: 0,
743
+ values: identity,
744
+ velocities: identity,
745
+ done: false,
746
+ losing: false,
747
+ fiber: undefined,
748
+ landing,
749
+ names: undefined,
750
+ kind,
751
+ frames: 0,
752
+ // Doubles from the start (#464): a field made an integer turns every leg's shape when its first double
753
+ // comes, and a read of each leg made before goes the slow way (the bench's unmount, +6%).
754
+ lastAt: Number.NEGATIVE_INFINITY,
755
+ last: undefined,
756
+ before: undefined,
757
+ beforeAt: Number.NEGATIVE_INFINITY,
758
+ })
759
+
760
+ /**
761
+ * A Blend leg's velocity for `key` (#464, Motion's `getVelocity`): its last two frames' change over
762
+ * their time apart, at most `MAX_VELOCITY_DELTA`; none for a string, nor for a Snap, a leg that landed
763
+ * on its first frame (a `set`, a `duration: 0`).
764
+ */
765
+ const blendVelocityOf = (running: Running, key: string): number => {
766
+ if (Bool.and(running.done, running.frames < 2)) return 0
767
+ // Per key, per Retarget: guards, nothing made.
768
+ const lastValues = running.last
769
+ const beforeValues = running.before
770
+ if (Predicate.isUndefined(lastValues)) return 0
771
+ if (Predicate.isUndefined(beforeValues)) return 0
772
+ const last = lastValues[key]
773
+ const before = beforeValues[key]
774
+ if (Bool.not(Predicate.isNumber(last))) return 0
775
+ if (Bool.not(Predicate.isNumber(before))) return 0
776
+ const apart = Math.min(running.lastAt - running.beforeAt, MAX_VELOCITY_DELTA)
777
+ if (apart <= 0) return 0
778
+ return (((last as number) - (before as number)) * 1000) / apart
779
+ }
780
+
781
+ /** A leg's frame drawn (#325) at `now`: its last lands the keys it draws. Per frame: plain calls. */
782
+ const drew = (running: Running, done: boolean, now: number): void => {
783
+ if (done) running.done = true
784
+ running.frames++
785
+ running.lastAt = now
786
+ running.landing.report(done)
787
+ }
788
+
789
+ /**
790
+ * A frame's values for `kept` alone (#325): a leg a later Retarget took keys from draws only the
791
+ * rest. Built once, when it gives them up; each frame copies into the one object it returns.
792
+ */
793
+ const keepingOnly = <A,>(kept: ReadonlyArray<string>): ((value: Readonly<Record<string, A>>) => Readonly<Record<string, A>>) => {
794
+ const out: Record<string, A> = {}
795
+ let frame: Readonly<Record<string, A>> = out
796
+ const copy = (key: string): void => {
797
+ out[key] = frame[key] as A
798
+ }
799
+ return (value) => {
800
+ frame = value
801
+ Arr.forEach(kept, copy)
802
+ return out
803
+ }
804
+ }
805
+
806
+ /**
807
+ * Where `axis` rests when `target` leaves it out (#574): a leg drawing it though its own Retarget
808
+ * didn't resolve it, a Path's whose target left it out too (#438) or an Imperative animation's (#433,
809
+ * whose legs resolve nothing), was taking it somewhere, and it rests there. `undefined` with none in
810
+ * flight.
811
+ */
812
+ const restOf = (owners: Owners, target: Values.Values, axis: "x" | "y"): number | string | undefined => {
813
+ if (Object.hasOwn(target, axis)) return undefined
814
+ const owner = owners.get(axis)
815
+ if (Predicate.isUndefined(owner)) return undefined
816
+ if (owner.done) return undefined
817
+ if (Object.hasOwn(owner.resolution.resolved, axis)) return undefined
818
+ return owner.targets[axis]
819
+ }
820
+
821
+ /**
822
+ * Where a Path's axes that `target` leaves out rest (#574), read before their legs give them up: a
823
+ * new Path ends them there, so a toss caught mid-air curves back to its line. `undefined` for none:
824
+ * every element's Retarget asks, nearly always with no Path in flight, so guards, nothing built.
825
+ */
826
+ const restsOf = (owners: Owners, target: Values.Values): Values.Values | undefined => {
827
+ const x = restOf(owners, target, "x")
828
+ const y = restOf(owners, target, "y")
829
+ if (Bool.and(Predicate.isUndefined(x), Predicate.isUndefined(y))) return undefined
830
+ if (Predicate.isUndefined(x)) return { y: UndefinedOr.getOrThrow(y) }
831
+ if (Predicate.isUndefined(y)) return { x }
832
+ return { x, y }
833
+ }
834
+
835
+ /** The groups of the keys a carried leg draws (#297, #325): the first alone when the keys aren't split. */
836
+ const groupsOfLeg = (running: Running, groups: ReadonlyArray<ReadonlySet<string>> | undefined, owners: Owners): ReadonlyArray<number> => {
837
+ if (Predicate.isUndefined(groups)) return [0]
838
+ const keys = Arr.filter(Rec.keys(running.targets), (key) => owners.get(key) === running)
839
+ return Arr.filter(Arr.makeBy(groups.length, identity), (g) => Arr.some(keys, (key) => UndefinedOr.match(groups[g], { onUndefined: constFalse, onDefined: (group) => group.has(key) })))
840
+ }
841
+
842
+ /** Each entry's gate shut now (#297's PR 2): a named one whose `when` holds its keys back. */
843
+ const shutOf = (layers: ReadonlyArray<OverrideEntry>, byName: NameOrchestration | undefined): ReadonlyArray<boolean> | undefined => {
844
+ if (Predicate.isUndefined(byName)) return undefined
845
+ return Arr.map(layers, (layer) => {
846
+ const name = layer.name
847
+ if (Predicate.isUndefined(name)) return false
848
+ return Bool.not(byName.mayStart(name))
849
+ })
850
+ }
851
+
852
+ /** Whether any entry's gate is shut (#297's PR 2): none without a list. */
853
+ const anyShutOf = (shut: ReadonlyArray<boolean> | undefined): boolean => {
854
+ if (Predicate.isUndefined(shut)) return false
855
+ return Arr.some(shut, identity)
856
+ }
857
+
858
+ /** A split Retarget's legs, each key group's (#291, #297), and the group each leg animates. */
859
+ interface SplitLegs {
860
+ readonly legs: ReadonlyArray<Leg>
861
+ readonly tags: ReadonlyArray<number>
862
+ }
863
+
864
+ /**
865
+ * A split Retarget's legs (#291, #297): each key group on its transition, over the keys that start a
866
+ * leg (`t`, #325). A group with none of them makes no leg: a list's settles at once as Motion's empty
867
+ * variant does, unless keys it drives stay running. A list's returns' Live values follow with its
868
+ * returns' group, last; any other's with the first group.
869
+ */
870
+ const splitLegsOf = (
871
+ t: Values.Values,
872
+ from: Values.Values,
873
+ groups: ReadonlyArray<ReadonlySet<string>>,
874
+ resolution: Resolution,
875
+ listed: boolean,
876
+ transition: WardicTransition | undefined,
877
+ element: WardicTransition | undefined,
878
+ extraDelay: ((name: string | undefined) => number) | undefined,
879
+ reuse: (transition: WardicTransition) => WardicTransition,
880
+ reduce: boolean,
881
+ skipped: boolean,
882
+ positionalKeys: ReducedMotion.PositionalKeys["Service"],
883
+ defaultTransition: DefaultTransition.DefaultTransition["Service"],
884
+ velocities: Velocities,
885
+ follow: Follows | undefined,
886
+ stops: StopsByKey | undefined,
887
+ measured: MeasuredPairs | undefined,
888
+ current: Values.Values,
889
+ rests: Values.Values | undefined,
890
+ ): SplitLegs => {
891
+ let returnsAt = 0
892
+ if (listed) returnsAt = resolution.layers.length
893
+ const legs: Array<Leg> = []
894
+ const tags: Array<number> = []
895
+ Arr.forEach(groups, (_, i) => {
896
+ // A group whose keys all stay starts none (#325), as one that drives no key.
897
+ const picked = pickKeys(t, groups, i)
898
+ if (Rec.isEmptyRecord(picked)) return
899
+ let followed: Follows | undefined
900
+ if (i === returnsAt) followed = follow
901
+ const groupLegs = legsOf(from, picked, groupTransitionOf(resolution, groups, i, transition, element, extraDelay, reuse), reduce, skipped, positionalKeys, defaultTransition, velocities, followed, stops, measured, current, rests)
902
+ Arr.forEach(groupLegs, (built) => {
903
+ legs.push(built)
904
+ tags.push(i)
905
+ })
906
+ })
907
+ return { legs, tags }
908
+ }
909
+
910
+ /** What a list's names make of a Retarget (#297): their settles told, and each shut one's legs' gate. */
911
+ interface Listing {
912
+ readonly names: NameSettles | undefined
913
+ readonly legGates: ReadonlyArray<string | undefined> | undefined
914
+ }
915
+
916
+ /** What {@link listingOf} reads of a Retarget. */
917
+ interface ListingOf {
918
+ readonly listed: boolean
919
+ readonly told: ToldNames | undefined
920
+ readonly byName: NameOrchestration | undefined
921
+ readonly resolution: Resolution
922
+ readonly groups: ReadonlyArray<ReadonlySet<string>> | undefined
923
+ readonly legGroups: ReadonlyArray<number> | undefined
924
+ readonly legCount: number
925
+ /** For each running leg it carries (#325), the groups of the keys it draws. */
926
+ readonly carriedGroups: ReadonlyArray<ReadonlyArray<number>>
927
+ readonly shut: ReadonlyArray<boolean> | undefined
928
+ /** Write a shut group's keys where they start. */
929
+ readonly hold: (group: number) => void
930
+ readonly afterFlush: (fn: () => void) => void
931
+ readonly config: WardConfig
932
+ }
933
+
934
+ /**
935
+ * A list's names at a Retarget (#297): told settled as the legs of the keys each drives settle, to
936
+ * the binding's callbacks (Solid 1's, PR 1) and to its orchestration (PR 2), told moving now; and each
937
+ * shut name's legs waiting on its gate (PR 2), its keys held where they start, so another name's first
938
+ * commit, which hands the element's style back (ADR-0034), doesn't drop them to their CSS value.
939
+ */
940
+ const listingOf = (of: ListingOf): Listing => {
941
+ const { listed, told, byName, resolution, groups, legGroups, legCount, carriedGroups, shut, config } = of
942
+ const listNames = Bool.match(listed, { onTrue: () => resolution.variant as ReadonlyArray<string>, onFalse: () => NO_NAMES })
943
+ const orchestrated = Bool.and(listed, Predicate.isNotUndefined(byName))
944
+ const toldNames = UndefinedOr.match(told, { onUndefined: () => NO_NAMES, onDefined: (list) => list.names })
945
+ let names: NameSettles | undefined
946
+ if (Bool.or(orchestrated, Predicate.isNotUndefined(told))) {
947
+ if (orchestrated) (byName as NameOrchestration).moving(listNames)
948
+ names = nameSettlesOf(Arr.dedupe([...listNames, ...toldNames]), resolution, groups, legGroups, legCount, carriedGroups, (settled) =>
949
+ of.afterFlush(() => {
950
+ UndefinedOr.map(told, (list) => {
951
+ const mine = Arr.filter(settled, (name) => Arr.contains(list.names, name))
952
+ if (mine.length > 0) list.tell(mine, config)
953
+ })
954
+ if (orchestrated) (byName as NameOrchestration).settled(Arr.filter(settled, (name) => Arr.contains(listNames, name)))
955
+ }))
956
+ }
957
+ let legGates: ReadonlyArray<string | undefined> | undefined
958
+ if (Bool.and(anyShutOf(shut), Predicate.isNotUndefined(legGroups))) {
959
+ const closed = shut as ReadonlyArray<boolean>
960
+ legGates = Arr.map(legGroups as ReadonlyArray<number>, (g) => gateNameOf(resolution.layers, closed, g))
961
+ Arr.forEach(closed, (isShut, g) => {
962
+ if (isShut) of.hold(g)
963
+ })
964
+ }
965
+ return { names, legGates }
966
+ }
967
+
968
+ /** The name a leg of key group `g` waits for, if its entry's gate is shut (#297's PR 2): a list's returns wait for none. */
969
+ const gateNameOf = (layers: ReadonlyArray<OverrideEntry>, shut: ReadonlyArray<boolean>, g: number): string | undefined => {
970
+ if (shut[g] !== true) return undefined
971
+ return UndefinedOr.match(layers[g], { onUndefined: constUndefined, onDefined: (layer) => layer.name })
972
+ }
973
+
974
+ /** A gate's wait (#297's PR 2): done once `open()` says so, read each tick. */
975
+ const gateWaitOf = (open: () => boolean): Machine.Machine<Frame.Frame<undefined>> =>
976
+ Machine.make({ settles: true, span: GATE_SPAN, start: () => () => ({ value: undefined, done: open() }) })
977
+
978
+ const GATE_SPAN = { name: "wardic.spine.whenGate", attributes: {} }
979
+
980
+ /** Nothing drawn while a gate is waited on. */
981
+ const NO_SINK = (): undefined => undefined
982
+
983
+ /** Whether a key's leg has landed (#428): its owner's done, or it has none. A guard: asked at each leg's landing while a Transition end waits (#508). */
984
+ const ownerLanded = (owner: Running | undefined): boolean => {
985
+ if (Predicate.isUndefined(owner)) return true
986
+ return owner.done
987
+ }
988
+
989
+ /** Whether `runtime` keeps a Debug log: read once a runtime, so a log no level keeps forks nothing (#618). */
990
+ // Module state (#460, Q7): each runtime's answer, held weakly by the runtime.
991
+ const logsDebug = new WeakMap<WardicRuntime, boolean>()
992
+ const logsDebugOn = (runtime: WardicRuntime): boolean => {
993
+ const known = logsDebug.get(runtime)
994
+ if (Predicate.isNotUndefined(known)) return known
995
+ const on = runtime.runSync(Report.debugKept)
996
+ logsDebug.set(runtime, on)
997
+ return on
998
+ }
999
+
1000
+ /**
1001
+ * No key taken by an Imperative animation (#433): every spine's until its first, shared, so an element
1002
+ * none animates holds no map of its own (#460). Never written: a spine sets keys in a map of its own,
1003
+ * and deletes only from one that has some.
1004
+ */
1005
+ // Module state (#460, Q7): a constant: an empty map every spine shares until its first, which none writes.
1006
+ const NONE_TAKEN: Map<string, number | string | undefined> = new Map()
1007
+
1008
+ /**
1009
+ * A leg that waits for its name's gate first (#297's PR 2), as Motion runs a variant's `when` per
1010
+ * name: started once the gate opens, on the same token, so a later Retarget ends the wait as it ends
1011
+ * a leg. Without a name, the leg as it is.
1012
+ */
1013
+ const gatedBy = <R,>(
1014
+ name: string | undefined,
1015
+ byName: NameOrchestration | undefined,
1016
+ options: Machine.RunOptions,
1017
+ program: Effect.Effect<unknown, never, R>,
1018
+ ): Effect.Effect<unknown, never, R | FrameLoop.FrameLoop> => {
1019
+ if (Bool.or(Predicate.isUndefined(name), Predicate.isUndefined(byName))) return program
1020
+ const orchestration = byName as NameOrchestration
1021
+ const gated = name as string
1022
+ return gateWaitOf(() => orchestration.mayStart(gated)).pipe(
1023
+ Machine.run(NO_SINK, options),
1024
+ Effect.flatMap((end) => Bool.match(Supersede.isSuperseded(end), { onTrue: () => Effect.succeed(end as unknown), onFalse: () => program })),
1025
+ )
1026
+ }
1027
+
1028
+ /** Whether an entry is on with its own transition: hoisted, as it's asked per Retarget. */
1029
+ const hasOwnTransition = (layer: OverrideEntry): boolean => Bool.and(layer.active, Predicate.isNotUndefined(layer.transition))
1030
+
1031
+ /** A target as an active entry, with the name it resolved. */
1032
+ const layerOf = (target: Target, name: string | undefined): OverrideEntry => ({
1033
+ active: true,
1034
+ values: target.values,
1035
+ transition: target.transition,
1036
+ name,
1037
+ ends: endsOfTarget(target),
1038
+ keyframes: target.keyframes,
1039
+ })
1040
+
1041
+ /** A list's target as an active entry (#297). */
1042
+ const namedLayerOf = (target: NamedTarget): OverrideEntry => layerOf(target, target.name)
1043
+
1044
+ /** A target's Transition end as an entry's (#428): none shared, so the common case allocates nothing. Per entry, per Retarget (#460): a guard. */
1045
+ const endsOfTarget = (target: Target): Values.Values => {
1046
+ if (Predicate.isUndefined(target.transitionEnd)) return NO_VALUES
1047
+ return target.transitionEnd
1048
+ }
1049
+
1050
+ /** Whether an entry is on with a Transition end (#428). */
1051
+ const hasEnds = (layer: OverrideEntry): boolean => Bool.and(layer.active, layer.ends !== NO_VALUES)
1052
+
1053
+ /** The highest active entry that sets `key`, in its values or its Transition end (#428). */
1054
+ const driverOf = (layers: ReadonlyArray<OverrideEntry>, key: string): number =>
1055
+ Option.getOrElse(Arr.findLastIndex(layers, (layer) => Bool.and(layer.active, Bool.or(Object.hasOwn(layer.values, key), Object.hasOwn(layer.ends, key)))), () => -1)
1056
+
1057
+ /**
1058
+ * The Override stack resolved (#428): `Override.resolve` as before when no active entry has a
1059
+ * Transition end; else over each entry's values and Transition end, its values winning a key both set, so
1060
+ * a key only an end sets is the entry's (Motion's `{ ...target, ...transitionEnd }`), and the ends
1061
+ * each entry drives.
1062
+ */
1063
+ const resolvedOf = (layers: ReadonlyArray<OverrideEntry>): Resolved => {
1064
+ if (!Arr.some(layers, hasEnds)) {
1065
+ const resolved = Override.resolve(layers)
1066
+ return { resolved, ends: undefined, keyframes: keyframesNowOf(layers, resolved) }
1067
+ }
1068
+ const merged = Arr.map(layers, (layer): OverrideEntry => Bool.match(hasEnds(layer), { onTrue: () => ({ ...layer, values: { ...layer.ends, ...layer.values } }), onFalse: () => layer }))
1069
+ const resolved = Override.resolve(merged)
1070
+ const endOnly = new Map<string, number>()
1071
+ const byLayer: Array<Record<string, number | string> | undefined> = Arr.makeBy(layers.length, constUndefined)
1072
+ Arr.forEach(Rec.keys(resolved), (key) => {
1073
+ const at = driverOf(layers, key)
1074
+ const layer = layers[at]
1075
+ if (Bool.or(Predicate.isUndefined(layer), Bool.not(Object.hasOwn((layer as OverrideEntry).ends, key)))) return
1076
+ const driving = layer as OverrideEntry
1077
+ if (Bool.not(Object.hasOwn(driving.values, key))) endOnly.set(key, at)
1078
+ const into = UndefinedOr.match(byLayer[at], { onUndefined: (): Record<string, number | string> => ({}), onDefined: identity })
1079
+ into[key] = driving.ends[key] as number | string
1080
+ byLayer[at] = into
1081
+ })
1082
+ return { resolved, ends: { endOnly, byLayer }, keyframes: keyframesNowOf(layers, resolved) }
1083
+ }
1084
+
1085
+ /** The Override stack resolved: each key's value, its entries' Transition ends (#428) and Keyframes (#429). */
1086
+ interface Resolved {
1087
+ readonly resolved: Values.Values
1088
+ readonly ends: Ends | undefined
1089
+ readonly keyframes: KeyframesNow | undefined
1090
+ }
1091
+
1092
+ /** Whether an entry is on with Keyframes (#429). Per entry, per Retarget (#452): guards, nothing built. */
1093
+ const hasKeyframes = (layer: OverrideEntry): boolean => {
1094
+ if (Predicate.isUndefined(layer.keyframes)) return false
1095
+ return layer.active
1096
+ }
1097
+
1098
+ /**
1099
+ * Each resolved key's Keyframes (#429): the stops of the entry that drives it, when that entry gives
1100
+ * it Keyframes. `undefined`, with nothing made, when no active entry has any: every element's common
1101
+ * case.
1102
+ */
1103
+ const keyframesNowOf = (layers: ReadonlyArray<OverrideEntry>, resolved: Values.Values): KeyframesNow | undefined => {
1104
+ if (!Arr.some(layers, hasKeyframes)) return undefined
1105
+ const now: Record<string, KeyframesAt> = {}
1106
+ Arr.forEach(Rec.keys(resolved), (key) => {
1107
+ const at = driverOf(layers, key)
1108
+ const layer = layers[at]
1109
+ if (Predicate.isUndefined(layer)) return
1110
+ const stops = UndefinedOr.map((layer as OverrideEntry).keyframes, (byKey) => byKey[key])
1111
+ if (Bool.or(Predicate.isUndefined(stops), Bool.not(Object.hasOwn((layer as OverrideEntry).values, key)))) return
1112
+ now[key] = { stops: stops as Style.Stops, layer: at, name: (layer as OverrideEntry).name }
1113
+ })
1114
+ return Bool.match(Rec.isEmptyRecord(now), { onTrue: constUndefined, onFalse: (): KeyframesNow => now })
1115
+ }
1116
+
1117
+
1118
+ /** Two values maps with the same keys, each holding the same value. Built once, at module load. */
1119
+ const sameValues: Equivalence.Equivalence<Values.Values> = Rec.makeEquivalence(Equivalence.strictEqual<number | string>())
1120
+
1121
+ /**
1122
+ * Whether two resolutions are the same target (#209, #470): the same values for the same keys, in
1123
+ * the base entry and resolved, the same drag, the same variant name, Keyframes and Transition ends,
1124
+ * and the same gesture layers on, with the same names. Motion's rule: a config that resolves to the
1125
+ * same values doesn't animate (a `transition` change applies from the next change), and a new
1126
+ * variant name does, even to the same values, as a gesture turning on or off does. Both bindings'
1127
+ * target memos compare with it, so a `style`, `transition` or callback change doesn't Retarget.
1128
+ */
1129
+ export const sameResolution = (a: Resolution, b: Resolution): boolean =>
1130
+ a.dragging === b.dragging && sameLabels(a.variant, b.variant) && a.change === b.change && sameValues(a.resolved, b.resolved) && sameValues(a.base, b.base) &&
1131
+ sameKeyframesNow(a.keyframes, b.keyframes) && sameLayersOn(a.layersOn, b.layersOn) && sameNamesOn(a.names, b.names) && sameEnds(a.ends, b.ends)
1132
+
1133
+ /** Two resolutions' gesture layers on that set values (#470): none on both, the common case, at once. */
1134
+ const sameLayersOn = (a: GestureStates, b: GestureStates): boolean => {
1135
+ if (a === b) return true
1136
+ return a.inView === b.inView && a.focused === b.focused && a.hovered === b.hovered && a.pressed === b.pressed && a.dragged === b.dragged
1137
+ }
1138
+
1139
+ /** Two resolutions' active gesture names (#470): a named entry turning on or off, or a new name. None on both, the common case, at once. */
1140
+ const sameNamesOn = (a: GestureNames, b: GestureNames): boolean => {
1141
+ if (a === b) return true
1142
+ return sameGestureNames(a, b)
1143
+ }
1144
+
1145
+ /**
1146
+ * Two resolutions' Transition ends the same (#470), entry by entry: a key an entry both animates and
1147
+ * ends resolves to its value, so its end is compared here. `undefined` on both, the common case, at once.
1148
+ */
1149
+ const sameEnds = (a: Ends | undefined, b: Ends | undefined): boolean => {
1150
+ if (a === b) return true
1151
+ if (Predicate.isUndefined(a)) return false
1152
+ if (Predicate.isUndefined(b)) return false
1153
+ const y = b.byLayer
1154
+ return Bool.and(a.byLayer.length === y.length, Arr.every(a.byLayer, (ends, i) => sameEndsAt(ends, y[i])))
1155
+ }
1156
+
1157
+ /** The value `key`'s Transition end sets it to in `ends` (#470): its driving entry's, the one entry that ends it. */
1158
+ const endFor = (ends: Ends | undefined, key: string): number | string | undefined => {
1159
+ if (Predicate.isUndefined(ends)) return undefined
1160
+ return Option.match(Arr.findFirst(ends.byLayer, (values) => endsKey(values, key)), { onNone: constUndefined, onSome: (values) => (values as Values.Values)[key] })
1161
+ }
1162
+
1163
+ /** Whether an entry's Transition end sets `key`. */
1164
+ const endsKey = (values: Values.Values | undefined, key: string): boolean => {
1165
+ if (Predicate.isUndefined(values)) return false
1166
+ return Object.hasOwn(values, key)
1167
+ }
1168
+
1169
+ /**
1170
+ * Whether `key`'s Transition end changed since the last Retarget (#470): Motion compares a target's
1171
+ * `transitionEnd` with its values, so a new end animates its key again. None on either, the common
1172
+ * case, at once.
1173
+ */
1174
+ const endMoved = (last: Resolution | undefined, now: Resolution, key: string): boolean => {
1175
+ if (Predicate.isUndefined(last)) return false
1176
+ if (last.ends === now.ends) return false
1177
+ return endFor(last.ends, key) !== endFor(now.ends, key)
1178
+ }
1179
+
1180
+ /** An entry's Transition end the same in two resolutions (#470): none on both, or the same values. */
1181
+ const sameEndsAt = (a: Values.Values | undefined, b: Values.Values | undefined): boolean => {
1182
+ if (a === b) return true
1183
+ if (Predicate.isUndefined(a)) return false
1184
+ if (Predicate.isUndefined(b)) return false
1185
+ return sameValues(a, b)
1186
+ }
1187
+
1188
+ /** Two lists of stops equal stop by stop (#429, Motion's `shallowCompare`). */
1189
+ const sameStops = (a: Style.Stops, b: Style.Stops): boolean => Bool.or(a === b, Bool.and(a.length === b.length, Arr.every(a, (stop, i) => stop === b[i])))
1190
+
1191
+ /**
1192
+ * Whether a start that can't take its target's shape stays as it is (#430): it makes a Measured pair
1193
+ * with it, so its leg measures both ends rather than starting at the target.
1194
+ */
1195
+ const keepsStart = (key: string, start: number | string | undefined, target: number | string): boolean => {
1196
+ if (Predicate.isUndefined(start)) return false
1197
+ return MeasuredPair.needs(key, start, target)
1198
+ }
1199
+
1200
+ /** The keys that may be Measured pairs (#430): those found, and each Keyframes key, its start now its first stop. */
1201
+ const measuringOf = (found: ReadonlyArray<string> | undefined, keyframes: KeyframesNow | undefined): ReadonlyArray<string> =>
1202
+ Arr.appendAll(UndefinedOr.match(found, { onUndefined: (): ReadonlyArray<string> => [], onDefined: identity }), UndefinedOr.match(keyframes, { onUndefined: (): ReadonlyArray<string> => [], onDefined: Rec.keys }))
1203
+
1204
+ /**
1205
+ * A Retarget's Measured pairs (#430): each of `keys` whose start and target are one, asked of the
1206
+ * end-of-task batch with the values the element draws now, but a key with Keyframes of more than two
1207
+ * stops (`many`, #460). `undefined` with none.
1208
+ */
1209
+ const measuredOf = (element: HTMLElement, keys: ReadonlyArray<string>, from: Values.Values, to: Values.Values, values: Values.Values, many: StopsByKey | undefined): MeasuredPairs | undefined => {
1210
+ const pairs: Record<string, { readonly from: number | string; readonly to: number | string }> = {}
1211
+ Arr.forEach(keys, (key) => {
1212
+ if (hasManyStops(many, key)) return
1213
+ const start = from[key]
1214
+ const target = to[key]
1215
+ if (Bool.or(Predicate.isUndefined(start), Predicate.isUndefined(target))) return
1216
+ if (MeasuredPair.needs(key, start as number | string, target as number | string)) pairs[key] = { from: start as number | string, to: target as number | string }
1217
+ })
1218
+ if (Rec.isEmptyRecord(pairs)) return undefined
1219
+ return MeasuredPair.measure(element, pairs, values)
1220
+ }
1221
+
1222
+ /** A key's Keyframes in `keyframes` (#429): per key, per Retarget, so a guard, nothing made. */
1223
+ const keyframesAtOf = (keyframes: KeyframesNow | undefined, key: string): KeyframesAt | undefined => {
1224
+ if (Predicate.isUndefined(keyframes)) return undefined
1225
+ return keyframes[key]
1226
+ }
1227
+
1228
+ /** Whether a key's Keyframes are the same (#429, {@link KeyframesAt}): its stops, its entry and that entry's name. */
1229
+ export const sameKeyframesAt = (a: KeyframesAt | undefined, b: KeyframesAt | undefined): boolean => {
1230
+ // Per key, per Retarget (#452): guards, the common case (neither) first.
1231
+ if (a === b) return true
1232
+ if (Predicate.isUndefined(a)) return false
1233
+ if (Predicate.isUndefined(b)) return false
1234
+ return Bool.and(Bool.and(a.layer === b.layer, a.name === b.name), sameStops(a.stops, b.stops))
1235
+ }
1236
+
1237
+ /** Whether two resolutions' Keyframes are the same, key by key (#429): `undefined` on both, the common case, at once. */
1238
+ const sameKeyframesNow = (a: KeyframesNow | undefined, b: KeyframesNow | undefined): boolean => {
1239
+ if (Bool.or(Predicate.isUndefined(a), Predicate.isUndefined(b))) return a === b
1240
+ const x = a as KeyframesNow
1241
+ const y = b as KeyframesNow
1242
+ const keys = Rec.keys(x)
1243
+ return Bool.and(keys.length === Rec.keys(y).length, Arr.every(keys, (key) => sameKeyframesAt(x[key], y[key])))
1244
+ }
1245
+
1246
+ /** Whether `resolution` is `last` with only its `dragging` handed back (#340). */
1247
+ const handsBackOnly = (resolution: Resolution, last: Resolution | undefined): boolean =>
1248
+ UndefinedOr.match(last, { onUndefined: () => false, onDefined: (l) => sameResolution({ ...resolution, dragging: l.dragging }, l) })
1249
+
1250
+ /** Motion's `definition` of an animation (#257): a variant name, or its target values. */
1251
+ export type AnimationDefinition = WardicVariantLabels | Values.Values
1252
+
1253
+ /**
1254
+ * A Retarget's `definition`, as Motion's `onAnimationStart` / `onAnimationComplete` hand it over
1255
+ * (#257): the variant name its base entry resolved, when that name differs from the last started
1256
+ * Retarget's (`previous`), else the target's values. Motion's definition is per animation type: a
1257
+ * new `animate` variant animates as its name, and a gesture turning on or off as values (its own,
1258
+ * or the keys it leaves falling back), so a variant's name is only told when the variant changed.
1259
+ */
1260
+ export const definitionOf = (resolution: Resolution, previous: Resolution | undefined): AnimationDefinition => {
1261
+ const name = resolution.variant
1262
+ // A list is told as a list (#297): a change name by name, as Motion's `checkVariantsDidChange`.
1263
+ if (Bool.and(Predicate.isNotUndefined(name), Bool.not(sameLabels(name, UndefinedOr.map(previous, (p) => p.variant))))) return name as WardicVariantLabels
1264
+ // A gesture's name that just came on (#291), the highest first, as Motion's names its type's.
1265
+ const before = UndefinedOr.match(previous, { onUndefined: () => NO_GESTURE_NAMES, onDefined: (p) => p.names })
1266
+ const started = Arr.findFirst(GESTURES_DOWN, (layer) =>
1267
+ Bool.and(Predicate.isNotUndefined(resolution.names[layer]), Bool.not(sameLabels(resolution.names[layer], before[layer]))))
1268
+ return Option.match(started, { onNone: (): AnimationDefinition => resolution.resolved, onSome: (layer) => resolution.names[layer] as WardicVariantLabels })
1269
+ }
1270
+
1271
+ /** The gesture layers, highest first. */
1272
+ const GESTURES_DOWN: ReadonlyArray<GestureLayer> = Arr.reverse(GESTURE_LAYERS)
1273
+
1274
+ /**
1275
+ * What a Retarget tells its binding (#257): that it started, and that its last leg settled. Each is
1276
+ * handed the Retarget's resolution, the variant name the last started Retarget resolved before it
1277
+ * (for {@link definitionOf}), and the config it read.
1278
+ */
1279
+ export interface AnimationHooks {
1280
+ /** A Retarget started its legs (the `when` gate let it); with no leg, it settles at once. */
1281
+ readonly started: (resolution: Resolution, previous: Resolution | undefined, config: WardConfig) => void
1282
+ /** That Retarget's last leg settled: not for one the next Retarget superseded, nor one a leg's failure cut off. */
1283
+ readonly settled: (resolution: Resolution, previous: Resolution | undefined, config: WardConfig) => void
1284
+ /**
1285
+ * A leg of that Retarget failed (#257 item 4): it can't land. Told once a Retarget, at once (a
1286
+ * leg that fails before it writes leaves no flush to wait for), and never before `started`; the
1287
+ * failure is logged and reported apart (ADR-0030).
1288
+ */
1289
+ readonly failed?: ((resolution: Resolution, error: unknown) => void) | undefined
1290
+ /**
1291
+ * Names of a list that settled (#297): a binding told each name's end on its own (Solid 1's
1292
+ * callbacks, Motion's `animateVariant` a name) has it, called as the legs of the keys each drives
1293
+ * settle; one with none hears the list's end through `settled` alone.
1294
+ */
1295
+ readonly namesSettled?: ((names: ReadonlyArray<string>, config: WardConfig) => void) | undefined
1296
+ }
1297
+
1298
+ /** A list a Retarget tells settled name by name (#297): its names, and what it tells. */
1299
+ interface ToldNames {
1300
+ readonly names: ReadonlyArray<string>
1301
+ readonly tell: (names: ReadonlyArray<string>, config: WardConfig) => void
1302
+ }
1303
+
1304
+ /** Whether a resolution resolved a list (#297): its base, or an active gesture's. Cheap for the common case. */
1305
+ const hasList = (resolution: Resolution): boolean => {
1306
+ if (Arr.isArray(resolution.variant)) return true
1307
+ if (resolution.names === NO_GESTURE_NAMES) return false
1308
+ return Arr.some(GESTURE_LAYERS, (layer) => Arr.isArray(resolution.names[layer]))
1309
+ }
1310
+
1311
+ /** The list a Retarget tells settled name by name (#297): when its binding is told so, and its definition is a list. */
1312
+ const namesToldOf = (animation: AnimationHooks | undefined, resolution: Resolution, previous: Resolution | undefined): ToldNames | undefined => {
1313
+ if (Predicate.isUndefined(animation)) return undefined
1314
+ const tell = animation.namesSettled
1315
+ if (Predicate.isUndefined(tell)) return undefined
1316
+ if (Bool.not(hasList(resolution))) return undefined
1317
+ const definition = definitionOf(resolution, previous)
1318
+ if (Bool.not(Arr.isArray(definition))) return undefined
1319
+ return { names: definition as ReadonlyArray<string>, tell }
1320
+ }
1321
+
1322
+ /**
1323
+ * A list's names told settled one by one (#297): what each leg's end is told to, legs started in the
1324
+ * Retarget's order, and each running leg it carries (#325), by its place in `carriedGroups`.
1325
+ */
1326
+ interface NameSettles {
1327
+ readonly leg: () => (end: unknown) => void
1328
+ readonly carried: (i: number) => (end: unknown) => void
1329
+ }
1330
+
1331
+ /**
1332
+ * A list's names, each told settled with the last leg of the keys it drives (#297): its entry's group,
1333
+ * or every leg's when the keys aren't split, the running legs the Retarget carries among them (#325).
1334
+ * A name that drives none is told at once.
1335
+ */
1336
+ const nameSettlesOf = (
1337
+ names: ReadonlyArray<string>,
1338
+ resolution: Resolution,
1339
+ groups: ReadonlyArray<ReadonlySet<string>> | undefined,
1340
+ legGroups: ReadonlyArray<number> | undefined,
1341
+ legCount: number,
1342
+ carriedGroups: ReadonlyArray<ReadonlyArray<number>>,
1343
+ tell: (names: ReadonlyArray<string>) => void,
1344
+ ): NameSettles => {
1345
+ const groupOf = (name: string): number => {
1346
+ if (Predicate.isUndefined(groups)) return 0
1347
+ return Option.getOrElse(Arr.findFirstIndex(resolution.layers, (layer) => layer.name === name), () => 0)
1348
+ }
1349
+ // The legs still running in each group.
1350
+ const left = new Map<number, number>()
1351
+ const add = (g: number): void => {
1352
+ left.set(g, Option.getOrElse(Option.fromUndefinedOr(left.get(g)), () => 0) + 1)
1353
+ }
1354
+ UndefinedOr.match(legGroups, {
1355
+ onUndefined: () => {
1356
+ if (legCount > 0) left.set(0, legCount)
1357
+ },
1358
+ onDefined: (tags) => Arr.forEach(tags, add),
1359
+ })
1360
+ Arr.forEach(carriedGroups, (gs) => Arr.forEach(gs, add))
1361
+ const running = (name: string): boolean => left.has(groupOf(name))
1362
+ let pending = Arr.filter(names, running)
1363
+ const idle = Arr.filter(names, (name) => Bool.not(running(name)))
1364
+ if (idle.length > 0) tell(idle)
1365
+ // A leg in group `g` ended: the names of that group are told once its last has.
1366
+ const endIn = (g: number): void => {
1367
+ const n = Option.getOrElse(Option.fromUndefinedOr(left.get(g)), () => 1) - 1
1368
+ if (n > 0) {
1369
+ left.set(g, n)
1370
+ return
1371
+ }
1372
+ left.delete(g)
1373
+ const done = Arr.filter(pending, (name) => groupOf(name) === g)
1374
+ pending = Arr.filter(pending, (name) => groupOf(name) !== g)
1375
+ if (done.length > 0) tell(done)
1376
+ }
1377
+ let next = 0
1378
+ return {
1379
+ leg: () => {
1380
+ const g = UndefinedOr.match(legGroups, { onUndefined: () => 0, onDefined: (tags) => Option.getOrElse(Option.fromUndefinedOr(tags[next]), () => 0) })
1381
+ next++
1382
+ return (end) => {
1383
+ // A Superseded leg (#200) settles nothing: the next Retarget's tells.
1384
+ if (Supersede.isSuperseded(end)) return
1385
+ endIn(g)
1386
+ }
1387
+ },
1388
+ carried: (i) => (end) => {
1389
+ if (Supersede.isSuperseded(end)) return
1390
+ Arr.forEach(UndefinedOr.match(carriedGroups[i], { onUndefined: (): ReadonlyArray<number> => [], onDefined: identity }), endIn)
1391
+ },
1392
+ }
1393
+ }
1394
+
1395
+ /**
1396
+ * Solid 1's animation callbacks (#257, Motion's props): each Retarget's start and settle told to the
1397
+ * config's `onAnimationStart` / `onAnimationComplete`, with its `definition`, as the Retarget read
1398
+ * the config. A callback that throws is reported, and the element animates on. The Solid 2 binding's
1399
+ * config has neither: it hands the same facts over as async values.
1400
+ */
1401
+ export const animationCallbacks = (runtime: WardicRuntime, id: string): AnimationHooks => {
1402
+ // Per Retarget, per element: the callback looked up first, and nothing made without one.
1403
+ const tell = (name: "onAnimationStart" | "onAnimationComplete", callback: (definition: WardicAnimationDefinition) => void, definition: WardicAnimationDefinition): void => {
1404
+ try {
1405
+ callback(definition)
1406
+ } catch (defect) {
1407
+ runtime.runFork(Report.failure(`wardic.spine: ${name} failed`, Cause.die(defect)).pipe(Effect.annotateLogs({ id })))
1408
+ }
1409
+ }
1410
+ return {
1411
+ // A list starts as each of its names, in order (#297, Motion's `animateVisualElement` a name).
1412
+ started: (resolution, previous, config) => {
1413
+ const callback = config.onAnimationStart
1414
+ if (Predicate.isUndefined(callback)) return
1415
+ const definition = definitionOf(resolution, previous)
1416
+ if (Arr.isArray(definition)) {
1417
+ Arr.forEach(definition as ReadonlyArray<string>, (name) => tell("onAnimationStart", callback, name))
1418
+ return
1419
+ }
1420
+ tell("onAnimationStart", callback, definition)
1421
+ },
1422
+ // A list's names were each told as they settled (`namesSettled`).
1423
+ settled: (resolution, previous, config) => {
1424
+ const callback = config.onAnimationComplete
1425
+ if (Predicate.isUndefined(callback)) return
1426
+ const definition = definitionOf(resolution, previous)
1427
+ if (Arr.isArray(definition)) return
1428
+ tell("onAnimationComplete", callback, definition)
1429
+ },
1430
+ namesSettled: (names, config) => {
1431
+ const callback = config.onAnimationComplete
1432
+ if (Predicate.isUndefined(callback)) return
1433
+ Arr.forEach(names, (name) => tell("onAnimationComplete", callback, name))
1434
+ },
1435
+ }
1436
+ }
1437
+
1438
+ /** Which entries of the Override stack are active now, as the binding reads them. */
1439
+ export interface Active {
1440
+ /** In view (#273): `whileInView` applies. */
1441
+ readonly inView: boolean
1442
+ /** Focused, as the Environment shows it (`:focus-visible`, #273): `whileFocus` applies. */
1443
+ readonly focused: boolean
1444
+ readonly hovered: boolean
1445
+ readonly pressed: boolean
1446
+ /** A drag, or a **Keyboard reorder**'s lift (ADR-0037): `whileDrag` applies. */
1447
+ readonly dragged: boolean
1448
+ /** A drag: the translate keys are the drag's (ADR-0004). */
1449
+ readonly dragging: boolean
1450
+ }
1451
+
1452
+ /** The variant name an element animates to: its own `animate`'s, else the one its provider hands down. */
1453
+ const variantOf = (animate: WardConfig["animate"], parent: WardicVariantContextValue | undefined): WardicVariantLabels | undefined => {
1454
+ if (Predicate.isNotUndefined(animate)) return nameOf(animate)
1455
+ if (Predicate.isUndefined(parent)) return undefined
1456
+ return parent.variant()
1457
+ }
1458
+
1459
+ /** The base target (ADR-0007): its own `animate`'s, else the inherited name's, else the seeded `initial`. */
1460
+ const baseTargetOf = (
1461
+ own: Entry | undefined,
1462
+ variant: WardicVariantLabels | undefined,
1463
+ variants: WardicVariants | undefined,
1464
+ custom: unknown,
1465
+ state: VariantState,
1466
+ initialLink: Values.Values,
1467
+ ): Target => {
1468
+ if (Predicate.isNotUndefined(own)) return resolveTarget(own, variants, custom, state)
1469
+ if (Predicate.isNotUndefined(variant)) return resolveTarget(variant, variants, custom, state)
1470
+ return { values: initialLink, transition: undefined, transitionEnd: undefined, keyframes: undefined }
1471
+ }
1472
+
1473
+ /**
1474
+ * The Override stack resolved (ascending priority, Motion's `variantPriorityOrder`): base (animate, or
1475
+ * initial when no animate) -> whileInView -> whileFocus -> whileHover -> whileTap -> whileDrag (#273
1476
+ * added the first two). `Override.resolve` picks the last active entry per key. Pure:
1477
+ * a binding computes it in a memo, so a config change, an inherited variant name's
1478
+ * (`parent.variant()`, read only when there's no `animate`) or an entry's drives a Retarget.
1479
+ */
1480
+ export const resolutionOf = (
1481
+ c: WardConfig,
1482
+ parent: WardicVariantContextValue | undefined,
1483
+ initialLink: Values.Values,
1484
+ active: Active,
1485
+ state: VariantState,
1486
+ own?: ControlsChange | undefined,
1487
+ ): Resolution => {
1488
+ // The Controls change in effect (#433): its own controls', else its provider's, read here so a new one Retargets.
1489
+ const change = changeIn(own, parent)
1490
+ const variants = c.variants
1491
+ // Base target resolution priority (ADR-0007):
1492
+ // (1) local `animate` (a Values map or a variant name) — overrides any
1493
+ // inherited variant entirely;
1494
+ // (2) else an INHERITED variant name from the parent context, resolved
1495
+ // against THIS child's OWN `variants` (a child's "open" != its
1496
+ // sibling's "open"); read parent.variant() here so a parent flip
1497
+ // recomputes the memo and retargets;
1498
+ // (3) else the SSR-seeded `initial`.
1499
+ // Per Retarget, per element (#460, compose once): statements.
1500
+ const variant = variantOf(c.animate, parent)
1501
+ // A list of names (#297, Motion's `VariantLabels`): a base entry a name, in order, so the last name
1502
+ // that sets a key drives it. A single name or a values map takes the path below, as before.
1503
+ if (Arr.isArray(c.animate) || (Predicate.isUndefined(c.animate) && Arr.isArray(variant))) {
1504
+ const targets = resolveTargets(variant as ReadonlyArray<string>, variants, c.custom, state)
1505
+ const merged = mergedOf(targets)
1506
+ const listLayers: Array<OverrideEntry> = Arr.map(targets, namedLayerOf)
1507
+ return withGestures(c, parent, listLayers, merged.values, variant, active, merged.transition, state, change)
1508
+ }
1509
+ // A dynamic variant resolves with this element's own `custom` (#277), as Motion's each child's.
1510
+ // Animation controls never reach here: its binding reads them once, each change its entry (#433).
1511
+ const target = baseTargetOf(c.animate as Entry | undefined, variant, variants, c.custom, state, initialLink)
1512
+ const base = target.values
1513
+ const baseLayer: OverrideEntry = layerOf(target, variant as string | undefined)
1514
+ // A Variant child's gestures are on while its provider's are (#291, Motion's `setActive`), each on
1515
+ // its own `while*`, else the label the provider hands down. With no provider, its own: nothing made.
1516
+ // The common case: nothing handed down and no gesture on. The base entry alone, and nothing else
1517
+ // made or called, at every element's mount and Retarget.
1518
+ if (handDownFrom(parent) === NO_HAND_DOWN && !anyOn(active)) {
1519
+ const alone: ReadonlyArray<OverrideEntry> = [baseLayer]
1520
+ const { resolved, ends, keyframes } = resolvedOf(alone)
1521
+ return { resolved, base, dragging: active.dragging, variant, active, transition: target.transition, layers: alone, names: NO_GESTURE_NAMES, layersOn: NO_GESTURE_STATES, ends, keyframes, change }
1522
+ }
1523
+ return withGestures(c, parent, [baseLayer], base, variant, active, target.transition, state, change)
1524
+ }
1525
+
1526
+ /** The **Controls change** in effect for an element (#433): its own, else its provider's; per Retarget, a guard. */
1527
+ const changeIn = (own: ControlsChange | undefined, parent: WardicVariantContextValue | undefined): ControlsChange | undefined => {
1528
+ if (Predicate.isNotUndefined(own)) return own
1529
+ if (Predicate.isUndefined(parent)) return undefined
1530
+ const inherited = parent.change
1531
+ if (Predicate.isUndefined(inherited)) return undefined
1532
+ return inherited()
1533
+ }
1534
+
1535
+ /**
1536
+ * `resolution` run on its Controls change's override (#433, Motion's `transitionOverride`): its base
1537
+ * entries' own transitions beaten by it, its gestures' kept. The first Retarget for the change only.
1538
+ */
1539
+ const overriddenOf = (resolution: Resolution, override: WardicTransition): Resolution => {
1540
+ const variant = resolution.variant
1541
+ let base = 1
1542
+ if (Arr.isArray(variant)) base = variant.length
1543
+ return {
1544
+ ...resolution,
1545
+ transition: override as WardicVariantTransition,
1546
+ layers: Arr.map(resolution.layers, (layer, i) => Bool.match(i < base, { onTrue: (): OverrideEntry => ({ ...layer, transition: override as WardicVariantTransition }), onFalse: () => layer })),
1547
+ }
1548
+ }
1549
+
1550
+ /**
1551
+ * A resolution from its base entries (one, or one a name of a list, #297) and its gesture layers on
1552
+ * top (#291), each gesture's an entry a name too: the Override stack resolved, and the names its
1553
+ * active gestures resolved.
1554
+ */
1555
+ const withGestures = (
1556
+ c: WardConfig,
1557
+ parent: WardicVariantContextValue | undefined,
1558
+ layers: Array<OverrideEntry>,
1559
+ base: Values.Values,
1560
+ variant: WardicVariantLabels | undefined,
1561
+ active: Active,
1562
+ transition: WardicVariantTransition | undefined,
1563
+ state: VariantState,
1564
+ change: ControlsChange | undefined,
1565
+ ): Resolution => {
1566
+ const variants = c.variants
1567
+ const above = handDownFrom(parent)
1568
+ if (Bool.and(above === NO_HAND_DOWN, Bool.not(anyOn(active)))) {
1569
+ const { resolved, ends, keyframes } = resolvedOf(layers)
1570
+ return { resolved, base, dragging: active.dragging, variant, active, transition, layers, names: NO_GESTURE_NAMES, layersOn: NO_GESTURE_STATES, ends, keyframes, change }
1571
+ }
1572
+ const on = gesturesOnOf(active, above)
1573
+ const labels = above.names
1574
+ // In Motion's priority, lowest first: a literal's fields are evaluated in order.
1575
+ const layersOn: GestureStates = {
1576
+ inView: gestureLayersInto(layers, c.whileInView, on.inView, labels.inView, variants, c.custom, state),
1577
+ focused: gestureLayersInto(layers, c.whileFocus, on.focused, labels.focused, variants, c.custom, state),
1578
+ hovered: gestureLayersInto(layers, c.whileHover, on.hovered, labels.hovered, variants, c.custom, state),
1579
+ pressed: gestureLayersInto(layers, c.whileTap, on.pressed, labels.pressed, variants, c.custom, state),
1580
+ // whileDrag sits ABOVE tap (highest priority) — driven by the spring,
1581
+ // NOT stripped, so e.g. `scale: 1.1` animates while held and returns
1582
+ // after release.
1583
+ dragged: gestureLayersInto(layers, c.whileDrag, on.dragged, labels.dragged, variants, c.custom, state),
1584
+ }
1585
+ const { resolved, ends, keyframes } = resolvedOf(layers)
1586
+ const names = activeNamesFor(c, on, labels)
1587
+ return { resolved, base, dragging: active.dragging, variant, active, transition, layers, names, layersOn, ends, keyframes, change }
1588
+ }
1589
+
1590
+ /** The values an element starts from, read once at setup (ADR-0003, #134). */
1591
+ export interface Start {
1592
+ /** Its Starting style's values: its `initial` (own or inherited, #50), or its `animate` when it starts there. */
1593
+ readonly initialValues: Values.Values
1594
+ /** Its `initial` link in the Base-value chain and its fallback base entry: none when it started at `animate`. */
1595
+ readonly initialLink: Values.Values
1596
+ /** When it started at `animate`, those values, which come after `style` (Motion's `baseTarget`, ADR-0022). */
1597
+ readonly startedLink: Values.Values
1598
+ /**
1599
+ * Whether its mount tells nothing (#448, Motion's `animation-state.ts`): it starts at its `animate`
1600
+ * (`initial={false}`, or an `<AnimatePresence initial={false}>`'s first render), or its `initial` is
1601
+ * the same name, list or values map as its `animate`, each its own or inherited. Its first Retarget,
1602
+ * landing with nothing to animate, is told to no one.
1603
+ */
1604
+ readonly quiet: boolean
1605
+ }
1606
+
1607
+ /**
1608
+ * An element's {@link Start}, from its config read once and the context it inherits from. With
1609
+ * `initial={false}` (its own, inherited, or an `<AnimatePresence initial={false}>`'s first render)
1610
+ * it starts at its `animate`, and nothing animates at mount (#134).
1611
+ */
1612
+ export const startOf = (
1613
+ config: WardConfig,
1614
+ parent: WardicVariantContextValue | undefined,
1615
+ presenceBlocks: boolean,
1616
+ untrack: Reactivity["untrack"],
1617
+ ): Start => {
1618
+ const startedAtAnimate = startsAtAnimate(config, parent, presenceBlocks)
1619
+ const initialValues = startingValuesOf(config, parent, presenceBlocks, untrack)
1620
+ return {
1621
+ quiet: startsQuiet(config, parent, presenceBlocks, untrack),
1622
+ initialValues,
1623
+ initialLink: Bool.match(startedAtAnimate, { onTrue: () => ({}), onFalse: () => initialValues }),
1624
+ startedLink: Bool.match(startedAtAnimate, { onTrue: () => initialValues, onFalse: () => ({}) }),
1625
+ }
1626
+ }
1627
+
1628
+ /**
1629
+ * The Snapshot: each key's last emitted value, a number or a string, and the numeric velocities.
1630
+ * A Retarget starts each key from where it is, with its velocity carried across the seam (ADR-0005,
1631
+ * ADR-0024). Plain, not reactive; a drag writes its `x`/`y` into it too (ADR-0004).
1632
+ */
1633
+ export interface Snapshot {
1634
+ values: Values.Values
1635
+ /**
1636
+ * Each numeric key's velocity (#464, Motion's): a spring's own, a drag's pointer's, or, for a key a
1637
+ * leg let go, the one its last two frames gave it. Read through the spine, which takes a running
1638
+ * leg's and reads one drawn more than `MAX_VELOCITY_DELTA` ago as 0.
1639
+ */
1640
+ velocities: Record<string, number>
1641
+ /**
1642
+ * When each key's velocity here was last drawn, on {@link frameNow}'s clock (#464): the last frame of
1643
+ * the leg that let it go, or a drag's or a presence seed's setting.
1644
+ */
1645
+ drawnAt: Record<string, number>
1646
+ /** The leg drawing each key, its spine's (#464): a running leg's velocity is read from it. None before its spine runs. */
1647
+ owners: ReadonlyMap<string, Running | undefined> | undefined
1648
+ /** The time now, its provider's Clock's once its spine runs (#460, Q7), {@link frameNow} before. */
1649
+ now: () => number
1650
+ }
1651
+
1652
+ /** A Snapshot seeded from the Starting values, velocities 0, so frame 1 flows out of the seed (no snap). */
1653
+ export const snapshotOf = (start: Start): Snapshot => emptySnapshotOf({ ...start.initialValues })
1654
+
1655
+ /** A Snapshot of `values`, nothing moving: read as it is until a spine reads it. */
1656
+ export const emptySnapshotOf = (values: Values.Values): Snapshot => ({ values, velocities: {}, drawnAt: {}, owners: undefined, now: frameNow })
1657
+
1658
+ // --- Velocities (#464) ---------------------------------------------------------------------------
1659
+
1660
+ /** A leg's velocity for `key`: a Blend leg's from its frames, a Snap's none, a spring's or a follow's as it wrote it. */
1661
+ const legVelocityOf = (snapshot: Snapshot, running: Running, key: string): number => {
1662
+ if (running.kind === "Blend") return blendVelocityOf(running, key)
1663
+ if (running.kind === "Snap") return 0
1664
+ return velocityOf(snapshot, key)
1665
+ }
1666
+
1667
+ /**
1668
+ * `key`'s velocity at `now` (#464, Motion's `getVelocity`): the leg drawing it, once it has drawn a
1669
+ * frame, else what the Snapshot holds for it (the last leg to let it go left it, a drag or a seed set
1670
+ * it), whichever drew it last; 0 once nothing has moved it for `MAX_VELOCITY_DELTA`. Read only for a
1671
+ * key a spring or a follow starts, or one a leg lets go: guards, nothing made.
1672
+ */
1673
+ const velocityAt = (snapshot: Snapshot, owner: Running | undefined, key: string, now: number): number => {
1674
+ const at = snapshot.drawnAt[key]
1675
+ // Guards, not `Bool.and`, which reads both sides: a leg that hasn't drawn yet stands for nothing.
1676
+ if (Predicate.isNotUndefined(owner)) {
1677
+ if (owner.frames > 0) {
1678
+ if (Predicate.isUndefined(at) || owner.lastAt >= (at as number)) {
1679
+ if (now - owner.lastAt > MAX_VELOCITY_DELTA) return 0
1680
+ return legVelocityOf(snapshot, owner, key)
1681
+ }
1682
+ }
1683
+ }
1684
+ if (Predicate.isUndefined(at)) return 0
1685
+ if (now - at > MAX_VELOCITY_DELTA) return 0
1686
+ return velocityOf(snapshot, key)
1687
+ }
1688
+
1689
+ /**
1690
+ * `running` lets `key` go, having drawn it (#464): the velocity it gives the key now (0 once it's drawn
1691
+ * nothing for 30 ms) and its last frame's time stay on the Snapshot, as numbers. Keeping the leg itself
1692
+ * kept its Retarget's closures alive until the unmount, which paid for them. A string carries none.
1693
+ */
1694
+ const letGo = (snapshot: Snapshot, key: string, running: Running): void => {
1695
+ if (running.frames === 0) return
1696
+ if (!Predicate.isNumber(snapshot.values[key])) return
1697
+ snapshot.velocities[key] = velocityAt(snapshot, running, key, snapshot.now())
1698
+ snapshot.drawnAt[key] = running.lastAt
1699
+ }
1700
+
1701
+ /** Every numeric key's velocity now (#464): a presence's exit and takeover read it (#286). */
1702
+ export const velocitiesNowOf = (snapshot: Snapshot): Readonly<Record<string, number>> => {
1703
+ const now = snapshot.now()
1704
+ const owners = snapshot.owners
1705
+ return Rec.map(Rec.filter(snapshot.values, Predicate.isNumber), (_, key) =>
1706
+ velocityAt(snapshot, UndefinedOr.match(owners, { onUndefined: constUndefined, onDefined: (map) => map.get(key) }), key, now))
1707
+ }
1708
+
1709
+ /**
1710
+ * The transition a Retarget runs on (#66): the element's last one when the new one has the same
1711
+ * fields, so core's decode cache hits when the object is rebuilt with the same values (a staggered
1712
+ * child's, ADR-0007, or one Solid rebuilds as it reads a signal). One per element.
1713
+ */
1714
+ export const makeReuse = (): ((transition: WardicTransition) => WardicTransition) => {
1715
+ let lastTransition: WardicTransition | undefined
1716
+ // Per Retarget (#460, compose once): statements.
1717
+ return (transition) => {
1718
+ if (Predicate.isNotUndefined(lastTransition) && sameFields(lastTransition, transition)) return lastTransition
1719
+ lastTransition = transition
1720
+ return transition
1721
+ }
1722
+ }
1723
+
1724
+ /**
1725
+ * A mounted element's Base-value links (ADR-0022): a key with no value starts from its `style`
1726
+ * value, else its Own value. The Own value is read from the element once per key, at first need
1727
+ * (D3): after mount, so never on a server (ADR-0021). Each link is coerced to the shape of the
1728
+ * key's target (`like`). `styleNow` reads the user's style untracked; a Live value in it is read now.
1729
+ */
1730
+ export const startLinksOf = (element: HTMLElement, styleNow: (() => object | string | undefined) | undefined, live: LiveStyle | undefined) => {
1731
+ const ownValue = OwnValues.of(element)
1732
+ // A `style` value read now: a Live value's current value (#130), anything else as it is.
1733
+ const readStyle = (raw: unknown): unknown => {
1734
+ if (Predicate.isUndefined(live)) return raw
1735
+ return live.read(raw)
1736
+ }
1737
+ const linksFor = (like: number | string) => ({
1738
+ style: (key: string) =>
1739
+ Option.flatMap(Option.fromUndefinedOr(styleNow), (now) =>
1740
+ Option.flatMap(OwnValues.styleValueOf(now(), key), (raw) => OwnValues.valueLike(readStyle(raw), like)),
1741
+ ),
1742
+ own: (key: string) => Option.flatMap(ownValue(key), (raw) => OwnValues.valueLike(raw, like)),
1743
+ })
1744
+ const startLinkOf = (key: string, like: number | string) => BaseValue.start(key, linksFor(like))
1745
+ return { ownValue, linksFor, startLinkOf }
1746
+ }
1747
+
1748
+ /** {@link startLinksOf}'s links. */
1749
+ export type StartLinks = ReturnType<typeof startLinksOf>
1750
+
1751
+ /**
1752
+ * An element's presence record (ADR-0007 exit): seeded with its Starting values, so an exit that
1753
+ * fires before any frame still has a `from`, and its `exit` ref, which the ward keeps current. An exit key with no value starts
1754
+ * from its Base value's start links (ADR-0022), read from the retained node at the exit.
1755
+ */
1756
+ export const presenceRecordOf = (
1757
+ element: HTMLElement,
1758
+ start: Start,
1759
+ exitOf: (custom: unknown, inherited: WardicVariantLabels | undefined) => ExitTarget,
1760
+ links: StartLinks,
1761
+ tree: PresenceTree,
1762
+ snapshot: Snapshot,
1763
+ reducedMotion: () => boolean,
1764
+ skipAnimations: () => boolean,
1765
+ ): PresenceRecord => ({
1766
+ element,
1767
+ snapshot: { current: { ...start.initialValues } },
1768
+ exitOf,
1769
+ tree,
1770
+ startOf: (key, like) => Option.getOrUndefined(Option.map(links.startLinkOf(key, like), (s) => s.value)),
1771
+ // Its spine's, read when a child back under its key takes over from it (#286): its running legs' too (#464).
1772
+ velocities: () => velocitiesNowOf(snapshot),
1773
+ // Its own, under its nearest WardicConfig (#434): its exit honours it, not the presence's.
1774
+ reducedMotion,
1775
+ // Its nearest WardicConfig's (#468): an exit is skipped as its element's animations are.
1776
+ skipAnimations,
1777
+ })
1778
+
1779
+ /**
1780
+ * Merge an emitted frame's value-map into a presence record's snapshot (nothing without one). It
1781
+ * mirrors what the gate accumulates, so an exit departs from the element's actual resting value-map.
1782
+ */
1783
+ export const recordFrameOf = (presence: PresenceRecord | undefined): ((value: Values.Values) => void) => (value) => {
1784
+ if (Predicate.isNotUndefined(presence)) Object.assign(presence.snapshot.current, value)
1785
+ }
1786
+
1787
+ /**
1788
+ * Turn the element's will-change value on (#443, Motion's `addValueToWillChange`) when its `style`
1789
+ * gives it one and one of `legs` animates a transform key or one a browser composites. A key already
1790
+ * at its target starts no leg (#448), and a layout animation runs none, so neither does. Per start:
1791
+ * a lookup in its routed keys, none for a style that routes nothing.
1792
+ */
1793
+ const turnWillChangeOn = (live: LiveStyle | undefined, legs: ReadonlyArray<Leg>): void => {
1794
+ if (Predicate.isUndefined(live)) return
1795
+ const turnOn = live.willChange()
1796
+ if (Predicate.isUndefined(turnOn)) return
1797
+ if (Arr.some(legs, (leg) => Arr.some(Rec.keys(leg.to), turnsWillChangeOn))) turnOn()
1798
+ }
1799
+
1800
+ /**
1801
+ * A binding's `setDragging`, turning the element's will-change value on as a drag starts (#443,
1802
+ * Motion's): `"transform"`, as its drag draws `x` and `y`.
1803
+ */
1804
+ export const draggingWithWillChange = (live: LiveStyle | undefined, setDragging: (on: boolean) => void): ((on: boolean) => void) =>
1805
+ UndefinedOr.match(live, {
1806
+ onUndefined: () => setDragging,
1807
+ onDefined: (style) => (on: boolean) => {
1808
+ if (on) UndefinedOr.map(style.willChange(), (turnOn) => turnOn())
1809
+ setDragging(on)
1810
+ },
1811
+ })
1812
+
1813
+ /** What {@link makeElementSpine} reads. */
1814
+ export interface ElementSpineOptions {
1815
+ /** The provider runtime the legs fork on. */
1816
+ readonly runtime: WardicRuntime
1817
+ /** The provider-owned flush gate (ADR-0006). */
1818
+ readonly gate: FlushGate.Shape
1819
+ /** The element's gate id. */
1820
+ readonly id: string
1821
+ /** The mounted element. */
1822
+ readonly element: HTMLElement
1823
+ /** Its tag, for a Handoff's check (SVG's routing): `undefined` when it isn't known. */
1824
+ readonly tag: string | undefined
1825
+ /** Its config now, read where the binding doesn't track. */
1826
+ readonly config: () => WardConfig
1827
+ /** The variant context it inherits names and its default transition from (`variant-tree.ts`). */
1828
+ readonly parent: WardicVariantContextValue | undefined
1829
+ /** Whether a Retarget may start now (ADR-0007 `when`); omitted, always. */
1830
+ readonly canStart: (() => boolean) | undefined
1831
+ /** Its stagger delay in seconds, read at each Retarget (ADR-0007); omitted, none. */
1832
+ readonly extraDelay: ((name: string | undefined) => number) | undefined
1833
+ /** Told every frame whether it has settled (ADR-0007 orchestration). */
1834
+ readonly onFrame: ((done: boolean) => void) | undefined
1835
+ /** Whether reduced motion applies (ADR-0029), read at each Retarget. */
1836
+ readonly reducedMotion: () => boolean
1837
+ /**
1838
+ * Whether its animations are skipped (#468, its nearest `WardicConfig`'s `skipAnimations`), read at
1839
+ * each Retarget and each Imperative animation: every key lands at its end on the next tick. Omitted, never.
1840
+ */
1841
+ readonly skipAnimations?: (() => boolean) | undefined
1842
+ /** Which keys reduced motion Snaps (ADR-0036). */
1843
+ readonly positionalKeys: ReducedMotion.PositionalKeys["Service"]
1844
+ /** What a key with no transition of its own runs on (ADR-0051). */
1845
+ readonly defaultTransition: DefaultTransition.DefaultTransition["Service"]
1846
+ readonly start: Start
1847
+ readonly snapshot: Snapshot
1848
+ readonly reuse: (transition: WardicTransition) => WardicTransition
1849
+ readonly links: StartLinks
1850
+ /** The user's style now, read untracked: a key's `style` link (ADR-0022). */
1851
+ readonly styleNow: (() => object | string | undefined) | undefined
1852
+ /** Its routed `style` keys (#130, ADR-0043). */
1853
+ readonly live: LiveStyle | undefined
1854
+ /** Its presence record, under an `<AnimatePresence>`. */
1855
+ readonly presence: PresenceRecord | undefined
1856
+ /**
1857
+ * Whether a projection node owns its translate keys (ADR-0016): its drag drives its layout node. A
1858
+ * getter while its track waits for `drag` (#551, #582), so it's read where it's used.
1859
+ */
1860
+ readonly projected: boolean
1861
+ /** Its drag axis, `undefined` without a drag (ADR-0004). */
1862
+ readonly dragAxis: boolean | "x" | "y" | undefined
1863
+ /** Its drag track, whose release a Retarget may take `x`/`y` from (#340); omitted, the drag holds them while `dragging`. */
1864
+ readonly drag?: DragTrack | undefined
1865
+ /** Its Appear animation, while hydrating (#48, ADR-0044 decision 6). */
1866
+ readonly handoff: Handoff | undefined
1867
+ /** Told each Retarget's start and settle (#257); omitted, nothing is told. */
1868
+ readonly animation?: AnimationHooks | undefined
1869
+ /**
1870
+ * A list's names orchestrated each on their own (#297's PR 2): a name's keys start once its gate
1871
+ * opens, and its starts and settles are told. Omitted for an element that joins nothing and
1872
+ * provides nothing.
1873
+ */
1874
+ readonly byName?: NameOrchestration | undefined
1875
+ }
1876
+
1877
+ /** What the follower reads of the element's Override stack and drag, untracked. */
1878
+ export interface FollowNow {
1879
+ readonly resolved: () => Values.Values
1880
+ readonly dragging: () => boolean
1881
+ }
1882
+
1883
+ /** What an **Imperative animation** tells of its legs on one element (#433). */
1884
+ export interface ImperativeHooks {
1885
+ /** Every leg it started on the element landed, told after the gate's flush of their last frames. */
1886
+ readonly settled: () => void
1887
+ /** A leg failed, reported already (ADR-0030). */
1888
+ readonly failed: (cause: Cause.Cause<unknown>) => void
1889
+ }
1890
+
1891
+ /** An **Imperative animation** on one element (#433): its legs, built at the call, run through its Playhead. */
1892
+ export interface ImperativeTrack {
1893
+ /** Run every leg from the Playhead's time: those running end first, so a seek starts them again there. */
1894
+ readonly run: () => void
1895
+ /** End every leg where it is: its keys stay there, the animation's. */
1896
+ readonly stop: () => void
1897
+ /** End every leg, and put its keys back where it started them. */
1898
+ readonly cancel: () => void
1899
+ /** How long its longest leg runs, in seconds (`Machine.durationOf`, Motion's `duration`). */
1900
+ readonly duration: () => number
1901
+ }
1902
+
1903
+ /** A mounted element's spine. */
1904
+ export interface ElementSpine {
1905
+ /** A Retarget toward `resolution`: called by the binding on each change of its target, untracked. */
1906
+ readonly retarget: (resolution: Resolution) => void
1907
+ /** Follow the element's Live values in `style` (#130), from its first routed key on. */
1908
+ readonly follow: (now: FollowNow) => void
1909
+ /** The element's teardown: following stops, and the legs end. */
1910
+ readonly dispose: () => void
1911
+ /**
1912
+ * Start where a leaver is drawn (#286, ADR-0048), before the first Retarget: each key's value and
1913
+ * velocity, drawn now. A key no entry sets returns to its Base value from there, as one a Retarget
1914
+ * drove does.
1915
+ */
1916
+ readonly seed: (from: PresenceSeed) => void
1917
+ /**
1918
+ * An **Imperative animation** of the element (#433): it takes `target`'s keys from whatever runs
1919
+ * them, each noted with the target the Override stack has for it now, so a Retarget leaves it where
1920
+ * the animation leaves it until that target changes (Motion's latest-wins). Its legs start where
1921
+ * the keys are drawn, with their velocity, on `transition` (a key with none of its own on its
1922
+ * Default transition), reduced motion as the provider says, and run through `head` once
1923
+ * {@link ImperativeTrack.run} is called.
1924
+ */
1925
+ readonly animate: (target: Target, transition: WardicTransition | undefined, head: Playback.Playhead, hooks: ImperativeHooks) => ImperativeTrack
1926
+ /** End every running leg where it is (#433, **Animation controls**' `stop`): its keys stay there, until the next Retarget. */
1927
+ readonly stop: () => void
1928
+ }
1929
+
1930
+ /**
1931
+ * A mounted element's spine: its Retarget, the returns to its Base values, the follower of its
1932
+ * Live values, and its legs' lifetime. Every leg is a fiber of its provider's runtime, and joins
1933
+ * its Retarget's token: a Retarget ends the token before it starts its own legs, and {@link
1934
+ * ElementSpine.dispose} ends every leg's (#542). Both end the legs in the calling task: each leg's
1935
+ * run leaves the loop at once, and its fiber ends Superseded, inline (ADR-0027, decision 5,
1936
+ * *Amendment (#200)*). A leg the token didn't reach is interrupted (`endLeg`). The runtime's own
1937
+ * fiber Scope interrupts what's left when the provider ends.
1938
+ */
1939
+ export const makeElementSpine = (options: ElementSpineOptions): ElementSpine => {
1940
+ const { animation, byName, canStart, config, defaultTransition, element, extraDelay, gate, id, links, live, onFrame, parent, positionalKeys, presence, runtime, snapshot, start, styleNow, tag } = options
1941
+ const { initialLink, initialValues, startedLink } = start
1942
+ const { linksFor, ownValue, startLinkOf } = links
1943
+ let handoff = options.handoff
1944
+ // Its mount tells nothing when it starts at its `animate` (#448): on until its first Retarget.
1945
+ let quiet = start.quiet
1946
+ // Its Variable values (#55, ADR-0035 *Amendment (#55)*): the Key rule bound to this element,
1947
+ // added to each leg it starts, so a `var()` end blends what it resolves to here.
1948
+ const elementRules = [Variables.values(element)]
1949
+ const recordFrame = recordFrameOf(presence)
1950
+ // Whether its animations are skipped (#468): never, with nothing given.
1951
+ const skipAnimations = UndefinedOr.match(options.skipAnimations, { onUndefined: () => constFalse, onDefined: identity })
1952
+
1953
+ // A routed key a return handed back: written by the follower from now on (#130). Set by
1954
+ // `follow`; a return settles a tick after it runs at the earliest.
1955
+ let handBack: (key: string) => void = constVoid
1956
+
1957
+ // The keys a Retarget drove, each with its last target value (its shape), and the
1958
+ // ones returning to their Base value until that return settles (ADR-0022). Both are
1959
+ // the spine's: a Retarget mid-return carries them again, so a return is never
1960
+ // frozen half-way, and a key that settled has left them, so a Retarget of the same
1961
+ // target (a `when` gate reopening, ADR-0007) leaves it be. On a drag element, the keys
1962
+ // the drag moves leave the return while it runs, so they stay where it dropped them (C9)
1963
+ // until an entry sets them again; a projected element's drag moves none, its projection
1964
+ // target does (ADR-0016), and its own translate returns as any key does (#363).
1965
+ const driven = new Map<string, number | string>()
1966
+ let returning = new Map<string, BaseValue.BaseSource>()
1967
+ // Read as a drag holds them: `projected` is a getter while the track waits for `drag` (#551), whose
1968
+ // track may drive a layout node that arrived with it (#582).
1969
+ const dragMoves = (): ReadonlyArray<string> => {
1970
+ if (options.projected) return NO_KEYS
1971
+ return UndefinedOr.match(options.dragAxis, { onUndefined: () => NO_KEYS, onDefined: dragMovesOf })
1972
+ }
1973
+
1974
+ // A Retarget's returns have settled (ADR-0022, D4). A key back at its `style` value is
1975
+ // handed back to the element's style, so a later style change shows at rest and the
1976
+ // next gesture starts from it; any other key rests inline at its Base value and leaves
1977
+ // the target. A key a later Retarget took over is left alone. A routed key (#130) stays
1978
+ // in the gate, handed to the follower, which writes its value from now on.
1979
+ const settleReturns = (returns: ReadonlyArray<readonly [string, BaseValue.BaseSource]>): void => {
1980
+ // The returns still this Retarget's: a later one took over the rest.
1981
+ const settled = Arr.filter(returns, ([key, source]) => returning.get(key) === source)
1982
+ Arr.forEach(settled, ([key]) => {
1983
+ returning.delete(key)
1984
+ driven.delete(key)
1985
+ owners.set(key, undefined)
1986
+ })
1987
+ const toStyle = Arr.map(Arr.filter(settled, ([, source]) => source === "style"), ([key]) => key)
1988
+ const routedNow = (key: string): boolean => UndefinedOr.match(live, { onUndefined: constFalse, onDefined: (routes) => routes.routes(key) })
1989
+ Arr.forEach(Arr.filter(toStyle, routedNow), (key) => handBack(key))
1990
+ const handedBack = Arr.filter(toStyle, Predicate.not(routedNow))
1991
+ if (Arr.isReadonlyArrayEmpty(handedBack)) return
1992
+ // The gate writes the user's current value back, as the element's `style` would
1993
+ // (ADR-0034). A key gone from the user's style by now is cleared, not restored stale.
1994
+ const restore = UndefinedOr.map(styleNow, (now) => {
1995
+ const style = now()
1996
+ return Object.fromEntries(
1997
+ Arr.map(handedBack, (key) => [key, Option.match(OwnValues.styleValueOf(style, key), { onNone: () => "", onSome: (value) => String(value) })]),
1998
+ ) as Record<string, string>
1999
+ })
2000
+ gate.release(id, handedBack, restore)
2001
+ Arr.forEach(handedBack, (key) => {
2002
+ delete snapshot.values[key]
2003
+ delete snapshot.velocities[key]
2004
+ if (Predicate.isNotUndefined(presence)) delete presence.snapshot.current[key]
2005
+ })
2006
+ }
2007
+
2008
+ // Cold path: once per Retarget that started a key from its Base value or returned one,
2009
+ // run at the head of that Retarget's first leg (no fiber of its own: forking one per
2010
+ // element cost 10-20 µs each at a 1000-element mount).
2011
+ const baseLog = (started: Record<string, string>, returns: ReadonlyArray<readonly [string, BaseValue.BaseSource]>): Effect.Effect<void> =>
2012
+ Effect.logDebug("wardic.base: a key with no value started from, or returned to, its Base value (ADR-0022)").pipe(
2013
+ Effect.annotateLogs({ id, started, returned: Object.fromEntries(returns) }),
2014
+ )
2015
+
2016
+ // Each key's leg (#325, Motion's per-key rule): the running leg that draws it, or the last one that
2017
+ // did, landed. A Retarget leaves a key its running leg when it resolves it to the same target, starts
2018
+ // none for a key whose last leg landed there, and starts every other key afresh. Each leg has its
2019
+ // own token (#200, ADR-0027 *Amendment (#200)*), ended once it has no key left: Superseded, not
2020
+ // interrupted, so off the loop at once and its fiber ended normally, at about a sixth of an
2021
+ // interrupt's cost.
2022
+ const owners: Owners = new Map()
2023
+ // The keys an Imperative animation took (#433), each with the target the Override stack had for it
2024
+ // then: a Retarget leaves each where the animation leaves it while its target is still that one, and
2025
+ // takes it back once it isn't, as a newer animation of Motion's value takes it (latest-wins).
2026
+ // Every element reads it, nearly none sets it (#460): the shared empty one until the first key taken.
2027
+ let taken: Map<string, number | string | undefined> = NONE_TAKEN
2028
+ // The legs that gave up a key in this Retarget: what each still draws is worked out at its end.
2029
+ const losing: Array<Running> = []
2030
+ // The landing every running leg counts toward: the last Retarget's.
2031
+ let current: Landing | undefined
2032
+ // A gated Retarget's (ADR-0007 `when`, #325): made at the first.
2033
+ let gated: Landing | undefined
2034
+ // The variant name the last started Retarget resolved, for its successor's `definition` (#257).
2035
+ let lastResolution: Resolution | undefined
2036
+ // The Controls change (#433) it last joined, whether it's still counted there (until a landing),
2037
+ // and the one its last started Retarget ran for: only the first runs on its override.
2038
+ let joined: ControlsChange | undefined
2039
+ let counted = false
2040
+ let startedChange: ControlsChange | undefined
2041
+ /** Its Retargets' change is `change` now: it leaves the last, and joins this one, held or not. */
2042
+ const joinChange = (change: ControlsChange | undefined): void => {
2043
+ if (counted) leave(joined as ControlsChange)
2044
+ joined = change
2045
+ counted = Predicate.isNotUndefined(change)
2046
+ if (counted) join(change as ControlsChange)
2047
+ }
2048
+ /** It landed, or can't (a leg failed, its unmount): it leaves its change. */
2049
+ const leaveChange = (): void => {
2050
+ if (!counted) return
2051
+ counted = false
2052
+ leave(joined as ControlsChange)
2053
+ }
2054
+ /** It landed: it leaves its change once the gate has flushed its last frame, unless it joined another meanwhile. */
2055
+ const leaveAfterFlush = (): void => {
2056
+ if (!counted) return
2057
+ const change = joined
2058
+ gate.afterFlush(() => {
2059
+ if (joined === change) leaveChange()
2060
+ })
2061
+ }
2062
+
2063
+ // The element's waiting Transition ends (#508), made at its first: most elements never have one.
2064
+ let waiting: WaitingEnds | undefined
2065
+
2066
+ // A leg with no key left ends. Its fiber ends inline (ADR-0027, *Amendment (#200)*); one its token
2067
+ // didn't reach, none of its runs on the loop, is interrupted. A Transition end it is (#508) is
2068
+ // dropped, written never, as its leg was.
2069
+ const endLeg = (running: Running): void => {
2070
+ Supersede.end(running.supersede)
2071
+ if (Predicate.isNotUndefined(waiting)) waiting.drop(running)
2072
+ const fiber = running.fiber
2073
+ if (Predicate.isUndefined(fiber)) return
2074
+ if (Predicate.isNotUndefined(fiber.pollUnsafe())) return
2075
+ // Interrupted here, nothing waiting on its end, as `runCallback`'s interruptor does: a forked
2076
+ // `Fiber.interrupt` was a fiber of its own per ended leg (#618, L2).
2077
+ fiber.interruptUnsafe()
2078
+ }
2079
+
2080
+ // A leg takes its keys (#325): each key's owner from now on. One callback a spine, not one a leg.
2081
+ let owning: Running | undefined
2082
+ const ownKey = (key: string): void => {
2083
+ owners.set(key, owning)
2084
+ }
2085
+ const own = (running: Running): void => {
2086
+ const keys = Rec.keys(running.targets)
2087
+ running.count = keys.length
2088
+ owning = running
2089
+ Arr.forEach(keys, ownKey)
2090
+ }
2091
+
2092
+ // The legs drawing each key: a running leg's velocity is read from it (#464).
2093
+ snapshot.owners = owners
2094
+ // Its time, its provider's Clock's (#460, Q7).
2095
+ snapshot.now = clockNowOf(runtime)
2096
+ // Each key's velocity, at the time the Retarget or Imperative animation reading it read (#464).
2097
+ let readAt = 0
2098
+ const readVelocity: Velocities = (key) => velocityAt(snapshot, owners.get(key), key, readAt)
2099
+
2100
+ // `key`'s leg gives it up: a leg ends with its last key, and draws only the rest before.
2101
+ const giveUp = (key: string, running: Running): void => {
2102
+ letGo(snapshot, key, running)
2103
+ owners.set(key, undefined)
2104
+ if (running.done) return
2105
+ running.count--
2106
+ if (running.count === 0) return endLeg(running)
2107
+ if (running.losing) return
2108
+ running.losing = true
2109
+ losing.push(running)
2110
+ }
2111
+
2112
+ // The keys the Retarget being worked out resolves, for `giveUpUnresolved`: one callback a spine,
2113
+ // not one a Retarget.
2114
+ let resolvedNow: Values.Values = NO_VALUES
2115
+ // Whether `running` is whole: it still draws every key it was started for, each held now, resolved
2116
+ // by the Retarget being worked out or taken by its Imperative animation. A key its Retarget didn't
2117
+ // resolve, a Path's turn or the axis its target leaves out (#438), is the leg's own: not counted.
2118
+ const holdsWhole = (running: Running): boolean =>
2119
+ Arr.every(Rec.keys(running.targets), (key) => {
2120
+ if (taken.has(key)) return owners.get(key) === running
2121
+ if (Bool.not(Object.hasOwn(running.resolution.resolved, key))) return true
2122
+ return Bool.and(owners.get(key) === running, Object.hasOwn(resolvedNow, key))
2123
+ })
2124
+ const giveUpUnresolved = (owner: Running | undefined, key: string): void => {
2125
+ if (Predicate.isUndefined(owner)) return
2126
+ // An Imperative animation's key (#433) is its own while taken.
2127
+ if (taken.has(key)) return
2128
+ if (Object.hasOwn(resolvedNow, key)) return
2129
+ if (Object.hasOwn(owner.resolution.resolved, key)) return giveUp(key, owner)
2130
+ // A key its leg draws though its own Retarget didn't resolve it rides on with that leg while the
2131
+ // leg is whole (#460, ADR-0065): a Retarget of another key leaves a Path as it was. Once the leg
2132
+ // loses a key, its turn goes back to 0 (`turnBack`) and an axis its target left out stays.
2133
+ if (holdsWhole(owner)) return
2134
+ giveUp(key, owner)
2135
+ }
2136
+
2137
+ // A Path's turn goes back to 0 once no leg draws it (#460, ADR-0065 decision 3): after a Retarget
2138
+ // whose legs don't turn, a stop, a cancel. Most elements never turn: a guard.
2139
+ const turnBack = (): void => {
2140
+ const turn = snapshot.values[PATH_ROTATION]
2141
+ if (Bool.or(Predicate.isUndefined(turn), turn === 0)) return
2142
+ if (Predicate.isNotUndefined(owners.get(PATH_ROTATION))) return
2143
+ snapshot.values = { ...snapshot.values, ...TURNED_BACK }
2144
+ snapshot.velocities = { ...snapshot.velocities, [PATH_ROTATION]: 0 }
2145
+ snapshot.drawnAt[PATH_ROTATION] = snapshot.now()
2146
+ gate.write(id, TURNED_BACK)
2147
+ recordFrame(TURNED_BACK)
2148
+ }
2149
+
2150
+ // Each leg that gave up keys draws the ones it kept from now on: once per such leg, a Retarget.
2151
+ const keepTheRest = (): void => {
2152
+ if (losing.length === 0) return
2153
+ Arr.forEach(losing, (running) => {
2154
+ running.losing = false
2155
+ if (running.count === 0) return
2156
+ const kept = Arr.filter(Rec.keys(running.targets), (key) => owners.get(key) === running)
2157
+ running.values = keepingOnly(kept)
2158
+ running.velocities = keepingOnly(kept)
2159
+ })
2160
+ losing.length = 0
2161
+ }
2162
+
2163
+ /**
2164
+ * Where `key` starts toward `like` (ADR-0024, D1; ADR-0022, D3): its Snapshot value, coerced to its
2165
+ * target's shape; one of another type on a positional key as it is, a Measured pair (#430); else
2166
+ * its Base value's start link, read at its first need, noted in `started`; with none, at its target
2167
+ * (no motion). Guards, not a match: per key, per Retarget, and a key with a value builds nothing.
2168
+ */
2169
+ const startKey = (key: string, like: number | string, started: Record<string, string>): void => {
2170
+ const coerced = OwnValues.valueLike(snapshot.values[key], like)
2171
+ if (Option.isSome(coerced)) snapshot.values[key] = coerced.value
2172
+ // A start of another type than its target's, on a positional key, stays as it is: a Measured
2173
+ // pair (#430), measured at the end of the task.
2174
+ if (Option.isSome(coerced)) return
2175
+ if (keepsStart(key, snapshot.values[key], like)) return
2176
+ const link = startLinkOf(key, like)
2177
+ if (Option.isSome(link) && isSameKind(link.value.value, like)) {
2178
+ snapshot.values[key] = link.value.value
2179
+ started[key] = link.value.source
2180
+ return
2181
+ }
2182
+ snapshot.values[key] = like
2183
+ started[key] = "target"
2184
+ }
2185
+
2186
+ // A key's leg ended by a failure (#257 item 4): nothing draws its keys, so a later Retarget starts them afresh.
2187
+ const forget = (running: Running): void =>
2188
+ Arr.forEach(Rec.keys(running.targets), (key) => {
2189
+ if (owners.get(key) !== running) return
2190
+ letGo(snapshot, key, running)
2191
+ owners.set(key, undefined)
2192
+ })
2193
+
2194
+ /**
2195
+ * A leg's run into its sink: one dispatcher, each sink built for the leg that needs it, a
2196
+ * Retarget's and an Imperative animation's (#433). A blend's machine is built under the element's
2197
+ * Key rules when its change holds a Variable value (`variables`, #542).
2198
+ */
2199
+ const legProgram = (leg: Leg, running: Running, variables: boolean): Effect.Effect<unknown, never, WardicServices> => {
2200
+ if (leg._tag === "Follow") {
2201
+ const key = leg.key
2202
+ const out: Record<string, number> = { [key]: 0 }
2203
+ // Per leg (#460): Machine's calls data-first; per frame, statements.
2204
+ return Effect.suspend(() =>
2205
+ Machine.run(leg.machine(), (frame) => {
2206
+ out[key] = frame.value
2207
+ snapshot.values[key] = frame.value
2208
+ let velocity = frame.velocity
2209
+ if (Predicate.isUndefined(velocity)) velocity = 0
2210
+ snapshot.velocities[key] = velocity
2211
+ gate.write(id, out)
2212
+ recordFrame(out)
2213
+ drew(running, frame.done, snapshot.now())
2214
+ if (frame.done) landEndsOf(waiting)
2215
+ return undefined
2216
+ }, running)
2217
+ )
2218
+ }
2219
+ if (leg._tag === "Numbers") {
2220
+ return Effect.suspend(() =>
2221
+ Machine.run(leg.machine(), (frame) => {
2222
+ // MULTI-OWNER MERGE (ADR-0004): merge the spring's keys into the snapshot
2223
+ // rather than replacing it, so the drag's direct-set x/y survive alongside the
2224
+ // spring's keys (drag owns x/y, spring owns the rest) and the post-drag
2225
+ // handoff continues from the rested position. Only the keys it still draws (#325).
2226
+ const value = running.values(frame.value)
2227
+ snapshot.values = { ...snapshot.values, ...value }
2228
+ snapshot.velocities = { ...snapshot.velocities, ...running.velocities(frame.velocity) }
2229
+ gate.write(id, value)
2230
+ recordFrame(value)
2231
+ drew(running, frame.done, snapshot.now())
2232
+ if (frame.done) landEndsOf(waiting)
2233
+ return undefined
2234
+ }, running)
2235
+ )
2236
+ }
2237
+ // A snap's or a blend's frames: merged into the Snapshot (ADR-0004), as the spring's are. A blend's
2238
+ // last two are kept, its keys' velocities read from them (#464): the frame's own values, which a
2239
+ // blend makes anew each frame (`values` writes one object for a leg that lost keys).
2240
+ const sink = (frame: Frame.Frame<Values.Values>): undefined => {
2241
+ const value = running.values(frame.value)
2242
+ let before = running.last
2243
+ let beforeAt = running.lastAt
2244
+ // Its first frame: from the Snapshot's values, a nominal frame before it.
2245
+ if (Predicate.isUndefined(before)) {
2246
+ before = snapshot.values
2247
+ beforeAt = snapshot.now() - NOMINAL_FRAME
2248
+ }
2249
+ running.before = before
2250
+ running.beforeAt = beforeAt
2251
+ running.last = frame.value
2252
+ snapshot.values = { ...snapshot.values, ...value }
2253
+ gate.write(id, value)
2254
+ recordFrame(value)
2255
+ drew(running, frame.done, snapshot.now())
2256
+ if (frame.done) landEndsOf(waiting)
2257
+ return undefined
2258
+ }
2259
+ if (leg._tag === "Snap") {
2260
+ // A snapped key comes to rest, so a later spring starts it at rest.
2261
+ snapshot.velocities = { ...snapshot.velocities, ...Rec.fromEntries(Arr.map(leg.keys, (key) => [key, 0] as const)) }
2262
+ return Effect.suspend(() => Machine.run(leg.machine(), sink, running))
2263
+ }
2264
+ // Per leg (#460): a statement, Effect's calls data-first.
2265
+ let built = Effect.suspend(leg.machine)
2266
+ if (variables) built = InterpolatorRegistry.withKeyRules(built, elementRules)
2267
+ return Effect.flatMap(built, (machine) => Machine.run(machine, sink, running))
2268
+ }
2269
+
2270
+ // A leg's end, told its landing: a Retarget's legs' and an Imperative animation's (#433).
2271
+ const legEnded = (running: Running) => (exit: Exit.Exit<unknown>): Effect.Effect<void> => {
2272
+ // Its fiber has ended, and is let go: a leg kept for its keys' velocity (#464) keeps no fiber alive.
2273
+ running.fiber = undefined
2274
+ // Per leg (#460): statements.
2275
+ if (Exit.isSuccess(exit)) {
2276
+ // A Superseded leg (#200) counts toward nothing, nor tells a name: the next Retarget's legs
2277
+ // land. Nothing made for it: a Retarget ends its element's legs inline.
2278
+ const end = exit.value
2279
+ if (Supersede.isSuperseded(end)) return Effect.void
2280
+ return Effect.sync(() => {
2281
+ running.landing.settled()
2282
+ const tell = running.names
2283
+ if (Predicate.isNotUndefined(tell)) tell(end)
2284
+ })
2285
+ }
2286
+ // A leg its token didn't reach is interrupted: its keys are given up already, and it isn't a failure.
2287
+ const cause = exit.cause
2288
+ if (Cause.hasInterruptsOnly(cause)) return Effect.void
2289
+ return Report.failure("wardic.spine: a leg failed", cause).pipe(
2290
+ Effect.annotateLogs({ id }),
2291
+ Effect.andThen(Effect.sync(() => {
2292
+ forget(running)
2293
+ running.landing.failed(cause)
2294
+ })),
2295
+ )
2296
+ }
2297
+
2298
+ // A gated Retarget (ADR-0007 `when`, #325): a running key it resolves to its leg's target runs on,
2299
+ // the element reported unsettled meanwhile, when an earlier change started that leg; every other
2300
+ // running key freezes where it is. The change the gate holds may have started legs just before
2301
+ // it shut (a child Retargets before its provider's effect resets its `beforeChildren` wait; an
2302
+ // `afterChildren` provider starts before its children report): those freeze too, as before.
2303
+ const hold = (resolution: Resolution): void => {
2304
+ if (Predicate.isUndefined(gated)) gated = gatedLandingOf(onFrame)
2305
+ const landing = gated
2306
+ const resolved = resolution.resolved
2307
+ current = landing
2308
+ owners.forEach((running, key) => {
2309
+ if (Predicate.isUndefined(running)) return
2310
+ if (running.done) return
2311
+ // An Imperative animation's key (#433) is its own while taken.
2312
+ if (taken.has(key)) return
2313
+ if (Object.hasOwn(resolved, key) && running.targets[key] === resolved[key] && !sameResolution(running.resolution, resolution)) {
2314
+ running.landing = landing
2315
+ running.names = undefined
2316
+ return
2317
+ }
2318
+ giveUp(key, running)
2319
+ })
2320
+ keepTheRest()
2321
+ }
2322
+
2323
+ // The translate targets of the last Retarget that ran, held or not: what a takeover of the drag's
2324
+ // release looks for a change in (#340).
2325
+ let lastX: number | string | undefined = undefined
2326
+ let lastY: number | string | undefined = undefined
2327
+ // A Retarget took `x`/`y` from the release, and the hand-back of `dragging` hasn't come yet.
2328
+ let tookRelease = false
2329
+ /**
2330
+ * Whether the drag holds `x`/`y` for this Retarget (ADR-0004): while its pointer is down and
2331
+ * through its release, unless this Retarget gives the release's axis a new target. Then it takes
2332
+ * them from the release (#340, ADR-0016 *Amendment (#340)*), as a newer animation of Motion's value
2333
+ * stops the one running, and they go on from where the release has them, at its velocity. A key a
2334
+ * entry stops setting is no new target: it stays where the drag dropped it (ADR-0022).
2335
+ */
2336
+ const dragHolds = (resolution: Resolution): boolean => {
2337
+ const { x, y } = resolution.resolved
2338
+ // Per Retarget (#460, compose once): statements.
2339
+ const newX = Predicate.isNotUndefined(x) && x !== lastX
2340
+ const newY = Predicate.isNotUndefined(y) && y !== lastY
2341
+ lastX = x
2342
+ lastY = y
2343
+ if (!resolution.dragging) return false
2344
+ // From a takeover to the hand-back of `dragging` at the end of its task, the drag holds nothing.
2345
+ if (tookRelease) return false
2346
+ const drag = options.drag
2347
+ if (Predicate.isUndefined(drag)) return true
2348
+ if (!newX && !newY) return true
2349
+ tookRelease = drag.takeRelease({ x: newX, y: newY })
2350
+ return !tookRelease
2351
+ }
2352
+
2353
+ const retarget = (given: Resolution): void => {
2354
+ // A Controls change (#433): the element is in it from the Retarget it makes it run, held or not.
2355
+ if (given.change !== joined) joinChange(given.change)
2356
+
2357
+ // `when` start-gate (ADR-0007): when canStart() is false, the keys whose target changed freeze
2358
+ // where they are (#325: the rest run on), and the element waits; the binding retargets once
2359
+ // the gate flips true.
2360
+ if (Predicate.isNotUndefined(canStart) && !canStart()) {
2361
+ hold(given)
2362
+ // Report NOT settled: a gated child sits at its snapshot, still
2363
+ // owing an animation, so it must not count as settled (afterChildren).
2364
+ if (Predicate.isNotUndefined(onFrame)) onFrame(false)
2365
+ return
2366
+ }
2367
+ // The first Retarget a Controls change starts here runs on its override (#433); a later one, a
2368
+ // gesture's, on the targets' own.
2369
+ let resolution = given
2370
+ // On an override, every key starts again on it, a running leg toward the same target too: `set`
2371
+ // lands it at once, as Motion's.
2372
+ let restarting = false
2373
+ if (given.change !== startedChange) {
2374
+ startedChange = given.change
2375
+ const override = UndefinedOr.map(given.change, (change) => change.override)
2376
+ if (Predicate.isNotUndefined(override)) {
2377
+ resolution = overriddenOf(given, override)
2378
+ restarting = true
2379
+ }
2380
+ }
2381
+ const { resolved, base } = resolution
2382
+ // The hand-back of `dragging` after a takeover (#340): the last Retarget already ran with `x`/`y`
2383
+ // its own, so one that changes nothing else is no new animation, as Motion's has none. It goes
2384
+ // on, and lands and is told as itself.
2385
+ if (tookRelease && !resolution.dragging) {
2386
+ tookRelease = false
2387
+ if (handsBackOnly(resolution, lastResolution)) {
2388
+ lastResolution = resolution
2389
+ return
2390
+ }
2391
+ }
2392
+ const held = dragHolds(resolution)
2393
+ // The keys an Imperative animation took (#433): one whose target here isn't the one it had when
2394
+ // taken is the Override stack's again.
2395
+ if (taken.size > 0) Iter.forEach(taken, ([key, was]) => {
2396
+ if (resolved[key] !== was) taken.delete(key)
2397
+ })
2398
+
2399
+ // A key a Retarget drove and no entry sets now returns to its Base value
2400
+ // (ADR-0022); with none, it stays where it is (as before #47).
2401
+ const t: Values.Values = { ...resolved }
2402
+ Arr.forEach(Rec.keys(resolved), (key) => {
2403
+ driven.set(key, resolved[key])
2404
+ })
2405
+ if (held) Arr.forEach(dragMoves(), (key) => driven.delete(key))
2406
+ returning = new Map()
2407
+ // Over the Map itself: copying it into an array first costs ~20 times the walk, per element
2408
+ // per Retarget (#69's PR 4). Deleting the entry being visited is safe in a Map's iteration.
2409
+ Iter.forEach(driven, ([key, like]) => {
2410
+ // A translate key the strip below holds back returns once the drag lets go.
2411
+ if (Object.hasOwn(resolved, key) || (held && TRANSLATE_KEYS.has(key))) return
2412
+ // One an Imperative animation holds (#433) stays where it leaves it.
2413
+ if (taken.has(key)) return
2414
+ const back = BaseValue.of(key, { base, initial: initialLink, started: startedLink, ...linksFor(like) })
2415
+ if (Option.isNone(back)) {
2416
+ driven.delete(key)
2417
+ return
2418
+ }
2419
+ t[key] = back.value.value
2420
+ returning.set(key, back.value.source)
2421
+ })
2422
+ // MULTI-OWNER strip (ADR-0004): while dragging, x/y are DIRECT-SET by the
2423
+ // drag track, so strip the translate keys from the spring's target — the
2424
+ // spring must never fight the direct-set. Once dragging is false the
2425
+ // keys re-enter normally (post-drag handoff: the spring continues x/y only
2426
+ // if `animate` sets them, from the snapshot's rested position).
2427
+ if (held) Arr.forEach(TRANSLATE_KEY_LIST, (key) => delete t[key])
2428
+ // Every key an Imperative animation holds stays where it leaves it (#433).
2429
+ if (taken.size > 0) Iter.forEach(taken, ([key]) => {
2430
+ delete t[key]
2431
+ })
2432
+ // The keys this Retarget returns; once it lands, a key back at its `style` value is
2433
+ // handed back to the element's style (D4) and the rest rest inline.
2434
+ const returns = [...returning]
2435
+ // The transition, read at Retarget time so a change applies to the next Retarget. A child
2436
+ // with no local transition inherits the parent context's (ADR-0007).
2437
+ const c = config()
2438
+
2439
+ // This Retarget's landing (#257, #325): it lands when every leg drawing a key it resolves has
2440
+ // settled, its own and the ones it carries. A leg's end, told apart (ADR-0027, decision 7): a
2441
+ // settle counts; a Superseded end (a Retarget, an unmount, #200) or an interruption (a leg its
2442
+ // token didn't reach) is nothing; anything else (a step or a sink that threw, the Frame loop's
2443
+ // own failure) is logged and reported (ADR-0030, decision 4), and doesn't count.
2444
+ let legs = 0
2445
+ // The variant the Retarget before this one resolved, set once this one starts (#257).
2446
+ let previous: Resolution | undefined
2447
+ const legDone = (): void => {
2448
+ if (current !== landing) return
2449
+ if (--legs !== 0) return
2450
+ settleReturns(returns)
2451
+ // The Retarget settled with its last leg (#257): told once the gate has flushed its last frame,
2452
+ // so the element shows where it landed. Its Controls change hears it then too (#433).
2453
+ if (Predicate.isNotUndefined(animation)) gate.afterFlush(() => animation.settled(resolution, previous, c))
2454
+ leaveAfterFlush()
2455
+ }
2456
+ // A leg's failure (#257 item 4): the Retarget can't land, so a binding waiting on it is told,
2457
+ // once, at once: a leg that fails before it writes leaves no flush to wait for. A leg failing
2458
+ // as it's built, before `started` is told, is told right after it.
2459
+ let failedTold = false
2460
+ let startedTold = false
2461
+ let failedEarly: { readonly error: unknown } | undefined
2462
+ const tellFailed = (error: unknown): void => {
2463
+ const hooks = animation as AnimationHooks
2464
+ // Called on its hooks, which may be a class's: not taken off them.
2465
+ if (Predicate.isNotUndefined(hooks.failed)) hooks.failed(resolution, error)
2466
+ }
2467
+ const legFailed = (cause: Cause.Cause<unknown>): void => {
2468
+ // It can't land: its Controls change waits for it no longer (#433).
2469
+ if (current === landing) leaveChange()
2470
+ if (failedTold || Predicate.isUndefined(animation)) return
2471
+ failedTold = true
2472
+ const error = Cause.squash(cause)
2473
+ if (startedTold) return tellFailed(error)
2474
+ failedEarly = { error }
2475
+ }
2476
+ // The element settles with its last leg (ADR-0024, D5): a string leg can outlast the
2477
+ // numeric one, so each leg's frames report, and only the last leg's settle reports done.
2478
+ let reporting = 0
2479
+ let settled = 0
2480
+ const report = (done: boolean): void => {
2481
+ if (done) settled++
2482
+ if (Predicate.isNotUndefined(onFrame)) onFrame(settled === reporting)
2483
+ }
2484
+ const landing: Landing = { report, settled: legDone, failed: legFailed }
2485
+ current = landing
2486
+
2487
+ // The Retarget's transitions, read before its keys: a key already there asks its own for a
2488
+ // velocity (#448).
2489
+ const elementTransition = ownOrInherited(c.transition, parent)
2490
+ // The base target's own transition (#277): the keys its entry drives animate on it.
2491
+ const baseTransition = transitionOfTarget(resolution.transition, elementTransition)
2492
+ // Fold the per-child stagger delay (ADR-0007) into the effective
2493
+ // transition.delay = base.delay + computedDelay. extraDelay() is read
2494
+ // at Retarget time so a re-snapshot before this start is reflected. Each name's keys take that
2495
+ // name's delay (#297): the base's, its first name's.
2496
+ const layers = resolution.layers
2497
+ const extra = extraOf(extraDelay, layers[0])
2498
+ const transition = staggeredOf(baseTransition, extra, options.reuse)
2499
+ // With an entry's own transition (#277, #291), each key animates on its entry's: the base's keys
2500
+ // on the base target's, each active gesture's on its target's, else the element's, as Motion's
2501
+ // each animation type runs on its own.
2502
+ // A list's names (#297) split them too, each name's at its own delay; a list's returns run on the
2503
+ // element's transition, in a group of their own, last.
2504
+ // Guards, not matches: per Retarget, per element. A list's work (#297) is done apart, for a list:
2505
+ // the Retarget's other calls keep their inlining (docs/agents/effect-first.md).
2506
+ const listed = Arr.isArray(resolution.variant)
2507
+ // A list's names each wait for their own `when` (#297's PR 2): the entries whose gate is shut now.
2508
+ let shut: ReadonlyArray<boolean> | undefined
2509
+ if (listed) shut = shutOf(layers, byName)
2510
+ // Every key the Retarget resolves goes in its entry's group, the ones that stay too (#325): a
2511
+ // name's settle waits for them.
2512
+ const groups = keysByLayerOf(t, layers, extraDelay, extra, listed, shut)
2513
+ // Per key (#325, Motion's): a key whose running leg heads where this Retarget resolves it runs
2514
+ // on, counted toward this landing; one whose last leg landed there stays; every other's leg
2515
+ // gives it up, and it starts from its Snapshot value, coerced to its target's shape (ADR-0024,
2516
+ // D1). A key with no value yet, or one whose value can't take that shape, starts from its Base
2517
+ // value's start links, read here at its first need (ADR-0022, D3); with none, it starts at its
2518
+ // target (no motion).
2519
+ //
2520
+ // Every key's Own value is read first, at its first need, before anything writes it, so a return
2521
+ // later finds the element's value, not Wardic's (ADR-0022, D3). The read is kept: a later need is
2522
+ // a lookup. A transform key reads nothing.
2523
+ let stays: Set<string> | undefined
2524
+ let carried: Array<Running> | undefined
2525
+ let there: Record<string, number | string> | undefined
2526
+ const started: Record<string, string> = {}
2527
+ // Each key's Keyframes (#429), when any entry gives some: a key's carries on only toward the same.
2528
+ const keyframesNow = resolution.keyframes
2529
+ // The keys whose two ends may be a Measured pair (#430), found in the pass below.
2530
+ let measuring: Array<string> | undefined
2531
+ // Each key's velocity, read now (#464), for a key a spring starts or one already there.
2532
+ readAt = snapshot.now()
2533
+ // Where a Path's axis this target leaves out rests (#574), before the pass below gives up its leg.
2534
+ const rests = restsOf(owners, t)
2535
+ Arr.forEach(Rec.keys(t), (key) => {
2536
+ if (!Object.hasOwn(initialValues, key)) ownValue(key)
2537
+ const like = t[key]
2538
+ const owner = owners.get(key)
2539
+ const stops = keyframesAtOf(keyframesNow, key)
2540
+ // A leg drawing it toward another target: it's moving, so it's never already there (#448).
2541
+ let drawn = false
2542
+ if (Predicate.isNotUndefined(owner)) {
2543
+ drawn = !owner.done
2544
+ // A key whose Transition end changed starts again (#470), as Motion's value does, its end in
2545
+ // its resolved values.
2546
+ if (owner.targets[key] === like && !restarting && sameKeyframesAt(keyframesAtOf(owner.resolution.keyframes, key), stops) && !endMoved(lastResolution, resolution, key)) {
2547
+ if (Predicate.isUndefined(stays)) stays = new Set()
2548
+ stays.add(key)
2549
+ if (owner.done || owner.landing === landing) return
2550
+ owner.landing = landing
2551
+ owner.names = undefined
2552
+ legs++
2553
+ reporting++
2554
+ if (Predicate.isUndefined(carried)) carried = []
2555
+ carried.push(owner)
2556
+ return
2557
+ }
2558
+ giveUp(key, owner)
2559
+ }
2560
+ startKey(key, like, started)
2561
+ // A Measured pair (#430): its two ends of different types, found in this pass, so a Retarget
2562
+ // with none builds nothing for them.
2563
+ if (MeasuredPair.needs(key, UndefinedOr.getOrThrow(snapshot.values[key]), like)) {
2564
+ if (Predicate.isUndefined(measuring)) measuring = []
2565
+ measuring.push(key)
2566
+ }
2567
+ // Already there (#448, Motion's `visual-element-target.ts`): a key at its target, coerced to its
2568
+ // shape, with no leg drawing it, at rest and given no velocity by its transition, starts none.
2569
+ // It stays, as a carried key does, and is written once more (below), as Motion sets it on the
2570
+ // next frame. One that started at its target had no value to show, so its leg writes it, as
2571
+ // Motion's does for a value it has none of. Keyframes are never there (#429): they play.
2572
+ // Its velocity read last, for a key there alone (#464): per key, per Retarget.
2573
+ let still = !drawn && started[key] !== "target"
2574
+ if (still) still = snapshot.values[key] === like
2575
+ if (still) still = readVelocity(key) === 0
2576
+ // Its transition asked last, for a key already there alone: per key, per Retarget. A quiet
2577
+ // mount's never asks (#475): Motion animates nothing at a first render that starts at its
2578
+ // `animate`, whatever velocity its transition gives (`animation-state.ts`, `shouldAnimate`).
2579
+ if (still && Predicate.isUndefined(stops) && (quiet || !givesVelocity(keyTransitionOf(resolution, groups, key, transition, elementTransition), key))) {
2580
+ if (Predicate.isUndefined(stays)) stays = new Set()
2581
+ stays.add(key)
2582
+ if (Predicate.isUndefined(there)) there = {}
2583
+ there[key] = like
2584
+ }
2585
+ // A quiet mount's Keyframes (#429): Motion animates nothing at a first render that starts at its
2586
+ // `animate`, so they stay where they start, `animate`'s last stop with `initial={false}`.
2587
+ if (quiet && Predicate.isNotUndefined(stops)) {
2588
+ if (Predicate.isUndefined(stays)) stays = new Set()
2589
+ stays.add(key)
2590
+ if (Predicate.isUndefined(there)) there = {}
2591
+ there[key] = UndefinedOr.getOrThrow(snapshot.values[key])
2592
+ }
2593
+ })
2594
+ // A key no longer resolved (one the drag holds, or one with no Base value) is given up: it stays
2595
+ // where it is.
2596
+ resolvedNow = t
2597
+ owners.forEach(giveUpUnresolved)
2598
+ keepTheRest()
2599
+ // The keys this Retarget starts legs for: all of them, unless some stay.
2600
+ let fresh: Values.Values = t
2601
+ if (Predicate.isNotUndefined(stays)) {
2602
+ const kept = stays
2603
+ fresh = Rec.filter(t, (_, key) => !kept.has(key))
2604
+ // A Path couples `x` and `y` (#438): either retargeted, the other goes along it to its target.
2605
+ fresh = withPathAxes(fresh, t, transition)
2606
+ }
2607
+ // A mount that starts at its `animate`, with nothing to animate, tells no one (#448, Motion's):
2608
+ // no start, no landing, and no list's names. It starts no leg, so it lands at once.
2609
+ const silent = quiet && Rec.isEmptyRecord(fresh) && Predicate.isUndefined(carried)
2610
+ quiet = false
2611
+ // A key only a Transition end sets (#428) starts no leg of its own: its entry's end leg holds it
2612
+ // where it is, and sets it once the entry's animated keys land.
2613
+ const ends = resolution.ends
2614
+ let freshEnds: Values.Values = NO_VALUES
2615
+ if (Predicate.isNotUndefined(ends)) {
2616
+ const endOnly = ends.endOnly
2617
+ freshEnds = Rec.filter(fresh, (_, key) => endOnly.has(key))
2618
+ if (hasKeys(freshEnds)) fresh = Rec.filter(fresh, (_, key) => !endOnly.has(key))
2619
+ }
2620
+ let from: Values.Values = Rec.map(fresh, (_, key) => UndefinedOr.getOrThrow(snapshot.values[key]))
2621
+ // Keyframes (#429) start at their first stop, a `null` one where the key is; those of more than
2622
+ // two stops run through them.
2623
+ let manyStops: StopsByKey | undefined
2624
+ if (Predicate.isNotUndefined(keyframesNow)) {
2625
+ const begun = keyframesFrom(from, fresh, Rec.map(keyframesNow, (at) => at.stops))
2626
+ from = begun.from
2627
+ manyStops = begun.stops
2628
+ }
2629
+ // Each leg: the base-value log at the head of the first, and, once the leg's run
2630
+ // settles, a count toward this landing, so the per-frame handlers stay as they were.
2631
+ let pendingLog: Effect.Effect<void> | undefined
2632
+ if (returns.length > 0 || !Rec.isEmptyRecord(started)) pendingLog = baseLog(started, returns)
2633
+ // A list's names told settled one by one (#297, Solid 1's callbacks): each as the legs of the keys
2634
+ // it drives settle. Made only for a list with a binding that's told so.
2635
+ let names: NameSettles | undefined
2636
+ const leg = <R,>(running: Running, program: Effect.Effect<unknown, never, R>): Effect.Effect<void, never, R> => {
2637
+ legs++
2638
+ const log = pendingLog
2639
+ pendingLog = undefined
2640
+ // Per leg (#460): statements, Effect's calls data-first.
2641
+ let run: Effect.Effect<unknown, never, R> = program
2642
+ if (Predicate.isNotUndefined(log)) run = Effect.andThen(log, program)
2643
+ if (Predicate.isNotUndefined(names)) running.names = names.leg()
2644
+ return Effect.asVoid(Effect.onExit(run, legEnded(running)))
2645
+ }
2646
+ // Start a leg: forked on the provider's runtime, which runs it inline up to its add on the
2647
+ // loop, so every leg started in a task is on the loop by the end of that task and takes its
2648
+ // first step at the next tick (ADR-0027 decision 5, ADR-0033). Forked from a `runSync`, a leg
2649
+ // would inherit that call's scheduler (ADR-0027, decision 6). The runtime keeps it in its own
2650
+ // fiber Scope, which interrupts it if it's still running when the provider ends (#542).
2651
+ // The name the leg being started waits for (#297's PR 2), set as each is started; none for most.
2652
+ let gateNow: string | undefined
2653
+ const runLeg = <R extends WardicServices>(running: Running, program: Effect.Effect<unknown, never, R>): void => {
2654
+ let run: Effect.Effect<unknown, never, R | FrameLoop.FrameLoop> = program
2655
+ if (Predicate.isNotUndefined(gateNow)) run = gatedBy(gateNow, byName, running, program)
2656
+ running.fiber = runtime.runFork(leg(running, run))
2657
+ }
2658
+ // The legs (#48, ADR-0044 decision 8): one pure builder, which a server render's Appear
2659
+ // animation samples too, so the two can't drift. Built here; each leg's machine is built
2660
+ // in its own fiber, so a transition core rejects (#66, ADR-0025 *Amendment (#66)*) fails
2661
+ // that leg alone, reported as any leg's failure is, while the element's other legs run on.
2662
+ // The returns to a moving Live value (#130, ADR-0043 decision 6): a number's follows it,
2663
+ // in a leg of its own, and lands on it; the rest return to where it is now. Looked for
2664
+ // only when this Retarget returns a key.
2665
+ let follow: Follows | undefined
2666
+ if (returning.size > 0 && Predicate.isNotUndefined(live)) {
2667
+ const routes = live
2668
+ follow = { keysOf: (rest) => followingOf(routes, rest, returning), targetOf: (key, start) => liveTargetOf(routes, key, start) }
2669
+ }
2670
+ const reduce = options.reducedMotion()
2671
+ const skipped = skipAnimations()
2672
+ // Measured pairs (#430), asked of the end-of-task batch, unless reduced motion snaps them or the
2673
+ // animation is skipped (#468): the keys found above, and those Keyframes of two stops start from their first.
2674
+ let measured: MeasuredPairs | undefined
2675
+ if (!reduce && !skipped && (Predicate.isNotUndefined(measuring) || Predicate.isNotUndefined(keyframesNow))) {
2676
+ measured = measuredOf(element, measuringOf(measuring, keyframesNow), from, fresh, snapshot.values, manyStops)
2677
+ }
2678
+ let told: ToldNames | undefined
2679
+ if (!silent) told = namesToldOf(animation, resolution, lastResolution)
2680
+ // Every key on one transition when they aren't split, as before; else each group's legs, tagged.
2681
+ // A key that stays starts none, and no keys make no leg (#325).
2682
+ let retargetLegs: ReadonlyArray<Leg> = NO_LEGS
2683
+ let legGroups: ReadonlyArray<number> | undefined
2684
+ if (Predicate.isUndefined(groups) && hasKeys(fresh)) {
2685
+ // Where every key is now: a Path's axis the target leaves out starts there (#438), and ends where
2686
+ // it rests (#574).
2687
+ retargetLegs = legsOf(from, fresh, transition, reduce, skipped, positionalKeys, defaultTransition, readVelocity, follow, manyStops, measured, snapshot.values, rests)
2688
+ }
2689
+ if (Predicate.isNotUndefined(groups)) {
2690
+ const split = splitLegsOf(fresh, from, groups, resolution, listed, transition, elementTransition, extraDelay, options.reuse, reduce, skipped, positionalKeys, defaultTransition, readVelocity, follow, manyStops, measured, snapshot.values, rests)
2691
+ retargetLegs = split.legs
2692
+ legGroups = split.tags
2693
+ }
2694
+ // The Handoff (#48, ADR-0044 decision 6): the first Retarget that starts picks the Appear
2695
+ // animation up as far in as its CSS has got, read at the legs' first tick.
2696
+ if (Predicate.isNotUndefined(handoff)) {
2697
+ const taken = handoff
2698
+ handoff = undefined
2699
+ checkHandoff(runtime, id, taken, { tag, from, to: fresh, transition: baseTransition, reduced: reduce, layout: isLayoutNode(c), stops: manyStops, ...skippedField(skipped), ...templateField(c.transformTemplate) })
2700
+ const at = startAtOf(taken, baseTransition, delayOf(transition))
2701
+ retargetLegs = Arr.map(retargetLegs, (one) => startingAt(one, at))
2702
+ }
2703
+ reporting += retargetLegs.length
2704
+ // A list's names (#297): told settled with the legs of the keys each drives, the ones a key that
2705
+ // stays carries too (#325), to the binding's callbacks and its orchestration, and each shut
2706
+ // one's legs waiting on its gate (PR 2).
2707
+ let legGates: ReadonlyArray<string | undefined> | undefined
2708
+ if (listed || Predicate.isNotUndefined(told)) {
2709
+ const carriedLegs = UndefinedOr.match(carried, { onUndefined: (): ReadonlyArray<Running> => NO_RUNNING, onDefined: identity })
2710
+ const listing = listingOf({
2711
+ listed,
2712
+ told,
2713
+ byName,
2714
+ resolution,
2715
+ groups,
2716
+ legGroups,
2717
+ legCount: retargetLegs.length,
2718
+ carriedGroups: Arr.map(carriedLegs, (running) => groupsOfLeg(running, groups, owners)),
2719
+ shut,
2720
+ hold: (g) => {
2721
+ const kept = pickKeys(from, groups, g)
2722
+ if (Bool.not(Rec.isEmptyRecord(kept))) gate.write(id, kept)
2723
+ },
2724
+ afterFlush: (fn) => gate.afterFlush(fn),
2725
+ config: c,
2726
+ })
2727
+ names = listing.names
2728
+ legGates = listing.legGates
2729
+ UndefinedOr.map(names, (settles) =>
2730
+ Arr.forEach(carriedLegs, (running, i) => {
2731
+ running.names = settles.carried(i)
2732
+ }))
2733
+ }
2734
+ // Its `style`'s will-change value turns on as a leg starts a key Motion's would (#443).
2735
+ turnWillChangeOn(live, retargetLegs)
2736
+ // The element's Key rules only for a change a Variable value is in (#542).
2737
+ const variables = holdsVariable(from, fresh, manyStops)
2738
+ // Each leg into its sink, in the builder's order (#69's PR 2: a Retarget is per element). Each
2739
+ // leg draws the keys it animates (#325) until a later Retarget takes them.
2740
+ Arr.forEach(retargetLegs, (leg: Leg, i): void => {
2741
+ if (Predicate.isNotUndefined(legGates)) gateNow = legGates[i]
2742
+ const running = runningOf(leg.to, resolution, landing, leg._tag)
2743
+ own(running)
2744
+ runLeg(running, legProgram(leg, running, variables))
2745
+ })
2746
+ // Each entry's Transition end (#428): a leg holding the keys only its end sets where they are,
2747
+ // waiting for the keys the entry animates to land (the legs drawing them now, this Retarget's or
2748
+ // carried), then setting its end values, the keys it also animates among them. It counts toward
2749
+ // this landing, so the landing includes it. A later Retarget that resolves its keys to the same
2750
+ // values carries it (#325); one that doesn't gives them up, and it never sets them.
2751
+ if (Predicate.isNotUndefined(ends)) {
2752
+ gateNow = undefined
2753
+ Arr.forEach(ends.byLayer, (writes, at) => {
2754
+ if (Predicate.isUndefined(writes)) return
2755
+ const owned = Rec.filter(freshEnds, (_, key) => ends.endOnly.get(key) === at)
2756
+ // Its end starts again when a key it also animates starts again, or its end for one changed
2757
+ // (#470, one already there starts none), or a key only it sets does.
2758
+ const anew = Bool.or(
2759
+ hasKeys(owned),
2760
+ Arr.some(Rec.keys(writes), (key) => Bool.and(Bool.not(ends.endOnly.has(key)), Bool.or(Object.hasOwn(fresh, key), endMoved(lastResolution, resolution, key)))),
2761
+ )
2762
+ if (Bool.not(anew)) return
2763
+ const animated = Arr.filter(Rec.keys(resolved), (key) => Bool.and(Bool.not(ends.endOnly.has(key)), driverOf(layers, key) === at))
2764
+ // Its keys set at their end, at once: no motion, so no velocity (#464).
2765
+ const running = runningOf(owned, resolution, landing, "Snap")
2766
+ own(running)
2767
+ // Held where they are: a key with nothing to start from (it would start at its target, no
2768
+ // motion) is left unset until its end, not set to it now.
2769
+ const holding = Rec.map(Rec.filter(owned, (_, key) => started[key] !== "target"), (_, key) => UndefinedOr.getOrThrow(snapshot.values[key]))
2770
+ if (hasKeys(holding)) gate.write(id, holding)
2771
+ snapshot.velocities = { ...snapshot.velocities, ...Rec.map(owned, () => 0) }
2772
+ // Counted toward this landing as a leg is (#508), with no fiber of its own: the landing of its
2773
+ // keys' last leg writes it, or the next flush when they've landed already.
2774
+ reporting++
2775
+ legs++
2776
+ const log = pendingLog
2777
+ pendingLog = undefined
2778
+ // Forked only where a Debug log is kept (#618); a leg's runs inside the leg's own fiber.
2779
+ if (Predicate.isNotUndefined(log)) {
2780
+ if (logsDebugOn(runtime)) runtime.runFork(log)
2781
+ }
2782
+ if (Predicate.isNotUndefined(names)) running.names = names.leg()
2783
+ // One that owns no key records the legs it waits for: their interrupt drops it (ADR-0057 Q1).
2784
+ let waitsOn: ReadonlyArray<Running | undefined> | undefined
2785
+ if (Bool.not(hasKeys(owned))) waitsOn = Arr.map(animated, (key) => owners.get(key))
2786
+ if (Predicate.isUndefined(waiting)) waiting = waitingEndsOf(owners, snapshot, gate, id, recordFrame)
2787
+ waiting.add({ running, animated, writes, legs: waitsOn, state: "waiting" })
2788
+ })
2789
+ }
2790
+ // A turn none of its legs draws now goes back (#460).
2791
+ turnBack()
2792
+ // The keys already there (#448), written with each key the Retarget moves at where it starts, as
2793
+ // its leg's first frame writes it: the element's first commit, which takes its Starting style off,
2794
+ // holds every key, whatever frame the legs first draw in (a gated name's draws later).
2795
+ if (Predicate.isNotUndefined(there)) {
2796
+ const written = { ...from, ...there }
2797
+ gate.write(id, written)
2798
+ recordFrame(written)
2799
+ }
2800
+ // The Retarget started, its legs on their way (#257); with none, its own or carried, it landed
2801
+ // at once (#325): its returns settle, and the element reports settled at the gate's next flush,
2802
+ // after the effects that start its orchestration's wait (ADR-0007).
2803
+ previous = lastResolution
2804
+ lastResolution = resolution
2805
+ const landed = legs === 0
2806
+ if (landed) {
2807
+ settleReturns(returns)
2808
+ leaveAfterFlush()
2809
+ if (Predicate.isNotUndefined(pendingLog)) {
2810
+ if (logsDebugOn(runtime)) runtime.runFork(pendingLog)
2811
+ }
2812
+ if (Predicate.isNotUndefined(onFrame)) {
2813
+ const tell = onFrame
2814
+ gate.afterFlush(() => {
2815
+ if (current === landing) tell(true)
2816
+ })
2817
+ }
2818
+ }
2819
+ if (Predicate.isNotUndefined(animation) && !silent) {
2820
+ const hooks = animation as AnimationHooks
2821
+ hooks.started(resolution, previous, c)
2822
+ startedTold = true
2823
+ if (landed) hooks.settled(resolution, previous, c)
2824
+ if (Predicate.isNotUndefined(failedEarly)) tellFailed(failedEarly.error)
2825
+ }
2826
+ }
2827
+
2828
+ // --- Live values in `style` (#130, ADR-0043) ------------------------------
2829
+ // A routed key (a Live value, or a transform key) is its `style` link, live: while no entry of
2830
+ // the Override stack sets it, no return is running to it and no drag moves it, the element
2831
+ // follows it, written through the gate on every change. A return hands it back here when it
2832
+ // settles (`settleReturns`). The Starting style showed each one's value at render; from mount
2833
+ // the gate holds them.
2834
+ const follow = (now: FollowNow): void => {
2835
+ if (Predicate.isUndefined(live)) return
2836
+ const routes = live
2837
+ // Built at the first routed key, at mount or later: an element whose `style` routes none builds nothing.
2838
+ routes.whenRouted(() => {
2839
+ // Read at each ask: `projected` is a getter while the track waits for `drag` (#551, #582).
2840
+ const dragHolds = (): boolean => Bool.and(Bool.not(options.projected), Predicate.isNotUndefined(options.dragAxis))
2841
+ // Whether something other than the follower moves `key` now.
2842
+ const owned = (key: string): boolean =>
2843
+ Bool.some([
2844
+ driven.has(key),
2845
+ Object.hasOwn(now.resolved(), key),
2846
+ // An Imperative animation's (#433).
2847
+ taken.has(key),
2848
+ // The drag direct-sets both translate keys while it, and its release, run (ADR-0004).
2849
+ Bool.and(dragHolds(), Bool.and(now.dragging(), Bool.or(key === "x", key === "y"))),
2850
+ ])
2851
+ // Written as any frame is: into the gate, the Snapshot (at rest) and the presence record.
2852
+ const put = (values: Values.Values): void => {
2853
+ Arr.forEach(Rec.keys(values), (key) => {
2854
+ snapshot.values[key] = UndefinedOr.getOrThrow(values[key])
2855
+ delete snapshot.velocities[key]
2856
+ })
2857
+ gate.write(id, values)
2858
+ recordFrame(values)
2859
+ }
2860
+ handBack = (key) => {
2861
+ Option.match(Option.filter(routes.valueOf(key), isValue), {
2862
+ onNone: constVoid,
2863
+ onSome: (value) => put({ [key]: value }),
2864
+ })
2865
+ }
2866
+ // Every routed key nothing owns, with, before anything's committed, the values the Override
2867
+ // stack's keys start from, so a held start (a `when` gate) keeps showing them.
2868
+ const first = Rec.filter(routes.values(), (_, key) => Bool.not(owned(key)))
2869
+ if (hasKeys(first)) put({ ...Values.pick(snapshot.values, now.resolved()), ...first })
2870
+ return {
2871
+ change: (key, value) => {
2872
+ if (Bool.or(owned(key), Bool.not(isValue(value)))) return
2873
+ put({ [key]: value as number | string })
2874
+ },
2875
+ removed: (key) => {
2876
+ if (owned(key)) return
2877
+ delete snapshot.values[key]
2878
+ delete snapshot.velocities[key]
2879
+ if (Predicate.isNotUndefined(presence)) delete presence.snapshot.current[key]
2880
+ // Gone from `style`: the element's own value comes back, or the key's CSS value now.
2881
+ const restore = Option.match(OwnValues.styleValueOf(UndefinedOr.match(styleNow, { onUndefined: constUndefined, onDefined: (style) => style() }), key), {
2882
+ onNone: () => "",
2883
+ onSome: String,
2884
+ })
2885
+ gate.release(id, [key], { [key]: restore })
2886
+ },
2887
+ }
2888
+ })
2889
+ }
2890
+
2891
+ const dispose = (): void => {
2892
+ // Unmounted, it lands in no Controls change (#433).
2893
+ leaveChange()
2894
+ if (Predicate.isNotUndefined(live)) live.stop()
2895
+ // The legs end normally first, so closing the Scope has nothing left to interrupt. A Transition
2896
+ // end waiting or due writes nothing (#508).
2897
+ if (Predicate.isNotUndefined(waiting)) waiting.dispose()
2898
+ // Each leg not landed ends as a Retarget ends one (#542): by its token, and interrupted if its
2899
+ // token didn't reach it. Nothing else ends them before the provider does.
2900
+ owners.forEach((running) => {
2901
+ if (Predicate.isUndefined(running)) return
2902
+ if (!running.done) endLeg(running)
2903
+ })
2904
+ }
2905
+
2906
+ // A child back under its key (#286): its values and velocities from where the leaver is drawn, a
2907
+ // projected element's own translate among them (#363). Drawn at the end of the task, so nothing
2908
+ // paints the element at its `initial` first: not in the mount effect it's called in, where the
2909
+ // first commit's Starting-style switch would flush Solid 2 inside an effect.
2910
+ const seed = (from: PresenceSeed): void => {
2911
+ const values = from.values
2912
+ Object.assign(snapshot.values, values)
2913
+ snapshot.velocities = { ...snapshot.velocities, ...from.velocities }
2914
+ // Drawn now, by the leaver (#464).
2915
+ const now = snapshot.now()
2916
+ Arr.forEach(Rec.keys(from.velocities), (key) => {
2917
+ snapshot.drawnAt[key] = now
2918
+ })
2919
+ if (Predicate.isNotUndefined(presence)) Object.assign(presence.snapshot.current, values)
2920
+ Arr.forEach(Rec.keys(values), (key) => {
2921
+ driven.set(key, values[key])
2922
+ })
2923
+ queueMicrotask(() => gate.flushPass(() => gate.write(id, values)))
2924
+ }
2925
+
2926
+ // --- Imperative animations (#433) -------------------------------------------
2927
+ /** A leg of an Imperative animation, forked as a Retarget's are; it lands on its track. */
2928
+ // Data-first: a pipe's curried forms are two closures more for every leg (#618, H1).
2929
+ const runImperative = (running: Running, program: Effect.Effect<unknown, never, WardicServices>): void => {
2930
+ running.fiber = runtime.runFork(Effect.asVoid(Effect.onExit(program, legEnded(running))))
2931
+ }
2932
+
2933
+ const animate = (target: Target, given: WardicTransition | undefined, head: Playback.Playhead, hooks: ImperativeHooks): ImperativeTrack => {
2934
+ const to = target.values
2935
+ const before = UndefinedOr.match(lastResolution, { onUndefined: () => NO_VALUES, onDefined: (last) => last.resolved })
2936
+ const started: Record<string, string> = {}
2937
+ let measuring: Array<string> | undefined
2938
+ // Each key taken from whatever runs it, noted with its target now, and started where it's drawn.
2939
+ // Its velocity read now (#464), as its legs are built.
2940
+ readAt = snapshot.now()
2941
+ // Where a Path's axis this target leaves out rests (#574), before its keys are taken below.
2942
+ const rests = restsOf(owners, to)
2943
+ if (taken === NONE_TAKEN) taken = new Map()
2944
+ const takenNow = taken
2945
+ Arr.forEach(Rec.keys(to), (key) => {
2946
+ takenNow.set(key, before[key])
2947
+ returning.delete(key)
2948
+ const owner = owners.get(key)
2949
+ if (Predicate.isNotUndefined(owner)) giveUp(key, owner)
2950
+ if (!Object.hasOwn(initialValues, key)) ownValue(key)
2951
+ const like = UndefinedOr.getOrThrow(to[key])
2952
+ startKey(key, like, started)
2953
+ if (MeasuredPair.needs(key, UndefinedOr.getOrThrow(snapshot.values[key]), like)) {
2954
+ if (Predicate.isUndefined(measuring)) measuring = []
2955
+ measuring.push(key)
2956
+ }
2957
+ })
2958
+ keepTheRest()
2959
+ let from: Values.Values = Rec.map(to, (_, key) => UndefinedOr.getOrThrow(snapshot.values[key]))
2960
+ let stops: StopsByKey | undefined
2961
+ if (Predicate.isNotUndefined(target.keyframes)) {
2962
+ const begun = keyframesFrom(from, to, target.keyframes)
2963
+ from = begun.from
2964
+ stops = begun.stops
2965
+ }
2966
+ const reduce = options.reducedMotion()
2967
+ const skipped = skipAnimations()
2968
+ let measured: MeasuredPairs | undefined
2969
+ if (Bool.and(Bool.not(Bool.or(reduce, skipped)), Predicate.isNotUndefined(measuring))) measured = measuredOf(element, UndefinedOr.getOrThrow(measuring), from, to, snapshot.values, stops)
2970
+ // Built once: a seek or a replay runs the same legs, from the same start, with the same velocities.
2971
+ const built = legsOf(from, to, given, reduce, skipped, positionalKeys, defaultTransition, readVelocity, undefined, stops, measured, snapshot.values, rests)
2972
+ const variables = holdsVariable(from, to, stops)
2973
+ const legs = Arr.map(built, (leg) => mapMachine(leg, Playback.drive(head)))
2974
+ let runnings: ReadonlyArray<Running> = NO_RUNNING
2975
+ let left = 0
2976
+ const landing: Landing = {
2977
+ report: constVoid,
2978
+ settled: () => {
2979
+ left--
2980
+ if (left === 0) gate.afterFlush(hooks.settled)
2981
+ },
2982
+ failed: hooks.failed,
2983
+ }
2984
+ // Its legs ended where they are: the keys they draw are drawn by none.
2985
+ const end = (): void =>
2986
+ Arr.forEach(runnings, (running) => {
2987
+ forget(running)
2988
+ if (Bool.not(running.done)) endLeg(running)
2989
+ })
2990
+ const run = (): void => {
2991
+ end()
2992
+ left = legs.length
2993
+ turnWillChangeOn(live, legs)
2994
+ runnings = Arr.map(legs, (leg) => {
2995
+ const running = runningOf(leg.to, IMPERATIVE, landing, leg._tag)
2996
+ own(running)
2997
+ runImperative(running, legProgram(leg, running, variables))
2998
+ return running
2999
+ })
3000
+ // A target with no key lands at once.
3001
+ if (left === 0) gate.afterFlush(hooks.settled)
3002
+ }
3003
+ const cancel = (): void => {
3004
+ end()
3005
+ turnBack()
3006
+ snapshot.values = { ...snapshot.values, ...from }
3007
+ snapshot.velocities = { ...snapshot.velocities, ...Rec.map(from, () => 0) }
3008
+ // Put back at once: at rest, newer than the legs that let them go (#464).
3009
+ const now = snapshot.now()
3010
+ Arr.forEach(Rec.keys(from), (key) => {
3011
+ snapshot.drawnAt[key] = now
3012
+ })
3013
+ gate.write(id, from)
3014
+ recordFrame(from)
3015
+ }
3016
+ // Each leg's machine, run from its start to rest, apart from the Playhead, which it would move: a
3017
+ // blend's built with the element's Key rules.
3018
+ const duration = (): number =>
3019
+ Arr.reduce(built, 0, (longest, leg) => Math.max(longest, Machine.durationOf(machineOf(leg))))
3020
+ const machineOf = (leg: Leg): Machine.Machine<Frame.Frame<unknown>> => {
3021
+ if (leg._tag === "Blend") return runtime.runSync(Effect.suspend(leg.machine).pipe(InterpolatorRegistry.withKeyRules(elementRules)))
3022
+ return leg.machine() as Machine.Machine<Frame.Frame<unknown>>
3023
+ }
3024
+ const stop = (): void => {
3025
+ end()
3026
+ turnBack()
3027
+ }
3028
+ return { run, stop, cancel, duration }
3029
+ }
3030
+
3031
+ // **Animation controls**' `stop` (#433): every running leg ends where it is, its keys given up, so
3032
+ // the next Retarget starts them from where they're drawn.
3033
+ const stop = (): void => {
3034
+ owners.forEach((running) => {
3035
+ if (Predicate.isUndefined(running)) return
3036
+ forget(running)
3037
+ if (Bool.not(running.done)) endLeg(running)
3038
+ })
3039
+ turnBack()
3040
+ }
3041
+
3042
+ return { retarget, follow, dispose, seed, animate, stop }
3043
+ }
3044
+
3045
+
3046
+ /**
3047
+ * `sink` with an `onCommit` that calls the config's current `onUpdate` (#233), when the config had
3048
+ * one at mount; `sink` as it is otherwise. `config` reads it untracked.
3049
+ */
3050
+ export const withOnUpdate = (sink: FlushGate.Sink, atMount: WardConfig["onUpdate"], config: () => WardConfig): FlushGate.Sink => {
3051
+ // Per element at mount: most have none, and pay a check.
3052
+ if (Predicate.isUndefined(atMount)) return sink
3053
+ return {
3054
+ ...sink,
3055
+ onCommit: (latest) => {
3056
+ const onUpdate = config().onUpdate
3057
+ if (Predicate.isNotUndefined(onUpdate)) onUpdate(latest as Readonly<Record<string, number | string>>)
3058
+ },
3059
+ }
3060
+ }
3061
+
3062
+ /**
3063
+ * `sink`, removing the element's Appear animation in its first commit (#48, ADR-0044 decision 6):
3064
+ * in the task that writes the engine's first frame, so no paint falls between. Without one, `sink`.
3065
+ */
3066
+ export const releasingAppear = (sink: FlushGate.Sink, handoff: Handoff | undefined, element: HTMLElement): FlushGate.Sink => {
3067
+ if (Predicate.isUndefined(handoff)) return sink
3068
+ const before = sink.beforeFirstCommit
3069
+ return {
3070
+ ...sink,
3071
+ beforeFirstCommit: () => {
3072
+ Appear.release(element)
3073
+ if (Predicate.isNotUndefined(before)) before()
3074
+ },
3075
+ }
3076
+ }
3077
+
3078
+ /**
3079
+ * A Handoff whose Appear animation the server sampled from another mount animation than the
3080
+ * client's: the app rendered differently on the server, or a function it gave has no easing name.
3081
+ * Noted once (cold path, `wardic.hydration`); the client's own animation goes on from the same time.
3082
+ */
3083
+ const checkHandoff = (runtime: WardicRuntime, id: string, handoff: Handoff, mount: MountAnimation): void => {
3084
+ // A templated element's rule is named by its stops (#443), which the client doesn't sample to check.
3085
+ if (Predicate.isNotUndefined(mount.template)) return
3086
+ const same = Option.exists(keyOf(mount), (key) =>
3087
+ Appear.matches(handoff.animation, { key, tag: mount.tag, infinite: repeatsForever(mount.transition), projected: mount.layout }))
3088
+ if (same) return
3089
+ runtime.runFork(
3090
+ Effect.logDebug("wardic.hydration: the server's Appear animation was sampled from another mount animation than this element's; it goes on from the same time").pipe(
3091
+ Effect.annotateLogs({ id }),
3092
+ ),
3093
+ )
3094
+ }
3095
+
3096
+ /** The keys a Retarget returns to a Live value that's a number: each one's return follows it (#130). */
3097
+ const followingOf = (routes: LiveStyle, rest: Values.Values, returning: ReadonlyMap<string, BaseValue.BaseSource>): ReadonlyArray<string> =>
3098
+ Arr.filter(Rec.keys(rest), (key) => Bool.and(returning.get(key) === "style", Bool.and(routes.isLive(key), Predicate.isNumber(rest[key]))))
3099
+
3100
+ /** Where `key`'s Live value is now, a number; where it last was when it's none (#130). */
3101
+ const liveTargetOf = (routes: LiveStyle, key: string, start: number): (() => number) => {
3102
+ let last = start
3103
+ return () => {
3104
+ const now = Option.flatMap(routes.valueOf(key), (raw) => OwnValues.valueLike(raw, last))
3105
+ if (Option.isSome(now)) last = now.value as number
3106
+ return last
3107
+ }
3108
+ }
3109
+
3110
+ /** Whether a value is one an element can take: a number or a string. */
3111
+ const isValue = (value: unknown): value is number | string => Bool.or(Predicate.isNumber(value), Predicate.isString(value))
3112
+
3113
+ /**
3114
+ * Where `key` rests outside the gate (#130): its `initial`, else its `style` value (a Live value's
3115
+ * now), else a transform key's identity, else `undefined`.
3116
+ */
3117
+ export const restingOf = (key: string, initial: Values.Values, style: object | string | undefined, read: (value: unknown) => unknown): unknown =>
3118
+ Option.getOrUndefined(
3119
+ Option.fromUndefinedOr(initial[key]).pipe(
3120
+ Option.orElse((): Option.Option<unknown> => Option.flatMap(OwnValues.styleValueOf(style, key), (raw) => Option.fromNullishOr(read(raw)))),
3121
+ Option.orElse((): Option.Option<unknown> => BaseValue.transformIdentity(key)),
3122
+ ),
3123
+ )
3124
+
3125
+ /** A provider runtime's `AtomRegistry`, read on first need: an element with no Atom never reads it. */
3126
+ export const registryOf = (runtime: WardicRuntime): (() => AtomRegistry.AtomRegistry) => {
3127
+ let registry: AtomRegistry.AtomRegistry | undefined
3128
+ return () => {
3129
+ if (Predicate.isUndefined(registry)) registry = runtime.runSync(AtomRegistry.AtomRegistry)
3130
+ return registry
3131
+ }
3132
+ }
3133
+
3134
+ /** Log, once per element, that a `transform` string gave way to the transform keys in its `style` (#130). */
3135
+ export const warnDroppedTransform = (runtime: WardicRuntime, id: string): void => {
3136
+ runtime.runFork(
3137
+ Effect.logWarning(
3138
+ "wardic.style: a `transform` string is dropped while `style` sets a transform key (x, scale, rotate…); " +
3139
+ "the keys win, as Motion's do. Give the transform as keys, or drop them",
3140
+ ).pipe(Effect.annotateLogs({ id })),
3141
+ )
3142
+ }
3143
+
3144
+ /**
3145
+ * Log, at debug level, the keys whose Starting style the Environment's Renderer projects
3146
+ * differently from the DOM's `project`, which rendered the server markup. Hydration keeps
3147
+ * the server's values (the Hydration hold); the Renderer's take over at the first frame.
3148
+ * Hydration only, once per element. Internal.
3149
+ */
3150
+ export const flagStartingStyle = (runtime: WardicRuntime, id: string, server: Renderer.Patch, client: Renderer.Patch): void => {
3151
+ const keys = Arr.appendAll(
3152
+ Arr.filter(Rec.keys(server), (key) => String(server[key]) !== String(client[key])),
3153
+ Arr.filter(Rec.keys(client), (key) => Bool.not(key in server)),
3154
+ )
3155
+ if (Arr.isReadonlyArrayEmpty(keys)) return
3156
+ const pick = (patch: Renderer.Patch) => Object.fromEntries(keys.map((key) => [key, patch[key]]))
3157
+ runtime.runFork(
3158
+ Effect.logDebug(
3159
+ "wardic.hydration: the Environment's Renderer projects the Starting style differently from the DOM's; " +
3160
+ "hydration keeps the server's until the first frame, and an element that never animates keeps it",
3161
+ ).pipe(
3162
+ Effect.annotateLogs({ id, keys, server: pick(server), client: pick(client) }),
3163
+ ),
3164
+ )
3165
+ }
3166
+
3167
+ /** An element's Appear animation on a server (#48, ADR-0044), as both bindings' server wards and component wraps use it. */
3168
+ export interface ServerAppearOf {
3169
+ /** Its inline `animation`, under the user's style: none when it plays none. */
3170
+ readonly style: { readonly animation: string } | undefined
3171
+ /** The context its children read: its variant node's, with its Appear group when it leads one. */
3172
+ readonly provided: WardicVariantContextValue | undefined
3173
+ /** Rules it out once it has rendered: its user style is read when `ward()` is called. */
3174
+ readonly veto: (reason: string) => void
3175
+ /**
3176
+ * Rendered after the shell (#245): in a late chunk, and its root when no late element is around
3177
+ * it, which puts the chunk's `<style>` after itself. `state` is the render's.
3178
+ */
3179
+ readonly late: boolean
3180
+ readonly chunkRoot: boolean
3181
+ readonly state: ServerAppear | undefined
3182
+ }
3183
+
3184
+ /** No Appear animation: a provider with `appear={false}`. */
3185
+ const NO_APPEAR_ENTRY = (provided: WardicVariantContextValue | undefined): ServerAppearOf => ({
3186
+ style: undefined,
3187
+ provided,
3188
+ veto: constVoid,
3189
+ late: false,
3190
+ chunkRoot: false,
3191
+ state: undefined,
3192
+ })
3193
+
3194
+ /**
3195
+ * An element's entry in the server render's Appear animations (#48, ADR-0044): its starting
3196
+ * values, its targets at mount (`animate`, or an inherited variant name against its `variants`),
3197
+ * its transition, its place in its parent's group, and its nearest `WardicConfig`'s reduced motion
3198
+ * (#434). `state` is the provider's, `undefined` with `appear={false}`: each binding reads it from its
3199
+ * own context.
3200
+ */
3201
+ export const appearEntryOf = (
3202
+ state: ServerAppear | undefined,
3203
+ c: WardConfig,
3204
+ tag: string | undefined,
3205
+ initialValues: Values.Values,
3206
+ node: ServerVariantNode,
3207
+ quiet: boolean,
3208
+ reducedMotion: ReducedMotion.Config | undefined,
3209
+ skipAnimations = false,
3210
+ ): ServerAppearOf =>
3211
+ UndefinedOr.match(state, {
3212
+ onUndefined: () => NO_APPEAR_ENTRY(node.provided),
3213
+ onDefined: (state) => {
3214
+ // The target's own transition (#277) drives its mount animation, and its orchestration.
3215
+ const target = serverTargetOf(c, node.inherited)
3216
+ const own = Option.getOrUndefined(Option.flatMap(target, (t) => Option.fromUndefinedOr(t.transition)))
3217
+ const entered = enterServer(state, {
3218
+ appear: c.appear,
3219
+ tag,
3220
+ initial: initialValues,
3221
+ to: Option.map(target, (t) => t.values),
3222
+ keyframes: Option.getOrUndefined(Option.flatMap(target, (t) => Option.fromUndefinedOr(t.keyframes))),
3223
+ quiet,
3224
+ transition: transitionOfTarget(own, ownOrInherited(c.transition, node.inherited)),
3225
+ layout: isLayoutNode(c),
3226
+ template: c.transformTemplate,
3227
+ group: Option.flatMap(Option.fromUndefinedOr(node.inherited), (inherited) => Option.fromUndefinedOr(inherited.appearGroup)),
3228
+ leads: hasOwnVariants(c),
3229
+ ownTransition: transitionOfTarget(own, c.transition),
3230
+ reducedMotion,
3231
+ skipAnimations,
3232
+ })
3233
+ return {
3234
+ style: Option.match(entered.animation, { onNone: constUndefined, onSome: (animation) => ({ animation }) }),
3235
+ provided: Option.match(entered.group, {
3236
+ onNone: () => node.provided,
3237
+ onSome: (appearGroup) => UndefinedOr.map(node.provided, (provided): WardicVariantContextValue => ({ ...provided, appearGroup })),
3238
+ }),
3239
+ veto: entered.veto,
3240
+ late: entered.late,
3241
+ chunkRoot: entered.chunkRoot,
3242
+ state,
3243
+ }
3244
+ },
3245
+ })
3246
+
3247
+ /**
3248
+ * An element's target at mount on a server: its `animate`, else an inherited variant name resolved
3249
+ * against its own `variants`, a dynamic one with its `custom` and no values yet (#277).
3250
+ */
3251
+ export const serverTargetOf = (c: WardConfig, inherited: WardicVariantContextValue | undefined): Option.Option<Target> =>
3252
+ UndefinedOr.match(c.animate as Entry, {
3253
+ onDefined: (own) => Option.some(resolveTarget(own, c.variants, c.custom, NO_VARIANT_STATE)),
3254
+ onUndefined: () =>
3255
+ Option.map(
3256
+ Option.flatMap(Option.fromUndefinedOr(inherited), (context) => Option.fromUndefinedOr(context.variant())),
3257
+ (name) => resolveTarget(name, c.variants, c.custom, NO_VARIANT_STATE),
3258
+ ),
3259
+ })
3260
+
3261
+ /**
3262
+ * A server's Starting style for an element whose `style` has routed keys (#130): the projected
3263
+ * `initial` with their values under it. With none, its Starting style as it was.
3264
+ */
3265
+ export const serverStartingStyle = (
3266
+ tag: string | undefined,
3267
+ starting: Renderer.Patch,
3268
+ initialValues: Values.Values,
3269
+ routed: Readonly<Record<string, unknown>>,
3270
+ layout: boolean,
3271
+ untrack: Reactivity["untrack"],
3272
+ template: WardConfig["transformTemplate"],
3273
+ ): Renderer.Patch =>
3274
+ Bool.match(Rec.isEmptyRecord(routed), {
3275
+ onTrue: () => starting,
3276
+ onFalse: () => Style.starting(tag, drawnAtRest({ ...valuesOf(routed, serverRegistryOf, untrack), ...initialValues }, layout, template)).style,
3277
+ })
3278
+
3279
+ /** Whether a config makes its element a layout node: `layout` (or a mode), or a `layoutId`. */
3280
+ export const isLayoutNode = (c: WardConfig): boolean =>
3281
+ Bool.or(Bool.and(Predicate.isNotUndefined(c.layout), c.layout !== false), Predicate.isNotUndefined(c.layoutId))
3282
+
3283
+ /**
3284
+ * The values a layout node's Starting style is drawn from (#245, ADR-0044 *Amendment (#245)*):
3285
+ * through its projection at rest, as its first commit draws it, its own translate on top (#363).
3286
+ * Any other element's, as they are. A templated element's, with its Transform template (#443).
3287
+ */
3288
+ export const drawnAtRest = (values: Values.Values, layout: boolean, template: WardConfig["transformTemplate"]): Readonly<Record<string, unknown>> => {
3289
+ // Per mount (#460): guards, nothing built for an element neither a layout node nor templated.
3290
+ if (Bool.not(layout)) return withTemplate(values, template)
3291
+ return withTemplate({ ...values, [Projection.KEY]: Projection.AT_REST }, template)
3292
+ }
3293
+
3294
+ /** `values` with `template` under the renderer's reserved key, as its projection rides (#443); as they are with none. */
3295
+ export const withTemplate = <V extends Readonly<Record<string, unknown>>>(values: V, template: WardConfig["transformTemplate"]): V => {
3296
+ if (Predicate.isUndefined(template)) return values
3297
+ return { ...values, [DomRenderer.TEMPLATE_KEY]: template }
3298
+ }
3299
+
3300
+ /**
3301
+ * What an element registers with in the gate (#443): its Transform template at mount, under the
3302
+ * renderer's reserved key, drawn with its first write (a write of its own would take its Starting
3303
+ * style off early). Nothing with none.
3304
+ */
3305
+ export const registeredValuesOf = (template: WardConfig["transformTemplate"]): Readonly<Record<string, unknown>> | undefined => {
3306
+ if (Predicate.isUndefined(template)) return undefined
3307
+ return { [DomRenderer.TEMPLATE_KEY]: template }
3308
+ }
3309
+
3310
+ /**
3311
+ * What an element's projection node is held at for a Measure pass (#443, Motion's
3312
+ * `transformTemplate(values, "")`): its Transform template's, from its values now, when it had one
3313
+ * at mount. `undefined` otherwise, so a node without one pays a field read a pass.
3314
+ */
3315
+ export const heldTransformFor = (
3316
+ snapshot: Snapshot,
3317
+ atMount: WardConfig["transformTemplate"],
3318
+ template: () => WardConfig["transformTemplate"],
3319
+ ): (() => string) | undefined => {
3320
+ if (Predicate.isUndefined(atMount)) return undefined
3321
+ return () => DomRenderer.heldTransformOf(withTemplate(snapshot.values, template()))
3322
+ }
3323
+
3324
+ /**
3325
+ * Follow an element's Transform template after mount (#443): `write` is called with each other one
3326
+ * its config gives, and draws it at the next frame. Only for an element with one at mount, as
3327
+ * `onUpdate` (#233): its caller asks only then, so another makes nothing (#460). Returns the stop.
3328
+ */
3329
+ export const followTemplate = (
3330
+ atMount: DomRenderer.TransformTemplate,
3331
+ template: () => WardConfig["transformTemplate"],
3332
+ watch: Reactivity["watch"],
3333
+ write: (template: WardConfig["transformTemplate"]) => void,
3334
+ ): (() => void) => {
3335
+ let last: WardConfig["transformTemplate"] = atMount
3336
+ return watch(template, (next) => {
3337
+ if (next === last) return
3338
+ last = next
3339
+ write(next)
3340
+ })
3341
+ }
3342
+
3343
+ /** A mount animation's template field (#443): left out with none, as its key reads it. */
3344
+ export const templateField = (template: WardConfig["transformTemplate"]): { readonly template?: DomRenderer.TransformTemplate } =>
3345
+ UndefinedOr.match(template, { onUndefined: () => ({}), onDefined: (t) => ({ template: t }) })
3346
+
3347
+ /** What a `<Reorder>` item adds to an element's drag: its gesture's axis, read at each drag's start. */
3348
+ interface DragInternals {
3349
+ readonly dragAxis?: (() => boolean | "x" | "y") | undefined
3350
+ }
3351
+
3352
+ /** A plain element's drag internals: none. */
3353
+ const NO_DRAG_INTERNALS: DragInternals = {}
3354
+
3355
+ /**
3356
+ * The drag axis a spine runs with: its static `drag` config, else `true` for a
3357
+ * `<Reorder>` item (its gesture's axis comes from `dragAxis`), else none.
3358
+ */
3359
+ export const dragAxisOf = (config: WardConfig, internal: DragInternals = NO_DRAG_INTERNALS): boolean | "x" | "y" | undefined =>
3360
+ Option.getOrUndefined(
3361
+ Option.orElse(Option.filter(Option.fromUndefinedOr(config.drag), (drag) => drag !== false), () =>
3362
+ Option.map(Option.fromUndefinedOr(internal.dragAxis), (): true => true)),
3363
+ )
3364
+
3365
+ /**
3366
+ * A drag element's defaults (ADR-0019 *Amendment (Reorder)*): its axis's, unless its own presses don't
3367
+ * drag it (`dragListener={false}`, #431), as Motion's come with its listener.
3368
+ */
3369
+ export const dragDefaultsOf = (config: WardConfig, internal: DragInternals = NO_DRAG_INTERNALS): Style.DragDefaults | undefined => {
3370
+ if (config.dragListener === false) return undefined
3371
+ return UndefinedOr.map(dragAxisOf(config, internal), Style.dragDefaults)
3372
+ }
3373
+
3374
+ /**
3375
+ * Set each of a drag element's defaults its inline style doesn't already set, and
3376
+ * `draggable="false"` unless it has the attribute, at mount: for an element whose props don't carry
3377
+ * them, a directive's (`use:wardic`, `use:w`) and a `wardic.create(Component)` wrap's, whose
3378
+ * component may not pass them on.
3379
+ */
3380
+ export const applyDragDefaults = (element: HTMLElement, defaults: Style.DragDefaults): void => {
3381
+ Arr.forEach(Rec.keys(defaults), (key) => {
3382
+ if (element.style.getPropertyValue(key) === "") element.style.setProperty(key, UndefinedOr.getOrThrow(defaults[key]))
3383
+ })
3384
+ if (!element.hasAttribute("draggable")) element.setAttribute("draggable", Style.DRAG_DEFAULT_ATTRIBUTES.draggable)
3385
+ }