@vizejs/composable 0.426.2 → 0.427.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/dist/abort-signal.d.mts +1 -1
  2. package/dist/active-element.d.mts +37 -0
  3. package/dist/active-element.mjs +56 -0
  4. package/dist/animate.d.mts +114 -0
  5. package/dist/animate.mjs +157 -0
  6. package/dist/battery.d.mts +61 -0
  7. package/dist/battery.mjs +90 -0
  8. package/dist/breakpoints.d.mts +82 -0
  9. package/dist/breakpoints.mjs +91 -0
  10. package/dist/catalog-BeTXFKxF.d.mts +4188 -0
  11. package/dist/catalog-r4Z5nptX.mjs +5144 -0
  12. package/dist/catalog.d.mts +1 -1
  13. package/dist/catalog.mjs +1 -1
  14. package/dist/color-mode.d.mts +131 -0
  15. package/dist/color-mode.mjs +133 -0
  16. package/dist/computed-async.d.mts +63 -0
  17. package/dist/computed-async.mjs +43 -0
  18. package/dist/computed-with-control.d.mts +44 -0
  19. package/dist/computed-with-control.mjs +54 -0
  20. package/dist/create-event-hook.d.mts +77 -0
  21. package/dist/create-event-hook.mjs +66 -0
  22. package/dist/create-global-state.d.mts +24 -0
  23. package/dist/create-global-state.mjs +34 -0
  24. package/dist/create-injection-state.d.mts +51 -0
  25. package/dist/create-injection-state.mjs +19 -0
  26. package/dist/create-shared-composable.d.mts +38 -0
  27. package/dist/create-shared-composable.mjs +54 -0
  28. package/dist/device-motion.d.mts +71 -0
  29. package/dist/device-motion.mjs +75 -0
  30. package/dist/device-orientation.d.mts +82 -0
  31. package/dist/device-orientation.mjs +86 -0
  32. package/dist/device-pixel-ratio.d.mts +45 -0
  33. package/dist/device-pixel-ratio.mjs +50 -0
  34. package/dist/document-visibility.mjs +6 -2
  35. package/dist/draggable.d.mts +121 -0
  36. package/dist/draggable.mjs +153 -0
  37. package/dist/element-bounding.d.mts +87 -0
  38. package/dist/element-bounding.mjs +95 -0
  39. package/dist/element-by-point.d.mts +70 -0
  40. package/dist/element-by-point.mjs +69 -0
  41. package/dist/element-hover.d.mts +42 -0
  42. package/dist/element-hover.mjs +70 -0
  43. package/dist/element-ref.d.mts +34 -0
  44. package/dist/element-ref.mjs +23 -0
  45. package/dist/element-target-Crpxl4D9.d.mts +60 -0
  46. package/dist/element-target.d.mts +2 -0
  47. package/dist/element-target.mjs +58 -0
  48. package/dist/event-listener.mjs +7 -3
  49. package/dist/focus.d.mts +69 -0
  50. package/dist/focus.mjs +124 -0
  51. package/dist/fps.d.mts +59 -0
  52. package/dist/fps.mjs +64 -0
  53. package/dist/geolocation.d.mts +98 -0
  54. package/dist/geolocation.mjs +86 -0
  55. package/dist/i18n.d.mts +237 -0
  56. package/dist/i18n.mjs +215 -0
  57. package/dist/icu-message.d.mts +235 -0
  58. package/dist/icu-message.mjs +343 -0
  59. package/dist/idle.d.mts +79 -0
  60. package/dist/idle.mjs +90 -0
  61. package/dist/index.d.mts +172 -6
  62. package/dist/index.mjs +173 -7
  63. package/dist/infinite-scroll.d.mts +56 -0
  64. package/dist/infinite-scroll.mjs +72 -0
  65. package/dist/intersection-observer.d.mts +122 -0
  66. package/dist/intersection-observer.mjs +117 -0
  67. package/dist/magic-keys.d.mts +121 -0
  68. package/dist/magic-keys.mjs +163 -0
  69. package/dist/math.d.mts +96 -0
  70. package/dist/math.mjs +84 -0
  71. package/dist/media-query.d.mts +3 -1
  72. package/dist/media-query.mjs +5 -3
  73. package/dist/mouse-in-element.d.mts +49 -0
  74. package/dist/mouse-in-element.mjs +66 -0
  75. package/dist/mouse.d.mts +77 -0
  76. package/dist/mouse.mjs +100 -0
  77. package/dist/mutation-observer.d.mts +98 -0
  78. package/dist/mutation-observer.mjs +69 -0
  79. package/dist/network.d.mts +96 -0
  80. package/dist/network.mjs +117 -0
  81. package/dist/on-click-outside.d.mts +69 -0
  82. package/dist/on-click-outside.mjs +115 -0
  83. package/dist/on-key-stroke.d.mts +71 -0
  84. package/dist/on-key-stroke.mjs +79 -0
  85. package/dist/on-long-press.d.mts +82 -0
  86. package/dist/on-long-press.mjs +105 -0
  87. package/dist/on-start-typing.d.mts +44 -0
  88. package/dist/on-start-typing.mjs +61 -0
  89. package/dist/page-leave.d.mts +26 -0
  90. package/dist/page-leave.mjs +40 -0
  91. package/dist/parent-element.d.mts +16 -0
  92. package/dist/parent-element.mjs +27 -0
  93. package/dist/pinch.d.mts +73 -0
  94. package/dist/pinch.mjs +138 -0
  95. package/dist/pointer-lock.d.mts +79 -0
  96. package/dist/pointer-lock.mjs +126 -0
  97. package/dist/pointer.d.mts +78 -0
  98. package/dist/pointer.mjs +95 -0
  99. package/dist/preferences.d.mts +55 -0
  100. package/dist/preferences.mjs +63 -0
  101. package/dist/preferred-languages.d.mts +43 -0
  102. package/dist/preferred-languages.mjs +44 -0
  103. package/dist/reactify.d.mts +28 -0
  104. package/dist/reactify.mjs +7 -0
  105. package/dist/ref-auto-reset.d.mts +47 -0
  106. package/dist/ref-auto-reset.mjs +70 -0
  107. package/dist/ref-debounced.d.mts +29 -0
  108. package/dist/ref-debounced.mjs +29 -0
  109. package/dist/ref-default.d.mts +27 -0
  110. package/dist/ref-default.mjs +33 -0
  111. package/dist/resize-observer.d.mts +96 -0
  112. package/dist/resize-observer.mjs +111 -0
  113. package/dist/resolver.d.mts +124 -0
  114. package/dist/resolver.mjs +138 -0
  115. package/dist/retry-async.d.mts +2 -2
  116. package/dist/retry-delay-DYsdq4SE.d.mts +73 -0
  117. package/dist/retry-delay.d.mts +1 -72
  118. package/dist/screen-orientation.d.mts +77 -0
  119. package/dist/screen-orientation.mjs +74 -0
  120. package/dist/scroll-lock.d.mts +37 -0
  121. package/dist/scroll-lock.mjs +50 -0
  122. package/dist/scroll.d.mts +158 -0
  123. package/dist/scroll.mjs +172 -0
  124. package/dist/standard-schema-DmNgFVK5.d.mts +107 -0
  125. package/dist/standard-schema.d.mts +2 -0
  126. package/dist/standard-schema.mjs +60 -0
  127. package/dist/swipe.d.mts +125 -0
  128. package/dist/swipe.mjs +225 -0
  129. package/dist/sync-ref.d.mts +80 -0
  130. package/dist/sync-ref.mjs +43 -0
  131. package/dist/text-selection.d.mts +46 -0
  132. package/dist/text-selection.mjs +62 -0
  133. package/dist/textarea-autosize.d.mts +58 -0
  134. package/dist/textarea-autosize.mjs +54 -0
  135. package/dist/timeout-scheduler-CI8RVLZs.d.mts +18 -0
  136. package/dist/timeout-scheduler.d.mts +1 -17
  137. package/dist/to-reactive.d.mts +26 -0
  138. package/dist/to-reactive.mjs +46 -0
  139. package/dist/transition.d.mts +125 -0
  140. package/dist/transition.mjs +266 -0
  141. package/dist/until.d.mts +177 -0
  142. package/dist/until.mjs +111 -0
  143. package/dist/use-array.d.mts +112 -0
  144. package/dist/use-array.mjs +90 -0
  145. package/dist/use-async-queue.d.mts +109 -0
  146. package/dist/use-async-queue.mjs +96 -0
  147. package/dist/use-async-state.d.mts +86 -0
  148. package/dist/use-async-state.mjs +41 -0
  149. package/dist/use-barcode-detector.d.mts +159 -0
  150. package/dist/use-barcode-detector.mjs +143 -0
  151. package/dist/use-bluetooth.d.mts +164 -0
  152. package/dist/use-bluetooth.mjs +183 -0
  153. package/dist/use-broadcast-channel.d.mts +115 -0
  154. package/dist/use-broadcast-channel.mjs +121 -0
  155. package/dist/use-builtin-ai.d.mts +342 -0
  156. package/dist/use-builtin-ai.mjs +261 -0
  157. package/dist/use-clipboard.d.mts +169 -0
  158. package/dist/use-clipboard.mjs +226 -0
  159. package/dist/use-compression-stream.d.mts +173 -0
  160. package/dist/use-compression-stream.mjs +166 -0
  161. package/dist/use-confirm-dialog.d.mts +70 -0
  162. package/dist/use-confirm-dialog.mjs +57 -0
  163. package/dist/use-contact-picker.d.mts +117 -0
  164. package/dist/use-contact-picker.mjs +103 -0
  165. package/dist/use-cookie.d.mts +196 -0
  166. package/dist/use-cookie.mjs +259 -0
  167. package/dist/use-countdown.d.mts +85 -0
  168. package/dist/use-countdown.mjs +74 -0
  169. package/dist/use-css-var.d.mts +96 -0
  170. package/dist/use-css-var.mjs +104 -0
  171. package/dist/use-cycle-list.d.mts +76 -0
  172. package/dist/use-cycle-list.mjs +39 -0
  173. package/dist/use-date-format.d.mts +103 -0
  174. package/dist/use-date-format.mjs +147 -0
  175. package/dist/use-date-time-format.d.mts +75 -0
  176. package/dist/use-date-time-format.mjs +53 -0
  177. package/dist/use-debounced.d.mts +1 -1
  178. package/dist/use-display-media.d.mts +62 -0
  179. package/dist/use-display-media.mjs +46 -0
  180. package/dist/use-display-names.d.mts +75 -0
  181. package/dist/use-display-names.mjs +52 -0
  182. package/dist/use-document-title.d.mts +88 -0
  183. package/dist/use-document-title.mjs +100 -0
  184. package/dist/use-drop-zone.d.mts +128 -0
  185. package/dist/use-drop-zone.mjs +154 -0
  186. package/dist/use-event-source.d.mts +184 -0
  187. package/dist/use-event-source.mjs +226 -0
  188. package/dist/use-eye-dropper.d.mts +79 -0
  189. package/dist/use-eye-dropper.mjs +68 -0
  190. package/dist/use-favicon.d.mts +78 -0
  191. package/dist/use-favicon.mjs +68 -0
  192. package/dist/use-fetch.d.mts +230 -0
  193. package/dist/use-fetch.mjs +263 -0
  194. package/dist/use-field.d.mts +107 -0
  195. package/dist/use-field.mjs +117 -0
  196. package/dist/use-file-dialog.d.mts +139 -0
  197. package/dist/use-file-dialog.mjs +101 -0
  198. package/dist/use-file-system-access.d.mts +184 -0
  199. package/dist/use-file-system-access.mjs +151 -0
  200. package/dist/use-form-field-props.d.mts +235 -0
  201. package/dist/use-form-field-props.mjs +164 -0
  202. package/dist/use-form.d.mts +324 -0
  203. package/dist/use-form.mjs +482 -0
  204. package/dist/use-fullscreen.d.mts +104 -0
  205. package/dist/use-fullscreen.mjs +95 -0
  206. package/dist/use-gamepad.d.mts +242 -0
  207. package/dist/use-gamepad.mjs +218 -0
  208. package/dist/use-hid.d.mts +160 -0
  209. package/dist/use-hid.mjs +156 -0
  210. package/dist/use-id-generator.d.mts +44 -0
  211. package/dist/use-id-generator.mjs +38 -0
  212. package/dist/use-image.d.mts +125 -0
  213. package/dist/use-image.mjs +109 -0
  214. package/dist/use-indexed-db.d.mts +207 -0
  215. package/dist/use-indexed-db.mjs +251 -0
  216. package/dist/use-interval-BA55gTHT.d.mts +140 -0
  217. package/dist/use-interval.d.mts +2 -0
  218. package/dist/use-interval.mjs +100 -0
  219. package/dist/use-list-format.d.mts +60 -0
  220. package/dist/use-list-format.mjs +40 -0
  221. package/dist/use-machine.d.mts +90 -0
  222. package/dist/use-machine.mjs +78 -0
  223. package/dist/use-map.d.mts +90 -0
  224. package/dist/use-map.mjs +70 -0
  225. package/dist/use-media-controls.d.mts +198 -0
  226. package/dist/use-media-controls.mjs +264 -0
  227. package/dist/use-memoize.d.mts +73 -0
  228. package/dist/use-memoize.mjs +28 -0
  229. package/dist/use-mounted.d.mts +24 -0
  230. package/dist/use-mounted.mjs +29 -0
  231. package/dist/use-navigation-api.d.mts +360 -0
  232. package/dist/use-navigation-api.mjs +231 -0
  233. package/dist/use-notification.d.mts +139 -0
  234. package/dist/use-notification.mjs +131 -0
  235. package/dist/use-now.d.mts +137 -0
  236. package/dist/use-now.mjs +44 -0
  237. package/dist/use-number-format.d.mts +73 -0
  238. package/dist/use-number-format.mjs +58 -0
  239. package/dist/use-object-url.d.mts +47 -0
  240. package/dist/use-object-url.mjs +54 -0
  241. package/dist/use-offset-pagination.d.mts +91 -0
  242. package/dist/use-offset-pagination.mjs +80 -0
  243. package/dist/use-payment-request.d.mts +239 -0
  244. package/dist/use-payment-request.mjs +206 -0
  245. package/dist/use-performance-observer.d.mts +285 -0
  246. package/dist/use-performance-observer.mjs +132 -0
  247. package/dist/use-permission.d.mts +99 -0
  248. package/dist/use-permission.mjs +92 -0
  249. package/dist/use-plural-rules.d.mts +79 -0
  250. package/dist/use-plural-rules.mjs +59 -0
  251. package/dist/use-push-subscription.d.mts +154 -0
  252. package/dist/use-push-subscription.mjs +146 -0
  253. package/dist/use-queue.d.mts +89 -0
  254. package/dist/use-queue.mjs +116 -0
  255. package/dist/use-raf-fn.d.mts +87 -0
  256. package/dist/use-raf-fn.mjs +99 -0
  257. package/dist/use-relative-time-format.d.mts +111 -0
  258. package/dist/use-relative-time-format.mjs +119 -0
  259. package/dist/use-request-idle-callback.d.mts +122 -0
  260. package/dist/use-request-idle-callback.mjs +147 -0
  261. package/dist/use-route-query.d.mts +149 -0
  262. package/dist/use-route-query.mjs +86 -0
  263. package/dist/use-scheduler-post-task.d.mts +156 -0
  264. package/dist/use-scheduler-post-task.mjs +182 -0
  265. package/dist/use-screen-details.d.mts +205 -0
  266. package/dist/use-screen-details.mjs +188 -0
  267. package/dist/use-script-tag.d.mts +162 -0
  268. package/dist/use-script-tag.mjs +171 -0
  269. package/dist/use-segmenter.d.mts +78 -0
  270. package/dist/use-segmenter.mjs +66 -0
  271. package/dist/use-selection.d.mts +125 -0
  272. package/dist/use-selection.mjs +77 -0
  273. package/dist/use-serial.d.mts +165 -0
  274. package/dist/use-serial.mjs +205 -0
  275. package/dist/use-service-worker.d.mts +177 -0
  276. package/dist/use-service-worker.mjs +178 -0
  277. package/dist/use-set.d.mts +96 -0
  278. package/dist/use-set.mjs +74 -0
  279. package/dist/use-share.d.mts +92 -0
  280. package/dist/use-share.mjs +99 -0
  281. package/dist/use-sorted-locale.d.mts +62 -0
  282. package/dist/use-sorted-locale.mjs +52 -0
  283. package/dist/use-sorted.d.mts +29 -0
  284. package/dist/use-sorted.mjs +14 -0
  285. package/dist/use-speech-recognition.d.mts +150 -0
  286. package/dist/use-speech-recognition.mjs +168 -0
  287. package/dist/use-speech-synthesis.d.mts +148 -0
  288. package/dist/use-speech-synthesis.mjs +152 -0
  289. package/dist/use-stack.d.mts +83 -0
  290. package/dist/use-stack.mjs +93 -0
  291. package/dist/use-stepper.d.mts +79 -0
  292. package/dist/use-stepper.mjs +52 -0
  293. package/dist/use-storage-estimate.d.mts +151 -0
  294. package/dist/use-storage-estimate.mjs +170 -0
  295. package/dist/use-storage.d.mts +214 -0
  296. package/dist/use-storage.mjs +415 -0
  297. package/dist/use-style-tag.d.mts +102 -0
  298. package/dist/use-style-tag.mjs +91 -0
  299. package/dist/use-supported.d.mts +23 -0
  300. package/dist/use-supported.mjs +26 -0
  301. package/dist/use-throttled.d.mts +1 -1
  302. package/dist/use-time-ago.d.mts +163 -0
  303. package/dist/use-time-ago.mjs +95 -0
  304. package/dist/use-timeout.d.mts +122 -0
  305. package/dist/use-timeout.mjs +65 -0
  306. package/dist/use-url-hash.d.mts +88 -0
  307. package/dist/use-url-hash.mjs +145 -0
  308. package/dist/use-url-search-params.d.mts +223 -0
  309. package/dist/use-url-search-params.mjs +295 -0
  310. package/dist/use-usb.d.mts +212 -0
  311. package/dist/use-usb.mjs +137 -0
  312. package/dist/use-user-activation.d.mts +83 -0
  313. package/dist/use-user-activation.mjs +113 -0
  314. package/dist/use-user-media.d.mts +194 -0
  315. package/dist/use-user-media.mjs +214 -0
  316. package/dist/use-v-model.d.mts +113 -0
  317. package/dist/use-v-model.mjs +40 -0
  318. package/dist/use-vibrate.d.mts +81 -0
  319. package/dist/use-vibrate.mjs +90 -0
  320. package/dist/use-view-transition.d.mts +106 -0
  321. package/dist/use-view-transition.mjs +101 -0
  322. package/dist/use-visual-viewport.d.mts +105 -0
  323. package/dist/use-visual-viewport.mjs +104 -0
  324. package/dist/use-wake-lock.d.mts +96 -0
  325. package/dist/use-wake-lock.mjs +106 -0
  326. package/dist/use-web-authn.d.mts +404 -0
  327. package/dist/use-web-authn.mjs +323 -0
  328. package/dist/use-web-locks.d.mts +180 -0
  329. package/dist/use-web-locks.mjs +136 -0
  330. package/dist/use-web-midi.d.mts +148 -0
  331. package/dist/use-web-midi.mjs +140 -0
  332. package/dist/use-web-vitals.d.mts +142 -0
  333. package/dist/use-web-vitals.mjs +248 -0
  334. package/dist/use-websocket.d.mts +218 -0
  335. package/dist/use-websocket.mjs +257 -0
  336. package/dist/use-worker-fn.d.mts +119 -0
  337. package/dist/use-worker-fn.mjs +162 -0
  338. package/dist/virtual-list.d.mts +105 -0
  339. package/dist/virtual-list.mjs +128 -0
  340. package/dist/watch-debounced.d.mts +84 -0
  341. package/dist/watch-debounced.mjs +84 -0
  342. package/dist/watch-ignorable.d.mts +47 -0
  343. package/dist/watch-ignorable.mjs +61 -0
  344. package/dist/watch-once.d.mts +29 -0
  345. package/dist/watch-once.mjs +10 -0
  346. package/dist/watch-pausable.d.mts +51 -0
  347. package/dist/watch-pausable.mjs +23 -0
  348. package/dist/watch-source.d.mts +29 -0
  349. package/dist/watch-source.mjs +1 -0
  350. package/dist/watch-throttled.d.mts +70 -0
  351. package/dist/watch-throttled.mjs +94 -0
  352. package/dist/whenever.d.mts +39 -0
  353. package/dist/whenever.mjs +41 -0
  354. package/dist/window-size.d.mts +87 -0
  355. package/dist/window-size.mjs +65 -0
  356. package/package.json +846 -5
  357. package/registry/files/abort-signal.ts +292 -0
  358. package/registry/files/active-element.ts +93 -0
  359. package/registry/files/animate.ts +322 -0
  360. package/registry/files/async-resource.ts +190 -0
  361. package/registry/files/battery.ts +166 -0
  362. package/registry/files/breakpoints.ts +166 -0
  363. package/registry/files/capability.ts +171 -0
  364. package/registry/files/color-mode.ts +274 -0
  365. package/registry/files/computed-async.ts +123 -0
  366. package/registry/files/computed-with-control.ts +80 -0
  367. package/registry/files/create-event-hook.ts +139 -0
  368. package/registry/files/create-global-state.ts +34 -0
  369. package/registry/files/create-injection-state.ts +75 -0
  370. package/registry/files/create-shared-composable.ts +74 -0
  371. package/registry/files/device-motion.ts +152 -0
  372. package/registry/files/device-orientation.ts +168 -0
  373. package/registry/files/device-pixel-ratio.ts +100 -0
  374. package/registry/files/disposal-scope.ts +201 -0
  375. package/registry/files/document-visibility.ts +152 -0
  376. package/registry/files/draggable.ts +273 -0
  377. package/registry/files/element-bounding.ts +175 -0
  378. package/registry/files/element-by-point.ts +149 -0
  379. package/registry/files/element-hover.ts +104 -0
  380. package/registry/files/element-ref.ts +58 -0
  381. package/registry/files/element-target.ts +99 -0
  382. package/registry/files/event-listener.ts +188 -0
  383. package/registry/files/focus.ts +181 -0
  384. package/registry/files/fps.ts +133 -0
  385. package/registry/files/geolocation.ts +214 -0
  386. package/registry/files/i18n.ts +524 -0
  387. package/registry/files/icu-message.ts +701 -0
  388. package/registry/files/idle.ts +176 -0
  389. package/registry/files/infinite-scroll.ts +135 -0
  390. package/registry/files/intersection-observer.ts +261 -0
  391. package/registry/files/locale.ts +148 -0
  392. package/registry/files/magic-keys.ts +298 -0
  393. package/registry/files/math.ts +175 -0
  394. package/registry/files/media-query.ts +102 -0
  395. package/registry/files/mouse-in-element.ts +107 -0
  396. package/registry/files/mouse.ts +167 -0
  397. package/registry/files/mutation-observer.ts +183 -0
  398. package/registry/files/network.ts +229 -0
  399. package/registry/files/on-click-outside.ts +178 -0
  400. package/registry/files/on-key-stroke.ts +135 -0
  401. package/registry/files/on-long-press.ts +188 -0
  402. package/registry/files/on-start-typing.ts +88 -0
  403. package/registry/files/page-leave.ts +57 -0
  404. package/registry/files/parent-element.ts +29 -0
  405. package/registry/files/pinch.ts +187 -0
  406. package/registry/files/pointer-lock.ts +232 -0
  407. package/registry/files/pointer.ts +153 -0
  408. package/registry/files/preferences.ts +98 -0
  409. package/registry/files/preferred-languages.ts +88 -0
  410. package/registry/files/reactify.ts +39 -0
  411. package/registry/files/ref-auto-reset.ts +102 -0
  412. package/registry/files/ref-debounced.ts +34 -0
  413. package/registry/files/ref-default.ts +35 -0
  414. package/registry/files/resize-observer.ts +220 -0
  415. package/registry/files/retry-async.ts +261 -0
  416. package/registry/files/retry-delay.ts +132 -0
  417. package/registry/files/scope.ts +21 -0
  418. package/registry/files/screen-orientation.ts +165 -0
  419. package/registry/files/scroll-lock.ts +80 -0
  420. package/registry/files/scroll.ts +338 -0
  421. package/registry/files/standard-schema.ts +163 -0
  422. package/registry/files/swipe.ts +321 -0
  423. package/registry/files/sync-ref.ts +166 -0
  424. package/registry/files/temporal.ts +182 -0
  425. package/registry/files/text-selection.ts +110 -0
  426. package/registry/files/textarea-autosize.ts +114 -0
  427. package/registry/files/timeout-scheduler.ts +16 -0
  428. package/registry/files/to-reactive.ts +44 -0
  429. package/registry/files/transition.ts +271 -0
  430. package/registry/files/until.ts +352 -0
  431. package/registry/files/use-array.ts +201 -0
  432. package/registry/files/use-async-queue.ts +278 -0
  433. package/registry/files/use-async-state.ts +139 -0
  434. package/registry/files/use-barcode-detector.ts +321 -0
  435. package/registry/files/use-bluetooth.ts +409 -0
  436. package/registry/files/use-broadcast-channel.ts +250 -0
  437. package/registry/files/use-builtin-ai.ts +674 -0
  438. package/registry/files/use-clipboard.ts +425 -0
  439. package/registry/files/use-compression-stream.ts +364 -0
  440. package/registry/files/use-confirm-dialog.ts +137 -0
  441. package/registry/files/use-contact-picker.ts +246 -0
  442. package/registry/files/use-cookie.ts +500 -0
  443. package/registry/files/use-countdown.ts +161 -0
  444. package/registry/files/use-counter.ts +147 -0
  445. package/registry/files/use-css-var.ts +191 -0
  446. package/registry/files/use-cycle-list.ts +136 -0
  447. package/registry/files/use-date-format.ts +281 -0
  448. package/registry/files/use-date-time-format.ts +113 -0
  449. package/registry/files/use-debounced.ts +163 -0
  450. package/registry/files/use-display-media.ts +89 -0
  451. package/registry/files/use-display-names.ts +122 -0
  452. package/registry/files/use-document-title.ts +196 -0
  453. package/registry/files/use-drop-zone.ts +287 -0
  454. package/registry/files/use-event-source.ts +470 -0
  455. package/registry/files/use-eye-dropper.ts +134 -0
  456. package/registry/files/use-favicon.ts +140 -0
  457. package/registry/files/use-fetch.ts +578 -0
  458. package/registry/files/use-field.ts +247 -0
  459. package/registry/files/use-file-dialog.ts +257 -0
  460. package/registry/files/use-file-system-access.ts +383 -0
  461. package/registry/files/use-form-field-props.ts +381 -0
  462. package/registry/files/use-form.ts +980 -0
  463. package/registry/files/use-fullscreen.ts +214 -0
  464. package/registry/files/use-gamepad.ts +463 -0
  465. package/registry/files/use-hid.ts +359 -0
  466. package/registry/files/use-history.ts +231 -0
  467. package/registry/files/use-id-generator.ts +61 -0
  468. package/registry/files/use-image.ts +253 -0
  469. package/registry/files/use-indexed-db.ts +508 -0
  470. package/registry/files/use-interval.ts +253 -0
  471. package/registry/files/use-list-format.ts +85 -0
  472. package/registry/files/use-machine.ts +171 -0
  473. package/registry/files/use-map.ts +145 -0
  474. package/registry/files/use-media-controls.ts +545 -0
  475. package/registry/files/use-memoize.ts +118 -0
  476. package/registry/files/use-mounted.ts +30 -0
  477. package/registry/files/use-navigation-api.ts +641 -0
  478. package/registry/files/use-notification.ts +285 -0
  479. package/registry/files/use-now.ts +194 -0
  480. package/registry/files/use-number-format.ts +120 -0
  481. package/registry/files/use-object-url.ts +87 -0
  482. package/registry/files/use-offset-pagination.ts +168 -0
  483. package/registry/files/use-payment-request.ts +465 -0
  484. package/registry/files/use-performance-observer.ts +469 -0
  485. package/registry/files/use-permission.ts +220 -0
  486. package/registry/files/use-plural-rules.ts +134 -0
  487. package/registry/files/use-previous.ts +62 -0
  488. package/registry/files/use-push-subscription.ts +352 -0
  489. package/registry/files/use-queue.ts +197 -0
  490. package/registry/files/use-raf-fn.ts +176 -0
  491. package/registry/files/use-relative-time-format.ts +201 -0
  492. package/registry/files/use-request-idle-callback.ts +278 -0
  493. package/registry/files/use-route-query.ts +300 -0
  494. package/registry/files/use-scheduler-post-task.ts +397 -0
  495. package/registry/files/use-screen-details.ts +393 -0
  496. package/registry/files/use-script-tag.ts +341 -0
  497. package/registry/files/use-segmenter.ts +147 -0
  498. package/registry/files/use-selection.ts +233 -0
  499. package/registry/files/use-serial.ts +404 -0
  500. package/registry/files/use-service-worker.ts +413 -0
  501. package/registry/files/use-set.ts +154 -0
  502. package/registry/files/use-share.ts +168 -0
  503. package/registry/files/use-sorted-locale.ts +130 -0
  504. package/registry/files/use-sorted.ts +49 -0
  505. package/registry/files/use-speech-recognition.ts +357 -0
  506. package/registry/files/use-speech-synthesis.ts +333 -0
  507. package/registry/files/use-stack.ts +164 -0
  508. package/registry/files/use-stepper.ts +166 -0
  509. package/registry/files/use-storage-estimate.ts +352 -0
  510. package/registry/files/use-storage.ts +635 -0
  511. package/registry/files/use-style-tag.ts +200 -0
  512. package/registry/files/use-supported.ts +26 -0
  513. package/registry/files/use-throttled.ts +215 -0
  514. package/registry/files/use-time-ago.ts +276 -0
  515. package/registry/files/use-timeout.ts +218 -0
  516. package/registry/files/use-toggle.ts +54 -0
  517. package/registry/files/use-url-hash.ts +280 -0
  518. package/registry/files/use-url-search-params.ts +497 -0
  519. package/registry/files/use-usb.ts +395 -0
  520. package/registry/files/use-user-activation.ts +215 -0
  521. package/registry/files/use-user-media.ts +422 -0
  522. package/registry/files/use-v-model.ts +210 -0
  523. package/registry/files/use-vibrate.ts +174 -0
  524. package/registry/files/use-view-transition.ts +229 -0
  525. package/registry/files/use-visual-viewport.ts +228 -0
  526. package/registry/files/use-wake-lock.ts +206 -0
  527. package/registry/files/use-web-authn.ts +793 -0
  528. package/registry/files/use-web-locks.ts +363 -0
  529. package/registry/files/use-web-midi.ts +306 -0
  530. package/registry/files/use-web-vitals.ts +409 -0
  531. package/registry/files/use-websocket.ts +553 -0
  532. package/registry/files/use-worker-fn.ts +306 -0
  533. package/registry/files/virtual-list.ts +230 -0
  534. package/registry/files/watch-debounced.ts +206 -0
  535. package/registry/files/watch-ignorable.ts +128 -0
  536. package/registry/files/watch-once.ts +46 -0
  537. package/registry/files/watch-pausable.ts +93 -0
  538. package/registry/files/watch-source.ts +51 -0
  539. package/registry/files/watch-throttled.ts +201 -0
  540. package/registry/files/whenever.ts +70 -0
  541. package/registry/files/window-size.ts +151 -0
  542. package/registry/registry.json +5792 -0
  543. package/dist/catalog-D2AL3xYl.d.mts +0 -523
  544. package/dist/catalog-D5SYCsgW.mjs +0 -549
@@ -0,0 +1,980 @@
1
+ import { computed, ref, shallowRef, toRaw, triggerRef } from "vue";
2
+ import type { ComputedRef, Ref, ShallowRef, WritableComputedRef } from "vue";
3
+
4
+ import { tryOnScopeDispose } from "./scope.ts";
5
+ import { validateStandardSchema } from "./standard-schema.ts";
6
+ import type { NormalizedSchemaIssue, StandardSchemaV1 } from "./standard-schema.ts";
7
+
8
+ /** Values treated as leaves: paths never descend into them. */
9
+ export type FormLeaf =
10
+ | string
11
+ | number
12
+ | bigint
13
+ | boolean
14
+ | symbol
15
+ | null
16
+ | undefined
17
+ | Date
18
+ | RegExp
19
+ | Blob
20
+ | Map<unknown, unknown>
21
+ | Set<unknown>
22
+ | ((...arguments_: never[]) => unknown);
23
+
24
+ type Decrement = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8];
25
+
26
+ /**
27
+ * Every dotted path into `Values`, as template-literal keys.
28
+ *
29
+ * Objects contribute their string keys, arrays and tuples contribute
30
+ * `${number}` segments, and {@link FormLeaf} values end a path. Recursion
31
+ * is bounded at eight levels to keep type checking fast.
32
+ */
33
+ export type FormPath<Values, Depth extends number = 8> = [Depth] extends [never]
34
+ ? never
35
+ : Values extends FormLeaf
36
+ ? never
37
+ : Values extends readonly (infer Item)[]
38
+ ? `${number}` | `${number}.${FormPath<Item, Decrement[Depth]>}`
39
+ : {
40
+ [Key in keyof Values & string]:
41
+ | Key
42
+ | (FormPath<Values[Key], Decrement[Depth]> extends infer Rest extends string
43
+ ? [Rest] extends [never]
44
+ ? never
45
+ : `${Key}.${Rest}`
46
+ : never);
47
+ }[keyof Values & string];
48
+
49
+ /** Value type found at `Path` inside `Values`. */
50
+ export type FormPathValue<Values, Path extends string> = Path extends `${infer Head}.${infer Rest}`
51
+ ? Values extends readonly (infer Item)[]
52
+ ? Head extends `${number}`
53
+ ? FormPathValue<Item, Rest>
54
+ : never
55
+ : Head extends keyof Values
56
+ ? FormPathValue<Values[Head], Rest>
57
+ : never
58
+ : Values extends readonly (infer Item)[]
59
+ ? Path extends `${number}`
60
+ ? Item
61
+ : never
62
+ : Path extends keyof Values
63
+ ? Values[Path]
64
+ : never;
65
+
66
+ /** Paths whose value is an array (usable with {@link FormControls.fieldArray}). */
67
+ export type FormArrayPath<Values> = {
68
+ [Path in FormPath<Values>]: FormPathValue<Values, Path> extends readonly unknown[] ? Path : never;
69
+ }[FormPath<Values>];
70
+
71
+ /** Item type of the array at `Path`. */
72
+ export type FormArrayItem<Values, Path extends string> =
73
+ FormPathValue<Values, Path> extends readonly (infer Item)[] ? Item : never;
74
+
75
+ /**
76
+ * Error messages keyed by dotted path; `""` holds form-level errors.
77
+ *
78
+ * Known paths are typed for autocompletion; the string index signature
79
+ * stays because schemas and servers may report paths that are not fields.
80
+ */
81
+ export type FormErrors<Values> = {
82
+ readonly [Path in FormPath<Values> | ""]?: readonly string[];
83
+ } & { readonly [path: string]: readonly string[] | undefined };
84
+
85
+ /** Current errors as recorded: messages keyed by dotted path (`""` = form level). */
86
+ export type FormErrorRecord = Readonly<Record<string, readonly string[]>>;
87
+
88
+ /** Result of a validator: messages, one message, or nothing when valid. */
89
+ export type ValidatorResult = string | readonly string[] | null | undefined | void;
90
+
91
+ /** Context passed to field validators. */
92
+ export interface FieldValidatorContext<Values> {
93
+ /** Current form values (`undefined` for standalone fields). */
94
+ readonly values: Values;
95
+
96
+ /** Dotted path of the validated field. */
97
+ readonly path: string;
98
+
99
+ /** Aborted when a newer validation supersedes this one. */
100
+ readonly signal: AbortSignal;
101
+ }
102
+
103
+ /** Plain validator for one field value. */
104
+ export type FieldValidator<Value, Values = undefined> = (
105
+ value: Value,
106
+ context: FieldValidatorContext<Values>,
107
+ ) => ValidatorResult | Promise<ValidatorResult>;
108
+
109
+ /** Plain validator for the whole form, returning errors keyed by path. */
110
+ export type FormValidator<Values> = (
111
+ values: Values,
112
+ context: { readonly signal: AbortSignal },
113
+ ) => FormErrors<Values> | undefined | void | Promise<FormErrors<Values> | undefined | void>;
114
+
115
+ /** Per-field validators keyed by path. */
116
+ export type FormFieldValidators<Values> = {
117
+ readonly [Path in FormPath<Values>]?: FieldValidator<FormPathValue<Values, Path>, Values>;
118
+ };
119
+
120
+ /** When validation runs automatically. */
121
+ export type FormValidationTrigger = "change" | "blur" | "submit";
122
+
123
+ /** Discriminated outcome of {@link FormControls.validate} and submission. */
124
+ export type FormResult<Output> =
125
+ | {
126
+ /** Every validator passed. */
127
+ readonly status: "valid";
128
+ /** Schema output, or the values when no schema is configured. */
129
+ readonly value: Output;
130
+ }
131
+ | {
132
+ /** At least one validator failed. */
133
+ readonly status: "invalid";
134
+ /** Errors keyed by path. */
135
+ readonly errors: FormErrorRecord;
136
+ }
137
+ | {
138
+ /** A newer validation started before this one finished. */
139
+ readonly status: "superseded";
140
+ };
141
+
142
+ /** Options for {@link useForm}. */
143
+ export interface UseFormOptions<Values extends object, Output> {
144
+ /** Initial values, or a factory producing fresh initial values. */
145
+ readonly initialValues: Values | (() => Values);
146
+
147
+ /**
148
+ * Standard Schema v1 validator for the whole form. Its output becomes the
149
+ * submitted value.
150
+ *
151
+ * @default undefined
152
+ */
153
+ readonly schema?: StandardSchemaV1<NoInfer<Values>, Output>;
154
+
155
+ /**
156
+ * Plain whole-form validator.
157
+ *
158
+ * @default undefined
159
+ */
160
+ readonly validate?: NoInfer<FormValidator<Values>>;
161
+
162
+ /**
163
+ * Plain per-field validators keyed by path.
164
+ *
165
+ * @default {}
166
+ */
167
+ readonly validators?: NoInfer<FormFieldValidators<Values>>;
168
+
169
+ /**
170
+ * When fields validate before the first submit.
171
+ *
172
+ * @default "submit"
173
+ */
174
+ readonly validateOn?: FormValidationTrigger;
175
+
176
+ /**
177
+ * When fields re-validate after the first submit.
178
+ *
179
+ * @default "change"
180
+ */
181
+ readonly revalidateOn?: FormValidationTrigger;
182
+
183
+ /**
184
+ * Default submit handler for {@link FormControls.submit}.
185
+ *
186
+ * @default undefined
187
+ */
188
+ readonly onSubmit?: (value: Output, context: { readonly signal: AbortSignal }) => unknown;
189
+ }
190
+
191
+ /** Options for {@link FormControls.setValue}. */
192
+ export interface SetFieldValueOptions {
193
+ /**
194
+ * Mark the field touched.
195
+ *
196
+ * @default false
197
+ */
198
+ readonly touch?: boolean;
199
+
200
+ /**
201
+ * Validate the field after setting it.
202
+ *
203
+ * @default true while the active trigger is "change"
204
+ */
205
+ readonly validate?: boolean;
206
+ }
207
+
208
+ /** Reactive controls for one field, returned by {@link FormControls.field}. */
209
+ export interface FormFieldControls<Value, Path extends string = string> {
210
+ /** Dotted path of the field (also a suitable `name` attribute). */
211
+ readonly path: Path;
212
+
213
+ /** Writable value bound to the form state (use with `v-model`). */
214
+ readonly value: WritableComputedRef<Value>;
215
+
216
+ /** Current error messages. */
217
+ readonly errors: ComputedRef<readonly string[]>;
218
+
219
+ /** First error message. */
220
+ readonly error: ComputedRef<string | undefined>;
221
+
222
+ /** Whether the value differs from its initial value. */
223
+ readonly dirty: ComputedRef<boolean>;
224
+
225
+ /** Whether the field was blurred or touched programmatically. */
226
+ readonly touched: ComputedRef<boolean>;
227
+
228
+ /** Whether a validation of this field is pending. */
229
+ readonly validating: ComputedRef<boolean>;
230
+
231
+ /** Mark the field touched (wire to `blur`); validates when configured. */
232
+ readonly onBlur: () => void;
233
+
234
+ /**
235
+ * Validate this field.
236
+ *
237
+ * @returns Whether the field is valid (`false` also when superseded).
238
+ */
239
+ readonly validate: () => Promise<boolean>;
240
+
241
+ /** Restore the initial value and clear errors and touched state. */
242
+ readonly reset: () => void;
243
+ }
244
+
245
+ /** One entry of a field array, with a stable key for `v-for`. */
246
+ export interface FormArrayEntry<Item, Path extends string = string> {
247
+ /** Stable key that follows the item through moves. */
248
+ readonly key: number;
249
+
250
+ /** Current index. */
251
+ readonly index: number;
252
+
253
+ /** Dotted path of the item, e.g. `items.2`. */
254
+ readonly path: `${Path}.${number}`;
255
+
256
+ /** Current item value. */
257
+ readonly value: Item;
258
+ }
259
+
260
+ /** Typed operations on an array field, returned by {@link FormControls.fieldArray}. */
261
+ export interface FormFieldArrayControls<Item, Path extends string = string> {
262
+ /** Entries with stable keys. */
263
+ readonly entries: ComputedRef<readonly FormArrayEntry<Item, Path>[]>;
264
+
265
+ /** Append items. */
266
+ readonly append: (...items: Item[]) => void;
267
+
268
+ /** Prepend items. */
269
+ readonly prepend: (...items: Item[]) => void;
270
+
271
+ /** Insert an item at `index`. */
272
+ readonly insert: (index: number, item: Item) => void;
273
+
274
+ /** Remove the item at `index`, shifting errors and touched state. */
275
+ readonly remove: (index: number) => void;
276
+
277
+ /** Move an item from one index to another, carrying its state along. */
278
+ readonly move: (from: number, to: number) => void;
279
+
280
+ /** Swap two items. */
281
+ readonly swap: (first: number, second: number) => void;
282
+
283
+ /** Replace all items and reset their state. */
284
+ readonly replace: (items: readonly Item[]) => void;
285
+ }
286
+
287
+ /** Reactive state and actions returned by {@link useForm}. */
288
+ export interface FormControls<Values extends object, Output> {
289
+ /** Current values. Mutations are tracked (dirty state derives from them). */
290
+ readonly values: Ref<Values>;
291
+
292
+ /** Current errors keyed by path; `""` holds form-level errors. */
293
+ readonly errors: Readonly<ShallowRef<FormErrorRecord>>;
294
+
295
+ /** Whether no errors are currently recorded. */
296
+ readonly valid: ComputedRef<boolean>;
297
+
298
+ /** Whether any value differs from its initial value. */
299
+ readonly dirty: ComputedRef<boolean>;
300
+
301
+ /** Whether any validation is pending. */
302
+ readonly validating: ComputedRef<boolean>;
303
+
304
+ /** Whether a submission is in progress. */
305
+ readonly submitting: Readonly<Ref<boolean>>;
306
+
307
+ /** Number of submit attempts. */
308
+ readonly submitCount: Readonly<Ref<number>>;
309
+
310
+ /**
311
+ * Typed controls for one field.
312
+ *
313
+ * @param path Dotted path.
314
+ * @returns Field controls whose value type follows the path.
315
+ */
316
+ readonly field: <Path extends FormPath<Values>>(
317
+ path: Path,
318
+ ) => FormFieldControls<FormPathValue<Values, Path>, Path>;
319
+
320
+ /**
321
+ * Typed operations for an array field.
322
+ *
323
+ * @param path Dotted path of an array.
324
+ * @returns Field array controls.
325
+ */
326
+ readonly fieldArray: <Path extends FormArrayPath<Values>>(
327
+ path: Path,
328
+ ) => FormFieldArrayControls<FormArrayItem<Values, Path>, Path>;
329
+
330
+ /**
331
+ * Read the value at a path.
332
+ *
333
+ * @param path Dotted path.
334
+ * @returns The value.
335
+ */
336
+ readonly getValue: <Path extends FormPath<Values>>(path: Path) => FormPathValue<Values, Path>;
337
+
338
+ /**
339
+ * Write the value at a path.
340
+ *
341
+ * @param path Dotted path.
342
+ * @param value New value.
343
+ * @param options Touch and validation behavior.
344
+ */
345
+ readonly setValue: <Path extends FormPath<Values>>(
346
+ path: Path,
347
+ value: FormPathValue<Values, Path>,
348
+ options?: SetFieldValueOptions,
349
+ ) => void;
350
+
351
+ /**
352
+ * Replace (or shallowly merge) the values without touching initial values.
353
+ *
354
+ * @param values New values.
355
+ * @param options `merge: true` shallowly merges top-level keys.
356
+ */
357
+ readonly setValues: (values: Partial<Values>, options?: { readonly merge?: boolean }) => void;
358
+
359
+ /**
360
+ * Whether a field was touched.
361
+ *
362
+ * @param path Dotted path.
363
+ * @returns Touched state.
364
+ */
365
+ readonly isTouched: (path: FormPath<Values>) => boolean;
366
+
367
+ /**
368
+ * Replace errors (for example with server-side errors).
369
+ *
370
+ * @param errors Errors keyed by path.
371
+ */
372
+ readonly setErrors: (errors: FormErrors<Values>) => void;
373
+
374
+ /**
375
+ * Clear errors of one path, or all errors.
376
+ *
377
+ * @param path Dotted path; omit to clear everything.
378
+ */
379
+ readonly clearErrors: (path?: FormPath<Values> | "") => void;
380
+
381
+ /**
382
+ * Run every validator, aborting any older validation still in flight.
383
+ *
384
+ * @returns The discriminated result; never rejects on validation failure.
385
+ */
386
+ readonly validate: () => Promise<FormResult<Output>>;
387
+
388
+ /**
389
+ * Validate and, when valid, call `handler` (or the `onSubmit` option).
390
+ * A newer submit aborts an older one's pending validation.
391
+ *
392
+ * @param handler Submit handler overriding `onSubmit`.
393
+ * @returns The validation result.
394
+ */
395
+ readonly submit: (
396
+ handler?: (value: Output, context: { readonly signal: AbortSignal }) => unknown,
397
+ ) => Promise<FormResult<Output>>;
398
+
399
+ /**
400
+ * Create a `submit` event listener that prevents the native submission.
401
+ *
402
+ * @param handler Submit handler overriding `onSubmit`.
403
+ * @returns Event listener for `<form @submit>`.
404
+ */
405
+ readonly handleSubmit: (
406
+ handler?: (value: Output, context: { readonly signal: AbortSignal }) => unknown,
407
+ ) => (event?: Event) => Promise<FormResult<Output>>;
408
+
409
+ /**
410
+ * Restore initial values (or install new ones) and clear all state.
411
+ *
412
+ * @param values New initial values.
413
+ */
414
+ readonly reset: (values?: Values) => void;
415
+ }
416
+
417
+ type Container = Record<string, unknown> | unknown[];
418
+
419
+ function isContainer(value: unknown): value is Container {
420
+ if (Array.isArray(value)) return true;
421
+ if (typeof value !== "object" || value === null) return false;
422
+ const prototype: unknown = Object.getPrototypeOf(value);
423
+ return prototype === Object.prototype || prototype === null;
424
+ }
425
+
426
+ function splitPath(path: string): readonly string[] {
427
+ return path === "" ? [] : path.split(".");
428
+ }
429
+
430
+ function readChild(container: Container, key: string): unknown {
431
+ return Array.isArray(container) ? container[Number(key)] : container[key];
432
+ }
433
+
434
+ function writeChild(container: Container, key: string, value: unknown): void {
435
+ if (Array.isArray(container)) container[Number(key)] = value;
436
+ else container[key] = value;
437
+ }
438
+
439
+ /** Read a dotted path. */
440
+ function readPath(root: unknown, path: string): unknown {
441
+ let current = root;
442
+ for (const key of splitPath(path)) {
443
+ if (!isContainer(current)) return undefined;
444
+ current = readChild(current, key);
445
+ }
446
+ return current;
447
+ }
448
+
449
+ /** Write a dotted path, creating intermediate containers. */
450
+ function writePath(root: unknown, path: string, value: unknown): void {
451
+ const keys = splitPath(path);
452
+ const last = keys.at(-1);
453
+ if (last === undefined || !isContainer(root)) return;
454
+ let current: Container = root;
455
+ for (let index = 0; index < keys.length - 1; index += 1) {
456
+ const key = keys[index] ?? "";
457
+ let next = readChild(current, key);
458
+ if (!isContainer(next)) {
459
+ next = /^\d+$/.test(keys[index + 1] ?? "") ? [] : {};
460
+ writeChild(current, key, next);
461
+ }
462
+ if (!isContainer(next)) return;
463
+ current = next;
464
+ }
465
+ writeChild(current, last, value);
466
+ }
467
+
468
+ function cloneValue<Value>(value: Value): Value {
469
+ return structuredClone(toRaw(value));
470
+ }
471
+
472
+ function deepEqual(left: unknown, right: unknown): boolean {
473
+ if (Object.is(left, right)) return true;
474
+ if (left instanceof Date && right instanceof Date) return left.getTime() === right.getTime();
475
+ if (Array.isArray(left) && Array.isArray(right)) {
476
+ return (
477
+ left.length === right.length && left.every((item, index) => deepEqual(item, right[index]))
478
+ );
479
+ }
480
+ if (isContainer(left) && isContainer(right) && !Array.isArray(left) && !Array.isArray(right)) {
481
+ const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
482
+ for (const key of keys) if (!deepEqual(left[key], right[key])) return false;
483
+ return true;
484
+ }
485
+ return false;
486
+ }
487
+
488
+ function toMessages(result: ValidatorResult): readonly string[] {
489
+ if (result === undefined || result === null || result === "") return [];
490
+ return typeof result === "string" ? [result] : result.filter((message) => message !== "");
491
+ }
492
+
493
+ function unknownMessages(result: unknown): readonly string[] {
494
+ if (typeof result === "string") return result === "" ? [] : [result];
495
+ if (!Array.isArray(result)) return [];
496
+ return result.filter(
497
+ (message): message is string => typeof message === "string" && message !== "",
498
+ );
499
+ }
500
+
501
+ /** Rewrite `${arrayPath}.${index}…` keys through an index mapping (undefined drops). */
502
+ function remapKeys<Entry>(
503
+ entries: Iterable<[string, Entry]>,
504
+ arrayPath: string,
505
+ mapIndex: (index: number) => number | undefined,
506
+ ): [string, Entry][] {
507
+ const prefix = `${arrayPath}.`;
508
+ const result: [string, Entry][] = [];
509
+ for (const [key, entry] of entries) {
510
+ if (!key.startsWith(prefix)) {
511
+ result.push([key, entry]);
512
+ continue;
513
+ }
514
+ const rest = key.slice(prefix.length);
515
+ const dot = rest.indexOf(".");
516
+ const indexText = dot === -1 ? rest : rest.slice(0, dot);
517
+ const mapped = /^\d+$/.test(indexText) ? mapIndex(Number(indexText)) : Number.NaN;
518
+ if (mapped === undefined) continue;
519
+ if (Number.isNaN(mapped)) {
520
+ result.push([key, entry]);
521
+ continue;
522
+ }
523
+ result.push([`${prefix}${String(mapped)}${dot === -1 ? "" : rest.slice(dot)}`, entry]);
524
+ }
525
+ return result;
526
+ }
527
+
528
+ /**
529
+ * Fully typed form state with validation, field arrays, and submission.
530
+ *
531
+ * The value type is inferred from `initialValues`; every path is a
532
+ * template-literal key, so `field("address.city")` returns controls whose
533
+ * `value` is typed as the city's type and misspelled paths do not compile.
534
+ * Validation combines a Standard Schema v1 validator (Zod, Valibot, ArkType,
535
+ * … via the `~standard` protocol), a whole-form validator, and per-field
536
+ * validators; all may be asynchronous. A newer validation aborts older ones
537
+ * through their `signal` and their results are discarded, so a slow check
538
+ * can never overwrite fresher errors.
539
+ *
540
+ * This composable owns the *values*. `@vizejs/ui/form` owns accessible
541
+ * error presentation (error summaries, focus management, native constraint
542
+ * validation); feed {@link FormControls.errors} into it to render them.
543
+ *
544
+ * Server rendering: pure state, no host access; validation never runs
545
+ * automatically during setup, so server and client render the same markup.
546
+ * Pending validations are aborted when the owning scope stops.
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * const form = useForm({
551
+ * initialValues: { name: "", address: { city: "" }, tags: [] as string[] },
552
+ * validators: { name: (name) => (name ? undefined : "Required") },
553
+ * onSubmit: (values) => api.save(values),
554
+ * });
555
+ * const city = form.field("address.city"); // city.value: Ref<string>
556
+ * const tags = form.fieldArray("tags");
557
+ * tags.append("vue");
558
+ * ```
559
+ *
560
+ * @typeParam Values Form values, inferred from `initialValues`.
561
+ * @typeParam Output Submitted value, inferred from `schema` (defaults to `Values`).
562
+ * @param options Initial values, validators, triggers, and submit handler.
563
+ * @returns Form state and actions.
564
+ */
565
+ export function useForm<Values extends object, Output = Values>(
566
+ options: UseFormOptions<Values, Output>,
567
+ ): FormControls<Values, Output> {
568
+ const createInitial = (): Values =>
569
+ typeof options.initialValues === "function"
570
+ ? options.initialValues()
571
+ : cloneValue(options.initialValues);
572
+ let initial = createInitial();
573
+ // Form values are plain data, for which `UnwrapRef<Values>` equals `Values`;
574
+ // a deep `ref` keeps nested edits (including `v-model` on nested paths) reactive.
575
+ const values = ref(cloneValue(initial)) as Ref<Values>;
576
+ const errors = shallowRef<Record<string, readonly string[]>>({});
577
+ const touched = shallowRef(new Set<string>());
578
+ const pending = ref(new Map<string, number>());
579
+ const submitting = ref(false);
580
+ const submitCount = ref(0);
581
+ const arrayKeys = new Map<string, number[]>();
582
+ let nextKey = 0;
583
+ let formController: AbortController | undefined;
584
+ const fieldControllers = new Map<string, AbortController>();
585
+ const validators: readonly (readonly [string, unknown])[] = Object.entries(
586
+ options.validators ?? {},
587
+ );
588
+ const runValidator = (
589
+ validator: unknown,
590
+ path: string,
591
+ snapshot: Values,
592
+ signal: AbortSignal,
593
+ ): Promise<readonly string[]> => {
594
+ if (typeof validator !== "function") return Promise.resolve([]);
595
+ const outcome: unknown = Reflect.apply(validator, undefined, [
596
+ readPath(snapshot, path),
597
+ { values: snapshot, path, signal },
598
+ ]);
599
+ return Promise.resolve(outcome).then(unknownMessages);
600
+ };
601
+
602
+ const trigger = (): FormValidationTrigger =>
603
+ submitCount.value > 0 ? (options.revalidateOn ?? "change") : (options.validateOn ?? "submit");
604
+
605
+ const beginPending = (path: string): void => {
606
+ pending.value.set(path, (pending.value.get(path) ?? 0) + 1);
607
+ };
608
+ const endPending = (path: string): void => {
609
+ const count = (pending.value.get(path) ?? 1) - 1;
610
+ if (count <= 0) pending.value.delete(path);
611
+ else pending.value.set(path, count);
612
+ };
613
+
614
+ const setErrorsFor = (path: string, messages: readonly string[]): void => {
615
+ const next = { ...errors.value };
616
+ if (messages.length === 0) Reflect.deleteProperty(next, path);
617
+ else next[path] = messages;
618
+ errors.value = next;
619
+ };
620
+
621
+ const readFieldValidator = (path: string): unknown =>
622
+ validators.find(([candidate]) => candidate === path)?.[1];
623
+
624
+ /** Collect every error source; resolves to errors keyed by path. */
625
+ const collectErrors = async (
626
+ signal: AbortSignal,
627
+ ): Promise<{ readonly errors: Record<string, string[]>; readonly output: unknown }> => {
628
+ const snapshot = values.value;
629
+ const collected: Record<string, string[]> = {};
630
+ const add = (path: string, messages: readonly string[]): void => {
631
+ if (messages.length === 0) return;
632
+ (collected[path] ??= []).push(...messages);
633
+ };
634
+ let output: unknown = snapshot;
635
+ const tasks: Promise<void>[] = [];
636
+ if (options.schema) {
637
+ const schema = options.schema;
638
+ tasks.push(
639
+ validateStandardSchema(schema, cloneValue(snapshot)).then((result) => {
640
+ if (result.status === "valid") output = result.value;
641
+ else for (const issue of result.issues) add(issue.path, [issue.message]);
642
+ }),
643
+ );
644
+ }
645
+ if (options.validate) {
646
+ const validate = options.validate;
647
+ tasks.push(
648
+ Promise.resolve(validate(snapshot, { signal })).then((result) => {
649
+ if (!result) return;
650
+ for (const [path, messages] of Object.entries(result)) {
651
+ if (messages !== undefined) add(path, toMessages(messages));
652
+ }
653
+ }),
654
+ );
655
+ }
656
+ for (const [path, validator] of validators) {
657
+ tasks.push(
658
+ runValidator(validator, path, snapshot, signal).then((messages) => add(path, messages)),
659
+ );
660
+ }
661
+ await Promise.all(tasks);
662
+ return { errors: collected, output };
663
+ };
664
+
665
+ const validate = async (): Promise<FormResult<Output>> => {
666
+ formController?.abort(new DOMException("A newer validation started.", "AbortError"));
667
+ for (const controller of fieldControllers.values()) controller.abort();
668
+ fieldControllers.clear();
669
+ const controller = new AbortController();
670
+ formController = controller;
671
+ beginPending("");
672
+ try {
673
+ const outcome = await collectErrors(controller.signal);
674
+ if (controller.signal.aborted) return { status: "superseded" };
675
+ errors.value = outcome.errors;
676
+ if (Object.keys(outcome.errors).length > 0) {
677
+ return { status: "invalid", errors: { ...outcome.errors } };
678
+ }
679
+ // Without a schema the output is the values themselves (`Output`
680
+ // defaults to `Values`); with a schema it is the schema's parsed output.
681
+ return { status: "valid", value: outcome.output as Output };
682
+ } finally {
683
+ endPending("");
684
+ if (formController === controller) formController = undefined;
685
+ }
686
+ };
687
+
688
+ const schemaIssuesFor = async (path: string): Promise<readonly string[]> => {
689
+ if (!options.schema) return [];
690
+ const result = await validateStandardSchema(options.schema, cloneValue(values.value));
691
+ if (result.status === "valid") return [];
692
+ return result.issues
693
+ .filter((issue: NormalizedSchemaIssue) => issue.path === path)
694
+ .map((issue) => issue.message);
695
+ };
696
+
697
+ const validateField = async (path: string): Promise<boolean> => {
698
+ fieldControllers.get(path)?.abort();
699
+ const controller = new AbortController();
700
+ fieldControllers.set(path, controller);
701
+ beginPending(path);
702
+ try {
703
+ const validator = readFieldValidator(path);
704
+ const snapshot = values.value;
705
+ const [own, fromSchema, fromForm] = await Promise.all([
706
+ runValidator(validator, path, snapshot, controller.signal),
707
+ schemaIssuesFor(path),
708
+ options.validate
709
+ ? Promise.resolve(options.validate(snapshot, { signal: controller.signal })).then(
710
+ (result) => {
711
+ const messages: unknown = result ? Reflect.get(result, path) : undefined;
712
+ return Array.isArray(messages)
713
+ ? messages.filter((message): message is string => typeof message === "string")
714
+ : [];
715
+ },
716
+ )
717
+ : Promise.resolve([]),
718
+ ]);
719
+ if (controller.signal.aborted) return false;
720
+ const messages = [...fromSchema, ...fromForm, ...own];
721
+ setErrorsFor(path, messages);
722
+ return messages.length === 0;
723
+ } finally {
724
+ endPending(path);
725
+ if (fieldControllers.get(path) === controller) fieldControllers.delete(path);
726
+ }
727
+ };
728
+
729
+ const touch = (path: string): void => {
730
+ if (touched.value.has(path)) return;
731
+ const next = new Set(touched.value);
732
+ next.add(path);
733
+ touched.value = next;
734
+ };
735
+
736
+ const setValueAt = (path: string, value: unknown, setOptions: SetFieldValueOptions = {}) => {
737
+ writePath(values.value, path, value);
738
+ if (setOptions.touch) touch(path);
739
+ if (setOptions.validate ?? trigger() === "change") void validateField(path);
740
+ };
741
+
742
+ const syncKeys = (path: string, length: number): number[] => {
743
+ let keys = arrayKeys.get(path);
744
+ if (!keys) {
745
+ keys = [];
746
+ arrayKeys.set(path, keys);
747
+ }
748
+ while (keys.length < length) keys.push(nextKey++);
749
+ if (keys.length > length) keys.length = length;
750
+ return keys;
751
+ };
752
+
753
+ const readArray = (path: string): unknown[] => {
754
+ const current = readPath(values.value, path);
755
+ if (Array.isArray(current)) return current;
756
+ const created: unknown[] = [];
757
+ writePath(values.value, path, created);
758
+ return created;
759
+ };
760
+
761
+ const remapState = (path: string, mapIndex: (index: number) => number | undefined): void => {
762
+ errors.value = Object.fromEntries(remapKeys(Object.entries(errors.value), path, mapIndex));
763
+ touched.value = new Set(
764
+ remapKeys(
765
+ [...touched.value].map((key): [string, true] => [key, true]),
766
+ path,
767
+ mapIndex,
768
+ ).map(([key]) => key),
769
+ );
770
+ };
771
+
772
+ const keysVersion = shallowRef(0);
773
+ const bumpKeys = (): void => {
774
+ keysVersion.value += 1;
775
+ triggerRef(keysVersion);
776
+ };
777
+
778
+ const field = <Path extends FormPath<Values>>(
779
+ path: Path,
780
+ ): FormFieldControls<FormPathValue<Values, Path>, Path> => {
781
+ const key: string = path;
782
+ // `readPath` walks the same dotted path the type-level `FormPathValue`
783
+ // resolves, so the runtime value has the declared type.
784
+ const read = (): FormPathValue<Values, Path> =>
785
+ readPath(values.value, key) as FormPathValue<Values, Path>;
786
+ return {
787
+ path,
788
+ value: computed({
789
+ get: read,
790
+ set: (next) => setValueAt(key, next),
791
+ }),
792
+ errors: computed(() => errors.value[key] ?? []),
793
+ error: computed(() => errors.value[key]?.[0]),
794
+ dirty: computed(() => !deepEqual(readPath(values.value, key), readPath(initial, key))),
795
+ touched: computed(() => touched.value.has(key)),
796
+ validating: computed(() => pending.value.has(key) || pending.value.has("")),
797
+ onBlur: () => {
798
+ touch(key);
799
+ if (trigger() === "blur") void validateField(key);
800
+ },
801
+ validate: () => validateField(key),
802
+ reset: () => {
803
+ writePath(values.value, key, cloneValue(readPath(initial, key)));
804
+ setErrorsFor(key, []);
805
+ const next = new Set(touched.value);
806
+ next.delete(key);
807
+ touched.value = next;
808
+ },
809
+ };
810
+ };
811
+
812
+ const fieldArray = <Path extends FormArrayPath<Values>>(
813
+ path: Path,
814
+ ): FormFieldArrayControls<FormArrayItem<Values, Path>, Path> => {
815
+ type Item = FormArrayItem<Values, Path>;
816
+ const key: string = path;
817
+ const afterChange = (): void => {
818
+ bumpKeys();
819
+ if (trigger() === "change") void validateField(key);
820
+ };
821
+ const insertAt = (index: number, items: readonly Item[]): void => {
822
+ const array = readArray(key);
823
+ const keys = syncKeys(key, array.length);
824
+ const at = Math.max(0, Math.min(index, array.length));
825
+ remapState(key, (old) => (old >= at ? old + items.length : old));
826
+ array.splice(at, 0, ...items);
827
+ keys.splice(at, 0, ...items.map(() => nextKey++));
828
+ afterChange();
829
+ };
830
+ return {
831
+ entries: computed(() => {
832
+ void keysVersion.value;
833
+ const array = readPath(values.value, key);
834
+ if (!Array.isArray(array)) return [];
835
+ const keys = syncKeys(key, array.length);
836
+ return array.map((value: unknown, index) => ({
837
+ key: keys[index] ?? index,
838
+ index,
839
+ path: `${path}.${index}` as const,
840
+ // Items of the array at `Path` have the declared item type.
841
+ value: value as Item,
842
+ }));
843
+ }),
844
+ append: (...items) => insertAt(Number.MAX_SAFE_INTEGER, items),
845
+ prepend: (...items) => insertAt(0, items),
846
+ insert: (index, item) => insertAt(index, [item]),
847
+ remove: (index) => {
848
+ const array = readArray(key);
849
+ if (index < 0 || index >= array.length) return;
850
+ const keys = syncKeys(key, array.length);
851
+ remapState(key, (old) => (old === index ? undefined : old > index ? old - 1 : old));
852
+ array.splice(index, 1);
853
+ keys.splice(index, 1);
854
+ afterChange();
855
+ },
856
+ move: (from, to) => {
857
+ const array = readArray(key);
858
+ if (from < 0 || from >= array.length || to < 0 || to >= array.length || from === to) return;
859
+ const keys = syncKeys(key, array.length);
860
+ remapState(key, (old) => {
861
+ if (old === from) return to;
862
+ if (from < to && old > from && old <= to) return old - 1;
863
+ if (from > to && old >= to && old < from) return old + 1;
864
+ return old;
865
+ });
866
+ const [item] = array.splice(from, 1);
867
+ array.splice(to, 0, item);
868
+ const [movedKey] = keys.splice(from, 1);
869
+ keys.splice(to, 0, movedKey ?? nextKey++);
870
+ afterChange();
871
+ },
872
+ swap: (first, second) => {
873
+ const array = readArray(key);
874
+ if (first < 0 || second < 0 || first >= array.length || second >= array.length) return;
875
+ const keys = syncKeys(key, array.length);
876
+ remapState(key, (old) => (old === first ? second : old === second ? first : old));
877
+ const firstItem = array[first];
878
+ array[first] = array[second];
879
+ array[second] = firstItem;
880
+ const firstKey = keys[first] ?? nextKey++;
881
+ keys[first] = keys[second] ?? nextKey++;
882
+ keys[second] = firstKey;
883
+ afterChange();
884
+ },
885
+ replace: (items) => {
886
+ remapState(key, () => undefined);
887
+ writePath(values.value, key, [...items]);
888
+ arrayKeys.delete(key);
889
+ afterChange();
890
+ },
891
+ };
892
+ };
893
+
894
+ const clearErrors = (path?: string): void => {
895
+ if (path === undefined) errors.value = {};
896
+ else setErrorsFor(path, []);
897
+ };
898
+
899
+ const submitWith = async (
900
+ handler?: (value: Output, context: { readonly signal: AbortSignal }) => unknown,
901
+ ): Promise<FormResult<Output>> => {
902
+ submitCount.value += 1;
903
+ submitting.value = true;
904
+ try {
905
+ const result = await validate();
906
+ const signal = formController?.signal ?? new AbortController().signal;
907
+ if (result.status === "valid") {
908
+ const onSubmit = handler ?? options.onSubmit;
909
+ if (onSubmit) await onSubmit(result.value, { signal });
910
+ } else if (result.status === "invalid") {
911
+ const next = new Set(touched.value);
912
+ for (const path of Object.keys(result.errors)) if (path !== "") next.add(path);
913
+ touched.value = next;
914
+ }
915
+ return result;
916
+ } finally {
917
+ submitting.value = false;
918
+ }
919
+ };
920
+
921
+ const reset = (next?: Values): void => {
922
+ formController?.abort();
923
+ for (const controller of fieldControllers.values()) controller.abort();
924
+ fieldControllers.clear();
925
+ initial = next === undefined ? createInitial() : cloneValue(next);
926
+ values.value = cloneValue(initial);
927
+ errors.value = {};
928
+ touched.value = new Set();
929
+ pending.value.clear();
930
+ submitCount.value = 0;
931
+ arrayKeys.clear();
932
+ bumpKeys();
933
+ };
934
+
935
+ tryOnScopeDispose(() => {
936
+ formController?.abort();
937
+ for (const controller of fieldControllers.values()) controller.abort();
938
+ });
939
+
940
+ return {
941
+ values,
942
+ errors,
943
+ valid: computed(() => Object.keys(errors.value).length === 0),
944
+ dirty: computed(() => !deepEqual(values.value, initial)),
945
+ validating: computed(() => pending.value.size > 0),
946
+ submitting,
947
+ submitCount,
948
+ field,
949
+ fieldArray,
950
+ getValue: <Path extends FormPath<Values>>(path: Path) =>
951
+ // Same dotted-path walk as `FormPathValue` (see `field`).
952
+ readPath(values.value, path) as FormPathValue<Values, Path>,
953
+ setValue: (path, value, setOptions) => setValueAt(path, value, setOptions),
954
+ setValues: (next, setOptions = {}) => {
955
+ if (setOptions.merge) {
956
+ values.value = { ...values.value, ...cloneValue(next) };
957
+ } else {
958
+ values.value = { ...cloneValue(initial), ...cloneValue(next) };
959
+ }
960
+ arrayKeys.clear();
961
+ bumpKeys();
962
+ },
963
+ isTouched: (path) => touched.value.has(path),
964
+ setErrors: (next) => {
965
+ const normalized: Record<string, readonly string[]> = {};
966
+ for (const [path, messages] of Object.entries(next)) {
967
+ if (messages !== undefined && messages.length > 0) normalized[path] = messages;
968
+ }
969
+ errors.value = normalized;
970
+ },
971
+ clearErrors,
972
+ validate,
973
+ submit: submitWith,
974
+ handleSubmit: (handler) => (event) => {
975
+ event?.preventDefault();
976
+ return submitWith(handler);
977
+ },
978
+ reset,
979
+ };
980
+ }