bits-ui 1.8.0 → 2.2.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 (317) hide show
  1. package/dist/bits/accordion/accordion.svelte.d.ts +56 -53
  2. package/dist/bits/accordion/accordion.svelte.js +78 -89
  3. package/dist/bits/accordion/components/accordion-content.svelte +5 -3
  4. package/dist/bits/accordion/components/accordion-header.svelte +4 -2
  5. package/dist/bits/accordion/components/accordion-item.svelte +6 -3
  6. package/dist/bits/accordion/components/accordion-trigger.svelte +4 -2
  7. package/dist/bits/accordion/components/accordion.svelte +4 -2
  8. package/dist/bits/alert-dialog/components/alert-dialog-action.svelte +4 -2
  9. package/dist/bits/alert-dialog/components/alert-dialog-cancel.svelte +4 -2
  10. package/dist/bits/alert-dialog/components/alert-dialog-content.svelte +8 -3
  11. package/dist/bits/aspect-ratio/aspect-ratio.svelte.js +2 -2
  12. package/dist/bits/aspect-ratio/components/aspect-ratio.svelte +4 -2
  13. package/dist/bits/avatar/avatar.svelte.d.ts +2 -1
  14. package/dist/bits/avatar/avatar.svelte.js +8 -6
  15. package/dist/bits/avatar/components/avatar-fallback.svelte +4 -2
  16. package/dist/bits/avatar/components/avatar-image.svelte +4 -2
  17. package/dist/bits/avatar/components/avatar.svelte +4 -2
  18. package/dist/bits/button/components/button.svelte +1 -1
  19. package/dist/bits/calendar/calendar.svelte.d.ts +3 -9
  20. package/dist/bits/calendar/calendar.svelte.js +55 -41
  21. package/dist/bits/calendar/components/calendar-cell.svelte +4 -2
  22. package/dist/bits/calendar/components/calendar-day.svelte +4 -2
  23. package/dist/bits/calendar/components/calendar-grid-body.svelte +4 -2
  24. package/dist/bits/calendar/components/calendar-grid-head.svelte +4 -2
  25. package/dist/bits/calendar/components/calendar-grid-row.svelte +4 -2
  26. package/dist/bits/calendar/components/calendar-grid.svelte +4 -2
  27. package/dist/bits/calendar/components/calendar-head-cell.svelte +4 -2
  28. package/dist/bits/calendar/components/calendar-header.svelte +4 -2
  29. package/dist/bits/calendar/components/calendar-heading.svelte +4 -2
  30. package/dist/bits/calendar/components/calendar-next-button.svelte +4 -2
  31. package/dist/bits/calendar/components/calendar-prev-button.svelte +4 -2
  32. package/dist/bits/checkbox/checkbox.svelte.js +4 -14
  33. package/dist/bits/checkbox/components/checkbox-group-label.svelte +4 -2
  34. package/dist/bits/checkbox/components/checkbox-group.svelte +4 -2
  35. package/dist/bits/checkbox/components/checkbox.svelte +4 -2
  36. package/dist/bits/collapsible/collapsible.svelte.js +4 -10
  37. package/dist/bits/collapsible/components/collapsible-content.svelte +5 -3
  38. package/dist/bits/collapsible/components/collapsible-trigger.svelte +4 -2
  39. package/dist/bits/collapsible/components/collapsible.svelte +4 -2
  40. package/dist/bits/combobox/components/combobox-input.svelte +3 -3
  41. package/dist/bits/combobox/components/combobox.svelte +6 -1
  42. package/dist/bits/combobox/types.d.ts +18 -1
  43. package/dist/bits/command/command.svelte.js +13 -45
  44. package/dist/bits/command/components/_command-label.svelte +6 -7
  45. package/dist/bits/command/components/_command-label.svelte.d.ts +1 -1
  46. package/dist/bits/command/components/command-empty.svelte +4 -2
  47. package/dist/bits/command/components/command-group-heading.svelte +4 -2
  48. package/dist/bits/command/components/command-group-items.svelte +4 -2
  49. package/dist/bits/command/components/command-group.svelte +4 -2
  50. package/dist/bits/command/components/command-input.svelte +4 -2
  51. package/dist/bits/command/components/command-item.svelte +4 -2
  52. package/dist/bits/command/components/command-link-item.svelte +4 -2
  53. package/dist/bits/command/components/command-list.svelte +4 -2
  54. package/dist/bits/command/components/command-loading.svelte +4 -2
  55. package/dist/bits/command/components/command-separator.svelte +4 -2
  56. package/dist/bits/command/components/command-viewport.svelte +4 -2
  57. package/dist/bits/command/components/command.svelte +4 -2
  58. package/dist/bits/context-menu/components/context-menu-content-static.svelte +2 -3
  59. package/dist/bits/context-menu/components/context-menu-content.svelte +2 -3
  60. package/dist/bits/context-menu/components/context-menu-trigger.svelte +1 -1
  61. package/dist/bits/date-field/components/date-field-input.svelte +4 -2
  62. package/dist/bits/date-field/components/date-field-label.svelte +4 -2
  63. package/dist/bits/date-field/components/date-field-segment.svelte +4 -2
  64. package/dist/bits/date-field/date-field.svelte.d.ts +7 -5
  65. package/dist/bits/date-field/date-field.svelte.js +29 -38
  66. package/dist/bits/date-picker/components/date-picker-calendar.svelte +4 -2
  67. package/dist/bits/date-range-field/components/date-range-field-input.svelte +4 -2
  68. package/dist/bits/date-range-field/components/date-range-field-label.svelte +4 -2
  69. package/dist/bits/date-range-field/components/date-range-field.svelte +4 -2
  70. package/dist/bits/date-range-field/date-range-field.svelte.d.ts +2 -0
  71. package/dist/bits/date-range-field/date-range-field.svelte.js +6 -14
  72. package/dist/bits/date-range-picker/components/date-range-picker-calendar.svelte +4 -2
  73. package/dist/bits/dialog/components/dialog-close.svelte +4 -2
  74. package/dist/bits/dialog/components/dialog-content.svelte +8 -2
  75. package/dist/bits/dialog/components/dialog-description.svelte +4 -2
  76. package/dist/bits/dialog/components/dialog-overlay.svelte +8 -3
  77. package/dist/bits/dialog/components/dialog-title.svelte +4 -2
  78. package/dist/bits/dialog/components/dialog-trigger.svelte +4 -2
  79. package/dist/bits/dialog/dialog.svelte.d.ts +1 -1
  80. package/dist/bits/dialog/dialog.svelte.js +19 -47
  81. package/dist/bits/dropdown-menu/components/dropdown-menu-content-static.svelte +6 -5
  82. package/dist/bits/dropdown-menu/components/dropdown-menu-content.svelte +6 -5
  83. package/dist/bits/index.d.ts +2 -0
  84. package/dist/bits/index.js +2 -0
  85. package/dist/bits/label/components/label.svelte +4 -2
  86. package/dist/bits/label/label.svelte.js +2 -2
  87. package/dist/bits/link-preview/components/link-preview-content-static.svelte +6 -2
  88. package/dist/bits/link-preview/components/link-preview-content.svelte +6 -2
  89. package/dist/bits/link-preview/components/link-preview-trigger.svelte +5 -3
  90. package/dist/bits/link-preview/link-preview.svelte.d.ts +2 -0
  91. package/dist/bits/link-preview/link-preview.svelte.js +13 -19
  92. package/dist/bits/menu/components/menu-checkbox-group.svelte +4 -2
  93. package/dist/bits/menu/components/menu-checkbox-item.svelte +6 -4
  94. package/dist/bits/menu/components/menu-content-static.svelte +6 -5
  95. package/dist/bits/menu/components/menu-content.svelte +6 -5
  96. package/dist/bits/menu/components/menu-group-heading.svelte +4 -2
  97. package/dist/bits/menu/components/menu-group.svelte +4 -2
  98. package/dist/bits/menu/components/menu-item.svelte +4 -2
  99. package/dist/bits/menu/components/menu-radio-group.svelte +4 -2
  100. package/dist/bits/menu/components/menu-radio-item.svelte +4 -2
  101. package/dist/bits/menu/components/menu-separator.svelte +4 -2
  102. package/dist/bits/menu/components/menu-sub-content-static.svelte +6 -5
  103. package/dist/bits/menu/components/menu-sub-content.svelte +6 -5
  104. package/dist/bits/menu/components/menu-sub-trigger.svelte +6 -3
  105. package/dist/bits/menu/components/menu-trigger.svelte +5 -3
  106. package/dist/bits/menu/menu.svelte.d.ts +9 -20
  107. package/dist/bits/menu/menu.svelte.js +40 -63
  108. package/dist/bits/menubar/components/menubar-content-static.svelte +4 -2
  109. package/dist/bits/menubar/components/menubar-content.svelte +4 -2
  110. package/dist/bits/menubar/components/menubar-menu.svelte +4 -2
  111. package/dist/bits/menubar/components/menubar-trigger.svelte +14 -6
  112. package/dist/bits/menubar/components/menubar.svelte +4 -2
  113. package/dist/bits/menubar/menubar.svelte.d.ts +24 -20
  114. package/dist/bits/menubar/menubar.svelte.js +40 -56
  115. package/dist/bits/meter/components/meter.svelte +4 -2
  116. package/dist/bits/meter/meter.svelte.js +2 -2
  117. package/dist/bits/navigation-menu/components/navigation-menu-content-impl.svelte +5 -2
  118. package/dist/bits/navigation-menu/components/navigation-menu-content.svelte +8 -3
  119. package/dist/bits/navigation-menu/components/navigation-menu-indicator-impl.svelte +4 -2
  120. package/dist/bits/navigation-menu/components/navigation-menu-indicator.svelte +6 -4
  121. package/dist/bits/navigation-menu/components/navigation-menu-item.svelte +6 -3
  122. package/dist/bits/navigation-menu/components/navigation-menu-link.svelte +4 -2
  123. package/dist/bits/navigation-menu/components/navigation-menu-list.svelte +4 -2
  124. package/dist/bits/navigation-menu/components/navigation-menu-sub.svelte +4 -2
  125. package/dist/bits/navigation-menu/components/navigation-menu-trigger.svelte +4 -2
  126. package/dist/bits/navigation-menu/components/navigation-menu-viewport.svelte +5 -3
  127. package/dist/bits/navigation-menu/components/navigation-menu.svelte +4 -2
  128. package/dist/bits/navigation-menu/navigation-menu.svelte.d.ts +3 -1
  129. package/dist/bits/navigation-menu/navigation-menu.svelte.js +33 -60
  130. package/dist/bits/pagination/components/pagination-next-button.svelte +4 -2
  131. package/dist/bits/pagination/components/pagination-page.svelte +4 -2
  132. package/dist/bits/pagination/components/pagination-prev-button.svelte +4 -2
  133. package/dist/bits/pagination/components/pagination.svelte +4 -2
  134. package/dist/bits/pagination/pagination.svelte.js +4 -4
  135. package/dist/bits/pin-input/components/pin-input-cell.svelte +4 -2
  136. package/dist/bits/pin-input/components/pin-input.svelte +5 -3
  137. package/dist/bits/pin-input/pin-input.svelte.d.ts +4 -2
  138. package/dist/bits/pin-input/pin-input.svelte.js +20 -22
  139. package/dist/bits/pin-input/usePasswordManager.svelte.d.ts +3 -2
  140. package/dist/bits/pin-input/usePasswordManager.svelte.js +6 -5
  141. package/dist/bits/popover/components/popover-close.svelte +4 -2
  142. package/dist/bits/popover/components/popover-content-static.svelte +6 -2
  143. package/dist/bits/popover/components/popover-content.svelte +6 -2
  144. package/dist/bits/popover/components/popover-trigger.svelte +5 -3
  145. package/dist/bits/popover/popover.svelte.js +4 -18
  146. package/dist/bits/progress/components/progress.svelte +4 -2
  147. package/dist/bits/progress/progress.svelte.js +2 -2
  148. package/dist/bits/radio-group/components/radio-group-item.svelte +4 -2
  149. package/dist/bits/radio-group/components/radio-group.svelte +4 -2
  150. package/dist/bits/radio-group/radio-group.svelte.js +4 -7
  151. package/dist/bits/range-calendar/components/range-calendar-cell.svelte +4 -2
  152. package/dist/bits/range-calendar/components/range-calendar-day.svelte +4 -2
  153. package/dist/bits/range-calendar/components/range-calendar.svelte +4 -2
  154. package/dist/bits/range-calendar/range-calendar.svelte.d.ts +2 -0
  155. package/dist/bits/range-calendar/range-calendar.svelte.js +12 -6
  156. package/dist/bits/scroll-area/components/scroll-area-corner.svelte +8 -2
  157. package/dist/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte +4 -1
  158. package/dist/bits/scroll-area/components/scroll-area-scrollbar-hover.svelte +1 -1
  159. package/dist/bits/scroll-area/components/scroll-area-scrollbar-scroll.svelte +5 -1
  160. package/dist/bits/scroll-area/components/scroll-area-scrollbar.svelte +4 -2
  161. package/dist/bits/scroll-area/components/scroll-area-thumb.svelte +8 -3
  162. package/dist/bits/scroll-area/components/scroll-area-viewport.svelte +4 -2
  163. package/dist/bits/scroll-area/components/scroll-area.svelte +4 -2
  164. package/dist/bits/scroll-area/scroll-area.svelte.d.ts +2 -0
  165. package/dist/bits/scroll-area/scroll-area.svelte.js +27 -58
  166. package/dist/bits/select/components/select-content-static.svelte +6 -2
  167. package/dist/bits/select/components/select-content.svelte +6 -2
  168. package/dist/bits/select/components/select-group-heading.svelte +3 -2
  169. package/dist/bits/select/components/select-group.svelte +4 -2
  170. package/dist/bits/select/components/select-item.svelte +4 -2
  171. package/dist/bits/select/components/select-scroll-down-button.svelte +4 -2
  172. package/dist/bits/select/components/select-scroll-up-button.svelte +4 -2
  173. package/dist/bits/select/components/select-trigger.svelte +5 -3
  174. package/dist/bits/select/components/select-viewport.svelte +4 -2
  175. package/dist/bits/select/components/select.svelte +7 -1
  176. package/dist/bits/select/select.svelte.d.ts +5 -19
  177. package/dist/bits/select/select.svelte.js +43 -60
  178. package/dist/bits/separator/components/separator.svelte +4 -2
  179. package/dist/bits/separator/separator.svelte.js +2 -2
  180. package/dist/bits/slider/components/slider-range.svelte +4 -2
  181. package/dist/bits/slider/components/slider-thumb-label.svelte +50 -0
  182. package/dist/bits/slider/components/slider-thumb-label.svelte.d.ts +4 -0
  183. package/dist/bits/slider/components/slider-thumb.svelte +4 -2
  184. package/dist/bits/slider/components/slider-tick-label.svelte +50 -0
  185. package/dist/bits/slider/components/slider-tick-label.svelte.d.ts +4 -0
  186. package/dist/bits/slider/components/slider-tick.svelte +4 -2
  187. package/dist/bits/slider/components/slider.svelte +24 -5
  188. package/dist/bits/slider/exports.d.ts +3 -1
  189. package/dist/bits/slider/exports.js +2 -0
  190. package/dist/bits/slider/helpers.d.ts +14 -0
  191. package/dist/bits/slider/helpers.js +122 -0
  192. package/dist/bits/slider/slider.svelte.d.ts +91 -5
  193. package/dist/bits/slider/slider.svelte.js +194 -101
  194. package/dist/bits/slider/types.d.ts +105 -11
  195. package/dist/bits/switch/components/switch-thumb.svelte +4 -2
  196. package/dist/bits/switch/components/switch.svelte +4 -2
  197. package/dist/bits/switch/switch.svelte.js +3 -3
  198. package/dist/bits/tabs/components/tabs-content.svelte +4 -2
  199. package/dist/bits/tabs/components/tabs-list.svelte +4 -2
  200. package/dist/bits/tabs/components/tabs-trigger.svelte +4 -2
  201. package/dist/bits/tabs/components/tabs.svelte +4 -2
  202. package/dist/bits/tabs/tabs.svelte.js +6 -6
  203. package/dist/bits/time-field/components/time-field-hidden-input.svelte +10 -0
  204. package/dist/bits/{date-field/components/date-field-error.svelte.d.ts → time-field/components/time-field-hidden-input.svelte.d.ts} +6 -14
  205. package/dist/bits/time-field/components/time-field-input.svelte +39 -0
  206. package/dist/bits/time-field/components/time-field-input.svelte.d.ts +4 -0
  207. package/dist/bits/time-field/components/time-field-label.svelte +34 -0
  208. package/dist/bits/time-field/components/time-field-label.svelte.d.ts +4 -0
  209. package/dist/bits/time-field/components/time-field-segment.svelte +37 -0
  210. package/dist/bits/time-field/components/time-field-segment.svelte.d.ts +4 -0
  211. package/dist/bits/time-field/components/time-field.svelte +94 -0
  212. package/dist/bits/time-field/components/time-field.svelte.d.ts +20 -0
  213. package/dist/bits/time-field/exports.d.ts +5 -0
  214. package/dist/bits/time-field/exports.js +4 -0
  215. package/dist/bits/time-field/index.d.ts +1 -0
  216. package/dist/bits/time-field/index.js +1 -0
  217. package/dist/bits/time-field/time-field.svelte.d.ts +417 -0
  218. package/dist/bits/time-field/time-field.svelte.js +980 -0
  219. package/dist/bits/time-field/types.d.ts +137 -0
  220. package/dist/bits/time-field/types.js +1 -0
  221. package/dist/bits/time-range-field/components/time-range-field-input.svelte +43 -0
  222. package/dist/bits/time-range-field/components/time-range-field-input.svelte.d.ts +4 -0
  223. package/dist/bits/time-range-field/components/time-range-field-label.svelte +34 -0
  224. package/dist/bits/time-range-field/components/time-range-field-label.svelte.d.ts +4 -0
  225. package/dist/bits/time-range-field/components/time-range-field.svelte +144 -0
  226. package/dist/bits/time-range-field/components/time-range-field.svelte.d.ts +20 -0
  227. package/dist/bits/time-range-field/exports.d.ts +5 -0
  228. package/dist/bits/time-range-field/exports.js +4 -0
  229. package/dist/bits/time-range-field/index.d.ts +1 -0
  230. package/dist/bits/time-range-field/index.js +1 -0
  231. package/dist/bits/time-range-field/time-range-field.svelte.d.ts +92 -0
  232. package/dist/bits/time-range-field/time-range-field.svelte.js +212 -0
  233. package/dist/bits/time-range-field/types.d.ts +150 -0
  234. package/dist/bits/time-range-field/types.js +1 -0
  235. package/dist/bits/toggle/components/toggle.svelte +4 -2
  236. package/dist/bits/toggle/toggle.svelte.js +2 -2
  237. package/dist/bits/toggle-group/components/toggle-group-item.svelte +4 -2
  238. package/dist/bits/toggle-group/components/toggle-group.svelte +4 -2
  239. package/dist/bits/toggle-group/toggle-group.svelte.js +4 -4
  240. package/dist/bits/toolbar/components/toolbar-button.svelte +4 -2
  241. package/dist/bits/toolbar/components/toolbar-group-item.svelte +4 -2
  242. package/dist/bits/toolbar/components/toolbar-group.svelte +4 -2
  243. package/dist/bits/toolbar/components/toolbar-link.svelte +4 -2
  244. package/dist/bits/toolbar/components/toolbar.svelte +4 -2
  245. package/dist/bits/toolbar/toolbar.svelte.js +7 -7
  246. package/dist/bits/tooltip/components/tooltip-content-static.svelte +6 -2
  247. package/dist/bits/tooltip/components/tooltip-content.svelte +6 -2
  248. package/dist/bits/tooltip/components/tooltip-trigger.svelte +5 -3
  249. package/dist/bits/tooltip/tooltip.svelte.d.ts +2 -0
  250. package/dist/bits/tooltip/tooltip.svelte.js +6 -15
  251. package/dist/bits/utilities/dismissible-layer/dismissible-layer.svelte +2 -0
  252. package/dist/bits/utilities/dismissible-layer/types.d.ts +2 -0
  253. package/dist/bits/utilities/dismissible-layer/use-dismissable-layer.svelte.d.ts +3 -3
  254. package/dist/bits/utilities/dismissible-layer/use-dismissable-layer.svelte.js +16 -25
  255. package/dist/bits/utilities/floating-layer/components/floating-layer-anchor.svelte +2 -1
  256. package/dist/bits/utilities/floating-layer/types.d.ts +1 -0
  257. package/dist/bits/utilities/floating-layer/use-floating-layer.svelte.d.ts +3 -2
  258. package/dist/bits/utilities/floating-layer/use-floating-layer.svelte.js +7 -27
  259. package/dist/bits/utilities/focus-scope/focus-scope.svelte +2 -0
  260. package/dist/bits/utilities/focus-scope/types.d.ts +2 -0
  261. package/dist/bits/utilities/focus-scope/use-focus-scope.svelte.d.ts +2 -1
  262. package/dist/bits/utilities/focus-scope/use-focus-scope.svelte.js +15 -16
  263. package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte +4 -0
  264. package/dist/bits/utilities/popper-layer/popper-layer.svelte +3 -1
  265. package/dist/bits/utilities/portal/types.d.ts +1 -1
  266. package/dist/bits/utilities/presence-layer/presence-layer.svelte +2 -2
  267. package/dist/bits/utilities/presence-layer/types.d.ts +2 -1
  268. package/dist/bits/utilities/presence-layer/use-presence.svelte.d.ts +1 -1
  269. package/dist/bits/utilities/presence-layer/use-presence.svelte.js +19 -36
  270. package/dist/bits/utilities/text-selection-layer/text-selection-layer.svelte +2 -0
  271. package/dist/bits/utilities/text-selection-layer/types.d.ts +2 -0
  272. package/dist/bits/utilities/text-selection-layer/use-text-selection-layer.svelte.d.ts +5 -1
  273. package/dist/bits/utilities/text-selection-layer/use-text-selection-layer.svelte.js +8 -14
  274. package/dist/index.d.ts +1 -1
  275. package/dist/index.js +1 -1
  276. package/dist/internal/box-auto-reset.svelte.d.ts +7 -1
  277. package/dist/internal/box-auto-reset.svelte.js +11 -6
  278. package/dist/internal/create-id.d.ts +8 -0
  279. package/dist/internal/create-id.js +5 -0
  280. package/dist/internal/date-time/announcer.d.ts +1 -1
  281. package/dist/internal/date-time/announcer.js +20 -20
  282. package/dist/internal/date-time/calendar-helpers.svelte.js +7 -5
  283. package/dist/internal/date-time/field/helpers.d.ts +9 -2
  284. package/dist/internal/date-time/field/helpers.js +16 -9
  285. package/dist/internal/date-time/field/parts.d.ts +3 -1
  286. package/dist/internal/date-time/field/parts.js +10 -2
  287. package/dist/internal/date-time/field/segments.d.ts +9 -0
  288. package/dist/internal/date-time/field/segments.js +65 -0
  289. package/dist/internal/date-time/field/time-helpers.d.ts +83 -0
  290. package/dist/internal/date-time/field/time-helpers.js +301 -0
  291. package/dist/internal/date-time/field/types.d.ts +2 -2
  292. package/dist/internal/date-time/formatter.d.ts +11 -1
  293. package/dist/internal/date-time/formatter.js +56 -0
  294. package/dist/internal/date-time/utils.d.ts +7 -2
  295. package/dist/internal/date-time/utils.js +15 -1
  296. package/dist/internal/dom.d.ts +0 -1
  297. package/dist/internal/dom.js +0 -3
  298. package/dist/internal/focus.d.ts +2 -2
  299. package/dist/internal/focus.js +14 -9
  300. package/dist/internal/math.d.ts +0 -4
  301. package/dist/internal/math.js +0 -28
  302. package/dist/internal/tabbable.d.ts +0 -2
  303. package/dist/internal/tabbable.js +10 -14
  304. package/dist/internal/use-data-typeahead.svelte.d.ts +1 -0
  305. package/dist/internal/use-data-typeahead.svelte.js +4 -1
  306. package/dist/internal/use-dom-typeahead.svelte.d.ts +3 -1
  307. package/dist/internal/use-dom-typeahead.svelte.js +5 -2
  308. package/dist/internal/use-grace-area.svelte.js +9 -5
  309. package/dist/internal/use-roving-focus.svelte.d.ts +3 -3
  310. package/dist/internal/use-roving-focus.svelte.js +10 -11
  311. package/dist/shared/date/types.d.ts +27 -4
  312. package/dist/shared/index.d.ts +2 -2
  313. package/dist/types.d.ts +2 -0
  314. package/package.json +18 -16
  315. package/dist/bits/date-field/components/date-field-error.svelte +0 -0
  316. package/dist/internal/use-size.svelte.d.ts +0 -7
  317. package/dist/internal/use-size.svelte.js +0 -54
@@ -0,0 +1,980 @@
1
+ import { CalendarDateTime, Time, ZonedDateTime } from "@internationalized/date";
2
+ import { onDestroyEffect, attachRef, box, DOMContext } from "svelte-toolbelt";
3
+ import { onMount, untrack } from "svelte";
4
+ import { Context, watch } from "runed";
5
+ import { getAriaDisabled, getAriaHidden, getAriaInvalid, getAriaReadonly, getDataDisabled, getDataInvalid, getDataReadonly, } from "../../internal/attrs.js";
6
+ import { isBrowser, isNumberString } from "../../internal/is.js";
7
+ import { kbd } from "../../internal/kbd.js";
8
+ import { useId } from "../../internal/use-id.js";
9
+ import { createTimeFormatter } from "../../internal/date-time/formatter.js";
10
+ import { getAnnouncer } from "../../internal/date-time/announcer.js";
11
+ import { EDITABLE_TIME_SEGMENT_PARTS } from "../../internal/date-time/field/parts.js";
12
+ import { toDate } from "../../internal/date-time/utils.js";
13
+ import { areAllTimeSegmentsFilled, convertTimeValueToTime, createTimeContent, getISOTimeValue, getTimeValueFromSegments, initTimeSegmentStates, isFirstTimeSegment, isTimeBefore, removeTimeDescriptionElement, setTimeDescription, } from "../../internal/date-time/field/time-helpers.js";
14
+ import { getFirstTimeSegment, handleTimeSegmentNavigation, isSegmentNavigationKey, moveToNextTimeSegment, moveToPrevTimeSegment, } from "../../internal/date-time/field/segments.js";
15
+ import { getDefaultHourCycle, isAcceptableSegmentKey, } from "../../internal/date-time/field/helpers.js";
16
+ export const TIME_FIELD_INPUT_ATTR = "data-time-field-input";
17
+ const TIME_FIELD_LABEL_ATTR = "data-time-field-label";
18
+ const SEGMENT_CONFIGS = {
19
+ hour: {
20
+ min: (root) => (root.hourCycle === 12 ? 1 : 0),
21
+ max: (root) => {
22
+ if (root.hourCycle === 24)
23
+ return 23;
24
+ if ("dayPeriod" in root.segmentValues && root.segmentValues.dayPeriod !== null)
25
+ return 12;
26
+ return 23;
27
+ },
28
+ cycle: 1,
29
+ canBeZero: true,
30
+ padZero: true,
31
+ },
32
+ minute: {
33
+ min: 0,
34
+ max: 59,
35
+ cycle: 1,
36
+ canBeZero: true,
37
+ padZero: true,
38
+ },
39
+ second: {
40
+ min: 0,
41
+ max: 59,
42
+ cycle: 1,
43
+ canBeZero: true,
44
+ padZero: true,
45
+ },
46
+ };
47
+ export class TimeFieldRootState {
48
+ value;
49
+ placeholder;
50
+ validate;
51
+ minValue;
52
+ maxValue;
53
+ disabled;
54
+ readonly;
55
+ granularity;
56
+ readonlySegments;
57
+ hourCycleProp;
58
+ locale;
59
+ hideTimeZone;
60
+ required;
61
+ onInvalid;
62
+ errorMessageId;
63
+ isInvalidProp;
64
+ descriptionId = useId();
65
+ formatter;
66
+ initialSegments;
67
+ segmentValues = $state();
68
+ announcer;
69
+ readonlySegmentsSet = $derived.by(() => new Set(this.readonlySegments.current));
70
+ segmentStates = initTimeSegmentStates();
71
+ #fieldNode = $state(null);
72
+ #labelNode = $state(null);
73
+ descriptionNode = $state(null);
74
+ validationNode = $state(null);
75
+ states = initTimeSegmentStates();
76
+ dayPeriodNode = $state(null);
77
+ name = $state("");
78
+ maxValueTime = $derived.by(() => {
79
+ if (!this.maxValue.current)
80
+ return undefined;
81
+ return convertTimeValueToTime(this.maxValue.current);
82
+ });
83
+ minValueTime = $derived.by(() => {
84
+ if (!this.minValue.current)
85
+ return undefined;
86
+ return convertTimeValueToTime(this.minValue.current);
87
+ });
88
+ valueTime = $derived.by(() => {
89
+ if (!this.value.current)
90
+ return undefined;
91
+ return convertTimeValueToTime(this.value.current);
92
+ });
93
+ hourCycle = $derived.by(() => {
94
+ if (this.hourCycleProp.current)
95
+ return this.hourCycleProp.current;
96
+ return getDefaultHourCycle(this.locale.current);
97
+ });
98
+ rangeRoot = undefined;
99
+ domContext = new DOMContext(() => null);
100
+ constructor(props, rangeRoot) {
101
+ this.rangeRoot = rangeRoot;
102
+ /**
103
+ * Since the `TimeFieldRootState` can be used in two contexts, as a standalone
104
+ * field or as a field within a `TimeRangeField` component, we handle assigning
105
+ * the props based on that context.
106
+ */
107
+ this.value = props.value;
108
+ this.placeholder = rangeRoot ? rangeRoot.opts.placeholder : props.placeholder;
109
+ this.validate = rangeRoot ? box(undefined) : props.validate;
110
+ this.minValue = rangeRoot ? rangeRoot.opts.minValue : props.minValue;
111
+ this.maxValue = rangeRoot ? rangeRoot.opts.maxValue : props.maxValue;
112
+ this.disabled = rangeRoot ? rangeRoot.opts.disabled : props.disabled;
113
+ this.readonly = rangeRoot ? rangeRoot.opts.readonly : props.readonly;
114
+ this.granularity = rangeRoot ? rangeRoot.opts.granularity : props.granularity;
115
+ this.readonlySegments = rangeRoot
116
+ ? rangeRoot.opts.readonlySegments
117
+ : props.readonlySegments;
118
+ this.hourCycleProp = rangeRoot ? rangeRoot.opts.hourCycle : props.hourCycle;
119
+ this.locale = rangeRoot ? rangeRoot.opts.locale : props.locale;
120
+ this.hideTimeZone = rangeRoot ? rangeRoot.opts.hideTimeZone : props.hideTimeZone;
121
+ this.required = rangeRoot ? rangeRoot.opts.required : props.required;
122
+ this.onInvalid = rangeRoot ? rangeRoot.opts.onInvalid : props.onInvalid;
123
+ this.errorMessageId = rangeRoot ? rangeRoot.opts.errorMessageId : props.errorMessageId;
124
+ this.isInvalidProp = props.isInvalidProp;
125
+ this.formatter = createTimeFormatter(this.locale.current);
126
+ this.initialSegments = this.#initializeTimeSegmentValues();
127
+ this.segmentValues = this.initialSegments;
128
+ this.announcer = getAnnouncer(null);
129
+ this.getFieldNode = this.getFieldNode.bind(this);
130
+ this.updateSegment = this.updateSegment.bind(this);
131
+ this.handleSegmentClick = this.handleSegmentClick.bind(this);
132
+ this.getBaseSegmentAttrs = this.getBaseSegmentAttrs.bind(this);
133
+ $effect(() => {
134
+ untrack(() => {
135
+ this.initialSegments = this.#initializeTimeSegmentValues();
136
+ });
137
+ });
138
+ onMount(() => {
139
+ this.announcer = getAnnouncer(this.domContext.getDocument());
140
+ });
141
+ onDestroyEffect(() => {
142
+ removeTimeDescriptionElement(this.descriptionId, this.domContext.getDocument());
143
+ });
144
+ $effect(() => {
145
+ if (this.formatter.getLocale() === this.locale.current)
146
+ return;
147
+ this.formatter.setLocale(this.locale.current);
148
+ });
149
+ $effect(() => {
150
+ if (this.value.current) {
151
+ const descriptionId = untrack(() => this.descriptionId);
152
+ setTimeDescription({
153
+ id: descriptionId,
154
+ formatter: this.formatter,
155
+ value: this.#toDateValue(this.value.current),
156
+ doc: this.domContext.getDocument(),
157
+ });
158
+ }
159
+ const placeholder = untrack(() => this.placeholder.current);
160
+ if (this.value.current && placeholder !== this.value.current) {
161
+ untrack(() => {
162
+ if (this.value.current) {
163
+ this.placeholder.current = this.value.current;
164
+ }
165
+ });
166
+ }
167
+ });
168
+ if (this.value.current) {
169
+ this.syncSegmentValues(this.value.current);
170
+ }
171
+ $effect(() => {
172
+ this.locale.current;
173
+ if (this.value.current) {
174
+ this.syncSegmentValues(this.value.current);
175
+ }
176
+ this.#clearUpdating();
177
+ });
178
+ $effect(() => {
179
+ if (this.value.current === undefined) {
180
+ this.segmentValues = this.#initializeTimeSegmentValues();
181
+ }
182
+ });
183
+ watch(() => this.validationStatus, () => {
184
+ if (this.validationStatus !== false) {
185
+ this.onInvalid.current?.(this.validationStatus.reason, this.validationStatus.message);
186
+ }
187
+ });
188
+ }
189
+ #initializeTimeSegmentValues() {
190
+ const granularity = this.inferredGranularity;
191
+ const segments = {
192
+ hour: null,
193
+ minute: null,
194
+ second: null,
195
+ dayPeriod: "AM",
196
+ };
197
+ if (granularity === "second") {
198
+ segments.second = null;
199
+ }
200
+ if (this.hourCycle === 24) {
201
+ segments.dayPeriod = null;
202
+ }
203
+ return segments;
204
+ }
205
+ #toDateValue(timeValue) {
206
+ if ("calendar" in timeValue) {
207
+ // CalendarDateTime or ZonedDateTime
208
+ return timeValue;
209
+ }
210
+ else {
211
+ return new CalendarDateTime(2000, 1, 1, timeValue.hour, timeValue.minute, timeValue.second, timeValue.millisecond);
212
+ }
213
+ }
214
+ #clearUpdating() {
215
+ this.states.hour.updating = null;
216
+ this.states.minute.updating = null;
217
+ this.states.second.updating = null;
218
+ this.states.dayPeriod.updating = null;
219
+ }
220
+ setName(name) {
221
+ this.name = name;
222
+ }
223
+ setFieldNode(node) {
224
+ this.#fieldNode = node;
225
+ }
226
+ /**
227
+ * Gets the correct field node for the time field regardless of whether it's being
228
+ * used in a standalone context or within a `TimeRangeField` component.
229
+ */
230
+ getFieldNode() {
231
+ /** If we're not within a TimeRangeField, we return this field. */
232
+ if (!this.rangeRoot) {
233
+ return this.#fieldNode;
234
+ }
235
+ else {
236
+ /**
237
+ * Otherwise, we return the rangeRoot's field node which
238
+ * contains both start and end fields.
239
+ */
240
+ return this.rangeRoot.fieldNode;
241
+ }
242
+ }
243
+ setLabelNode(node) {
244
+ this.#labelNode = node;
245
+ }
246
+ getLabelNode() {
247
+ return this.#labelNode;
248
+ }
249
+ setValue(value) {
250
+ this.value.current = value;
251
+ }
252
+ syncSegmentValues(value) {
253
+ const timeValues = EDITABLE_TIME_SEGMENT_PARTS.map((part) => {
254
+ if (part === "dayPeriod") {
255
+ if (this.states.dayPeriod.updating) {
256
+ return [part, this.states.dayPeriod.updating];
257
+ }
258
+ else {
259
+ return [part, this.formatter.dayPeriod(toDate(this.#toDateValue(value)))];
260
+ }
261
+ }
262
+ else if (part === "hour") {
263
+ if (this.states.hour.updating) {
264
+ return [part, this.states.hour.updating];
265
+ }
266
+ if (value[part] !== undefined && value[part] < 10) {
267
+ return [part, `0${value[part]}`];
268
+ }
269
+ if (value[part] === 0 && this.dayPeriodNode) {
270
+ return [part, "12"];
271
+ }
272
+ }
273
+ else if (part === "minute") {
274
+ if (this.states.minute.updating) {
275
+ return [part, this.states.minute.updating];
276
+ }
277
+ if (value[part] !== undefined && value[part] < 10) {
278
+ return [part, `0${value[part]}`];
279
+ }
280
+ }
281
+ else if (part === "second") {
282
+ if (this.states.second.updating) {
283
+ return [part, this.states.second.updating];
284
+ }
285
+ if (value[part] !== undefined && value[part] < 10) {
286
+ return [part, `0${value[part]}`];
287
+ }
288
+ }
289
+ return [part, `${value[part]}`];
290
+ });
291
+ this.segmentValues = Object.fromEntries(timeValues);
292
+ this.#clearUpdating();
293
+ }
294
+ validationStatus = $derived.by(() => {
295
+ const value = this.value.current;
296
+ if (!value)
297
+ return false;
298
+ const msg = this.validate.current?.(value);
299
+ if (msg) {
300
+ return {
301
+ reason: "custom",
302
+ message: msg,
303
+ };
304
+ }
305
+ if (!this.valueTime)
306
+ return false;
307
+ if (this.minValueTime && isTimeBefore(this.valueTime, this.minValueTime)) {
308
+ return {
309
+ reason: "min",
310
+ };
311
+ }
312
+ if (this.maxValueTime && isTimeBefore(this.maxValueTime, this.valueTime)) {
313
+ return {
314
+ reason: "max",
315
+ };
316
+ }
317
+ return false;
318
+ });
319
+ isInvalid = $derived.by(() => {
320
+ if (this.validationStatus === false)
321
+ return false;
322
+ if (this.isInvalidProp.current)
323
+ return true;
324
+ return true;
325
+ });
326
+ inferredGranularity = $derived.by(() => {
327
+ return this.granularity.current ?? "minute";
328
+ });
329
+ timeRef = $derived.by(() => this.value.current ?? this.placeholder.current);
330
+ allSegmentContent = $derived.by(() => createTimeContent({
331
+ segmentValues: this.segmentValues,
332
+ formatter: this.formatter,
333
+ locale: this.locale.current,
334
+ granularity: this.inferredGranularity,
335
+ timeRef: this.timeRef,
336
+ hideTimeZone: this.hideTimeZone.current,
337
+ hourCycle: this.hourCycle,
338
+ }));
339
+ segmentContents = $derived.by(() => this.allSegmentContent.arr);
340
+ sharedSegmentAttrs = {
341
+ role: "spinbutton",
342
+ contenteditable: "true",
343
+ tabindex: 0,
344
+ spellcheck: false,
345
+ inputmode: "numeric",
346
+ autocorrect: "off",
347
+ enterkeyhint: "next",
348
+ style: {
349
+ caretColor: "transparent",
350
+ },
351
+ };
352
+ #getLabelledBy(segmentId) {
353
+ return `${segmentId} ${this.getLabelNode()?.id ?? ""}`;
354
+ }
355
+ updateSegment(part, cb) {
356
+ const disabled = this.disabled.current;
357
+ const readonly = this.readonly.current;
358
+ const readonlySegmentsSet = this.readonlySegmentsSet;
359
+ if (disabled || readonly || readonlySegmentsSet.has(part))
360
+ return;
361
+ const prev = this.segmentValues;
362
+ let newSegmentValues = prev;
363
+ if (part === "dayPeriod") {
364
+ const next = cb(prev[part]);
365
+ this.states.dayPeriod.updating = next;
366
+ const value = this.value.current;
367
+ if (value && "hour" in value) {
368
+ const trueHour = value.hour;
369
+ if (next === "AM") {
370
+ if (trueHour >= 12) {
371
+ prev.hour = `${trueHour - 12}`;
372
+ }
373
+ }
374
+ else if (next === "PM") {
375
+ if (trueHour < 12) {
376
+ prev.hour = `${trueHour + 12}`;
377
+ }
378
+ }
379
+ }
380
+ newSegmentValues = { ...prev, [part]: next };
381
+ }
382
+ else if (part === "hour") {
383
+ const next = cb(prev[part]);
384
+ this.states.hour.updating = next;
385
+ if (next !== null && prev.dayPeriod !== null) {
386
+ const dayPeriod = this.formatter.dayPeriod(toDate(this.#toDateValue(this.timeRef.set({ hour: Number.parseInt(next) }))), this.hourCycle);
387
+ if (dayPeriod === "AM" || dayPeriod === "PM") {
388
+ prev.dayPeriod = dayPeriod;
389
+ }
390
+ }
391
+ newSegmentValues = { ...prev, [part]: next };
392
+ }
393
+ else if (part === "minute") {
394
+ const next = cb(prev[part]);
395
+ this.states.minute.updating = next;
396
+ newSegmentValues = { ...prev, [part]: next };
397
+ }
398
+ else if (part === "second") {
399
+ const next = cb(prev[part]);
400
+ this.states.second.updating = next;
401
+ newSegmentValues = { ...prev, [part]: next };
402
+ }
403
+ this.segmentValues = newSegmentValues;
404
+ if (areAllTimeSegmentsFilled(newSegmentValues, this.#fieldNode)) {
405
+ this.setValue(getTimeValueFromSegments({
406
+ segmentObj: newSegmentValues,
407
+ fieldNode: this.#fieldNode,
408
+ timeRef: this.timeRef,
409
+ }));
410
+ }
411
+ else {
412
+ // this.setValue(undefined);
413
+ // this.segmentValues = newSegmentValues;
414
+ }
415
+ }
416
+ handleSegmentClick(e) {
417
+ if (this.disabled.current) {
418
+ e.preventDefault();
419
+ }
420
+ }
421
+ getBaseSegmentAttrs(part, segmentId) {
422
+ const inReadonlySegments = this.readonlySegmentsSet.has(part);
423
+ const defaultAttrs = {
424
+ "aria-invalid": getAriaInvalid(this.isInvalid),
425
+ "aria-disabled": getAriaDisabled(this.disabled.current),
426
+ "aria-readonly": getAriaReadonly(this.readonly.current || inReadonlySegments),
427
+ "data-invalid": getDataInvalid(this.isInvalid),
428
+ "data-disabled": getDataDisabled(this.disabled.current),
429
+ "data-readonly": getDataReadonly(this.readonly.current || inReadonlySegments),
430
+ "data-segment": `${part}`,
431
+ };
432
+ if (part === "literal")
433
+ return defaultAttrs;
434
+ const descriptionId = this.descriptionNode?.id;
435
+ const hasDescription = isFirstTimeSegment(segmentId, this.#fieldNode) && descriptionId;
436
+ const errorMsgId = this.errorMessageId?.current;
437
+ const describedBy = hasDescription
438
+ ? `${descriptionId} ${this.isInvalid && errorMsgId ? errorMsgId : ""}`
439
+ : undefined;
440
+ const contenteditable = !(this.readonly.current ||
441
+ inReadonlySegments ||
442
+ this.disabled.current);
443
+ return {
444
+ ...defaultAttrs,
445
+ "aria-labelledby": this.#getLabelledBy(segmentId),
446
+ contenteditable: contenteditable ? "true" : undefined,
447
+ "aria-describedby": describedBy,
448
+ tabindex: this.disabled.current ? undefined : 0,
449
+ };
450
+ }
451
+ }
452
+ export class TimeFieldInputState {
453
+ opts;
454
+ root;
455
+ domContext;
456
+ constructor(opts, root) {
457
+ this.opts = opts;
458
+ this.root = root;
459
+ this.domContext = new DOMContext(opts.ref);
460
+ this.root.setName(this.opts.name.current);
461
+ $effect(() => {
462
+ this.root.setName(this.opts.name.current);
463
+ });
464
+ }
465
+ #ariaDescribedBy = $derived.by(() => {
466
+ if (!isBrowser)
467
+ return undefined;
468
+ const doesDescriptionExist = this.domContext.getElementById(this.root.descriptionId);
469
+ if (!doesDescriptionExist)
470
+ return undefined;
471
+ return this.root.descriptionId;
472
+ });
473
+ props = $derived.by(() => ({
474
+ id: this.opts.id.current,
475
+ role: "group",
476
+ "aria-labelledby": this.root.getLabelNode()?.id ?? undefined,
477
+ "aria-describedby": this.#ariaDescribedBy,
478
+ "aria-disabled": getAriaDisabled(this.root.disabled.current),
479
+ "data-invalid": this.root.isInvalid ? "" : undefined,
480
+ "data-disabled": getDataDisabled(this.root.disabled.current),
481
+ [TIME_FIELD_INPUT_ATTR]: "",
482
+ ...attachRef(this.opts.ref, (v) => this.root.setFieldNode(v)),
483
+ }));
484
+ }
485
+ class TimeFieldHiddenInputState {
486
+ root;
487
+ shouldRender = $derived.by(() => this.root.name !== "");
488
+ isoValue = $derived.by(() => this.root.value.current ? getISOTimeValue(this.root.value.current) : undefined);
489
+ constructor(root) {
490
+ this.root = root;
491
+ }
492
+ props = $derived.by(() => ({
493
+ name: this.root.name,
494
+ value: this.isoValue,
495
+ required: this.root.required.current,
496
+ }));
497
+ }
498
+ class TimeFieldLabelState {
499
+ opts;
500
+ root;
501
+ constructor(opts, root) {
502
+ this.opts = opts;
503
+ this.root = root;
504
+ this.onclick = this.onclick.bind(this);
505
+ }
506
+ onclick(_) {
507
+ if (this.root.disabled.current)
508
+ return;
509
+ const firstSegment = getFirstTimeSegment(this.root.getFieldNode());
510
+ if (!firstSegment)
511
+ return;
512
+ firstSegment.focus();
513
+ }
514
+ props = $derived.by(() => ({
515
+ id: this.opts.id.current,
516
+ "data-invalid": getDataInvalid(this.root.isInvalid),
517
+ "data-disabled": getDataDisabled(this.root.disabled.current),
518
+ [TIME_FIELD_LABEL_ATTR]: "",
519
+ onclick: this.onclick,
520
+ ...attachRef(this.opts.ref, (v) => this.root.setLabelNode(v)),
521
+ }));
522
+ }
523
+ // Base class for time segments - simplified from date-field version
524
+ class BaseTimeSegmentState {
525
+ opts;
526
+ root;
527
+ announcer;
528
+ part;
529
+ config;
530
+ constructor(opts, root, part, config) {
531
+ this.opts = opts;
532
+ this.root = root;
533
+ this.part = part;
534
+ this.config = config;
535
+ this.announcer = root.announcer;
536
+ this.onkeydown = this.onkeydown.bind(this);
537
+ this.onfocusout = this.onfocusout.bind(this);
538
+ }
539
+ #getMax() {
540
+ return typeof this.config.max === "function" ? this.config.max(this.root) : this.config.max;
541
+ }
542
+ #getMin() {
543
+ return typeof this.config.min === "function" ? this.config.min(this.root) : this.config.min;
544
+ }
545
+ #formatValue(value, forDisplay = true) {
546
+ const str = String(value);
547
+ if (forDisplay && this.config.padZero && str.length === 1) {
548
+ return `0${value}`;
549
+ }
550
+ return str;
551
+ }
552
+ onkeydown(e) {
553
+ const placeholder = this.root.value.current ?? this.root.placeholder.current;
554
+ if (e.ctrlKey || e.metaKey || this.root.disabled.current)
555
+ return;
556
+ if (e.key !== kbd.TAB)
557
+ e.preventDefault();
558
+ if (!isAcceptableSegmentKey(e.key))
559
+ return;
560
+ if (isArrowUp(e.key)) {
561
+ this.#handleArrowUp(placeholder);
562
+ return;
563
+ }
564
+ if (isArrowDown(e.key)) {
565
+ this.#handleArrowDown(placeholder);
566
+ return;
567
+ }
568
+ if (isNumberString(e.key)) {
569
+ this.#handleNumberKey(e);
570
+ return;
571
+ }
572
+ if (isBackspace(e.key)) {
573
+ this.#handleBackspace(e);
574
+ return;
575
+ }
576
+ if (isSegmentNavigationKey(e.key)) {
577
+ handleTimeSegmentNavigation(e, this.root.getFieldNode());
578
+ }
579
+ }
580
+ #handleArrowUp(placeholder) {
581
+ const stateKey = this.part;
582
+ if (stateKey in this.root.states) {
583
+ this.root.states[stateKey].hasLeftFocus = false;
584
+ }
585
+ // @ts-expect-error shhh
586
+ this.root.updateSegment(this.part, (prev) => {
587
+ if (prev === null) {
588
+ const next = placeholder[this.part];
589
+ this.announcer.announce(String(next));
590
+ return this.#formatValue(next);
591
+ }
592
+ const current = placeholder.set({
593
+ [this.part]: Number.parseInt(prev),
594
+ });
595
+ // @ts-expect-error shhh
596
+ const next = current.cycle(this.part, this.config.cycle)[this.part];
597
+ this.announcer.announce(String(next));
598
+ return this.#formatValue(next);
599
+ });
600
+ }
601
+ #handleArrowDown(placeholder) {
602
+ const stateKey = this.part;
603
+ if (stateKey in this.root.states) {
604
+ this.root.states[stateKey].hasLeftFocus = false;
605
+ }
606
+ // @ts-expect-error - this is a part
607
+ this.root.updateSegment(this.part, (prev) => {
608
+ if (prev === null) {
609
+ const next = placeholder[this.part];
610
+ this.announcer.announce(String(next));
611
+ return this.#formatValue(next);
612
+ }
613
+ const current = placeholder.set({
614
+ [this.part]: Number.parseInt(prev),
615
+ });
616
+ // @ts-expect-error shhh
617
+ const next = current.cycle(this.part, -this.config.cycle)[this.part];
618
+ this.announcer.announce(String(next));
619
+ return this.#formatValue(next);
620
+ });
621
+ }
622
+ #handleNumberKey(e) {
623
+ const num = Number.parseInt(e.key);
624
+ let moveToNext = false;
625
+ const max = this.#getMax();
626
+ const maxStart = Math.floor(max / 10);
627
+ const numIsZero = num === 0;
628
+ const stateKey = this.part;
629
+ // @ts-expect-error this is a part
630
+ this.root.updateSegment(this.part, (prev) => {
631
+ if (stateKey in this.root.states && this.root.states[stateKey].hasLeftFocus) {
632
+ prev = null;
633
+ this.root.states[stateKey].hasLeftFocus = false;
634
+ }
635
+ if (prev === null) {
636
+ if (numIsZero) {
637
+ if (stateKey in this.root.states) {
638
+ this.root.states[stateKey].lastKeyZero = true;
639
+ }
640
+ this.announcer.announce("0");
641
+ return "0";
642
+ }
643
+ if (stateKey in this.root.states &&
644
+ (this.root.states[stateKey].lastKeyZero || num > maxStart)) {
645
+ moveToNext = true;
646
+ }
647
+ if (stateKey in this.root.states) {
648
+ this.root.states[stateKey].lastKeyZero = false;
649
+ }
650
+ if (moveToNext && String(num).length === 1) {
651
+ this.announcer.announce(num);
652
+ return `0${num}`;
653
+ }
654
+ return `${num}`;
655
+ }
656
+ if (stateKey in this.root.states && this.root.states[stateKey].lastKeyZero) {
657
+ if (num !== 0) {
658
+ moveToNext = true;
659
+ this.root.states[stateKey].lastKeyZero = false;
660
+ return `0${num}`;
661
+ }
662
+ if (this.part === "hour" && num === 0 && this.root.hourCycle === 24) {
663
+ moveToNext = true;
664
+ this.root.states[stateKey].lastKeyZero = false;
665
+ return `00`;
666
+ }
667
+ if ((this.part === "minute" || this.part === "second") && num === 0) {
668
+ moveToNext = true;
669
+ this.root.states[stateKey].lastKeyZero = false;
670
+ return "00";
671
+ }
672
+ return prev;
673
+ }
674
+ const total = Number.parseInt(prev + num.toString());
675
+ if (total > max) {
676
+ moveToNext = true;
677
+ return `0${num}`;
678
+ }
679
+ moveToNext = true;
680
+ return `${total}`;
681
+ });
682
+ if (moveToNext) {
683
+ moveToNextTimeSegment(e, this.root.getFieldNode());
684
+ }
685
+ }
686
+ #handleBackspace(e) {
687
+ const stateKey = this.part;
688
+ if (stateKey in this.root.states) {
689
+ this.root.states[stateKey].hasLeftFocus = false;
690
+ }
691
+ let moveToPrev = false;
692
+ // @ts-expect-error this is a part
693
+ this.root.updateSegment(this.part, (prev) => {
694
+ if (prev === null) {
695
+ moveToPrev = true;
696
+ this.announcer.announce(null);
697
+ return null;
698
+ }
699
+ if (prev.length === 2 && prev.startsWith("0")) {
700
+ this.announcer.announce(null);
701
+ return null;
702
+ }
703
+ const str = prev.toString();
704
+ if (str.length === 1) {
705
+ this.announcer.announce(null);
706
+ return null;
707
+ }
708
+ const next = Number.parseInt(str.slice(0, -1));
709
+ this.announcer.announce(String(next));
710
+ return `${next}`;
711
+ });
712
+ if (moveToPrev) {
713
+ moveToPrevTimeSegment(e, this.root.getFieldNode());
714
+ }
715
+ }
716
+ onfocusout(_) {
717
+ const stateKey = this.part;
718
+ if (stateKey in this.root.states) {
719
+ this.root.states[stateKey].hasLeftFocus = true;
720
+ }
721
+ // Pad with zero if needed
722
+ if (this.config.padZero) {
723
+ // @ts-expect-error this is a part
724
+ this.root.updateSegment(this.part, (prev) => {
725
+ if (prev && prev.length === 1) {
726
+ return `0${prev}`;
727
+ }
728
+ return prev;
729
+ });
730
+ }
731
+ }
732
+ getSegmentProps() {
733
+ const segmentValues = this.root.segmentValues;
734
+ const placeholder = this.root.placeholder.current;
735
+ const isEmpty = segmentValues[this.part] === null;
736
+ let value = placeholder;
737
+ if (segmentValues[this.part]) {
738
+ value = placeholder.set({
739
+ [this.part]: Number.parseInt(segmentValues[this.part]),
740
+ });
741
+ }
742
+ const valueNow = value[this.part];
743
+ const valueMin = this.#getMin();
744
+ const valueMax = this.#getMax();
745
+ let valueText = isEmpty ? "Empty" : `${valueNow}`;
746
+ // special handling for hour segment with dayPeriod
747
+ if (this.part === "hour" && "dayPeriod" in segmentValues && segmentValues.dayPeriod) {
748
+ valueText = isEmpty ? "Empty" : `${valueNow} ${segmentValues.dayPeriod}`;
749
+ }
750
+ return {
751
+ "aria-label": `${this.part}, `,
752
+ "aria-valuemin": valueMin,
753
+ "aria-valuemax": valueMax,
754
+ "aria-valuenow": valueNow,
755
+ "aria-valuetext": valueText,
756
+ };
757
+ }
758
+ props = $derived.by(() => {
759
+ return {
760
+ ...this.root.sharedSegmentAttrs,
761
+ id: this.opts.id.current,
762
+ ...this.getSegmentProps(),
763
+ onkeydown: this.onkeydown,
764
+ onfocusout: this.onfocusout,
765
+ onclick: this.root.handleSegmentClick,
766
+ ...this.root.getBaseSegmentAttrs(this.part, this.opts.id.current),
767
+ ...attachRef(this.opts.ref),
768
+ };
769
+ });
770
+ }
771
+ class TimeFieldHourSegmentState extends BaseTimeSegmentState {
772
+ constructor(opts, root) {
773
+ super(opts, root, "hour", SEGMENT_CONFIGS.hour);
774
+ }
775
+ onkeydown(e) {
776
+ if (isNumberString(e.key)) {
777
+ const oldUpdateSegment = this.root.updateSegment.bind(this.root);
778
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
779
+ this.root.updateSegment = (part, cb) => {
780
+ const result = oldUpdateSegment(part, cb);
781
+ // after updating hour, check if we need to display "12" instead of "0"
782
+ if (part === "hour" && "hour" in this.root.segmentValues) {
783
+ const hourValue = this.root.segmentValues.hour;
784
+ if (hourValue === "0" &&
785
+ this.root.dayPeriodNode &&
786
+ this.root.hourCycle !== 24) {
787
+ this.root.segmentValues.hour = "12";
788
+ }
789
+ }
790
+ return result;
791
+ };
792
+ }
793
+ super.onkeydown(e);
794
+ this.root.updateSegment = this.root.updateSegment.bind(this.root);
795
+ }
796
+ }
797
+ class TimeFieldMinuteSegmentState extends BaseTimeSegmentState {
798
+ constructor(opts, root) {
799
+ super(opts, root, "minute", SEGMENT_CONFIGS.minute);
800
+ }
801
+ }
802
+ class TimeFieldSecondSegmentState extends BaseTimeSegmentState {
803
+ constructor(opts, root) {
804
+ super(opts, root, "second", SEGMENT_CONFIGS.second);
805
+ }
806
+ }
807
+ class TimeFieldDayPeriodSegmentState {
808
+ opts;
809
+ root;
810
+ #announcer;
811
+ constructor(opts, root) {
812
+ this.opts = opts;
813
+ this.root = root;
814
+ this.#announcer = this.root.announcer;
815
+ this.onkeydown = this.onkeydown.bind(this);
816
+ }
817
+ onkeydown(e) {
818
+ if (e.ctrlKey || e.metaKey || this.root.disabled.current)
819
+ return;
820
+ if (e.key !== kbd.TAB)
821
+ e.preventDefault();
822
+ if (!isAcceptableDayPeriodKey(e.key))
823
+ return;
824
+ if (isArrowUp(e.key) || isArrowDown(e.key)) {
825
+ this.root.updateSegment("dayPeriod", (prev) => {
826
+ if (prev === "AM") {
827
+ const next = "PM";
828
+ this.#announcer.announce(next);
829
+ return next;
830
+ }
831
+ const next = "AM";
832
+ this.#announcer.announce(next);
833
+ return next;
834
+ });
835
+ return;
836
+ }
837
+ if (isBackspace(e.key)) {
838
+ this.root.states.dayPeriod.hasLeftFocus = false;
839
+ this.root.updateSegment("dayPeriod", () => {
840
+ const next = "AM";
841
+ this.#announcer.announce(next);
842
+ return next;
843
+ });
844
+ }
845
+ if (e.key === kbd.A || e.key === kbd.P || e.key === kbd.a || e.key === kbd.p) {
846
+ this.root.updateSegment("dayPeriod", () => {
847
+ const next = e.key === kbd.A || e.key === kbd.a ? "AM" : "PM";
848
+ this.#announcer.announce(next);
849
+ return next;
850
+ });
851
+ }
852
+ if (isSegmentNavigationKey(e.key)) {
853
+ handleTimeSegmentNavigation(e, this.root.getFieldNode());
854
+ }
855
+ }
856
+ props = $derived.by(() => {
857
+ const segmentValues = this.root.segmentValues;
858
+ if (!("dayPeriod" in segmentValues))
859
+ return;
860
+ const valueMin = 0;
861
+ const valueMax = 12;
862
+ const valueNow = segmentValues.dayPeriod === "AM" ? 0 : 12;
863
+ const valueText = segmentValues.dayPeriod === "AM" ? "AM" : "PM";
864
+ return {
865
+ ...this.root.sharedSegmentAttrs,
866
+ id: this.opts.id.current,
867
+ inputmode: "text",
868
+ "aria-label": "AM/PM",
869
+ "aria-valuemin": valueMin,
870
+ "aria-valuemax": valueMax,
871
+ "aria-valuenow": valueNow,
872
+ "aria-valuetext": valueText,
873
+ onkeydown: this.onkeydown,
874
+ onclick: this.root.handleSegmentClick,
875
+ ...this.root.getBaseSegmentAttrs("dayPeriod", this.opts.id.current),
876
+ ...attachRef(this.opts.ref, (v) => (this.root.dayPeriodNode = v)),
877
+ };
878
+ });
879
+ }
880
+ class TimeFieldLiteralSegmentState {
881
+ opts;
882
+ root;
883
+ constructor(opts, root) {
884
+ this.opts = opts;
885
+ this.root = root;
886
+ }
887
+ props = $derived.by(() => ({
888
+ id: this.opts.id.current,
889
+ "aria-hidden": getAriaHidden(true),
890
+ ...this.root.getBaseSegmentAttrs("literal", this.opts.id.current),
891
+ ...attachRef(this.opts.ref),
892
+ }));
893
+ }
894
+ class TimeFieldTimeZoneSegmentState {
895
+ opts;
896
+ root;
897
+ constructor(opts, root) {
898
+ this.opts = opts;
899
+ this.root = root;
900
+ this.onkeydown = this.onkeydown.bind(this);
901
+ }
902
+ onkeydown(e) {
903
+ if (e.key !== kbd.TAB)
904
+ e.preventDefault();
905
+ if (this.root.disabled.current)
906
+ return;
907
+ if (isSegmentNavigationKey(e.key)) {
908
+ handleTimeSegmentNavigation(e, this.root.getFieldNode());
909
+ }
910
+ }
911
+ props = $derived.by(() => ({
912
+ role: "textbox",
913
+ id: this.opts.id.current,
914
+ "aria-label": "timezone, ",
915
+ style: {
916
+ caretColor: "transparent",
917
+ },
918
+ onkeydown: this.onkeydown,
919
+ tabindex: 0,
920
+ ...this.root.getBaseSegmentAttrs("timeZoneName", this.opts.id.current),
921
+ "data-readonly": getDataReadonly(true),
922
+ ...attachRef(this.opts.ref),
923
+ }));
924
+ }
925
+ // Utils/helpers
926
+ function isAcceptableDayPeriodKey(key) {
927
+ return (isAcceptableSegmentKey(key) ||
928
+ key === kbd.A ||
929
+ key === kbd.P ||
930
+ key === kbd.a ||
931
+ key === kbd.p);
932
+ }
933
+ function isArrowUp(key) {
934
+ return key === kbd.ARROW_UP;
935
+ }
936
+ function isArrowDown(key) {
937
+ return key === kbd.ARROW_DOWN;
938
+ }
939
+ function isBackspace(key) {
940
+ return key === kbd.BACKSPACE;
941
+ }
942
+ const TimeFieldRootContext = new Context("TimeField.Root");
943
+ export function useTimeFieldRoot(props, rangeRoot) {
944
+ return TimeFieldRootContext.set(new TimeFieldRootState(props, rangeRoot));
945
+ }
946
+ export function useTimeFieldInput(props) {
947
+ return new TimeFieldInputState(props, TimeFieldRootContext.get());
948
+ }
949
+ export function useTimeFieldHiddenInput() {
950
+ return new TimeFieldHiddenInputState(TimeFieldRootContext.get());
951
+ }
952
+ export function useTimeFieldSegment(part, props) {
953
+ return segmentPartToInstance({
954
+ part,
955
+ segmentProps: props,
956
+ root: TimeFieldRootContext.get(),
957
+ });
958
+ }
959
+ export function useTimeFieldLabel(props) {
960
+ return new TimeFieldLabelState(props, TimeFieldRootContext.get());
961
+ }
962
+ function segmentPartToInstance(props) {
963
+ switch (props.part) {
964
+ case "hour":
965
+ return new TimeFieldHourSegmentState(props.segmentProps, props.root);
966
+ case "minute":
967
+ return new TimeFieldMinuteSegmentState(props.segmentProps, props.root);
968
+ case "second":
969
+ return new TimeFieldSecondSegmentState(props.segmentProps, props.root);
970
+ case "dayPeriod":
971
+ return new TimeFieldDayPeriodSegmentState(props.segmentProps, props.root);
972
+ case "literal":
973
+ return new TimeFieldLiteralSegmentState(props.segmentProps, props.root);
974
+ case "timeZoneName":
975
+ return new TimeFieldTimeZoneSegmentState(props.segmentProps, props.root);
976
+ default:
977
+ // For any date-related parts that shouldn't appear in time field
978
+ throw new Error(`Invalid segment part for time field: ${props.part}`);
979
+ }
980
+ }