sheer-ui 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (635) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -0
  3. package/package.json +369 -0
  4. package/src/lib/VENDORED.md +109 -0
  5. package/src/lib/assets/ui.css +733 -0
  6. package/src/lib/blocks/Appearance.svelte +104 -0
  7. package/src/lib/blocks/BoundaryFailed.svelte +33 -0
  8. package/src/lib/blocks/ErrorPage.svelte +65 -0
  9. package/src/lib/blocks/Footer.svelte +71 -0
  10. package/src/lib/blocks/Header.svelte +67 -0
  11. package/src/lib/blocks/Heading.svelte +86 -0
  12. package/src/lib/blocks/MobileNav.svelte +169 -0
  13. package/src/lib/blocks/PhoneInput.svelte +68 -0
  14. package/src/lib/blocks/Section.svelte +34 -0
  15. package/src/lib/blocks/alert-modal/AlertModal.svelte +83 -0
  16. package/src/lib/blocks/alert-modal/alert-modal.svelte.ts +81 -0
  17. package/src/lib/blocks/alert-modal/index.ts +2 -0
  18. package/src/lib/blocks/calendar.svelte +155 -0
  19. package/src/lib/blocks/copy-button/copy-button.svelte +43 -0
  20. package/src/lib/blocks/copy-button/copy.svelte.ts +52 -0
  21. package/src/lib/blocks/copy-button/index.ts +2 -0
  22. package/src/lib/blocks/date-picker/date-picker-with-presets.svelte +109 -0
  23. package/src/lib/blocks/date-picker/date-picker.svelte +91 -0
  24. package/src/lib/blocks/date-picker/index.ts +13 -0
  25. package/src/lib/blocks/date-picker/range-date-picker.svelte +128 -0
  26. package/src/lib/blocks/index.ts +12 -0
  27. package/src/lib/blocks/mockups/Browser.svelte +22 -0
  28. package/src/lib/blocks/mockups/Phone.svelte +44 -0
  29. package/src/lib/blocks/mockups/index.ts +2 -0
  30. package/src/lib/blocks/tab-nav/index.ts +1 -0
  31. package/src/lib/blocks/tab-nav/tab-nav.svelte +46 -0
  32. package/src/lib/blocks/time-picker/index.ts +16 -0
  33. package/src/lib/blocks/time-picker/time-input.svelte +118 -0
  34. package/src/lib/blocks/time-picker/time-picker.svelte +93 -0
  35. package/src/lib/blocks/time-picker/time-range-input.svelte +34 -0
  36. package/src/lib/blocks/time-picker/time-range-picker.svelte +180 -0
  37. package/src/lib/blocks/time-picker/time-slots.ts +61 -0
  38. package/src/lib/blocks/user-avatar/UserAvatar.svelte +36 -0
  39. package/src/lib/blocks/user-avatar/index.ts +1 -0
  40. package/src/lib/blocks/verification-code-field/VerificationCodeField.svelte +57 -0
  41. package/src/lib/blocks/verification-code-field/index.ts +1 -0
  42. package/src/lib/components/accordion/accordion.svelte.ts +43 -0
  43. package/src/lib/components/accordion/components/accordion-content.svelte +17 -0
  44. package/src/lib/components/accordion/components/accordion-item.svelte +58 -0
  45. package/src/lib/components/accordion/components/accordion-trigger.svelte +38 -0
  46. package/src/lib/components/accordion/components/accordion.svelte +24 -0
  47. package/src/lib/components/accordion/index.ts +11 -0
  48. package/src/lib/components/accordion/types.ts +19 -0
  49. package/src/lib/components/alert/alert-action.svelte +11 -0
  50. package/src/lib/components/alert/alert-description.svelte +18 -0
  51. package/src/lib/components/alert/alert-title.svelte +18 -0
  52. package/src/lib/components/alert/alert.svelte +37 -0
  53. package/src/lib/components/alert/index.ts +17 -0
  54. package/src/lib/components/avatar/avatar.svelte.ts +154 -0
  55. package/src/lib/components/avatar/components/avatar-fallback.svelte +38 -0
  56. package/src/lib/components/avatar/components/avatar-image.svelte +47 -0
  57. package/src/lib/components/avatar/components/avatar.svelte +57 -0
  58. package/src/lib/components/avatar/index.ts +9 -0
  59. package/src/lib/components/avatar/types.ts +46 -0
  60. package/src/lib/components/badge/badge.svelte +49 -0
  61. package/src/lib/components/badge/index.ts +1 -0
  62. package/src/lib/components/breadcrumb/breadcrumb-ellipsis.svelte +23 -0
  63. package/src/lib/components/breadcrumb/breadcrumb-item.svelte +11 -0
  64. package/src/lib/components/breadcrumb/breadcrumb-link.svelte +32 -0
  65. package/src/lib/components/breadcrumb/breadcrumb-list.svelte +15 -0
  66. package/src/lib/components/breadcrumb/breadcrumb-page.svelte +18 -0
  67. package/src/lib/components/breadcrumb/breadcrumb-separator.svelte +22 -0
  68. package/src/lib/components/breadcrumb/breadcrumb.svelte +10 -0
  69. package/src/lib/components/breadcrumb/index.ts +25 -0
  70. package/src/lib/components/button/button.svelte +55 -0
  71. package/src/lib/components/button/index.ts +12 -0
  72. package/src/lib/components/button/variants.ts +51 -0
  73. package/src/lib/components/calendar/calendar.svelte.ts +1081 -0
  74. package/src/lib/components/calendar/components/calendar-cell.svelte +34 -0
  75. package/src/lib/components/calendar/components/calendar-day.svelte +36 -0
  76. package/src/lib/components/calendar/components/calendar-grid-body.svelte +29 -0
  77. package/src/lib/components/calendar/components/calendar-grid-head.svelte +29 -0
  78. package/src/lib/components/calendar/components/calendar-grid-row.svelte +29 -0
  79. package/src/lib/components/calendar/components/calendar-grid.svelte +29 -0
  80. package/src/lib/components/calendar/components/calendar-head-cell.svelte +29 -0
  81. package/src/lib/components/calendar/components/calendar-header.svelte +29 -0
  82. package/src/lib/components/calendar/components/calendar-heading.svelte +33 -0
  83. package/src/lib/components/calendar/components/calendar-month-select.svelte +50 -0
  84. package/src/lib/components/calendar/components/calendar-next-button.svelte +37 -0
  85. package/src/lib/components/calendar/components/calendar-prev-button.svelte +37 -0
  86. package/src/lib/components/calendar/components/calendar-year-select.svelte +50 -0
  87. package/src/lib/components/calendar/components/calendar.svelte +123 -0
  88. package/src/lib/components/calendar/exports.ts +31 -0
  89. package/src/lib/components/calendar/index.ts +2 -0
  90. package/src/lib/components/calendar/types.ts +417 -0
  91. package/src/lib/components/card/card-action.svelte +15 -0
  92. package/src/lib/components/card/card-content.svelte +11 -0
  93. package/src/lib/components/card/card-description.svelte +11 -0
  94. package/src/lib/components/card/card-footer.svelte +11 -0
  95. package/src/lib/components/card/card-header.svelte +18 -0
  96. package/src/lib/components/card/card-title.svelte +11 -0
  97. package/src/lib/components/card/card.svelte +15 -0
  98. package/src/lib/components/card/index.ts +25 -0
  99. package/src/lib/components/carousel/carousel-arrow.svelte +42 -0
  100. package/src/lib/components/carousel/carousel-content.svelte +25 -0
  101. package/src/lib/components/carousel/carousel-dots.svelte +21 -0
  102. package/src/lib/components/carousel/carousel-item.svelte +21 -0
  103. package/src/lib/components/carousel/carousel-next.svelte +9 -0
  104. package/src/lib/components/carousel/carousel-previous.svelte +9 -0
  105. package/src/lib/components/carousel/carousel.svelte +245 -0
  106. package/src/lib/components/carousel/carouselState.svelte.ts +30 -0
  107. package/src/lib/components/carousel/index.ts +24 -0
  108. package/src/lib/components/chart/chart-container.svelte +52 -0
  109. package/src/lib/components/chart/chart-style.svelte +29 -0
  110. package/src/lib/components/chart/chart-tooltip.svelte +163 -0
  111. package/src/lib/components/chart/chart-utils.ts +50 -0
  112. package/src/lib/components/chart/index.ts +6 -0
  113. package/src/lib/components/checkbox/checkbox.svelte.ts +199 -0
  114. package/src/lib/components/checkbox/components/checkbox-group-label.svelte +29 -0
  115. package/src/lib/components/checkbox/components/checkbox-group.svelte +48 -0
  116. package/src/lib/components/checkbox/components/checkbox.svelte +85 -0
  117. package/src/lib/components/checkbox/index.ts +9 -0
  118. package/src/lib/components/checkbox/types.ts +131 -0
  119. package/src/lib/components/checkbox-native/checkbox.svelte +96 -0
  120. package/src/lib/components/checkbox-native/index.ts +8 -0
  121. package/src/lib/components/collapsible/components/collapsible-content.svelte +16 -0
  122. package/src/lib/components/collapsible/components/collapsible-trigger.svelte +14 -0
  123. package/src/lib/components/collapsible/components/collapsible.svelte +68 -0
  124. package/src/lib/components/collapsible/index.ts +9 -0
  125. package/src/lib/components/collapsible/types.ts +25 -0
  126. package/src/lib/components/combobox/components/combobox-arrow.svelte +8 -0
  127. package/src/lib/components/combobox/components/combobox-input.svelte +46 -0
  128. package/src/lib/components/combobox/components/combobox-trigger.svelte +44 -0
  129. package/src/lib/components/combobox/components/combobox.svelte +83 -0
  130. package/src/lib/components/combobox/index.ts +30 -0
  131. package/src/lib/components/combobox/select/components/select-content-static.svelte +56 -0
  132. package/src/lib/components/combobox/select/components/select-content.svelte +95 -0
  133. package/src/lib/components/combobox/select/components/select-group-heading.svelte +51 -0
  134. package/src/lib/components/combobox/select/components/select-group.svelte +51 -0
  135. package/src/lib/components/combobox/select/components/select-hidden-input.svelte +16 -0
  136. package/src/lib/components/combobox/select/components/select-item.svelte +86 -0
  137. package/src/lib/components/combobox/select/components/select-scroll-down-button.svelte +41 -0
  138. package/src/lib/components/combobox/select/components/select-scroll-up-button.svelte +34 -0
  139. package/src/lib/components/combobox/select/components/select-trigger.svelte +32 -0
  140. package/src/lib/components/combobox/select/components/select-value.svelte +40 -0
  141. package/src/lib/components/combobox/select/components/select-viewport.svelte +29 -0
  142. package/src/lib/components/combobox/select/components/select.svelte +92 -0
  143. package/src/lib/components/combobox/select/select.svelte.ts +1596 -0
  144. package/src/lib/components/combobox/select/types.ts +291 -0
  145. package/src/lib/components/combobox/types.ts +77 -0
  146. package/src/lib/components/command/command-dialog.svelte +42 -0
  147. package/src/lib/components/command/command.svelte.ts +1506 -0
  148. package/src/lib/components/command/components/_command-label.svelte +31 -0
  149. package/src/lib/components/command/components/command-empty.svelte +34 -0
  150. package/src/lib/components/command/components/command-group-heading.svelte +29 -0
  151. package/src/lib/components/command/components/command-group-items.svelte +31 -0
  152. package/src/lib/components/command/components/command-group.svelte +76 -0
  153. package/src/lib/components/command/components/command-input.svelte +55 -0
  154. package/src/lib/components/command/components/command-item.svelte +61 -0
  155. package/src/lib/components/command/components/command-link-item.svelte +61 -0
  156. package/src/lib/components/command/components/command-list.svelte +41 -0
  157. package/src/lib/components/command/components/command-loading.svelte +30 -0
  158. package/src/lib/components/command/components/command-separator.svelte +34 -0
  159. package/src/lib/components/command/components/command-viewport.svelte +29 -0
  160. package/src/lib/components/command/components/command.svelte +143 -0
  161. package/src/lib/components/command/compute-command-score.ts +207 -0
  162. package/src/lib/components/command/index.ts +29 -0
  163. package/src/lib/components/command/types.ts +222 -0
  164. package/src/lib/components/command/utils.ts +30 -0
  165. package/src/lib/components/context-menu/components/context-menu-content-static.svelte +22 -0
  166. package/src/lib/components/context-menu/components/context-menu-content.svelte +22 -0
  167. package/src/lib/components/context-menu/components/context-menu-trigger.svelte +46 -0
  168. package/src/lib/components/context-menu/components/context-menu.svelte +8 -0
  169. package/src/lib/components/context-menu/index.ts +39 -0
  170. package/src/lib/components/context-menu/types.ts +56 -0
  171. package/src/lib/components/data-table/column-helpers.ts +97 -0
  172. package/src/lib/components/data-table/data-table-checkbox.svelte +25 -0
  173. package/src/lib/components/data-table/data-table-sort-button.svelte +16 -0
  174. package/src/lib/components/data-table/flex-render.svelte +42 -0
  175. package/src/lib/components/data-table/index.ts +29 -0
  176. package/src/lib/components/data-table/render-helpers.ts +105 -0
  177. package/src/lib/components/data-table/table-cell.svelte +9 -0
  178. package/src/lib/components/data-table/table-column-header.svelte +51 -0
  179. package/src/lib/components/data-table/table-faceted-filter.svelte +109 -0
  180. package/src/lib/components/data-table/table-pagination.svelte +54 -0
  181. package/src/lib/components/data-table/table-priority-cell.svelte +22 -0
  182. package/src/lib/components/data-table/table-row-actions.svelte +29 -0
  183. package/src/lib/components/data-table/table-status-cell.svelte +34 -0
  184. package/src/lib/components/data-table/table-title-cell.svelte +24 -0
  185. package/src/lib/components/data-table/table-toolbar.svelte +55 -0
  186. package/src/lib/components/data-table/table-view-options.svelte +25 -0
  187. package/src/lib/components/date-field/components/date-field-hidden-input.svelte +9 -0
  188. package/src/lib/components/date-field/components/date-field-input.svelte +33 -0
  189. package/src/lib/components/date-field/components/date-field-label.svelte +29 -0
  190. package/src/lib/components/date-field/components/date-field-segment.svelte +29 -0
  191. package/src/lib/components/date-field/components/date-field.svelte +106 -0
  192. package/src/lib/components/date-field/date-field.svelte.ts +1474 -0
  193. package/src/lib/components/date-field/index.ts +11 -0
  194. package/src/lib/components/date-field/types.ts +165 -0
  195. package/src/lib/components/date-range-field/components/date-range-field-input.svelte +36 -0
  196. package/src/lib/components/date-range-field/components/date-range-field-label.svelte +29 -0
  197. package/src/lib/components/date-range-field/components/date-range-field.svelte +106 -0
  198. package/src/lib/components/date-range-field/date-range-field.svelte.ts +212 -0
  199. package/src/lib/components/date-range-field/index.ts +11 -0
  200. package/src/lib/components/date-range-field/types.ts +171 -0
  201. package/src/lib/components/dialog/components/dialog-close.svelte +31 -0
  202. package/src/lib/components/dialog/components/dialog-content-headless.svelte +104 -0
  203. package/src/lib/components/dialog/components/dialog-content.svelte +69 -0
  204. package/src/lib/components/dialog/components/dialog-description.svelte +29 -0
  205. package/src/lib/components/dialog/components/dialog-overlay.svelte +31 -0
  206. package/src/lib/components/dialog/components/dialog-title.svelte +30 -0
  207. package/src/lib/components/dialog/components/dialog-trigger.svelte +30 -0
  208. package/src/lib/components/dialog/components/dialog.svelte +21 -0
  209. package/src/lib/components/dialog/components/modal-surface.svelte +131 -0
  210. package/src/lib/components/dialog/dialog.svelte.ts +371 -0
  211. package/src/lib/components/dialog/index.ts +19 -0
  212. package/src/lib/components/dialog/types.ts +105 -0
  213. package/src/lib/components/drawer/drawer-close.svelte +7 -0
  214. package/src/lib/components/drawer/drawer-content.svelte +91 -0
  215. package/src/lib/components/drawer/drawer-description.svelte +8 -0
  216. package/src/lib/components/drawer/drawer-footer.svelte +11 -0
  217. package/src/lib/components/drawer/drawer-header.svelte +11 -0
  218. package/src/lib/components/drawer/drawer-nested.svelte +44 -0
  219. package/src/lib/components/drawer/drawer-overlay.svelte +60 -0
  220. package/src/lib/components/drawer/drawer-portal.svelte +10 -0
  221. package/src/lib/components/drawer/drawer-title.svelte +8 -0
  222. package/src/lib/components/drawer/drawer-trigger.svelte +7 -0
  223. package/src/lib/components/drawer/drawer.svelte +290 -0
  224. package/src/lib/components/drawer/index.ts +37 -0
  225. package/src/lib/components/dropdown-menu/components/dropdown-menu-content-static.svelte +22 -0
  226. package/src/lib/components/dropdown-menu/components/dropdown-menu-content.svelte +22 -0
  227. package/src/lib/components/dropdown-menu/index.ts +39 -0
  228. package/src/lib/components/dropdown-menu/types.ts +41 -0
  229. package/src/lib/components/empty/empty-content.svelte +15 -0
  230. package/src/lib/components/empty/empty-description.svelte +15 -0
  231. package/src/lib/components/empty/empty-header.svelte +15 -0
  232. package/src/lib/components/empty/empty-media.svelte +21 -0
  233. package/src/lib/components/empty/empty-title.svelte +11 -0
  234. package/src/lib/components/empty/empty.svelte +18 -0
  235. package/src/lib/components/empty/index.ts +22 -0
  236. package/src/lib/components/empty/variants.ts +16 -0
  237. package/src/lib/components/field/field-content.svelte +14 -0
  238. package/src/lib/components/field/field-description.svelte +19 -0
  239. package/src/lib/components/field/field-error.svelte +47 -0
  240. package/src/lib/components/field/field-group.svelte +17 -0
  241. package/src/lib/components/field/field-label.svelte +18 -0
  242. package/src/lib/components/field/field-legend.svelte +23 -0
  243. package/src/lib/components/field/field-separator.svelte +32 -0
  244. package/src/lib/components/field/field-set.svelte +14 -0
  245. package/src/lib/components/field/field-title.svelte +14 -0
  246. package/src/lib/components/field/field.svelte +36 -0
  247. package/src/lib/components/field/index.ts +32 -0
  248. package/src/lib/components/field/variants.ts +19 -0
  249. package/src/lib/components/input/file-input.svelte +26 -0
  250. package/src/lib/components/input/index.ts +12 -0
  251. package/src/lib/components/input/input.svelte +24 -0
  252. package/src/lib/components/input/variants.ts +28 -0
  253. package/src/lib/components/item/index.ts +34 -0
  254. package/src/lib/components/item/item-actions.svelte +11 -0
  255. package/src/lib/components/item/item-content.svelte +15 -0
  256. package/src/lib/components/item/item-description.svelte +18 -0
  257. package/src/lib/components/item/item-footer.svelte +11 -0
  258. package/src/lib/components/item/item-group.svelte +16 -0
  259. package/src/lib/components/item/item-header.svelte +11 -0
  260. package/src/lib/components/item/item-media.svelte +37 -0
  261. package/src/lib/components/item/item-separator.svelte +9 -0
  262. package/src/lib/components/item/item-title.svelte +15 -0
  263. package/src/lib/components/item/item.svelte +61 -0
  264. package/src/lib/components/kbd/index.ts +10 -0
  265. package/src/lib/components/kbd/kbd-group.svelte +11 -0
  266. package/src/lib/components/kbd/kbd.svelte +18 -0
  267. package/src/lib/components/label/exports.ts +2 -0
  268. package/src/lib/components/label/index.ts +2 -0
  269. package/src/lib/components/label/label.svelte +39 -0
  270. package/src/lib/components/label/label.svelte.ts +39 -0
  271. package/src/lib/components/label/types.ts +7 -0
  272. package/src/lib/components/link-preview/components/link-preview-content.svelte +60 -0
  273. package/src/lib/components/link-preview/components/link-preview-trigger.svelte +29 -0
  274. package/src/lib/components/link-preview/components/link-preview.svelte +34 -0
  275. package/src/lib/components/link-preview/exports.ts +11 -0
  276. package/src/lib/components/link-preview/index.ts +2 -0
  277. package/src/lib/components/link-preview/link-preview.svelte.ts +270 -0
  278. package/src/lib/components/link-preview/types.ts +102 -0
  279. package/src/lib/components/menu/components/menu-arrow.svelte +14 -0
  280. package/src/lib/components/menu/components/menu-checkbox-group.svelte +42 -0
  281. package/src/lib/components/menu/components/menu-checkbox-item.svelte +85 -0
  282. package/src/lib/components/menu/components/menu-content.svelte +98 -0
  283. package/src/lib/components/menu/components/menu-group-heading.svelte +47 -0
  284. package/src/lib/components/menu/components/menu-group.svelte +36 -0
  285. package/src/lib/components/menu/components/menu-item.svelte +58 -0
  286. package/src/lib/components/menu/components/menu-radio-group.svelte +44 -0
  287. package/src/lib/components/menu/components/menu-radio-item.svelte +65 -0
  288. package/src/lib/components/menu/components/menu-separator.svelte +38 -0
  289. package/src/lib/components/menu/components/menu-sub-content-static.svelte +8 -0
  290. package/src/lib/components/menu/components/menu-sub-content.svelte +133 -0
  291. package/src/lib/components/menu/components/menu-sub-trigger.svelte +60 -0
  292. package/src/lib/components/menu/components/menu-sub.svelte +23 -0
  293. package/src/lib/components/menu/components/menu-trigger.svelte +50 -0
  294. package/src/lib/components/menu/components/menu.svelte +58 -0
  295. package/src/lib/components/menu/exports.ts +38 -0
  296. package/src/lib/components/menu/menu.svelte.ts +1599 -0
  297. package/src/lib/components/menu/types.ts +285 -0
  298. package/src/lib/components/menu/utils.ts +68 -0
  299. package/src/lib/components/menubar/components/menubar-content-static.svelte +50 -0
  300. package/src/lib/components/menubar/components/menubar-content.svelte +54 -0
  301. package/src/lib/components/menubar/components/menubar-menu.svelte +34 -0
  302. package/src/lib/components/menubar/components/menubar-trigger.svelte +50 -0
  303. package/src/lib/components/menubar/components/menubar.svelte +57 -0
  304. package/src/lib/components/menubar/exports.ts +44 -0
  305. package/src/lib/components/menubar/index.ts +2 -0
  306. package/src/lib/components/menubar/menubar.svelte.ts +394 -0
  307. package/src/lib/components/menubar/types.ts +97 -0
  308. package/src/lib/components/meter/components/meter.svelte +41 -0
  309. package/src/lib/components/meter/exports.ts +2 -0
  310. package/src/lib/components/meter/index.ts +2 -0
  311. package/src/lib/components/meter/meter.svelte.ts +47 -0
  312. package/src/lib/components/meter/types.ts +28 -0
  313. package/src/lib/components/navigation-menu/components/navigation-menu-content-impl.svelte +85 -0
  314. package/src/lib/components/navigation-menu/components/navigation-menu-content.svelte +58 -0
  315. package/src/lib/components/navigation-menu/components/navigation-menu-indicator-impl.svelte +29 -0
  316. package/src/lib/components/navigation-menu/components/navigation-menu-indicator.svelte +56 -0
  317. package/src/lib/components/navigation-menu/components/navigation-menu-item.svelte +56 -0
  318. package/src/lib/components/navigation-menu/components/navigation-menu-link.svelte +64 -0
  319. package/src/lib/components/navigation-menu/components/navigation-menu-list.svelte +59 -0
  320. package/src/lib/components/navigation-menu/components/navigation-menu-sub.svelte +46 -0
  321. package/src/lib/components/navigation-menu/components/navigation-menu-trigger.svelte +80 -0
  322. package/src/lib/components/navigation-menu/components/navigation-menu-viewport.svelte +63 -0
  323. package/src/lib/components/navigation-menu/components/navigation-menu.svelte +80 -0
  324. package/src/lib/components/navigation-menu/index.ts +28 -0
  325. package/src/lib/components/navigation-menu/navigation-menu.svelte.ts +1092 -0
  326. package/src/lib/components/navigation-menu/types.ts +189 -0
  327. package/src/lib/components/pagination/components/pagination-next-button.svelte +60 -0
  328. package/src/lib/components/pagination/components/pagination-page.svelte +65 -0
  329. package/src/lib/components/pagination/components/pagination-prev-button.svelte +60 -0
  330. package/src/lib/components/pagination/components/pagination.svelte +65 -0
  331. package/src/lib/components/pagination/index.ts +11 -0
  332. package/src/lib/components/pagination/pagination.svelte.ts +275 -0
  333. package/src/lib/components/pagination/types.ts +100 -0
  334. package/src/lib/components/pin-input/components/pin-input-cell.svelte +49 -0
  335. package/src/lib/components/pin-input/components/pin-input.svelte +76 -0
  336. package/src/lib/components/pin-input/exports.ts +4 -0
  337. package/src/lib/components/pin-input/index.ts +2 -0
  338. package/src/lib/components/pin-input/pin-input.svelte.ts +541 -0
  339. package/src/lib/components/pin-input/types.ts +118 -0
  340. package/src/lib/components/pin-input/usePasswordManager.svelte.ts +122 -0
  341. package/src/lib/components/popover/components/popover-close.svelte +38 -0
  342. package/src/lib/components/popover/components/popover-content.svelte +70 -0
  343. package/src/lib/components/popover/components/popover-header.svelte +11 -0
  344. package/src/lib/components/popover/components/popover-title.svelte +11 -0
  345. package/src/lib/components/popover/components/popover-trigger.svelte +44 -0
  346. package/src/lib/components/popover/components/popover.svelte +26 -0
  347. package/src/lib/components/popover/exports.ts +13 -0
  348. package/src/lib/components/popover/index.ts +2 -0
  349. package/src/lib/components/popover/popover.svelte.ts +392 -0
  350. package/src/lib/components/popover/types.ts +92 -0
  351. package/src/lib/components/progress/components/progress.svelte +56 -0
  352. package/src/lib/components/progress/exports.ts +3 -0
  353. package/src/lib/components/progress/index.ts +2 -0
  354. package/src/lib/components/progress/progress.svelte.ts +58 -0
  355. package/src/lib/components/progress/types.ts +28 -0
  356. package/src/lib/components/radio-group/context.ts +13 -0
  357. package/src/lib/components/radio-group/index.ts +10 -0
  358. package/src/lib/components/radio-group/radio-group-item.svelte +67 -0
  359. package/src/lib/components/radio-group/radio-group.svelte +87 -0
  360. package/src/lib/components/range-calendar/components/range-calendar-cell.svelte +31 -0
  361. package/src/lib/components/range-calendar/components/range-calendar-day.svelte +33 -0
  362. package/src/lib/components/range-calendar/components/range-calendar.svelte +120 -0
  363. package/src/lib/components/range-calendar/exports.ts +31 -0
  364. package/src/lib/components/range-calendar/index.ts +2 -0
  365. package/src/lib/components/range-calendar/range-calendar.svelte.ts +739 -0
  366. package/src/lib/components/range-calendar/types.ts +258 -0
  367. package/src/lib/components/resizable/index.ts +15 -0
  368. package/src/lib/components/resizable/resizable-handle.svelte +30 -0
  369. package/src/lib/components/resizable/resizable-pane-group.svelte +19 -0
  370. package/src/lib/components/scroll-area/components/scroll-area-corner-impl.svelte +34 -0
  371. package/src/lib/components/scroll-area/components/scroll-area-corner.svelte +18 -0
  372. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-auto.svelte +15 -0
  373. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-hover.svelte +22 -0
  374. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-scroll.svelte +16 -0
  375. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-shared.svelte +19 -0
  376. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-visible.svelte +16 -0
  377. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-x.svelte +23 -0
  378. package/src/lib/components/scroll-area/components/scroll-area-scrollbar-y.svelte +24 -0
  379. package/src/lib/components/scroll-area/components/scroll-area-scrollbar.svelte +56 -0
  380. package/src/lib/components/scroll-area/components/scroll-area-thumb-impl.svelte +49 -0
  381. package/src/lib/components/scroll-area/components/scroll-area-thumb.svelte +21 -0
  382. package/src/lib/components/scroll-area/components/scroll-area-viewport.svelte +39 -0
  383. package/src/lib/components/scroll-area/components/scroll-area.svelte +82 -0
  384. package/src/lib/components/scroll-area/exports.ts +13 -0
  385. package/src/lib/components/scroll-area/index.ts +2 -0
  386. package/src/lib/components/scroll-area/scroll-area.svelte.ts +946 -0
  387. package/src/lib/components/scroll-area/types.ts +67 -0
  388. package/src/lib/components/select/index.ts +5 -0
  389. package/src/lib/components/select/select-opt-group.svelte +10 -0
  390. package/src/lib/components/select/select-option.svelte +15 -0
  391. package/src/lib/components/select/select.svelte +281 -0
  392. package/src/lib/components/separator/components/separator.svelte +49 -0
  393. package/src/lib/components/separator/index.ts +3 -0
  394. package/src/lib/components/separator/separator.svelte.ts +43 -0
  395. package/src/lib/components/separator/types.ts +22 -0
  396. package/src/lib/components/sheet/components/sheet-close.svelte +8 -0
  397. package/src/lib/components/sheet/components/sheet-content.svelte +108 -0
  398. package/src/lib/components/sheet/components/sheet-description.svelte +9 -0
  399. package/src/lib/components/sheet/components/sheet-footer.svelte +11 -0
  400. package/src/lib/components/sheet/components/sheet-header.svelte +11 -0
  401. package/src/lib/components/sheet/components/sheet-overlay.svelte +13 -0
  402. package/src/lib/components/sheet/components/sheet-title.svelte +9 -0
  403. package/src/lib/components/sheet/components/sheet-trigger.svelte +8 -0
  404. package/src/lib/components/sheet/index.ts +47 -0
  405. package/src/lib/components/sheet/variants.ts +20 -0
  406. package/src/lib/components/sidebar/constants.ts +6 -0
  407. package/src/lib/components/sidebar/context.svelte.ts +54 -0
  408. package/src/lib/components/sidebar/index.ts +77 -0
  409. package/src/lib/components/sidebar/sidebar-content.svelte +16 -0
  410. package/src/lib/components/sidebar/sidebar-desktop-surface.svelte +60 -0
  411. package/src/lib/components/sidebar/sidebar-footer.svelte +11 -0
  412. package/src/lib/components/sidebar/sidebar-group-action.svelte +34 -0
  413. package/src/lib/components/sidebar/sidebar-group-content.svelte +16 -0
  414. package/src/lib/components/sidebar/sidebar-group-label.svelte +34 -0
  415. package/src/lib/components/sidebar/sidebar-group.svelte +16 -0
  416. package/src/lib/components/sidebar/sidebar-header.svelte +11 -0
  417. package/src/lib/components/sidebar/sidebar-input.svelte +14 -0
  418. package/src/lib/components/sidebar/sidebar-inset.svelte +18 -0
  419. package/src/lib/components/sidebar/sidebar-menu-action.svelte +38 -0
  420. package/src/lib/components/sidebar/sidebar-menu-badge.svelte +19 -0
  421. package/src/lib/components/sidebar/sidebar-menu-button.svelte +99 -0
  422. package/src/lib/components/sidebar/sidebar-menu-item.svelte +21 -0
  423. package/src/lib/components/sidebar/sidebar-menu-skeleton.svelte +34 -0
  424. package/src/lib/components/sidebar/sidebar-menu-sub-button.svelte +40 -0
  425. package/src/lib/components/sidebar/sidebar-menu-sub-item.svelte +16 -0
  426. package/src/lib/components/sidebar/sidebar-menu-sub.svelte +19 -0
  427. package/src/lib/components/sidebar/sidebar-menu.svelte +21 -0
  428. package/src/lib/components/sidebar/sidebar-mobile-surface.svelte +48 -0
  429. package/src/lib/components/sidebar/sidebar-provider.svelte +60 -0
  430. package/src/lib/components/sidebar/sidebar-rail.svelte +36 -0
  431. package/src/lib/components/sidebar/sidebar-separator.svelte +9 -0
  432. package/src/lib/components/sidebar/sidebar-trigger.svelte +35 -0
  433. package/src/lib/components/sidebar/sidebar.svelte +30 -0
  434. package/src/lib/components/sidebar/types.ts +14 -0
  435. package/src/lib/components/skeleton/index.ts +7 -0
  436. package/src/lib/components/skeleton/skeleton.svelte +9 -0
  437. package/src/lib/components/slider/components/slider-range.svelte +37 -0
  438. package/src/lib/components/slider/components/slider-thumb-label.svelte +42 -0
  439. package/src/lib/components/slider/components/slider-thumb.svelte +46 -0
  440. package/src/lib/components/slider/components/slider-tick-label.svelte +42 -0
  441. package/src/lib/components/slider/components/slider-tick.svelte +28 -0
  442. package/src/lib/components/slider/components/slider.svelte +136 -0
  443. package/src/lib/components/slider/helpers.ts +249 -0
  444. package/src/lib/components/slider/index.ts +15 -0
  445. package/src/lib/components/slider/slider.svelte.ts +979 -0
  446. package/src/lib/components/slider/types.ts +294 -0
  447. package/src/lib/components/sonner/Toast.svelte +558 -0
  448. package/src/lib/components/sonner/Toaster.svelte +603 -0
  449. package/src/lib/components/sonner/index.ts +15 -0
  450. package/src/lib/components/sonner/toast-state.svelte.ts +217 -0
  451. package/src/lib/components/sonner/types.ts +384 -0
  452. package/src/lib/components/switch/index.ts +8 -0
  453. package/src/lib/components/switch/switch.svelte +78 -0
  454. package/src/lib/components/table/index.ts +28 -0
  455. package/src/lib/components/table/table-body.svelte +15 -0
  456. package/src/lib/components/table/table-caption.svelte +10 -0
  457. package/src/lib/components/table/table-cell.svelte +14 -0
  458. package/src/lib/components/table/table-footer.svelte +19 -0
  459. package/src/lib/components/table/table-head.svelte +17 -0
  460. package/src/lib/components/table/table-header.svelte +15 -0
  461. package/src/lib/components/table/table-row.svelte +14 -0
  462. package/src/lib/components/table/table.svelte +12 -0
  463. package/src/lib/components/tabs/components/tabs-content.svelte +30 -0
  464. package/src/lib/components/tabs/components/tabs-list.svelte +38 -0
  465. package/src/lib/components/tabs/components/tabs-trigger.svelte +51 -0
  466. package/src/lib/components/tabs/components/tabs.svelte +52 -0
  467. package/src/lib/components/tabs/index.ts +11 -0
  468. package/src/lib/components/tabs/tabs.svelte.ts +253 -0
  469. package/src/lib/components/tabs/types.ts +86 -0
  470. package/src/lib/components/textarea/index.ts +7 -0
  471. package/src/lib/components/textarea/textarea.svelte +23 -0
  472. package/src/lib/components/theme-toggle/index.ts +5 -0
  473. package/src/lib/components/theme-toggle/theme-toggle.svelte +49 -0
  474. package/src/lib/components/theme-toggle/theme.svelte.ts +81 -0
  475. package/src/lib/components/time-field/components/time-field-hidden-input.svelte +9 -0
  476. package/src/lib/components/time-field/components/time-field-input.svelte +33 -0
  477. package/src/lib/components/time-field/components/time-field-label.svelte +29 -0
  478. package/src/lib/components/time-field/components/time-field-segment.svelte +29 -0
  479. package/src/lib/components/time-field/components/time-field.svelte +99 -0
  480. package/src/lib/components/time-field/index.ts +11 -0
  481. package/src/lib/components/time-field/time-field.svelte.ts +1198 -0
  482. package/src/lib/components/time-field/types.ts +174 -0
  483. package/src/lib/components/time-range-field/components/time-range-field-input.svelte +36 -0
  484. package/src/lib/components/time-range-field/components/time-range-field-label.svelte +29 -0
  485. package/src/lib/components/time-range-field/components/time-range-field.svelte +104 -0
  486. package/src/lib/components/time-range-field/index.ts +11 -0
  487. package/src/lib/components/time-range-field/time-range-field.svelte.ts +235 -0
  488. package/src/lib/components/time-range-field/types.ts +181 -0
  489. package/src/lib/components/toggle/components/toggle.svelte +55 -0
  490. package/src/lib/components/toggle/index.ts +3 -0
  491. package/src/lib/components/toggle/toggle.svelte.ts +57 -0
  492. package/src/lib/components/toggle/types.ts +33 -0
  493. package/src/lib/components/toggle/variants.ts +25 -0
  494. package/src/lib/components/toggle-group/components/toggle-group-item.svelte +67 -0
  495. package/src/lib/components/toggle-group/components/toggle-group.svelte +109 -0
  496. package/src/lib/components/toggle-group/index.ts +7 -0
  497. package/src/lib/components/toggle-group/toggle-group.svelte.ts +235 -0
  498. package/src/lib/components/toggle-group/types.ts +89 -0
  499. package/src/lib/components/toolbar/components/toolbar-button.svelte +46 -0
  500. package/src/lib/components/toolbar/components/toolbar-group-item.svelte +56 -0
  501. package/src/lib/components/toolbar/components/toolbar-group.svelte +69 -0
  502. package/src/lib/components/toolbar/components/toolbar-link.svelte +39 -0
  503. package/src/lib/components/toolbar/components/toolbar.svelte +39 -0
  504. package/src/lib/components/toolbar/index.ts +13 -0
  505. package/src/lib/components/toolbar/toolbar.svelte.ts +373 -0
  506. package/src/lib/components/toolbar/types.ts +60 -0
  507. package/src/lib/components/tooltip/components/tooltip-content.svelte +81 -0
  508. package/src/lib/components/tooltip/components/tooltip-provider.svelte +26 -0
  509. package/src/lib/components/tooltip/components/tooltip-trigger.svelte +48 -0
  510. package/src/lib/components/tooltip/components/tooltip.svelte +55 -0
  511. package/src/lib/components/tooltip/index.ts +17 -0
  512. package/src/lib/components/tooltip/tooltip.svelte.ts +796 -0
  513. package/src/lib/components/tooltip/types.ts +175 -0
  514. package/src/lib/components/tooltip/utils.ts +1 -0
  515. package/src/lib/icons/google-icon.svelte +10 -0
  516. package/src/lib/icons/google-workspace.svelte +18 -0
  517. package/src/lib/icons/icon.d.ts +19 -0
  518. package/src/lib/icons/instagram.svelte +9 -0
  519. package/src/lib/icons/instantly.svelte +10 -0
  520. package/src/lib/icons/linkedin.svelte +9 -0
  521. package/src/lib/icons/mailshake.svelte +10 -0
  522. package/src/lib/icons/microsoft-365.svelte +7 -0
  523. package/src/lib/icons/passcode.svelte +12 -0
  524. package/src/lib/icons/replyio.svelte +10 -0
  525. package/src/lib/icons/smartlead.svelte +19 -0
  526. package/src/lib/icons/smtp.svelte +10 -0
  527. package/src/lib/icons/x-logo.svelte +9 -0
  528. package/src/lib/internal/animations-settled.svelte.ts +119 -0
  529. package/src/lib/internal/arrays.ts +253 -0
  530. package/src/lib/internal/attribute-types.ts +53 -0
  531. package/src/lib/internal/attrs.ts +64 -0
  532. package/src/lib/internal/body-scroll-lock.svelte.ts +330 -0
  533. package/src/lib/internal/create-id.ts +12 -0
  534. package/src/lib/internal/date-time/announcer.ts +74 -0
  535. package/src/lib/internal/date-time/calendar-helpers.svelte.ts +399 -0
  536. package/src/lib/internal/date-time/field/helpers.ts +431 -0
  537. package/src/lib/internal/date-time/field/parts.ts +15 -0
  538. package/src/lib/internal/date-time/field/range-field.svelte.ts +45 -0
  539. package/src/lib/internal/date-time/field/segments.ts +89 -0
  540. package/src/lib/internal/date-time/field/time-helpers.ts +311 -0
  541. package/src/lib/internal/date-time/formatter.ts +86 -0
  542. package/src/lib/internal/date-time/placeholders.ts +131 -0
  543. package/src/lib/internal/date-time/types.ts +121 -0
  544. package/src/lib/internal/date-time/utils.ts +243 -0
  545. package/src/lib/internal/dismissible-layer/index.ts +3 -0
  546. package/src/lib/internal/dismissible-layer/scheduler.ts +48 -0
  547. package/src/lib/internal/dismissible-layer/types.ts +57 -0
  548. package/src/lib/internal/dismissible-layer/use-dismissable-layer.svelte.ts +291 -0
  549. package/src/lib/internal/escape-layer/index.ts +3 -0
  550. package/src/lib/internal/escape-layer/types.ts +34 -0
  551. package/src/lib/internal/escape-layer/use-escape-layer.svelte.ts +91 -0
  552. package/src/lib/internal/floating-layer/components/floating-layer-arrow.svelte +35 -0
  553. package/src/lib/internal/floating-layer/components/floating-layer-content-static.svelte +19 -0
  554. package/src/lib/internal/floating-layer/components/floating-layer-content.svelte +52 -0
  555. package/src/lib/internal/floating-layer/components/floating-layer.svelte +12 -0
  556. package/src/lib/internal/floating-layer/components/index.ts +6 -0
  557. package/src/lib/internal/floating-layer/index.ts +2 -0
  558. package/src/lib/internal/floating-layer/types.ts +126 -0
  559. package/src/lib/internal/floating-layer/use-floating-layer.svelte.ts +471 -0
  560. package/src/lib/internal/focus-scope/focus-scope.svelte.ts +310 -0
  561. package/src/lib/internal/focus-scope/index.ts +4 -0
  562. package/src/lib/internal/focus-scope/types.ts +45 -0
  563. package/src/lib/internal/focus.ts +14 -0
  564. package/src/lib/internal/global-singleton.ts +10 -0
  565. package/src/lib/internal/group-value.svelte.ts +36 -0
  566. package/src/lib/internal/hover-intent-geometry.ts +96 -0
  567. package/src/lib/internal/index.ts +44 -0
  568. package/src/lib/internal/kbd.ts +60 -0
  569. package/src/lib/internal/layer-stack.ts +37 -0
  570. package/src/lib/internal/math.ts +11 -0
  571. package/src/lib/internal/merge-props.ts +7 -0
  572. package/src/lib/internal/native-dialog-controller.svelte.ts +102 -0
  573. package/src/lib/internal/native-popover.svelte.ts +173 -0
  574. package/src/lib/internal/open-cell.svelte.ts +41 -0
  575. package/src/lib/internal/paneforge/index.ts +5 -0
  576. package/src/lib/internal/paneforge/internal/constants.ts +2 -0
  577. package/src/lib/internal/paneforge/internal/helpers.ts +354 -0
  578. package/src/lib/internal/paneforge/internal/types.ts +33 -0
  579. package/src/lib/internal/paneforge/internal/utils/adjust-layout.ts +122 -0
  580. package/src/lib/internal/paneforge/internal/utils/aria.ts +36 -0
  581. package/src/lib/internal/paneforge/internal/utils/compare.ts +15 -0
  582. package/src/lib/internal/paneforge/internal/utils/is.ts +13 -0
  583. package/src/lib/internal/paneforge/internal/utils/resize.ts +31 -0
  584. package/src/lib/internal/paneforge/internal/utils/storage.ts +116 -0
  585. package/src/lib/internal/paneforge/internal/utils/style.ts +104 -0
  586. package/src/lib/internal/paneforge/pane-group.svelte +48 -0
  587. package/src/lib/internal/paneforge/pane-resizer.svelte +40 -0
  588. package/src/lib/internal/paneforge/pane.svelte +60 -0
  589. package/src/lib/internal/paneforge/paneforge.svelte.ts +821 -0
  590. package/src/lib/internal/paneforge/types.ts +179 -0
  591. package/src/lib/internal/popper-layer/index.ts +2 -0
  592. package/src/lib/internal/popper-layer/popper-content.svelte +19 -0
  593. package/src/lib/internal/popper-layer/popper-layer-inner.svelte +122 -0
  594. package/src/lib/internal/popper-layer/popper-layer.svelte +71 -0
  595. package/src/lib/internal/popper-layer/types.ts +65 -0
  596. package/src/lib/internal/portal/index.ts +2 -0
  597. package/src/lib/internal/portal/portal.svelte +61 -0
  598. package/src/lib/internal/prop-resolvers.ts +14 -0
  599. package/src/lib/internal/roving-focus-group.ts +147 -0
  600. package/src/lib/internal/roving-focus-item.svelte.ts +51 -0
  601. package/src/lib/internal/safe-polygon.svelte.ts +239 -0
  602. package/src/lib/internal/shared-state.svelte.ts +39 -0
  603. package/src/lib/internal/state-machine.ts +32 -0
  604. package/src/lib/internal/svelte-resize-observer.svelte.ts +37 -0
  605. package/src/lib/internal/tabbable.ts +398 -0
  606. package/src/lib/internal/table/core.ts +53 -0
  607. package/src/lib/internal/table/filter-fns.ts +10 -0
  608. package/src/lib/internal/table/index.ts +2 -0
  609. package/src/lib/internal/table/sorting-fns.ts +84 -0
  610. package/src/lib/internal/table/table.svelte.ts +330 -0
  611. package/src/lib/internal/table/types.ts +33 -0
  612. package/src/lib/internal/timeout-fn.svelte.ts +36 -0
  613. package/src/lib/internal/tools/box.svelte.ts +153 -0
  614. package/src/lib/internal/tools/index.ts +22 -0
  615. package/src/lib/internal/tools/types.ts +44 -0
  616. package/src/lib/internal/tools/utils/attach-ref.ts +74 -0
  617. package/src/lib/internal/tools/utils/compose-handlers.ts +36 -0
  618. package/src/lib/internal/tools/utils/dom-context.svelte.ts +63 -0
  619. package/src/lib/internal/tools/utils/dom.ts +62 -0
  620. package/src/lib/internal/tools/utils/events.ts +1 -0
  621. package/src/lib/internal/tools/utils/index.ts +5 -0
  622. package/src/lib/internal/tools/utils/strings.ts +28 -0
  623. package/src/lib/internal/typeahead.svelte.ts +48 -0
  624. package/src/lib/internal/types.ts +119 -0
  625. package/src/lib/internal/utils.ts +10 -0
  626. package/src/lib/internal/vaul/browser.ts +8 -0
  627. package/src/lib/internal/vaul/constants.ts +19 -0
  628. package/src/lib/internal/vaul/helpers.ts +39 -0
  629. package/src/lib/internal/vaul/types.ts +142 -0
  630. package/src/lib/internal/vaul/use-drawer-content.svelte.ts +219 -0
  631. package/src/lib/internal/vaul/use-drawer-root.svelte.ts +682 -0
  632. package/src/lib/internal/vaul/use-position-fixed.svelte.ts +142 -0
  633. package/src/lib/internal/vaul/use-prevent-scroll.svelte.ts +267 -0
  634. package/src/lib/internal/vaul/use-snap-points.svelte.ts +246 -0
  635. package/src/lib/time.ts +73 -0
@@ -0,0 +1,1474 @@
1
+ import type { Updater } from 'svelte/store';
2
+ import type { DateValue } from '@internationalized/date';
3
+ import {
4
+ type ReadableBox,
5
+ type WritableBox,
6
+ boxWith,
7
+ attachRef,
8
+ DOMContext,
9
+ type ReadableBoxedValues,
10
+ type WritableBoxedValues,
11
+ simpleBox,
12
+ } from '../../internal/tools/index.js';
13
+ import { createContext, onMount, untrack } from 'svelte';
14
+ import type { DateRangeFieldRootState } from '../date-range-field/date-range-field.svelte.js';
15
+ import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, WithRefOpts, RefAttachment } from '../../internal/types.js';
16
+ import { createBitsAttrs, boolToStr, boolToStrTrueOrUndef, boolToEmptyStrOrUndef } from '../../internal/attrs.js';
17
+ import { BROWSER } from 'esm-env';
18
+ import { kbd } from '../../internal/kbd.js';
19
+ import type {
20
+ DateAndTimeSegmentObj,
21
+ DateOnInvalid,
22
+ DateSegmentObj,
23
+ DateSegmentPart,
24
+ DateValidator,
25
+ Granularity,
26
+ HourCycle,
27
+ SegmentPart,
28
+ SegmentValueObj,
29
+ TimeSegmentObj,
30
+ EditableTimeSegmentPart,
31
+ } from '../../internal/date-time/types.js';
32
+ import { type Formatter, createFormatter } from '../../internal/date-time/formatter.js';
33
+ import { type Announcer, getAnnouncer } from '../../internal/date-time/announcer.js';
34
+ import {
35
+ areAllSegmentsFilled,
36
+ createContent,
37
+ getDefaultHourCycle,
38
+ getValueFromSegments,
39
+ inferGranularity,
40
+ initSegmentStates,
41
+ initializeSegmentValues,
42
+ isAcceptableDayPeriodKey,
43
+ isAcceptableSegmentKey,
44
+ isArrowDown,
45
+ isArrowUp,
46
+ isBackspace,
47
+ isDateAndTimeSegmentObj,
48
+ isDateSegmentPart,
49
+ isFirstSegment,
50
+ setDescription,
51
+ } from '../../internal/date-time/field/helpers.js';
52
+ import { DATE_SEGMENT_PARTS, EDITABLE_TIME_SEGMENT_PARTS } from '../../internal/date-time/field/parts.js';
53
+ import { getDaysInMonth, isBefore, toDate } from '../../internal/date-time/utils.js';
54
+ import {
55
+ getFirstSegment,
56
+ handleSegmentNavigation,
57
+ isSegmentNavigationKey,
58
+ moveToNextSegment,
59
+ moveToPrevSegment,
60
+ } from '../../internal/date-time/field/segments.js';
61
+
62
+ export const dateFieldAttrs = createBitsAttrs({
63
+ component: 'date-field',
64
+ parts: ['input', 'label', 'segment'],
65
+ });
66
+
67
+ // Common segment configuration
68
+ interface SegmentConfig {
69
+ min: number | ((root: DateFieldRootState) => number);
70
+ max: number | ((root: DateFieldRootState) => number);
71
+ cycle: number;
72
+ canBeZero?: boolean;
73
+ padZero?: boolean;
74
+ getAnnouncement?: (value: number, root: DateFieldRootState) => string | number;
75
+ updateLogic?: (props: { root: DateFieldRootState; prev: string | null; num: number; moveToNext: { value: boolean } }) => string | null;
76
+ }
77
+
78
+ const SEGMENT_CONFIGS: Record<'day' | 'month' | 'year' | 'hour' | 'minute' | 'second', SegmentConfig> = {
79
+ day: {
80
+ min: 1,
81
+ max: (root) => {
82
+ const segmentMonthValue = root.segmentValues.month;
83
+ const placeholder = root.value.current ?? root.placeholder.current;
84
+ return segmentMonthValue
85
+ ? getDaysInMonth(placeholder.set({ month: Number.parseInt(segmentMonthValue) }))
86
+ : getDaysInMonth(placeholder);
87
+ },
88
+ cycle: 1,
89
+ padZero: true,
90
+ },
91
+ month: {
92
+ min: 1,
93
+ max: 12,
94
+ cycle: 1,
95
+ padZero: true,
96
+ getAnnouncement: (month, root) => {
97
+ if (!root.placeholder.current) return '';
98
+ return `${month} - ${root.formatter.fullMonth(toDate(root.placeholder.current.set({ month })))}`;
99
+ },
100
+ },
101
+ year: {
102
+ min: 1,
103
+ max: 9999,
104
+ cycle: 1,
105
+ padZero: false,
106
+ },
107
+ hour: {
108
+ min: (root) => (root.hourCycle.current === 12 ? 1 : 0),
109
+ max: (root) => {
110
+ if (root.hourCycle.current === 24) return 23;
111
+ if (root.hourCycle.current === 12) return 12;
112
+ // if hourCycle is undefined, infer from locale
113
+ const inferredHourCycle = getDefaultHourCycle(root.locale.current);
114
+ return inferredHourCycle === 12 ? 12 : 23;
115
+ },
116
+ cycle: 1,
117
+ canBeZero: true,
118
+ padZero: true,
119
+ },
120
+ minute: {
121
+ min: 0,
122
+ max: 59,
123
+ cycle: 1,
124
+ canBeZero: true,
125
+ padZero: true,
126
+ },
127
+ second: {
128
+ min: 0,
129
+ max: 59,
130
+ cycle: 1,
131
+ canBeZero: true,
132
+ padZero: true,
133
+ },
134
+ };
135
+
136
+ const [getDateFieldRoot, setDateFieldRoot] = createContext<DateFieldRootState>();
137
+
138
+ interface DateFieldRootStateOpts
139
+ extends
140
+ WritableBoxedValues<{
141
+ value: DateValue | undefined;
142
+ placeholder: DateValue;
143
+ }>,
144
+ ReadableBoxedValues<{
145
+ readonlySegments: SegmentPart[];
146
+ validate: DateValidator | undefined;
147
+ onInvalid: DateOnInvalid | undefined;
148
+ minValue: DateValue | undefined;
149
+ maxValue: DateValue | undefined;
150
+ disabled: boolean;
151
+ readonly: boolean;
152
+ granularity: Granularity | undefined;
153
+ hourCycle: HourCycle | undefined;
154
+ locale: string;
155
+ hideTimeZone: boolean;
156
+ required: boolean;
157
+ errorMessageId: string | undefined;
158
+ isInvalidProp: boolean | undefined;
159
+ }> {
160
+ descriptionId: string;
161
+ }
162
+
163
+ export class DateFieldRootState {
164
+ static create(opts: DateFieldRootStateOpts, rangeRoot?: DateRangeFieldRootState) {
165
+ return setDateFieldRoot(new DateFieldRootState(opts, rangeRoot));
166
+ }
167
+
168
+ value: DateFieldRootStateOpts['value'];
169
+ placeholder: WritableBox<DateValue>;
170
+ validate: DateFieldRootStateOpts['validate'];
171
+ minValue: DateFieldRootStateOpts['minValue'];
172
+ maxValue: DateFieldRootStateOpts['maxValue'];
173
+ disabled: DateFieldRootStateOpts['disabled'];
174
+ readonly: DateFieldRootStateOpts['readonly'];
175
+ granularity: DateFieldRootStateOpts['granularity'];
176
+ readonlySegments: DateFieldRootStateOpts['readonlySegments'];
177
+ hourCycle: DateFieldRootStateOpts['hourCycle'];
178
+ locale: DateFieldRootStateOpts['locale'];
179
+ hideTimeZone: DateFieldRootStateOpts['hideTimeZone'];
180
+ required: DateFieldRootStateOpts['required'];
181
+ onInvalid: DateFieldRootStateOpts['onInvalid'];
182
+ errorMessageId: DateFieldRootStateOpts['errorMessageId'];
183
+ isInvalidProp: DateFieldRootStateOpts['isInvalidProp'];
184
+ readonly descriptionId: string;
185
+ formatter: Formatter;
186
+ segmentValues = $state() as SegmentValueObj;
187
+ announcer: Announcer;
188
+ readonly readonlySegmentsSet = $derived.by(() => new Set(this.readonlySegments.current));
189
+ #fieldNode = $state<HTMLElement | null>(null);
190
+ #labelNode = $state<HTMLElement | null>(null);
191
+ descriptionNode = $state<HTMLElement | null>(null);
192
+ validationNode = $state<HTMLElement | null>(null);
193
+ states = initSegmentStates();
194
+ dayPeriodNode = $state<HTMLElement | null>(null);
195
+ rangeRoot: DateRangeFieldRootState | undefined = undefined;
196
+ #nameSource: ReadableBox<string> = simpleBox('');
197
+ get name() {
198
+ return this.#nameSource.current;
199
+ }
200
+ domContext: DOMContext = new DOMContext(() => null);
201
+
202
+ constructor(props: DateFieldRootStateOpts, rangeRoot?: DateRangeFieldRootState) {
203
+ this.rangeRoot = rangeRoot;
204
+ this.descriptionId = props.descriptionId;
205
+ /**
206
+ * Since the `DateFieldRootState` can be used in two contexts, as a standalone
207
+ * field or as a field within a `DateRangeField` component, we handle assigning
208
+ * the props based on that context.
209
+ */
210
+ this.value = props.value;
211
+ this.placeholder = rangeRoot ? rangeRoot.opts.placeholder : props.placeholder;
212
+ this.validate = rangeRoot ? simpleBox(undefined) : props.validate;
213
+ this.minValue = rangeRoot ? rangeRoot.opts.minValue : props.minValue;
214
+ this.maxValue = rangeRoot ? rangeRoot.opts.maxValue : props.maxValue;
215
+ this.disabled = rangeRoot ? rangeRoot.opts.disabled : props.disabled;
216
+ this.readonly = rangeRoot ? rangeRoot.opts.readonly : props.readonly;
217
+ this.granularity = rangeRoot ? rangeRoot.opts.granularity : props.granularity;
218
+ this.readonlySegments = rangeRoot ? rangeRoot.opts.readonlySegments : props.readonlySegments;
219
+ this.hourCycle = rangeRoot ? rangeRoot.opts.hourCycle : props.hourCycle;
220
+ this.locale = rangeRoot ? rangeRoot.opts.locale : props.locale;
221
+ this.hideTimeZone = rangeRoot ? rangeRoot.opts.hideTimeZone : props.hideTimeZone;
222
+ this.required = rangeRoot ? rangeRoot.opts.required : props.required;
223
+ this.onInvalid = rangeRoot ? rangeRoot.opts.onInvalid : props.onInvalid;
224
+ this.errorMessageId = rangeRoot ? rangeRoot.opts.errorMessageId : props.errorMessageId;
225
+ this.isInvalidProp = props.isInvalidProp;
226
+ this.formatter = createFormatter({
227
+ locale: this.locale,
228
+ monthFormat: boxWith(() => 'long'),
229
+ yearFormat: boxWith(() => 'numeric'),
230
+ });
231
+ this.segmentValues = initializeSegmentValues(this.inferredGranularity);
232
+ this.announcer = getAnnouncer(null);
233
+ this.getFieldNode = this.getFieldNode.bind(this);
234
+ this.updateSegment = this.updateSegment.bind(this);
235
+ this.handleSegmentClick = this.handleSegmentClick.bind(this);
236
+ this.getBaseSegmentAttrs = this.getBaseSegmentAttrs.bind(this);
237
+
238
+ onMount(() => {
239
+ this.announcer = getAnnouncer(this.domContext.getDocument());
240
+ });
241
+
242
+ onMount(() => () => {
243
+ if (rangeRoot) return;
244
+ this.domContext.getDocument().getElementById(this.descriptionId)?.remove();
245
+ });
246
+
247
+ $effect(() => {
248
+ if (rangeRoot) return;
249
+ if (this.value.current) {
250
+ const descriptionId = untrack(() => this.descriptionId);
251
+ setDescription({
252
+ id: descriptionId,
253
+ formatter: this.formatter,
254
+ value: this.value.current,
255
+ doc: this.domContext.getDocument(),
256
+ });
257
+ }
258
+ const placeholder = untrack(() => this.placeholder.current);
259
+ if (this.value.current && placeholder !== this.value.current) {
260
+ untrack(() => {
261
+ if (this.value.current) {
262
+ this.placeholder.current = this.value.current;
263
+ }
264
+ });
265
+ }
266
+ });
267
+
268
+ if (this.value.current) {
269
+ this.syncSegmentValues(this.value.current);
270
+ }
271
+
272
+ $effect(() => {
273
+ this.locale.current;
274
+ if (this.value.current) {
275
+ this.syncSegmentValues(this.value.current);
276
+ }
277
+
278
+ this.#clearUpdating();
279
+ });
280
+
281
+ $effect(() => {
282
+ if (this.value.current === undefined) {
283
+ this.segmentValues = initializeSegmentValues(this.inferredGranularity);
284
+ }
285
+ });
286
+
287
+ $effect(() => {
288
+ this.validationStatus;
289
+
290
+ untrack(() => {
291
+ if (this.validationStatus !== false) {
292
+ this.onInvalid.current?.(this.validationStatus.reason, this.validationStatus.message);
293
+ }
294
+ });
295
+ });
296
+ }
297
+
298
+ setNameSource(name: ReadableBox<string>) {
299
+ this.#nameSource = name;
300
+ }
301
+
302
+ /**
303
+ * Sets the field node for the `DateFieldRootState` instance. We use this method so we can
304
+ * keep `#fieldNode` private to prevent accidental usage of the incorrect field node.
305
+ */
306
+ setFieldNode(node: HTMLElement | null) {
307
+ this.#fieldNode = node;
308
+ }
309
+
310
+ /**
311
+ * Gets the correct field node for the date field regardless of whether it's being
312
+ * used in a standalone context or within a `DateRangeField` component.
313
+ */
314
+ getFieldNode() {
315
+ return this.rangeRoot ? this.rangeRoot.fieldNode : this.#fieldNode;
316
+ }
317
+
318
+ /**
319
+ * Sets the label node for the `DateFieldRootState` instance. We use this method so we can
320
+ * keep `#labelNode` private to prevent accidental usage of the incorrect label node.
321
+ */
322
+ setLabelNode(node: HTMLElement | null) {
323
+ this.#labelNode = node;
324
+ }
325
+
326
+ /**
327
+ * Gets the correct label node for the date field regardless of whether it's being used in
328
+ * a standalone context or within a `DateRangeField` component.
329
+ */
330
+ getLabelNode() {
331
+ return this.rangeRoot ? this.rangeRoot.labelNode : this.#labelNode;
332
+ }
333
+
334
+ #clearUpdating() {
335
+ this.states.day.updating = null;
336
+ this.states.month.updating = null;
337
+ this.states.year.updating = null;
338
+ this.states.hour.updating = null;
339
+ this.states.minute.updating = null;
340
+ this.states.dayPeriod.updating = null;
341
+ }
342
+
343
+ setValue(value: DateValue | undefined) {
344
+ this.value.current = value;
345
+ }
346
+
347
+ syncSegmentValues(value: DateValue) {
348
+ const dateValues = DATE_SEGMENT_PARTS.map((part) => {
349
+ const partValue = value[part];
350
+
351
+ if (part === 'month') {
352
+ if (this.states.month.updating) {
353
+ return [part, this.states.month.updating];
354
+ }
355
+ if (partValue < 10) {
356
+ return [part, `0${partValue}`];
357
+ }
358
+ }
359
+
360
+ if (part === 'day') {
361
+ if (this.states.day.updating) {
362
+ return [part, this.states.day.updating];
363
+ }
364
+
365
+ if (partValue < 10) {
366
+ return [part, `0${partValue}`];
367
+ }
368
+ }
369
+
370
+ if (part === 'year') {
371
+ if (this.states.year.updating) {
372
+ return [part, this.states.year.updating];
373
+ }
374
+ const valueDigits = `${partValue}`.length;
375
+ const diff = 4 - valueDigits;
376
+ if (diff > 0) {
377
+ return [part, `${'0'.repeat(diff)}${partValue}`];
378
+ }
379
+ }
380
+
381
+ return [part, `${partValue}`];
382
+ });
383
+ if ('hour' in value) {
384
+ const timeValues = EDITABLE_TIME_SEGMENT_PARTS.map((part) => {
385
+ if (part === 'dayPeriod') {
386
+ if (this.states.dayPeriod.updating) {
387
+ return [part, this.states.dayPeriod.updating];
388
+ } else {
389
+ return [part, this.formatter.dayPeriod(toDate(value))];
390
+ }
391
+ } else if (part === 'hour') {
392
+ if (this.states.hour.updating) {
393
+ return [part, this.states.hour.updating];
394
+ }
395
+
396
+ if (value[part] !== undefined && value[part] < 10) {
397
+ return [part, `0${value[part]}`];
398
+ }
399
+
400
+ if (value[part] === 0) {
401
+ /**
402
+ * If we're rendering a `dayPeriod` segment, we're operating in a
403
+ * 12-hour clock, so we never allow the displayed hour to be 0.
404
+ */
405
+ if (this.dayPeriodNode) {
406
+ return [part, '12'];
407
+ }
408
+ }
409
+ } else if (part === 'minute') {
410
+ if (this.states.minute.updating) {
411
+ return [part, this.states.minute.updating];
412
+ }
413
+
414
+ if (value[part] !== undefined && value[part] < 10) {
415
+ return [part, `0${value[part]}`];
416
+ }
417
+ } else if (part === 'second') {
418
+ if (this.states.second.updating) {
419
+ return [part, this.states.second.updating];
420
+ }
421
+
422
+ if (value[part] !== undefined && value[part] < 10) {
423
+ return [part, `0${value[part]}`];
424
+ }
425
+ }
426
+ return [part, `${value[part]}`];
427
+ });
428
+
429
+ const mergedSegmentValues = [...dateValues, ...timeValues];
430
+ this.segmentValues = Object.fromEntries(mergedSegmentValues);
431
+ this.#clearUpdating();
432
+ return;
433
+ }
434
+
435
+ this.segmentValues = Object.fromEntries(dateValues);
436
+ }
437
+
438
+ readonly validationStatus = $derived.by(() => {
439
+ const value = this.value.current;
440
+ if (!value) return false as const;
441
+
442
+ const msg = this.validate.current?.(value);
443
+
444
+ if (msg) {
445
+ return {
446
+ reason: 'custom',
447
+ message: msg,
448
+ } as const;
449
+ }
450
+
451
+ const minValue = this.minValue.current;
452
+ if (minValue && isBefore(value, minValue)) {
453
+ return {
454
+ reason: 'min',
455
+ } as const;
456
+ }
457
+ const maxValue = this.maxValue.current;
458
+ if (maxValue && isBefore(maxValue, value)) {
459
+ return {
460
+ reason: 'max',
461
+ } as const;
462
+ }
463
+ return false;
464
+ });
465
+
466
+ readonly isInvalid = $derived.by(() => {
467
+ if (this.isInvalidProp.current) return true;
468
+ return this.validationStatus !== false;
469
+ });
470
+
471
+ readonly inferredGranularity = $derived.by(() => {
472
+ const granularity = this.granularity.current;
473
+ if (granularity) return granularity;
474
+ const inferred = inferGranularity(this.placeholder.current, this.granularity.current);
475
+ return inferred;
476
+ });
477
+
478
+ readonly dateRef = $derived.by(() => (this.value.current !== undefined ? this.value.current : this.placeholder.current));
479
+
480
+ readonly allSegmentContent = $derived.by(() => {
481
+ return createContent({
482
+ segmentValues: this.segmentValues,
483
+ formatter: this.formatter,
484
+ locale: this.locale.current,
485
+ granularity: this.inferredGranularity,
486
+ dateRef: this.dateRef,
487
+ hideTimeZone: this.hideTimeZone.current,
488
+ hourCycle: this.hourCycle.current,
489
+ });
490
+ });
491
+
492
+ readonly segmentContents = $derived.by(() => this.allSegmentContent.arr);
493
+
494
+ readonly sharedSegmentAttrs = {
495
+ role: 'spinbutton',
496
+ contenteditable: 'true',
497
+ tabindex: 0,
498
+ spellcheck: false,
499
+ inputmode: 'numeric',
500
+ autocorrect: 'off',
501
+ enterkeyhint: 'next',
502
+ style: {
503
+ caretColor: 'transparent',
504
+ },
505
+ onbeforeinput: (e: InputEvent) => {
506
+ if (!e.data || e.data.length <= 1) {
507
+ e.preventDefault();
508
+ }
509
+ },
510
+ };
511
+
512
+ #getLabelledBy(segmentId: string) {
513
+ return `${segmentId} ${this.getLabelNode()?.id ?? ''}`;
514
+ }
515
+
516
+ updateSegment<T extends keyof DateAndTimeSegmentObj>(
517
+ part: T,
518
+ cb: T extends DateSegmentPart
519
+ ? Updater<DateSegmentObj[T]>
520
+ : T extends EditableTimeSegmentPart
521
+ ? Updater<TimeSegmentObj[T]>
522
+ : Updater<DateAndTimeSegmentObj[T]>,
523
+ ) {
524
+ const disabled = this.disabled.current;
525
+ const readonly = this.readonly.current;
526
+ const readonlySegmentsSet = this.readonlySegmentsSet;
527
+ if (disabled || readonly || readonlySegmentsSet.has(part)) return;
528
+
529
+ const prev = this.segmentValues;
530
+
531
+ let newSegmentValues: SegmentValueObj = prev;
532
+
533
+ const dateRef = this.placeholder.current;
534
+ if (isDateAndTimeSegmentObj(prev)) {
535
+ const pVal = prev[part];
536
+ const castCb = cb as Updater<DateAndTimeSegmentObj[T]>;
537
+ if (part === 'month') {
538
+ const next = castCb(pVal) as DateAndTimeSegmentObj['month'];
539
+ this.states.month.updating = next;
540
+ if (next !== null && prev.day !== null) {
541
+ const date = dateRef.set({ month: Number.parseInt(next) });
542
+ const daysInMonth = getDaysInMonth(toDate(date));
543
+ const prevDay = Number.parseInt(prev.day);
544
+ if (prevDay > daysInMonth) {
545
+ prev.day = `${daysInMonth}`;
546
+ }
547
+ }
548
+ newSegmentValues = { ...prev, [part]: next };
549
+ } else if (part === 'dayPeriod') {
550
+ const next = castCb(pVal) as DateAndTimeSegmentObj['dayPeriod'];
551
+ this.states.dayPeriod.updating = next;
552
+ const date = this.value.current;
553
+ if (date && 'hour' in date) {
554
+ const trueHour = date.hour;
555
+ if (next === 'AM') {
556
+ if (trueHour >= 12) {
557
+ prev.hour = `${trueHour - 12}`;
558
+ }
559
+ } else if (next === 'PM') {
560
+ if (trueHour < 12) {
561
+ prev.hour = `${trueHour + 12}`;
562
+ }
563
+ }
564
+ }
565
+ newSegmentValues = { ...prev, [part]: next };
566
+ } else if (part === 'hour') {
567
+ const next = castCb(pVal) as DateAndTimeSegmentObj['hour'];
568
+ this.states.hour.updating = next;
569
+ if (next !== null && prev.dayPeriod !== null) {
570
+ const dayPeriod = this.formatter.dayPeriod(toDate(dateRef.set({ hour: Number.parseInt(next) })), this.hourCycle.current);
571
+ if (dayPeriod === 'AM' || dayPeriod === 'PM') {
572
+ prev.dayPeriod = dayPeriod;
573
+ }
574
+ }
575
+ newSegmentValues = { ...prev, [part]: next };
576
+ } else if (part === 'minute') {
577
+ const next = castCb(pVal) as DateAndTimeSegmentObj['minute'];
578
+ this.states.minute.updating = next;
579
+ newSegmentValues = { ...prev, [part]: next };
580
+ } else if (part === 'second') {
581
+ const next = castCb(pVal) as DateAndTimeSegmentObj['second'];
582
+ this.states.second.updating = next;
583
+ newSegmentValues = { ...prev, [part]: next };
584
+ } else if (part === 'year') {
585
+ const next = castCb(pVal) as DateAndTimeSegmentObj['year'];
586
+ this.states.year.updating = next;
587
+ newSegmentValues = { ...prev, [part]: next };
588
+ } else if (part === 'day') {
589
+ const next = castCb(pVal) as DateAndTimeSegmentObj['day'];
590
+ this.states.day.updating = next;
591
+ newSegmentValues = { ...prev, [part]: next };
592
+ } else {
593
+ const next = castCb(pVal);
594
+ newSegmentValues = { ...prev, [part]: next };
595
+ }
596
+ } else if (isDateSegmentPart(part)) {
597
+ const pVal = prev[part];
598
+ const castCb = cb as Updater<DateSegmentObj[DateSegmentPart]>;
599
+ const next = castCb(pVal);
600
+ if (part === 'month' && next !== null && prev.day !== null) {
601
+ this.states.month.updating = next;
602
+ const date = dateRef.set({ month: Number.parseInt(next) });
603
+ const daysInMonth = getDaysInMonth(toDate(date));
604
+ if (Number.parseInt(prev.day) > daysInMonth) {
605
+ prev.day = `${daysInMonth}`;
606
+ }
607
+ newSegmentValues = { ...prev, [part]: next };
608
+ } else if (part === 'year') {
609
+ const next = castCb(pVal) as DateAndTimeSegmentObj['year'];
610
+ this.states.year.updating = next;
611
+ newSegmentValues = { ...prev, [part]: next };
612
+ } else if (part === 'day') {
613
+ const next = castCb(pVal) as DateAndTimeSegmentObj['day'];
614
+ this.states.day.updating = next;
615
+ newSegmentValues = { ...prev, [part]: next };
616
+ } else {
617
+ newSegmentValues = { ...prev, [part]: next };
618
+ }
619
+ }
620
+ this.segmentValues = newSegmentValues;
621
+ if (areAllSegmentsFilled(newSegmentValues, this.#fieldNode)) {
622
+ this.setValue(
623
+ getValueFromSegments({
624
+ segmentObj: newSegmentValues,
625
+ fieldNode: this.#fieldNode,
626
+ dateRef: this.placeholder.current,
627
+ }),
628
+ );
629
+ } else {
630
+ this.setValue(undefined);
631
+ this.segmentValues = newSegmentValues;
632
+ }
633
+ }
634
+
635
+ handleSegmentClick(e: BitsMouseEvent) {
636
+ if (this.disabled.current) {
637
+ e.preventDefault();
638
+ }
639
+ }
640
+
641
+ getBaseSegmentAttrs(part: SegmentPart, segmentId: string) {
642
+ const inReadonlySegments = this.readonlySegmentsSet.has(part);
643
+ const defaultAttrs = {
644
+ 'aria-invalid': boolToStrTrueOrUndef(this.isInvalid),
645
+ 'aria-disabled': boolToStr(this.disabled.current),
646
+ 'aria-readonly': boolToStr(this.readonly.current || inReadonlySegments),
647
+ 'data-invalid': boolToEmptyStrOrUndef(this.isInvalid),
648
+ 'data-disabled': boolToEmptyStrOrUndef(this.disabled.current),
649
+ 'data-readonly': boolToEmptyStrOrUndef(this.readonly.current || inReadonlySegments),
650
+ 'data-segment': `${part}`,
651
+ [dateFieldAttrs.segment]: '',
652
+ };
653
+
654
+ if (part === 'literal') return defaultAttrs;
655
+
656
+ const descriptionId = this.descriptionNode?.id;
657
+ const hasDescription = isFirstSegment(segmentId, this.#fieldNode) && descriptionId;
658
+ const errorMsgId = this.errorMessageId?.current;
659
+
660
+ const describedBy = hasDescription ? `${descriptionId} ${this.isInvalid && errorMsgId ? errorMsgId : ''}` : undefined;
661
+
662
+ const contenteditable = !(this.readonly.current || inReadonlySegments || this.disabled.current);
663
+
664
+ return {
665
+ ...defaultAttrs,
666
+ 'aria-labelledby': this.#getLabelledBy(segmentId),
667
+ contenteditable: contenteditable ? 'true' : undefined,
668
+ 'aria-describedby': describedBy,
669
+ tabindex: this.disabled.current ? undefined : 0,
670
+ };
671
+ }
672
+ }
673
+
674
+ interface DateFieldInputStateOpts
675
+ extends
676
+ WithRefOpts,
677
+ ReadableBoxedValues<{
678
+ name: string;
679
+ }> {}
680
+
681
+ export class DateFieldInputState {
682
+ static create(opts: DateFieldInputStateOpts) {
683
+ return new DateFieldInputState(opts, getDateFieldRoot());
684
+ }
685
+
686
+ readonly opts: DateFieldInputStateOpts;
687
+ readonly root: DateFieldRootState;
688
+ readonly domContext: DOMContext;
689
+ readonly attachment: RefAttachment;
690
+
691
+ constructor(opts: DateFieldInputStateOpts, root: DateFieldRootState) {
692
+ this.opts = opts;
693
+ this.root = root;
694
+ this.domContext = new DOMContext(opts.ref);
695
+ this.root.domContext = this.domContext;
696
+ this.attachment = attachRef(opts.ref, (v) => this.root.setFieldNode(v));
697
+ this.root.setNameSource(this.opts.name);
698
+ }
699
+
700
+ readonly #ariaDescribedBy = $derived.by(() => {
701
+ if (!BROWSER) return undefined;
702
+ const doesDescriptionExist = this.domContext.getElementById(this.root.descriptionId);
703
+ if (!doesDescriptionExist) return undefined;
704
+ return this.root.descriptionId;
705
+ });
706
+
707
+ readonly props = $derived.by(
708
+ () =>
709
+ ({
710
+ id: this.opts.id.current,
711
+ role: 'group',
712
+ 'aria-labelledby': this.root.getLabelNode()?.id ?? undefined,
713
+ 'aria-describedby': this.#ariaDescribedBy,
714
+ 'aria-disabled': boolToStr(this.root.disabled.current),
715
+ 'data-invalid': this.root.isInvalid ? '' : undefined,
716
+ 'data-disabled': boolToEmptyStrOrUndef(this.root.disabled.current),
717
+ [dateFieldAttrs.input]: '',
718
+ ...this.attachment,
719
+ }) as const,
720
+ );
721
+ }
722
+ export class DateFieldHiddenInputState {
723
+ static create() {
724
+ return new DateFieldHiddenInputState(getDateFieldRoot());
725
+ }
726
+
727
+ readonly root: DateFieldRootState;
728
+ readonly shouldRender = $derived.by(() => this.root.name !== '');
729
+ readonly isoValue = $derived.by(() => (this.root.value.current ? this.root.value.current.toString() : ''));
730
+
731
+ constructor(root: DateFieldRootState) {
732
+ this.root = root;
733
+ }
734
+
735
+ readonly props = $derived.by(() => {
736
+ return {
737
+ name: this.root.name,
738
+ value: this.isoValue,
739
+ required: this.root.required.current,
740
+ };
741
+ });
742
+ }
743
+
744
+ interface DateFieldLabelStateOpts extends WithRefOpts {}
745
+
746
+ export class DateFieldLabelState {
747
+ static create(opts: DateFieldLabelStateOpts) {
748
+ return new DateFieldLabelState(opts, getDateFieldRoot());
749
+ }
750
+
751
+ readonly opts: DateFieldLabelStateOpts;
752
+ readonly root: DateFieldRootState;
753
+ readonly attachment: RefAttachment;
754
+
755
+ constructor(opts: DateFieldLabelStateOpts, root: DateFieldRootState) {
756
+ this.opts = opts;
757
+ this.root = root;
758
+ this.onclick = this.onclick.bind(this);
759
+ this.attachment = attachRef(opts.ref, (v) => this.root.setLabelNode(v));
760
+ }
761
+
762
+ onclick(_: BitsMouseEvent) {
763
+ if (this.root.disabled.current) return;
764
+ const firstSegment = getFirstSegment(this.root.getFieldNode());
765
+ if (!firstSegment) return;
766
+ firstSegment.focus();
767
+ }
768
+
769
+ readonly props = $derived.by(
770
+ () =>
771
+ ({
772
+ id: this.opts.id.current,
773
+ 'data-invalid': boolToEmptyStrOrUndef(this.root.isInvalid),
774
+ 'data-disabled': boolToEmptyStrOrUndef(this.root.disabled.current),
775
+ [dateFieldAttrs.label]: '',
776
+ onclick: this.onclick,
777
+ ...this.attachment,
778
+ }) as const,
779
+ );
780
+ }
781
+
782
+ // Base class for numeric segments
783
+ abstract class BaseNumericSegmentState {
784
+ readonly opts: WithRefOpts;
785
+ readonly root: DateFieldRootState;
786
+ readonly announcer: Announcer;
787
+ readonly part: string;
788
+ readonly config: SegmentConfig;
789
+ readonly attachment: RefAttachment;
790
+ constructor(opts: WithRefOpts, root: DateFieldRootState, part: string, config: SegmentConfig) {
791
+ this.opts = opts;
792
+ this.root = root;
793
+ this.part = part;
794
+ this.config = config;
795
+ this.announcer = root.announcer;
796
+ this.onkeydown = this.onkeydown.bind(this);
797
+ this.onfocusout = this.onfocusout.bind(this);
798
+ this.attachment = attachRef(opts.ref);
799
+ }
800
+
801
+ #getMax(): number {
802
+ return typeof this.config.max === 'function' ? this.config.max(this.root) : this.config.max;
803
+ }
804
+
805
+ #getMin(): number {
806
+ return typeof this.config.min === 'function' ? this.config.min(this.root) : this.config.min;
807
+ }
808
+
809
+ #getAnnouncement(value: number): string | number {
810
+ if (this.config.getAnnouncement) {
811
+ return this.config.getAnnouncement(value, this.root);
812
+ }
813
+ return value;
814
+ }
815
+
816
+ #formatValue(value: number, forDisplay = true): string {
817
+ const str = String(value);
818
+ if (forDisplay && this.config.padZero && str.length === 1) {
819
+ return `0${value}`;
820
+ }
821
+ return str;
822
+ }
823
+
824
+ onkeydown(e: BitsKeyboardEvent) {
825
+ const placeholder = this.root.value.current ?? this.root.placeholder.current;
826
+ if (e.ctrlKey || e.metaKey || this.root.disabled.current) return;
827
+
828
+ // Special check for time segments
829
+ if ((this.part === 'hour' || this.part === 'minute' || this.part === 'second') && !(this.part in placeholder)) return;
830
+
831
+ if (e.key !== kbd.TAB) e.preventDefault();
832
+ if (!isAcceptableSegmentKey(e.key)) return;
833
+
834
+ if (isArrowUp(e.key)) {
835
+ this.#handleArrowUp(placeholder);
836
+ return;
837
+ }
838
+
839
+ if (isArrowDown(e.key)) {
840
+ this.#handleArrowDown(placeholder);
841
+ return;
842
+ }
843
+
844
+ if (e.key.length === 1 && e.key >= '0' && e.key <= '9') {
845
+ this.#handleNumberKey(e);
846
+ return;
847
+ }
848
+
849
+ if (isBackspace(e.key)) {
850
+ this.#handleBackspace(e);
851
+ return;
852
+ }
853
+
854
+ if (isSegmentNavigationKey(e.key)) {
855
+ handleSegmentNavigation(e, this.root.getFieldNode());
856
+ }
857
+ }
858
+
859
+ #handleArrowUp(placeholder: DateValue) {
860
+ const stateKey = this.part as keyof typeof this.root.states;
861
+ if (stateKey in this.root.states) {
862
+ this.root.states[stateKey].hasLeftFocus = false;
863
+ }
864
+
865
+ // @ts-expect-error this is a part
866
+ this.root.updateSegment(this.part, (prev: string | null) => {
867
+ if (prev === null) {
868
+ const next = placeholder[this.part as keyof DateValue];
869
+ this.announcer.announce(this.#getAnnouncement(next as number));
870
+ return this.#formatValue(next as number);
871
+ }
872
+ const current = placeholder.set({
873
+ [this.part]: Number.parseInt(prev),
874
+ });
875
+ // @ts-expect-error this is a part
876
+ const next = current.cycle(this.part, this.config.cycle)[this.part as keyof DateValue];
877
+ this.announcer.announce(this.#getAnnouncement(next as number));
878
+ return this.#formatValue(next as number);
879
+ });
880
+ }
881
+
882
+ #handleArrowDown(placeholder: DateValue) {
883
+ const stateKey = this.part as keyof typeof this.root.states;
884
+ if (stateKey in this.root.states) {
885
+ this.root.states[stateKey].hasLeftFocus = false;
886
+ }
887
+
888
+ // @ts-expect-error this is a part
889
+ this.root.updateSegment(this.part, (prev: string | null) => {
890
+ if (prev === null) {
891
+ const next = placeholder[this.part as keyof DateValue];
892
+ this.announcer.announce(this.#getAnnouncement(next as number));
893
+ return this.#formatValue(next as number);
894
+ }
895
+ const current = placeholder.set({
896
+ [this.part]: Number.parseInt(prev),
897
+ });
898
+ // @ts-expect-error this is a part
899
+ const next = current.cycle(this.part, -this.config.cycle)[this.part as keyof DateValue];
900
+ this.announcer.announce(this.#getAnnouncement(next as number));
901
+ return this.#formatValue(next as number);
902
+ });
903
+ }
904
+
905
+ #handleNumberKey(e: BitsKeyboardEvent) {
906
+ const num = Number.parseInt(e.key);
907
+ let moveToNext = false;
908
+ const max = this.#getMax();
909
+ const maxStart = Math.floor(max / 10);
910
+ const numIsZero = num === 0;
911
+ const stateKey = this.part as keyof typeof this.root.states;
912
+
913
+ // @ts-expect-error this is a part
914
+ this.root.updateSegment(this.part, (prev: string | null) => {
915
+ // Check if user has left focus
916
+ if (stateKey in this.root.states && this.root.states[stateKey].hasLeftFocus) {
917
+ prev = null;
918
+ this.root.states[stateKey].hasLeftFocus = false;
919
+ }
920
+
921
+ // Starting fresh
922
+ if (prev === null) {
923
+ if (numIsZero) {
924
+ if (stateKey in this.root.states) {
925
+ this.root.states[stateKey].lastKeyZero = true;
926
+ }
927
+ this.announcer.announce('0');
928
+ return '0';
929
+ }
930
+
931
+ if (stateKey in this.root.states && (this.root.states[stateKey].lastKeyZero || num > maxStart)) {
932
+ moveToNext = true;
933
+ }
934
+
935
+ if (stateKey in this.root.states) {
936
+ this.root.states[stateKey].lastKeyZero = false;
937
+ }
938
+
939
+ if (moveToNext && String(num).length === 1) {
940
+ this.announcer.announce(num);
941
+ return `0${num}`;
942
+ }
943
+
944
+ return `${num}`;
945
+ }
946
+
947
+ // Handle special cases for segments with lastKeyZero tracking
948
+ if (stateKey in this.root.states && this.root.states[stateKey].lastKeyZero) {
949
+ if (num !== 0) {
950
+ moveToNext = true;
951
+ this.root.states[stateKey].lastKeyZero = false;
952
+ return `0${num}`;
953
+ }
954
+
955
+ // Special handling for hour segment with 24-hour cycle
956
+ if (this.part === 'hour' && num === 0 && this.root.hourCycle.current === 24) {
957
+ moveToNext = true;
958
+ this.root.states[stateKey].lastKeyZero = false;
959
+ return `00`;
960
+ }
961
+
962
+ // Special handling for minute/second segments
963
+ if ((this.part === 'minute' || this.part === 'second') && num === 0) {
964
+ moveToNext = true;
965
+ this.root.states[stateKey].lastKeyZero = false;
966
+ return '00';
967
+ }
968
+
969
+ return prev;
970
+ }
971
+
972
+ const total = Number.parseInt(prev + num.toString());
973
+
974
+ if (total > max) {
975
+ moveToNext = true;
976
+ return `0${num}`;
977
+ }
978
+
979
+ moveToNext = true;
980
+ return `${total}`;
981
+ });
982
+
983
+ if (moveToNext) {
984
+ moveToNextSegment(e, this.root.getFieldNode());
985
+ }
986
+ }
987
+
988
+ #handleBackspace(e: BitsKeyboardEvent) {
989
+ const stateKey = this.part as keyof typeof this.root.states;
990
+ if (stateKey in this.root.states) {
991
+ this.root.states[stateKey].hasLeftFocus = false;
992
+ }
993
+
994
+ let moveToPrev = false;
995
+ // @ts-expect-error this is a part
996
+ this.root.updateSegment(this.part, (prev: string | null) => {
997
+ if (prev === null) {
998
+ moveToPrev = true;
999
+ this.announcer.announce(null);
1000
+ return null;
1001
+ }
1002
+
1003
+ if (prev.length === 2 && prev.startsWith('0')) {
1004
+ this.announcer.announce(null);
1005
+ return null;
1006
+ }
1007
+
1008
+ const str = prev.toString();
1009
+ if (str.length === 1) {
1010
+ this.announcer.announce(null);
1011
+ return null;
1012
+ }
1013
+
1014
+ const next = Number.parseInt(str.slice(0, -1));
1015
+ this.announcer.announce(this.#getAnnouncement(next));
1016
+ return `${next}`;
1017
+ });
1018
+
1019
+ if (moveToPrev) {
1020
+ moveToPrevSegment(e, this.root.getFieldNode());
1021
+ }
1022
+ }
1023
+
1024
+ onfocusout(_: BitsFocusEvent) {
1025
+ const stateKey = this.part as keyof typeof this.root.states;
1026
+ if (stateKey in this.root.states) {
1027
+ this.root.states[stateKey].hasLeftFocus = true;
1028
+ }
1029
+
1030
+ // Pad with zero if needed
1031
+ if (this.config.padZero) {
1032
+ // @ts-expect-error this is a part
1033
+ this.root.updateSegment(this.part, (prev: string | null) => {
1034
+ if (prev && prev.length === 1) {
1035
+ return `0${prev}`;
1036
+ }
1037
+ return prev;
1038
+ });
1039
+ }
1040
+ }
1041
+
1042
+ getSegmentProps() {
1043
+ const segmentValues = this.root.segmentValues;
1044
+ const placeholder = this.root.placeholder.current;
1045
+ const isEmpty = segmentValues[this.part as keyof SegmentValueObj] === null;
1046
+
1047
+ let date = placeholder;
1048
+ if (segmentValues[this.part as keyof SegmentValueObj]) {
1049
+ date = placeholder.set({
1050
+ [this.part]: Number.parseInt(segmentValues[this.part as keyof SegmentValueObj] as string),
1051
+ });
1052
+ }
1053
+
1054
+ const valueNow = date[this.part as keyof DateValue] as number;
1055
+ const valueMin = this.#getMin();
1056
+ const valueMax = this.#getMax();
1057
+ let valueText = isEmpty ? 'Empty' : `${valueNow}`;
1058
+
1059
+ // Special handling for hour segment with dayPeriod
1060
+ if (this.part === 'hour' && 'dayPeriod' in segmentValues && segmentValues.dayPeriod) {
1061
+ valueText = isEmpty ? 'Empty' : `${valueNow} ${segmentValues.dayPeriod}`;
1062
+ }
1063
+
1064
+ return {
1065
+ 'aria-label': `${this.part}, `,
1066
+ 'aria-valuemin': valueMin,
1067
+ 'aria-valuemax': valueMax,
1068
+ 'aria-valuenow': valueNow,
1069
+ 'aria-valuetext': valueText,
1070
+ };
1071
+ }
1072
+
1073
+ readonly props = $derived.by(() => {
1074
+ return {
1075
+ ...this.root.sharedSegmentAttrs,
1076
+ id: this.opts.id.current,
1077
+ ...this.getSegmentProps(),
1078
+ onkeydown: this.onkeydown,
1079
+ onfocusout: this.onfocusout,
1080
+ onclick: this.root.handleSegmentClick,
1081
+ ...this.root.getBaseSegmentAttrs(this.part as SegmentPart, this.opts.id.current),
1082
+ ...this.attachment,
1083
+ };
1084
+ });
1085
+ }
1086
+
1087
+ class DateFieldYearSegmentState extends BaseNumericSegmentState {
1088
+ #pressedKeys: string[] = [];
1089
+ #backspaceCount = 0;
1090
+
1091
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1092
+ super(opts, root, 'year', SEGMENT_CONFIGS.year);
1093
+ }
1094
+
1095
+ override onkeydown(e: BitsKeyboardEvent) {
1096
+ if (e.ctrlKey || e.metaKey || this.root.disabled.current) return;
1097
+ if (e.key !== kbd.TAB) e.preventDefault();
1098
+ if (!isAcceptableSegmentKey(e.key)) return;
1099
+
1100
+ if (isArrowUp(e.key)) {
1101
+ this.#resetBackspaceCount();
1102
+ super.onkeydown(e);
1103
+ return;
1104
+ }
1105
+
1106
+ if (isArrowDown(e.key)) {
1107
+ this.#resetBackspaceCount();
1108
+ super.onkeydown(e);
1109
+ return;
1110
+ }
1111
+
1112
+ if (e.key.length === 1 && e.key >= '0' && e.key <= '9') {
1113
+ this.#handleYearNumberKey(e);
1114
+ return;
1115
+ }
1116
+
1117
+ if (isBackspace(e.key)) {
1118
+ this.#handleYearBackspace(e);
1119
+ return;
1120
+ }
1121
+
1122
+ if (isSegmentNavigationKey(e.key)) {
1123
+ handleSegmentNavigation(e, this.root.getFieldNode());
1124
+ }
1125
+ }
1126
+
1127
+ #resetBackspaceCount() {
1128
+ this.#backspaceCount = 0;
1129
+ }
1130
+
1131
+ #incrementBackspaceCount() {
1132
+ this.#backspaceCount++;
1133
+ }
1134
+
1135
+ #handleYearNumberKey(e: BitsKeyboardEvent) {
1136
+ this.#pressedKeys.push(e.key);
1137
+ let moveToNext = false;
1138
+ const num = Number.parseInt(e.key);
1139
+
1140
+ this.root.updateSegment('year', (prev) => {
1141
+ if (this.root.states.year.hasLeftFocus) {
1142
+ prev = null;
1143
+ this.root.states.year.hasLeftFocus = false;
1144
+ }
1145
+
1146
+ if (prev === null) {
1147
+ this.announcer.announce(num);
1148
+ return `000${num}`;
1149
+ }
1150
+
1151
+ const str = prev.toString() + num.toString();
1152
+ const mergedInt = Number.parseInt(str);
1153
+ const mergedIntDigits = String(mergedInt).length;
1154
+
1155
+ if (mergedIntDigits < 4) {
1156
+ if (this.#backspaceCount > 0 && this.#pressedKeys.length <= this.#backspaceCount && str.length <= 4) {
1157
+ this.announcer.announce(mergedInt);
1158
+ return str;
1159
+ }
1160
+
1161
+ this.announcer.announce(mergedInt);
1162
+ return prependYearZeros(mergedInt);
1163
+ }
1164
+
1165
+ this.announcer.announce(mergedInt);
1166
+ moveToNext = true;
1167
+
1168
+ const mergedIntStr = `${mergedInt}`;
1169
+
1170
+ if (mergedIntStr.length > 4) {
1171
+ return mergedIntStr.slice(0, 4);
1172
+ }
1173
+
1174
+ return mergedIntStr;
1175
+ });
1176
+
1177
+ if (this.#pressedKeys.length === 4 || this.#pressedKeys.length === this.#backspaceCount) {
1178
+ moveToNext = true;
1179
+ }
1180
+
1181
+ if (moveToNext) {
1182
+ moveToNextSegment(e, this.root.getFieldNode());
1183
+ }
1184
+ }
1185
+
1186
+ #handleYearBackspace(e: BitsKeyboardEvent) {
1187
+ this.#pressedKeys = [];
1188
+ this.#incrementBackspaceCount();
1189
+ let moveToPrev = false;
1190
+
1191
+ this.root.updateSegment('year', (prev) => {
1192
+ this.root.states.year.hasLeftFocus = false;
1193
+ if (prev === null) {
1194
+ moveToPrev = true;
1195
+ this.announcer.announce(null);
1196
+ return null;
1197
+ }
1198
+ const str = prev.toString();
1199
+ if (str.length === 1) {
1200
+ this.announcer.announce(null);
1201
+ return null;
1202
+ }
1203
+ const next = str.slice(0, -1);
1204
+ this.announcer.announce(next);
1205
+
1206
+ return `${next}`;
1207
+ });
1208
+
1209
+ if (moveToPrev) {
1210
+ moveToPrevSegment(e, this.root.getFieldNode());
1211
+ }
1212
+ }
1213
+
1214
+ override onfocusout(_: BitsFocusEvent) {
1215
+ this.root.states.year.hasLeftFocus = true;
1216
+ this.#pressedKeys = [];
1217
+ this.#resetBackspaceCount();
1218
+ this.root.updateSegment('year', (prev) => {
1219
+ if (prev && prev.length !== 4) {
1220
+ return prependYearZeros(Number.parseInt(prev));
1221
+ }
1222
+ return prev;
1223
+ });
1224
+ }
1225
+ }
1226
+
1227
+ class DateFieldDaySegmentState extends BaseNumericSegmentState {
1228
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1229
+ super(opts, root, 'day', SEGMENT_CONFIGS.day);
1230
+ }
1231
+ }
1232
+
1233
+ class DateFieldMonthSegmentState extends BaseNumericSegmentState {
1234
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1235
+ super(opts, root, 'month', SEGMENT_CONFIGS.month);
1236
+ }
1237
+ }
1238
+
1239
+ class DateFieldHourSegmentState extends BaseNumericSegmentState {
1240
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1241
+ super(opts, root, 'hour', SEGMENT_CONFIGS.hour);
1242
+ }
1243
+
1244
+ // Override to handle special hour logic
1245
+ override onkeydown(e: BitsKeyboardEvent) {
1246
+ // Add special handling for hour display with dayPeriod
1247
+ if (e.key.length === 1 && e.key >= '0' && e.key <= '9') {
1248
+ const oldUpdateSegment = this.root.updateSegment.bind(this.root);
1249
+ // oxlint-disable-next-line no-explicit-any
1250
+ this.root.updateSegment = (part: any, cb: any) => {
1251
+ const result = oldUpdateSegment(part, cb);
1252
+
1253
+ // After updating hour, check if we need to display "12" instead of "0"
1254
+ if (part === 'hour' && 'hour' in this.root.segmentValues) {
1255
+ const hourValue = this.root.segmentValues.hour;
1256
+ if (hourValue === '0' && this.root.dayPeriodNode && this.root.hourCycle.current !== 24) {
1257
+ this.root.segmentValues.hour = '12';
1258
+ }
1259
+ }
1260
+
1261
+ return result;
1262
+ };
1263
+ }
1264
+
1265
+ super.onkeydown(e);
1266
+
1267
+ // Restore original updateSegment
1268
+ this.root.updateSegment = this.root.updateSegment.bind(this.root);
1269
+ }
1270
+ }
1271
+
1272
+ class DateFieldMinuteSegmentState extends BaseNumericSegmentState {
1273
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1274
+ super(opts, root, 'minute', SEGMENT_CONFIGS.minute);
1275
+ }
1276
+ }
1277
+
1278
+ class DateFieldSecondSegmentState extends BaseNumericSegmentState {
1279
+ constructor(opts: WithRefOpts, root: DateFieldRootState) {
1280
+ super(opts, root, 'second', SEGMENT_CONFIGS.second);
1281
+ }
1282
+ }
1283
+
1284
+ // Special segments that don't extend the base class
1285
+ interface DateFieldDayPeriodSegmentStateOpts extends WithRefOpts {}
1286
+
1287
+ export class DateFieldDayPeriodSegmentState {
1288
+ static create(opts: DateFieldDayPeriodSegmentStateOpts) {
1289
+ return new DateFieldDayPeriodSegmentState(opts, getDateFieldRoot());
1290
+ }
1291
+
1292
+ readonly opts: DateFieldDayPeriodSegmentStateOpts;
1293
+ readonly root: DateFieldRootState;
1294
+ readonly attachment: RefAttachment;
1295
+ #announcer: Announcer;
1296
+
1297
+ constructor(opts: DateFieldDayPeriodSegmentStateOpts, root: DateFieldRootState) {
1298
+ this.opts = opts;
1299
+ this.root = root;
1300
+ this.#announcer = this.root.announcer;
1301
+ this.onkeydown = this.onkeydown.bind(this);
1302
+ this.attachment = attachRef(opts.ref, (v) => (this.root.dayPeriodNode = v));
1303
+ }
1304
+
1305
+ onkeydown(e: BitsKeyboardEvent) {
1306
+ if (e.ctrlKey || e.metaKey || this.root.disabled.current) return;
1307
+
1308
+ if (e.key !== kbd.TAB) e.preventDefault();
1309
+ if (!isAcceptableDayPeriodKey(e.key)) return;
1310
+
1311
+ if (isArrowUp(e.key) || isArrowDown(e.key)) {
1312
+ this.root.updateSegment('dayPeriod', (prev) => {
1313
+ if (prev === 'AM') {
1314
+ const next = 'PM';
1315
+ this.#announcer.announce(next);
1316
+ return next;
1317
+ }
1318
+ const next = 'AM';
1319
+ this.#announcer.announce(next);
1320
+ return next;
1321
+ });
1322
+ return;
1323
+ }
1324
+
1325
+ if (isBackspace(e.key)) {
1326
+ this.root.states.dayPeriod.hasLeftFocus = false;
1327
+ this.root.updateSegment('dayPeriod', () => {
1328
+ const next = 'AM';
1329
+ this.#announcer.announce(next);
1330
+ return next;
1331
+ });
1332
+ }
1333
+
1334
+ if (e.key === kbd.A || e.key === kbd.P || e.key === kbd.a || e.key === kbd.p) {
1335
+ this.root.updateSegment('dayPeriod', () => {
1336
+ const next = e.key === kbd.A || e.key === kbd.a ? 'AM' : 'PM';
1337
+ this.#announcer.announce(next);
1338
+ return next;
1339
+ });
1340
+ }
1341
+
1342
+ if (isSegmentNavigationKey(e.key)) {
1343
+ handleSegmentNavigation(e, this.root.getFieldNode());
1344
+ }
1345
+ }
1346
+
1347
+ readonly props = $derived.by(() => {
1348
+ const segmentValues = this.root.segmentValues;
1349
+ if (!('dayPeriod' in segmentValues)) return;
1350
+
1351
+ const valueMin = 0;
1352
+ const valueMax = 12;
1353
+ const valueNow = segmentValues.dayPeriod === 'AM' ? 0 : 12;
1354
+ const valueText = segmentValues.dayPeriod ?? 'AM';
1355
+
1356
+ return {
1357
+ ...this.root.sharedSegmentAttrs,
1358
+ id: this.opts.id.current,
1359
+ inputmode: 'text',
1360
+ 'aria-label': 'AM/PM',
1361
+ 'aria-valuemin': valueMin,
1362
+ 'aria-valuemax': valueMax,
1363
+ 'aria-valuenow': valueNow,
1364
+ 'aria-valuetext': valueText,
1365
+ onkeydown: this.onkeydown,
1366
+ onclick: this.root.handleSegmentClick,
1367
+ ...this.root.getBaseSegmentAttrs('dayPeriod', this.opts.id.current),
1368
+ ...this.attachment,
1369
+ };
1370
+ });
1371
+ }
1372
+
1373
+ interface DateFieldLiteralSegmentStateOpts extends WithRefOpts {}
1374
+
1375
+ export class DateFieldLiteralSegmentState {
1376
+ static create(opts: DateFieldLiteralSegmentStateOpts) {
1377
+ return new DateFieldLiteralSegmentState(opts, getDateFieldRoot());
1378
+ }
1379
+
1380
+ readonly opts: DateFieldLiteralSegmentStateOpts;
1381
+ readonly root: DateFieldRootState;
1382
+ readonly attachment: RefAttachment;
1383
+
1384
+ constructor(opts: DateFieldLiteralSegmentStateOpts, root: DateFieldRootState) {
1385
+ this.opts = opts;
1386
+ this.root = root;
1387
+ this.attachment = attachRef(opts.ref);
1388
+ }
1389
+
1390
+ readonly props = $derived.by(
1391
+ () =>
1392
+ ({
1393
+ id: this.opts.id.current,
1394
+ 'aria-hidden': boolToStrTrueOrUndef(true),
1395
+ ...this.root.getBaseSegmentAttrs('literal', this.opts.id.current),
1396
+ ...this.attachment,
1397
+ }) as const,
1398
+ );
1399
+ }
1400
+
1401
+ interface DateFieldTimeZoneSegmentStateOpts extends WithRefOpts {}
1402
+
1403
+ export class DateFieldTimeZoneSegmentState {
1404
+ static create(opts: DateFieldTimeZoneSegmentStateOpts) {
1405
+ return new DateFieldTimeZoneSegmentState(opts, getDateFieldRoot());
1406
+ }
1407
+
1408
+ readonly opts: DateFieldTimeZoneSegmentStateOpts;
1409
+ readonly root: DateFieldRootState;
1410
+ readonly attachment: RefAttachment;
1411
+
1412
+ constructor(opts: DateFieldTimeZoneSegmentStateOpts, root: DateFieldRootState) {
1413
+ this.opts = opts;
1414
+ this.root = root;
1415
+ this.onkeydown = this.onkeydown.bind(this);
1416
+ this.attachment = attachRef(opts.ref);
1417
+ }
1418
+
1419
+ onkeydown(e: BitsKeyboardEvent) {
1420
+ if (e.key !== kbd.TAB) e.preventDefault();
1421
+ if (this.root.disabled.current) return;
1422
+ if (isSegmentNavigationKey(e.key)) {
1423
+ handleSegmentNavigation(e, this.root.getFieldNode());
1424
+ }
1425
+ }
1426
+
1427
+ readonly props = $derived.by(
1428
+ () =>
1429
+ ({
1430
+ role: 'textbox',
1431
+ id: this.opts.id.current,
1432
+ 'aria-label': 'timezone, ',
1433
+ style: {
1434
+ caretColor: 'transparent',
1435
+ },
1436
+ onkeydown: this.onkeydown,
1437
+ ...this.root.getBaseSegmentAttrs('timeZoneName', this.opts.id.current),
1438
+ 'data-readonly': boolToEmptyStrOrUndef(true),
1439
+ ...this.attachment,
1440
+ }) as const,
1441
+ );
1442
+ }
1443
+
1444
+ export class DateFieldSegmentState {
1445
+ static create(part: SegmentPart, opts: WithRefOpts) {
1446
+ const root = getDateFieldRoot();
1447
+ switch (part) {
1448
+ case 'day':
1449
+ return new DateFieldDaySegmentState(opts, root);
1450
+ case 'month':
1451
+ return new DateFieldMonthSegmentState(opts, root);
1452
+ case 'year':
1453
+ return new DateFieldYearSegmentState(opts, root);
1454
+ case 'hour':
1455
+ return new DateFieldHourSegmentState(opts, root);
1456
+ case 'minute':
1457
+ return new DateFieldMinuteSegmentState(opts, root);
1458
+ case 'second':
1459
+ return new DateFieldSecondSegmentState(opts, root);
1460
+ case 'dayPeriod':
1461
+ return new DateFieldDayPeriodSegmentState(opts, root);
1462
+ case 'literal':
1463
+ return new DateFieldLiteralSegmentState(opts, root);
1464
+ case 'timeZoneName':
1465
+ return new DateFieldTimeZoneSegmentState(opts, root);
1466
+ }
1467
+ }
1468
+ }
1469
+
1470
+ function prependYearZeros(year: number) {
1471
+ const digits = String(year).length;
1472
+ const diff = 4 - digits;
1473
+ return `${'0'.repeat(diff)}${year}`;
1474
+ }