@coffer-org/web-ui 4.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 (387) hide show
  1. package/README.md +87 -0
  2. package/dist/Markdown.d.ts +4 -0
  3. package/dist/Markdown.js +13 -0
  4. package/dist/MarkdownEditor.d.ts +6 -0
  5. package/dist/MarkdownEditor.js +83 -0
  6. package/dist/actions/ActionButton.d.ts +7 -0
  7. package/dist/actions/ActionButton.js +54 -0
  8. package/dist/actions/PopupBody.d.ts +4 -0
  9. package/dist/actions/PopupBody.js +8 -0
  10. package/dist/actions/TemplateHost.d.ts +4 -0
  11. package/dist/actions/TemplateHost.js +36 -0
  12. package/dist/actions/registry.d.ts +20 -0
  13. package/dist/actions/registry.js +9 -0
  14. package/dist/components/ExtendReasonInfo.d.ts +6 -0
  15. package/dist/components/ExtendReasonInfo.js +12 -0
  16. package/dist/components/FavoriteButton.d.ts +8 -0
  17. package/dist/components/FavoriteButton.js +7 -0
  18. package/dist/components/Icon.d.ts +6 -0
  19. package/dist/components/Icon.js +12 -0
  20. package/dist/components/PageBody.d.ts +4 -0
  21. package/dist/components/PageBody.js +4 -0
  22. package/dist/components/RecordInline.d.ts +8 -0
  23. package/dist/components/RecordInline.js +29 -0
  24. package/dist/components/SaveStatus.d.ts +1 -0
  25. package/dist/components/SaveStatus.js +11 -0
  26. package/dist/components/Toolbar.d.ts +5 -0
  27. package/dist/components/Toolbar.js +4 -0
  28. package/dist/components/icons/color.d.ts +2 -0
  29. package/dist/components/icons/color.js +10 -0
  30. package/dist/components/icons/flag.d.ts +2 -0
  31. package/dist/components/icons/flag.js +6 -0
  32. package/dist/components/icons/lucide.d.ts +2 -0
  33. package/dist/components/icons/lucide.js +111 -0
  34. package/dist/components/icons/registry.d.ts +4 -0
  35. package/dist/components/icons/registry.js +22 -0
  36. package/dist/components/icons/simple.d.ts +2 -0
  37. package/dist/components/icons/simple.js +15 -0
  38. package/dist/components/icons/tabler.d.ts +2 -0
  39. package/dist/components/icons/tabler.js +11 -0
  40. package/dist/components/ui/FieldLabel.d.ts +9 -0
  41. package/dist/components/ui/FieldLabel.js +4 -0
  42. package/dist/components/ui/badge.d.ts +9 -0
  43. package/dist/components/ui/badge.js +19 -0
  44. package/dist/components/ui/button.d.ts +11 -0
  45. package/dist/components/ui/button.js +33 -0
  46. package/dist/components/ui/calendar.d.ts +8 -0
  47. package/dist/components/ui/calendar.js +72 -0
  48. package/dist/components/ui/card.d.ts +8 -0
  49. package/dist/components/ui/card.js +16 -0
  50. package/dist/components/ui/checkbox.d.ts +4 -0
  51. package/dist/components/ui/checkbox.js +8 -0
  52. package/dist/components/ui/chip-cls.d.ts +1 -0
  53. package/dist/components/ui/chip-cls.js +1 -0
  54. package/dist/components/ui/combobox.d.ts +24 -0
  55. package/dist/components/ui/combobox.js +58 -0
  56. package/dist/components/ui/confirm.d.ts +10 -0
  57. package/dist/components/ui/confirm.js +37 -0
  58. package/dist/components/ui/date-picker.d.ts +5 -0
  59. package/dist/components/ui/date-picker.js +16 -0
  60. package/dist/components/ui/dialog.d.ts +16 -0
  61. package/dist/components/ui/dialog.js +27 -0
  62. package/dist/components/ui/dropdown-menu.d.ts +15 -0
  63. package/dist/components/ui/dropdown-menu.js +18 -0
  64. package/dist/components/ui/input-group.d.ts +16 -0
  65. package/dist/components/ui/input-group.js +56 -0
  66. package/dist/components/ui/input.d.ts +3 -0
  67. package/dist/components/ui/input.js +6 -0
  68. package/dist/components/ui/label.d.ts +4 -0
  69. package/dist/components/ui/label.js +7 -0
  70. package/dist/components/ui/mask-input.d.ts +61 -0
  71. package/dist/components/ui/mask-input.js +1052 -0
  72. package/dist/components/ui/month-year-picker.d.ts +10 -0
  73. package/dist/components/ui/month-year-picker.js +46 -0
  74. package/dist/components/ui/option-icon.d.ts +15 -0
  75. package/dist/components/ui/option-icon.js +19 -0
  76. package/dist/components/ui/phone-input.d.ts +13 -0
  77. package/dist/components/ui/phone-input.js +53 -0
  78. package/dist/components/ui/popover.d.ts +11 -0
  79. package/dist/components/ui/popover.js +28 -0
  80. package/dist/components/ui/rating.d.ts +44 -0
  81. package/dist/components/ui/rating.js +501 -0
  82. package/dist/components/ui/scroll-area.d.ts +5 -0
  83. package/dist/components/ui/scroll-area.js +11 -0
  84. package/dist/components/ui/select-combobox.d.ts +25 -0
  85. package/dist/components/ui/select-combobox.js +36 -0
  86. package/dist/components/ui/select.d.ts +13 -0
  87. package/dist/components/ui/select.js +24 -0
  88. package/dist/components/ui/separator.d.ts +4 -0
  89. package/dist/components/ui/separator.js +7 -0
  90. package/dist/components/ui/switch.d.ts +4 -0
  91. package/dist/components/ui/switch.js +7 -0
  92. package/dist/components/ui/textarea.d.ts +3 -0
  93. package/dist/components/ui/textarea.js +6 -0
  94. package/dist/components/ui/time-picker.d.ts +84 -0
  95. package/dist/components/ui/time-picker.js +1258 -0
  96. package/dist/components/visually-hidden-input.d.ts +10 -0
  97. package/dist/components/visually-hidden-input.js +96 -0
  98. package/dist/hooks/use-as-ref.d.ts +3 -0
  99. package/dist/hooks/use-as-ref.js +10 -0
  100. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  101. package/dist/hooks/use-isomorphic-layout-effect.js +3 -0
  102. package/dist/hooks/use-lazy-ref.d.ts +3 -0
  103. package/dist/hooks/use-lazy-ref.js +9 -0
  104. package/dist/hooks/use-media-query.d.ts +3 -0
  105. package/dist/hooks/use-media-query.js +26 -0
  106. package/dist/host-services.d.ts +47 -0
  107. package/dist/host-services.js +35 -0
  108. package/dist/index.d.ts +70 -0
  109. package/dist/index.js +69 -0
  110. package/dist/layout.d.ts +29 -0
  111. package/dist/layout.js +323 -0
  112. package/dist/lib/cat-color.d.ts +1 -0
  113. package/dist/lib/cat-color.js +7 -0
  114. package/dist/lib/compose-refs.d.ts +5 -0
  115. package/dist/lib/compose-refs.js +38 -0
  116. package/dist/lib/date-format.d.ts +9 -0
  117. package/dist/lib/date-format.js +31 -0
  118. package/dist/lib/format.d.ts +14 -0
  119. package/dist/lib/format.js +34 -0
  120. package/dist/lib/json.d.ts +1 -0
  121. package/dist/lib/json.js +12 -0
  122. package/dist/lib/multi-value.d.ts +3 -0
  123. package/dist/lib/multi-value.js +22 -0
  124. package/dist/lib/record-option.d.ts +7 -0
  125. package/dist/lib/record-option.js +52 -0
  126. package/dist/lib/use-record-labels.d.ts +14 -0
  127. package/dist/lib/use-record-labels.js +130 -0
  128. package/dist/lib/utils.d.ts +2 -0
  129. package/dist/lib/utils.js +5 -0
  130. package/dist/list-view.d.ts +26 -0
  131. package/dist/list-view.js +11 -0
  132. package/dist/markdown/blocks.d.ts +10 -0
  133. package/dist/markdown/blocks.js +57 -0
  134. package/dist/markdown/extensions.d.ts +6 -0
  135. package/dist/markdown/extensions.js +25 -0
  136. package/dist/markdown/slash.d.ts +23 -0
  137. package/dist/markdown/slash.js +27 -0
  138. package/dist/markdown/toolbar.d.ts +13 -0
  139. package/dist/markdown/toolbar.js +119 -0
  140. package/dist/plugin-ui.d.ts +43 -0
  141. package/dist/plugin-ui.js +37 -0
  142. package/dist/registry.d.ts +26 -0
  143. package/dist/registry.js +169 -0
  144. package/dist/render/blocks/accordion.d.ts +1 -0
  145. package/dist/render/blocks/accordion.js +15 -0
  146. package/dist/render/blocks/aside.d.ts +1 -0
  147. package/dist/render/blocks/aside.js +14 -0
  148. package/dist/render/blocks/balance.d.ts +1 -0
  149. package/dist/render/blocks/balance.js +14 -0
  150. package/dist/render/blocks/bento.d.ts +1 -0
  151. package/dist/render/blocks/bento.js +24 -0
  152. package/dist/render/blocks/block-shell.d.ts +15 -0
  153. package/dist/render/blocks/block-shell.js +20 -0
  154. package/dist/render/blocks/calendar.d.ts +1 -0
  155. package/dist/render/blocks/calendar.js +142 -0
  156. package/dist/render/blocks/callout.d.ts +1 -0
  157. package/dist/render/blocks/callout.js +21 -0
  158. package/dist/render/blocks/chart.d.ts +1 -0
  159. package/dist/render/blocks/chart.js +46 -0
  160. package/dist/render/blocks/compare.d.ts +1 -0
  161. package/dist/render/blocks/compare.js +16 -0
  162. package/dist/render/blocks/countdown.d.ts +1 -0
  163. package/dist/render/blocks/countdown.js +36 -0
  164. package/dist/render/blocks/deck.d.ts +1 -0
  165. package/dist/render/blocks/deck.js +29 -0
  166. package/dist/render/blocks/epigraph.d.ts +1 -0
  167. package/dist/render/blocks/epigraph.js +13 -0
  168. package/dist/render/blocks/facets.d.ts +1 -0
  169. package/dist/render/blocks/facets.js +23 -0
  170. package/dist/render/blocks/figure.d.ts +1 -0
  171. package/dist/render/blocks/figure.js +13 -0
  172. package/dist/render/blocks/grid.d.ts +1 -0
  173. package/dist/render/blocks/grid.js +21 -0
  174. package/dist/render/blocks/heatmap.d.ts +1 -0
  175. package/dist/render/blocks/heatmap.js +135 -0
  176. package/dist/render/blocks/idcard.d.ts +1 -0
  177. package/dist/render/blocks/idcard.js +30 -0
  178. package/dist/render/blocks/identity.d.ts +1 -0
  179. package/dist/render/blocks/identity.js +46 -0
  180. package/dist/render/blocks/index.d.ts +40 -0
  181. package/dist/render/blocks/index.js +40 -0
  182. package/dist/render/blocks/journal.d.ts +1 -0
  183. package/dist/render/blocks/journal.js +50 -0
  184. package/dist/render/blocks/ledger.d.ts +1 -0
  185. package/dist/render/blocks/ledger.js +23 -0
  186. package/dist/render/blocks/manifest.d.ts +1 -0
  187. package/dist/render/blocks/manifest.js +50 -0
  188. package/dist/render/blocks/masthead.d.ts +1 -0
  189. package/dist/render/blocks/masthead.js +15 -0
  190. package/dist/render/blocks/meter.d.ts +1 -0
  191. package/dist/render/blocks/meter.js +32 -0
  192. package/dist/render/blocks/nutrition.d.ts +1 -0
  193. package/dist/render/blocks/nutrition.js +27 -0
  194. package/dist/render/blocks/people.d.ts +1 -0
  195. package/dist/render/blocks/people.js +35 -0
  196. package/dist/render/blocks/plaque.d.ts +1 -0
  197. package/dist/render/blocks/plaque.js +15 -0
  198. package/dist/render/blocks/properties.d.ts +1 -0
  199. package/dist/render/blocks/properties.js +22 -0
  200. package/dist/render/blocks/prose.d.ts +1 -0
  201. package/dist/render/blocks/prose.js +17 -0
  202. package/dist/render/blocks/receipt.d.ts +1 -0
  203. package/dist/render/blocks/receipt.js +23 -0
  204. package/dist/render/blocks/registry.d.ts +16 -0
  205. package/dist/render/blocks/registry.js +7 -0
  206. package/dist/render/blocks/relation-source.d.ts +2 -0
  207. package/dist/render/blocks/relation-source.js +6 -0
  208. package/dist/render/blocks/route.d.ts +1 -0
  209. package/dist/render/blocks/route.js +23 -0
  210. package/dist/render/blocks/score.d.ts +1 -0
  211. package/dist/render/blocks/score.js +15 -0
  212. package/dist/render/blocks/series.d.ts +23 -0
  213. package/dist/render/blocks/series.js +57 -0
  214. package/dist/render/blocks/specimen.d.ts +1 -0
  215. package/dist/render/blocks/specimen.js +19 -0
  216. package/dist/render/blocks/split.d.ts +1 -0
  217. package/dist/render/blocks/split.js +15 -0
  218. package/dist/render/blocks/spread.d.ts +1 -0
  219. package/dist/render/blocks/spread.js +15 -0
  220. package/dist/render/blocks/stack.d.ts +1 -0
  221. package/dist/render/blocks/stack.js +15 -0
  222. package/dist/render/blocks/stats.d.ts +1 -0
  223. package/dist/render/blocks/stats.js +23 -0
  224. package/dist/render/blocks/status.d.ts +1 -0
  225. package/dist/render/blocks/status.js +18 -0
  226. package/dist/render/blocks/table.d.ts +11 -0
  227. package/dist/render/blocks/table.js +136 -0
  228. package/dist/render/blocks/tabs.d.ts +1 -0
  229. package/dist/render/blocks/tabs.js +17 -0
  230. package/dist/render/blocks/terminal.d.ts +1 -0
  231. package/dist/render/blocks/terminal.js +18 -0
  232. package/dist/render/blocks/timeline.d.ts +1 -0
  233. package/dist/render/blocks/timeline.js +31 -0
  234. package/dist/render/box.d.ts +5 -0
  235. package/dist/render/box.js +23 -0
  236. package/dist/render/chrome.d.ts +64 -0
  237. package/dist/render/chrome.js +92 -0
  238. package/dist/render/core/amount.d.ts +1 -0
  239. package/dist/render/core/amount.js +19 -0
  240. package/dist/render/core/attachment.d.ts +29 -0
  241. package/dist/render/core/attachment.js +102 -0
  242. package/dist/render/core/choice.d.ts +1 -0
  243. package/dist/render/core/choice.js +40 -0
  244. package/dist/render/core/composite.d.ts +1 -0
  245. package/dist/render/core/composite.js +132 -0
  246. package/dist/render/core/datetime.d.ts +2 -0
  247. package/dist/render/core/datetime.js +215 -0
  248. package/dist/render/core/dimensions.d.ts +1 -0
  249. package/dist/render/core/dimensions.js +44 -0
  250. package/dist/render/core/embed.d.ts +11 -0
  251. package/dist/render/core/embed.js +99 -0
  252. package/dist/render/core/file.d.ts +12 -0
  253. package/dist/render/core/file.js +238 -0
  254. package/dist/render/core/illustrated.d.ts +39 -0
  255. package/dist/render/core/illustrated.js +113 -0
  256. package/dist/render/core/index.d.ts +23 -0
  257. package/dist/render/core/index.js +23 -0
  258. package/dist/render/core/layout-elements.d.ts +1 -0
  259. package/dist/render/core/layout-elements.js +78 -0
  260. package/dist/render/core/localpath.d.ts +6 -0
  261. package/dist/render/core/localpath.js +73 -0
  262. package/dist/render/core/money.d.ts +1 -0
  263. package/dist/render/core/money.js +39 -0
  264. package/dist/render/core/number.d.ts +17 -0
  265. package/dist/render/core/number.js +104 -0
  266. package/dist/render/core/period.d.ts +1 -0
  267. package/dist/render/core/period.js +60 -0
  268. package/dist/render/core/range.d.ts +1 -0
  269. package/dist/render/core/range.js +55 -0
  270. package/dist/render/core/reminder.d.ts +2 -0
  271. package/dist/render/core/reminder.js +56 -0
  272. package/dist/render/core/source.d.ts +3 -0
  273. package/dist/render/core/source.js +65 -0
  274. package/dist/render/core/stepper.d.ts +1 -0
  275. package/dist/render/core/stepper.js +81 -0
  276. package/dist/render/core/storage-group.d.ts +1 -0
  277. package/dist/render/core/storage-group.js +30 -0
  278. package/dist/render/core/text.d.ts +15 -0
  279. package/dist/render/core/text.js +370 -0
  280. package/dist/render/core/tristate.d.ts +1 -0
  281. package/dist/render/core/tristate.js +42 -0
  282. package/dist/render/core/weight.d.ts +4 -0
  283. package/dist/render/core/weight.js +38 -0
  284. package/dist/render/dispatch.d.ts +12 -0
  285. package/dist/render/dispatch.js +53 -0
  286. package/dist/render/display-override.d.ts +25 -0
  287. package/dist/render/display-override.js +23 -0
  288. package/dist/render/editor-mode.d.ts +4 -0
  289. package/dist/render/editor-mode.js +11 -0
  290. package/dist/render/field-address.d.ts +14 -0
  291. package/dist/render/field-address.js +10 -0
  292. package/dist/render/field-errors.d.ts +8 -0
  293. package/dist/render/field-errors.js +25 -0
  294. package/dist/render/field-frame.d.ts +20 -0
  295. package/dist/render/field-frame.js +78 -0
  296. package/dist/render/field-scope.d.ts +8 -0
  297. package/dist/render/field-scope.js +25 -0
  298. package/dist/render/field-width.d.ts +7 -0
  299. package/dist/render/field-width.js +12 -0
  300. package/dist/render/form-types.d.ts +12 -0
  301. package/dist/render/form-types.js +1 -0
  302. package/dist/render/hybrid-scope.d.ts +5 -0
  303. package/dist/render/hybrid-scope.js +9 -0
  304. package/dist/render/image.d.ts +64 -0
  305. package/dist/render/image.js +322 -0
  306. package/dist/render/live-kind.d.ts +7 -0
  307. package/dist/render/live-kind.js +104 -0
  308. package/dist/render/markdown-view.d.ts +5 -0
  309. package/dist/render/markdown-view.js +17 -0
  310. package/dist/render/multi.d.ts +10 -0
  311. package/dist/render/multi.js +26 -0
  312. package/dist/render/multiple-chips.d.ts +24 -0
  313. package/dist/render/multiple-chips.js +18 -0
  314. package/dist/render/option-list.d.ts +15 -0
  315. package/dist/render/option-list.js +47 -0
  316. package/dist/render/option-value.d.ts +20 -0
  317. package/dist/render/option-value.js +41 -0
  318. package/dist/render/picker-scrim.d.ts +7 -0
  319. package/dist/render/picker-scrim.js +32 -0
  320. package/dist/render/picker-surface.d.ts +5 -0
  321. package/dist/render/picker-surface.js +9 -0
  322. package/dist/render/popover-field.d.ts +16 -0
  323. package/dist/render/popover-field.js +153 -0
  324. package/dist/render/record-save-ctx.d.ts +11 -0
  325. package/dist/render/record-save-ctx.js +41 -0
  326. package/dist/render/shared.d.ts +92 -0
  327. package/dist/render/shared.js +182 -0
  328. package/dist/render/slot.d.ts +45 -0
  329. package/dist/render/slot.js +194 -0
  330. package/dist/render/sort-rows.d.ts +3 -0
  331. package/dist/render/sort-rows.js +38 -0
  332. package/dist/render/use-collection-rows.d.ts +10 -0
  333. package/dist/render/use-collection-rows.js +11 -0
  334. package/dist/render/use-field-edit.d.ts +28 -0
  335. package/dist/render/use-field-edit.js +50 -0
  336. package/dist/render/use-file-upload.d.ts +10 -0
  337. package/dist/render/use-file-upload.js +35 -0
  338. package/dist/render/use-form-bridge.d.ts +21 -0
  339. package/dist/render/use-form-bridge.js +53 -0
  340. package/dist/render/use-hybrid.d.ts +2 -0
  341. package/dist/render/use-hybrid.js +5 -0
  342. package/dist/render/widgets/attachment-group.d.ts +1 -0
  343. package/dist/render/widgets/attachment-group.js +35 -0
  344. package/dist/render/widgets/checklist-content.d.ts +15 -0
  345. package/dist/render/widgets/checklist-content.js +12 -0
  346. package/dist/render/widgets/checklist-group.d.ts +11 -0
  347. package/dist/render/widgets/checklist-group.js +47 -0
  348. package/dist/render/widgets/checklist-row.d.ts +14 -0
  349. package/dist/render/widgets/checklist-row.js +14 -0
  350. package/dist/render/widgets/display.d.ts +33 -0
  351. package/dist/render/widgets/display.js +97 -0
  352. package/dist/render/widgets/edit.d.ts +63 -0
  353. package/dist/render/widgets/edit.js +283 -0
  354. package/dist/render/widgets/fixed-collection.d.ts +11 -0
  355. package/dist/render/widgets/fixed-collection.js +34 -0
  356. package/dist/render/widgets/flow-row.d.ts +14 -0
  357. package/dist/render/widgets/flow-row.js +27 -0
  358. package/dist/render/widgets/group-edit.d.ts +9 -0
  359. package/dist/render/widgets/group-edit.js +23 -0
  360. package/dist/render/widgets/group-field.d.ts +9 -0
  361. package/dist/render/widgets/group-field.js +42 -0
  362. package/dist/render/widgets/group-widgets.d.ts +2 -0
  363. package/dist/render/widgets/group-widgets.js +41 -0
  364. package/dist/render/widgets/group.d.ts +26 -0
  365. package/dist/render/widgets/group.js +139 -0
  366. package/dist/render/widgets/illustrated-group.d.ts +1 -0
  367. package/dist/render/widgets/illustrated-group.js +41 -0
  368. package/dist/render/widgets/table-group.d.ts +11 -0
  369. package/dist/render/widgets/table-group.js +58 -0
  370. package/dist/render/widgets/two-cell-group.d.ts +21 -0
  371. package/dist/render/widgets/two-cell-group.js +42 -0
  372. package/dist/render/widgets/url-widget.d.ts +7 -0
  373. package/dist/render/widgets/url-widget.js +15 -0
  374. package/dist/render/widgets/weekday-grid.d.ts +13 -0
  375. package/dist/render/widgets/weekday-grid.js +47 -0
  376. package/dist/render/write.d.ts +5 -0
  377. package/dist/render/write.js +14 -0
  378. package/dist/schema-registry.d.ts +6 -0
  379. package/dist/schema-registry.js +25 -0
  380. package/dist/site-links.d.ts +13 -0
  381. package/dist/site-links.js +18 -0
  382. package/dist/strip-markdown.d.ts +1 -0
  383. package/dist/strip-markdown.js +11 -0
  384. package/dist/theme.css +189 -0
  385. package/dist/types.d.ts +84 -0
  386. package/dist/types.js +1 -0
  387. package/package.json +85 -0
@@ -0,0 +1,1258 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Clock } from 'lucide-react';
4
+ import * as SlotPrimitive from '@radix-ui/react-slot';
5
+ import * as React from 'react';
6
+ import { useComposedRefs } from "../../lib/compose-refs.js";
7
+ import { cn } from "../../lib/utils.js";
8
+ import { VisuallyHiddenInput } from "../visually-hidden-input.js";
9
+ import { useAsRef } from "../../hooks/use-as-ref.js";
10
+ import { useIsomorphicLayoutEffect } from "../../hooks/use-isomorphic-layout-effect.js";
11
+ import { useLazyRef } from "../../hooks/use-lazy-ref.js";
12
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "./popover.js";
13
+ const ROOT_NAME = 'TimePicker';
14
+ const LABEL_NAME = 'TimePickerLabel';
15
+ const INPUT_GROUP_NAME = 'TimePickerInputGroup';
16
+ const INPUT_NAME = 'TimePickerInput';
17
+ const TRIGGER_NAME = 'TimePickerTrigger';
18
+ const CONTENT_NAME = 'TimePickerContent';
19
+ const COLUMN_NAME = 'TimePickerColumn';
20
+ const COLUMN_ITEM_NAME = 'TimePickerColumnItem';
21
+ const HOUR_NAME = 'TimePickerHour';
22
+ const MINUTE_NAME = 'TimePickerMinute';
23
+ const SECOND_NAME = 'TimePickerSecond';
24
+ const PERIOD_NAME = 'TimePickerPeriod';
25
+ const CLEAR_NAME = 'TimePickerClear';
26
+ const DEFAULT_STEP = 1;
27
+ const DEFAULT_SEGMENT_PLACEHOLDER = '--';
28
+ const DEFAULT_LOCALE = undefined;
29
+ const SEGMENTS = ['hour', 'minute', 'second', 'period'];
30
+ const PERIODS = ['AM', 'PM'];
31
+ function focusFirst(candidates, preventScroll = false) {
32
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
33
+ for (const candidateRef of candidates) {
34
+ const candidate = candidateRef.current;
35
+ if (!candidate)
36
+ continue;
37
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT)
38
+ return;
39
+ candidate.focus({ preventScroll });
40
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT)
41
+ return;
42
+ }
43
+ }
44
+ function sortNodes(items) {
45
+ return items.sort((a, b) => {
46
+ const elementA = a.ref.current;
47
+ const elementB = b.ref.current;
48
+ if (!elementA || !elementB)
49
+ return 0;
50
+ const position = elementA.compareDocumentPosition(elementB);
51
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
52
+ return -1;
53
+ }
54
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
55
+ return 1;
56
+ }
57
+ return 0;
58
+ });
59
+ }
60
+ function getIs12Hour(locale) {
61
+ const testDate = new Date(2000, 0, 1, 13, 0, 0);
62
+ const formatted = new Intl.DateTimeFormat(locale, {
63
+ hour: 'numeric',
64
+ }).format(testDate);
65
+ return /am|pm/i.test(formatted) || !formatted.includes('13');
66
+ }
67
+ function parseTimeString(timeString) {
68
+ if (!timeString)
69
+ return null;
70
+ const parts = timeString.split(':');
71
+ if (parts.length < 2)
72
+ return null;
73
+ const result = {};
74
+ if (parts[0] && parts[0] !== DEFAULT_SEGMENT_PLACEHOLDER) {
75
+ const hour = Number.parseInt(parts[0], 10);
76
+ if (!Number.isNaN(hour) && hour >= 0 && hour <= 23) {
77
+ result.hour = hour;
78
+ }
79
+ }
80
+ if (parts[1] && parts[1] !== DEFAULT_SEGMENT_PLACEHOLDER) {
81
+ const minute = Number.parseInt(parts[1], 10);
82
+ if (!Number.isNaN(minute) && minute >= 0 && minute <= 59) {
83
+ result.minute = minute;
84
+ }
85
+ }
86
+ if (parts[2] && parts[2] !== DEFAULT_SEGMENT_PLACEHOLDER) {
87
+ const second = Number.parseInt(parts[2], 10);
88
+ if (!Number.isNaN(second) && second >= 0 && second <= 59) {
89
+ result.second = second;
90
+ }
91
+ }
92
+ if (result.hour === undefined && result.minute === undefined && result.second === undefined) {
93
+ return null;
94
+ }
95
+ return result;
96
+ }
97
+ function formatTimeValue(value, showSeconds) {
98
+ const hourStr = value.hour !== undefined ? value.hour.toString().padStart(2, '0') : DEFAULT_SEGMENT_PLACEHOLDER;
99
+ const minuteStr = value.minute !== undefined ? value.minute.toString().padStart(2, '0') : DEFAULT_SEGMENT_PLACEHOLDER;
100
+ const secondStr = value.second !== undefined ? value.second.toString().padStart(2, '0') : DEFAULT_SEGMENT_PLACEHOLDER;
101
+ if (showSeconds) {
102
+ return `${hourStr}:${minuteStr}:${secondStr}`;
103
+ }
104
+ return `${hourStr}:${minuteStr}`;
105
+ }
106
+ function to12Hour(hour24) {
107
+ const period = hour24 >= 12 ? 'PM' : 'AM';
108
+ const hour = hour24 % 12 || 12;
109
+ return { hour, period };
110
+ }
111
+ function to24Hour(hour12, period) {
112
+ if (hour12 === 12) {
113
+ return period === 'PM' ? 12 : 0;
114
+ }
115
+ return period === 'PM' ? hour12 + 12 : hour12;
116
+ }
117
+ function clamp(value, min, max) {
118
+ return Math.min(Math.max(value, min), max);
119
+ }
120
+ const StoreContext = React.createContext(null);
121
+ function useStoreContext(consumerName) {
122
+ const context = React.useContext(StoreContext);
123
+ if (!context) {
124
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
125
+ }
126
+ return context;
127
+ }
128
+ function useStore(selector, ogStore) {
129
+ const contextStore = React.useContext(StoreContext);
130
+ const store = ogStore ?? contextStore;
131
+ if (!store) {
132
+ throw new Error(`\`useStore\` must be used within \`${ROOT_NAME}\``);
133
+ }
134
+ const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);
135
+ return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
136
+ }
137
+ const TimePickerContext = React.createContext(null);
138
+ function useTimePickerContext(consumerName) {
139
+ const context = React.useContext(TimePickerContext);
140
+ if (!context) {
141
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
142
+ }
143
+ return context;
144
+ }
145
+ function TimePicker(props) {
146
+ const { value: valueProp, defaultValue, onValueChange, open, defaultOpen, onOpenChange, openOnFocus = false, inputGroupClickAction = 'focus', min, max, hourStep = DEFAULT_STEP, minuteStep = DEFAULT_STEP, secondStep = DEFAULT_STEP, segmentPlaceholder = DEFAULT_SEGMENT_PLACEHOLDER, locale = DEFAULT_LOCALE, name, asChild, disabled = false, invalid = false, readOnly = false, required = false, showSeconds = false, className, children, id, ...rootProps } = props;
147
+ const instanceId = React.useId();
148
+ const rootId = id ?? instanceId;
149
+ const inputGroupId = React.useId();
150
+ const labelId = React.useId();
151
+ const triggerId = React.useId();
152
+ const inputGroupRef = React.useRef(null);
153
+ const triggerRef = React.useRef(null);
154
+ const [inputGroup, setInputGroup] = React.useState(null);
155
+ const isFormControl = inputGroup ? !!inputGroup.closest('form') : true;
156
+ const listenersRef = useLazyRef(() => new Set());
157
+ const stateRef = useLazyRef(() => ({
158
+ value: valueProp ?? defaultValue ?? '',
159
+ open: open ?? defaultOpen ?? false,
160
+ openedViaFocus: false,
161
+ }));
162
+ const propsRef = useAsRef({ onValueChange, onOpenChange });
163
+ const store = React.useMemo(() => {
164
+ return {
165
+ subscribe: (cb) => {
166
+ listenersRef.current.add(cb);
167
+ return () => listenersRef.current.delete(cb);
168
+ },
169
+ getState: () => stateRef.current,
170
+ setState: (key, value) => {
171
+ if (Object.is(stateRef.current[key], value))
172
+ return;
173
+ if (key === 'value' && typeof value === 'string') {
174
+ stateRef.current.value = value;
175
+ propsRef.current.onValueChange?.(value);
176
+ }
177
+ else if (key === 'open' && typeof value === 'boolean') {
178
+ stateRef.current.open = value;
179
+ propsRef.current.onOpenChange?.(value);
180
+ if (!value) {
181
+ stateRef.current.openedViaFocus = false;
182
+ }
183
+ }
184
+ else {
185
+ stateRef.current[key] = value;
186
+ }
187
+ store.notify();
188
+ },
189
+ notify: () => {
190
+ for (const cb of listenersRef.current) {
191
+ cb();
192
+ }
193
+ },
194
+ };
195
+ }, [listenersRef, stateRef, propsRef]);
196
+ const value = useStore((state) => state.value, store);
197
+ useIsomorphicLayoutEffect(() => {
198
+ if (valueProp !== undefined) {
199
+ store.setState('value', valueProp);
200
+ }
201
+ }, [valueProp]);
202
+ useIsomorphicLayoutEffect(() => {
203
+ if (open !== undefined) {
204
+ store.setState('open', open);
205
+ }
206
+ }, [open]);
207
+ const storeOpen = useStore((state) => state.open, store);
208
+ const onPopoverOpenChange = React.useCallback((newOpen) => store.setState('open', newOpen), [store]);
209
+ const is12Hour = React.useMemo(() => getIs12Hour(locale), [locale]);
210
+ const normalizedPlaceholder = React.useMemo(() => {
211
+ if (typeof segmentPlaceholder === 'string') {
212
+ return {
213
+ hour: segmentPlaceholder,
214
+ minute: segmentPlaceholder,
215
+ second: segmentPlaceholder,
216
+ period: segmentPlaceholder,
217
+ };
218
+ }
219
+ return {
220
+ hour: segmentPlaceholder.hour ?? DEFAULT_SEGMENT_PLACEHOLDER,
221
+ minute: segmentPlaceholder.minute ?? DEFAULT_SEGMENT_PLACEHOLDER,
222
+ second: segmentPlaceholder.second ?? DEFAULT_SEGMENT_PLACEHOLDER,
223
+ period: segmentPlaceholder.period ?? DEFAULT_SEGMENT_PLACEHOLDER,
224
+ };
225
+ }, [segmentPlaceholder]);
226
+ const rootContext = React.useMemo(() => ({
227
+ id: rootId,
228
+ inputGroupId,
229
+ labelId,
230
+ triggerId,
231
+ inputGroupRef,
232
+ triggerRef,
233
+ openOnFocus,
234
+ inputGroupClickAction,
235
+ onInputGroupChange: setInputGroup,
236
+ disabled,
237
+ readOnly,
238
+ required,
239
+ invalid,
240
+ showSeconds,
241
+ is12Hour,
242
+ minuteStep,
243
+ secondStep,
244
+ hourStep,
245
+ segmentPlaceholder: normalizedPlaceholder,
246
+ min,
247
+ max,
248
+ }), [
249
+ rootId,
250
+ inputGroupId,
251
+ labelId,
252
+ triggerId,
253
+ openOnFocus,
254
+ inputGroupClickAction,
255
+ disabled,
256
+ readOnly,
257
+ required,
258
+ invalid,
259
+ showSeconds,
260
+ is12Hour,
261
+ minuteStep,
262
+ secondStep,
263
+ hourStep,
264
+ normalizedPlaceholder,
265
+ min,
266
+ max,
267
+ ]);
268
+ const RootPrimitive = asChild ? SlotPrimitive.Slot : 'div';
269
+ return (_jsxs(_Fragment, { children: [_jsx(StoreContext.Provider, { value: store, children: _jsx(TimePickerContext.Provider, { value: rootContext, children: _jsx(Popover, { open: storeOpen, onOpenChange: onPopoverOpenChange, children: _jsx(RootPrimitive, { "data-slot": "time-picker", "data-disabled": disabled ? '' : undefined, "data-invalid": invalid ? '' : undefined, ...rootProps, className: cn('relative', className), children: children }) }) }) }), isFormControl && (_jsx(VisuallyHiddenInput, { type: "hidden", control: inputGroup, name: name, value: value, disabled: disabled, readOnly: readOnly, required: required }))] }));
270
+ }
271
+ function TimePickerLabel(props) {
272
+ const { asChild, className, ...labelProps } = props;
273
+ const { labelId } = useTimePickerContext(LABEL_NAME);
274
+ const LabelPrimitive = asChild ? SlotPrimitive.Slot : 'label';
275
+ return (_jsx(LabelPrimitive, { "data-slot": "time-picker-label", ...labelProps, htmlFor: labelId, className: cn('font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', className) }));
276
+ }
277
+ const TimePickerInputGroupContext = React.createContext(null);
278
+ function useTimePickerInputGroupContext(consumerName) {
279
+ const context = React.useContext(TimePickerInputGroupContext);
280
+ if (!context) {
281
+ throw new Error(`\`${consumerName}\` must be used within \`${INPUT_GROUP_NAME}\``);
282
+ }
283
+ return context;
284
+ }
285
+ function TimePickerInputGroup(props) {
286
+ const { onPointerDown: onPointerDownProp, onClick: onClickProp, asChild, className, style, ref, ...inputGroupProps } = props;
287
+ const { inputGroupId, labelId, onInputGroupChange, disabled, readOnly, invalid, segmentPlaceholder, inputGroupRef, triggerRef, inputGroupClickAction, } = useTimePickerContext(INPUT_GROUP_NAME);
288
+ const store = useStoreContext(INPUT_GROUP_NAME);
289
+ const composedRef = useComposedRefs(ref, inputGroupRef, onInputGroupChange);
290
+ const inputRefsMap = React.useRef(new Map());
291
+ const onInputRegister = React.useCallback((segment, ref) => {
292
+ inputRefsMap.current.set(segment, ref);
293
+ }, []);
294
+ const onInputUnregister = React.useCallback((segment) => {
295
+ inputRefsMap.current.delete(segment);
296
+ }, []);
297
+ const getNextInput = React.useCallback((currentSegment) => {
298
+ const segmentOrder = ['hour', 'minute', 'second', 'period'];
299
+ const currentIndex = segmentOrder.indexOf(currentSegment);
300
+ if (currentIndex === -1 || currentIndex === segmentOrder.length - 1) {
301
+ return null;
302
+ }
303
+ for (let i = currentIndex + 1; i < segmentOrder.length; i++) {
304
+ const nextSegment = segmentOrder[i];
305
+ if (nextSegment) {
306
+ const nextRef = inputRefsMap.current.get(nextSegment);
307
+ if (nextRef?.current) {
308
+ return nextRef;
309
+ }
310
+ }
311
+ }
312
+ return null;
313
+ }, []);
314
+ const onPointerDown = React.useCallback((event) => {
315
+ onPointerDownProp?.(event);
316
+ if (disabled || readOnly || event.defaultPrevented)
317
+ return;
318
+ const target = event.target;
319
+ if (target.tagName === 'INPUT' || target.closest('input')) {
320
+ return;
321
+ }
322
+ if (triggerRef.current?.contains(target)) {
323
+ return;
324
+ }
325
+ event.preventDefault();
326
+ }, [onPointerDownProp, disabled, readOnly, triggerRef]);
327
+ const onClick = React.useCallback((event) => {
328
+ onClickProp?.(event);
329
+ if (disabled || readOnly || event.defaultPrevented)
330
+ return;
331
+ const target = event.target;
332
+ if (target.tagName === 'INPUT' || target.closest('input')) {
333
+ return;
334
+ }
335
+ if (triggerRef.current?.contains(target)) {
336
+ return;
337
+ }
338
+ if (inputGroupClickAction === 'open') {
339
+ store.setState('open', true);
340
+ }
341
+ else {
342
+ const activeElement = document.activeElement;
343
+ const isInputAlreadyFocused = activeElement && activeElement.tagName === 'INPUT' && inputGroupRef.current?.contains(activeElement);
344
+ if (!isInputAlreadyFocused) {
345
+ for (const segment of SEGMENTS) {
346
+ const inputRef = inputRefsMap.current.get(segment);
347
+ if (inputRef?.current) {
348
+ inputRef.current.focus();
349
+ inputRef.current.select();
350
+ break;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }, [onClickProp, disabled, readOnly, inputGroupClickAction, store, triggerRef, inputGroupRef]);
356
+ const inputGroupContextValue = React.useMemo(() => ({
357
+ onInputRegister,
358
+ onInputUnregister,
359
+ getNextInput,
360
+ }), [onInputRegister, onInputUnregister, getNextInput]);
361
+ const InputGroupPrimitive = asChild ? SlotPrimitive.Slot : 'div';
362
+ return (_jsx(TimePickerInputGroupContext.Provider, { value: inputGroupContextValue, children: _jsx(PopoverAnchor, { asChild: true, children: _jsx(InputGroupPrimitive, { role: "group", id: inputGroupId, "aria-labelledby": labelId, "data-slot": "time-picker-input-group", "data-disabled": disabled ? '' : undefined, "data-invalid": invalid ? '' : undefined, ...inputGroupProps, className: cn('flex h-10 w-full cursor-text items-center gap-0.5 rounded-md border border-input bg-background px-3 py-2 shadow-xs outline-none transition-shadow', 'has-[input:focus]:border-ring has-[input:focus]:ring-[3px] has-[input:focus]:ring-ring/50', invalid && 'border-destructive ring-destructive/20', disabled && 'cursor-not-allowed opacity-50', className), style: {
363
+ '--time-picker-hour-input-width': `${segmentPlaceholder.hour.length}ch`,
364
+ '--time-picker-minute-input-width': `${segmentPlaceholder.minute.length}ch`,
365
+ '--time-picker-second-input-width': `${segmentPlaceholder.second.length}ch`,
366
+ '--time-picker-period-input-width': `${Math.max(segmentPlaceholder.period.length, 2) + 0.5}ch`,
367
+ ...style,
368
+ }, ref: composedRef, onPointerDown: onPointerDown, onClick: onClick }) }) }));
369
+ }
370
+ function TimePickerInput(props) {
371
+ const { segment, onBlur: onBlurProp, onChange: onChangeProp, onClick: onClickProp, onFocus: onFocusProp, onKeyDown: onKeyDownProp, disabled: disabledProp, readOnly: readOnlyProp, className, style, ref, ...inputProps } = props;
372
+ const { is12Hour, showSeconds, disabled, readOnly, segmentPlaceholder, openOnFocus } = useTimePickerContext(INPUT_NAME);
373
+ const store = useStoreContext(INPUT_NAME);
374
+ const inputGroupContext = useTimePickerInputGroupContext(INPUT_NAME);
375
+ const isDisabled = disabledProp || disabled;
376
+ const isReadOnly = readOnlyProp || readOnly;
377
+ const value = useStore((state) => state.value);
378
+ const timeValue = parseTimeString(value);
379
+ const inputRef = React.useRef(null);
380
+ const composedRef = useComposedRefs(ref, inputRef);
381
+ useIsomorphicLayoutEffect(() => {
382
+ if (segment) {
383
+ inputGroupContext.onInputRegister(segment, inputRef);
384
+ return () => inputGroupContext.onInputUnregister(segment);
385
+ }
386
+ }, [inputGroupContext, segment]);
387
+ const getSegmentValue = React.useCallback(() => {
388
+ if (!timeValue) {
389
+ if (!segment)
390
+ return '';
391
+ return segmentPlaceholder[segment];
392
+ }
393
+ switch (segment) {
394
+ case 'hour': {
395
+ if (timeValue.hour === undefined)
396
+ return segmentPlaceholder.hour;
397
+ if (is12Hour) {
398
+ return to12Hour(timeValue.hour).hour.toString().padStart(2, '0');
399
+ }
400
+ return timeValue.hour.toString().padStart(2, '0');
401
+ }
402
+ case 'minute':
403
+ if (timeValue.minute === undefined)
404
+ return segmentPlaceholder.minute;
405
+ return timeValue.minute.toString().padStart(2, '0');
406
+ case 'second':
407
+ if (timeValue.second === undefined)
408
+ return segmentPlaceholder.second;
409
+ return timeValue.second.toString().padStart(2, '0');
410
+ case 'period': {
411
+ if (!timeValue || timeValue.hour === undefined)
412
+ return segmentPlaceholder.period;
413
+ return to12Hour(timeValue.hour).period;
414
+ }
415
+ default:
416
+ return '';
417
+ }
418
+ }, [timeValue, segment, is12Hour, segmentPlaceholder]);
419
+ const [editValue, setEditValue] = React.useState(getSegmentValue());
420
+ const [isEditing, setIsEditing] = React.useState(false);
421
+ const [pendingDigit, setPendingDigit] = React.useState(null);
422
+ React.useEffect(() => {
423
+ if (!isEditing) {
424
+ setEditValue(getSegmentValue());
425
+ setPendingDigit(null);
426
+ }
427
+ }, [getSegmentValue, isEditing]);
428
+ const updateTimeValue = React.useCallback((newSegmentValue, shouldCreateIfEmpty = false) => {
429
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
430
+ if (!newSegmentValue || newSegmentValue === placeholder)
431
+ return;
432
+ if (!timeValue && !shouldCreateIfEmpty)
433
+ return;
434
+ const currentTime = timeValue ?? {};
435
+ const newTime = { ...currentTime };
436
+ switch (segment) {
437
+ case 'hour': {
438
+ const displayHour = Number.parseInt(newSegmentValue, 10);
439
+ if (!Number.isNaN(displayHour)) {
440
+ if (is12Hour) {
441
+ const clampedHour = clamp(displayHour, 1, 12);
442
+ let currentPeriod;
443
+ if (timeValue?.period !== undefined) {
444
+ currentPeriod = timeValue.period;
445
+ }
446
+ else if (timeValue?.hour !== undefined) {
447
+ currentPeriod = to12Hour(timeValue.hour).period;
448
+ }
449
+ else {
450
+ const now = new Date();
451
+ currentPeriod = to12Hour(now.getHours()).period;
452
+ }
453
+ const hour24 = to24Hour(clampedHour, currentPeriod);
454
+ newTime.hour = hour24;
455
+ if (timeValue?.period !== undefined) {
456
+ newTime.period = timeValue.period;
457
+ }
458
+ }
459
+ else {
460
+ newTime.hour = clamp(displayHour, 0, 23);
461
+ }
462
+ }
463
+ break;
464
+ }
465
+ case 'minute': {
466
+ const minute = Number.parseInt(newSegmentValue, 10);
467
+ if (!Number.isNaN(minute)) {
468
+ newTime.minute = clamp(minute, 0, 59);
469
+ }
470
+ break;
471
+ }
472
+ case 'second': {
473
+ const second = Number.parseInt(newSegmentValue, 10);
474
+ if (!Number.isNaN(second)) {
475
+ newTime.second = clamp(second, 0, 59);
476
+ }
477
+ break;
478
+ }
479
+ case 'period': {
480
+ if (newSegmentValue === 'AM' || newSegmentValue === 'PM') {
481
+ newTime.period = newSegmentValue;
482
+ if (timeValue && timeValue.hour !== undefined) {
483
+ const currentDisplay = to12Hour(timeValue.hour);
484
+ newTime.hour = to24Hour(currentDisplay.hour, newSegmentValue);
485
+ }
486
+ }
487
+ break;
488
+ }
489
+ }
490
+ const newValue = formatTimeValue(newTime, showSeconds);
491
+ store.setState('value', newValue);
492
+ }, [timeValue, segment, is12Hour, showSeconds, store, segmentPlaceholder]);
493
+ const onBlur = React.useCallback((event) => {
494
+ onBlurProp?.(event);
495
+ if (event.defaultPrevented)
496
+ return;
497
+ setIsEditing(false);
498
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
499
+ if (editValue && editValue !== placeholder && editValue.length > 0) {
500
+ let valueToUpdate = editValue;
501
+ if (segment !== 'period') {
502
+ if (editValue.length === 2) {
503
+ valueToUpdate = editValue;
504
+ }
505
+ else if (editValue.length === 1) {
506
+ const numValue = Number.parseInt(editValue, 10);
507
+ if (!Number.isNaN(numValue)) {
508
+ valueToUpdate = numValue.toString().padStart(2, '0');
509
+ }
510
+ }
511
+ }
512
+ updateTimeValue(valueToUpdate, true);
513
+ queueMicrotask(() => {
514
+ const currentTimeValue = parseTimeString(store.getState().value);
515
+ if (currentTimeValue) {
516
+ const now = new Date();
517
+ const newTime = { ...currentTimeValue };
518
+ let needsUpdate = false;
519
+ if (newTime.hour === undefined) {
520
+ newTime.hour = now.getHours();
521
+ needsUpdate = true;
522
+ }
523
+ if (newTime.minute === undefined) {
524
+ newTime.minute = now.getMinutes();
525
+ needsUpdate = true;
526
+ }
527
+ if (showSeconds && newTime.second === undefined) {
528
+ newTime.second = now.getSeconds();
529
+ needsUpdate = true;
530
+ }
531
+ if (needsUpdate) {
532
+ const newValue = formatTimeValue(newTime, showSeconds);
533
+ store.setState('value', newValue);
534
+ }
535
+ }
536
+ });
537
+ }
538
+ setEditValue(getSegmentValue());
539
+ setPendingDigit(null);
540
+ }, [onBlurProp, editValue, updateTimeValue, getSegmentValue, segment, segmentPlaceholder, showSeconds, store]);
541
+ const onChange = React.useCallback((event) => {
542
+ onChangeProp?.(event);
543
+ if (event.defaultPrevented)
544
+ return;
545
+ let newValue = event.target.value;
546
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
547
+ if (editValue === placeholder && newValue.length > 0 && newValue !== placeholder) {
548
+ newValue = newValue.replace(new RegExp(`^${placeholder}`), '');
549
+ }
550
+ if (segment === 'period') {
551
+ const firstChar = newValue.charAt(0).toUpperCase();
552
+ let newPeriod = null;
553
+ if (firstChar === 'A' || firstChar === '1') {
554
+ newPeriod = 'AM';
555
+ }
556
+ else if (firstChar === 'P' || firstChar === '2') {
557
+ newPeriod = 'PM';
558
+ }
559
+ if (newPeriod) {
560
+ setEditValue(newPeriod);
561
+ updateTimeValue(newPeriod, true);
562
+ queueMicrotask(() => {
563
+ inputRef.current?.select();
564
+ });
565
+ }
566
+ return;
567
+ }
568
+ if (segment === 'hour' || segment === 'minute' || segment === 'second') {
569
+ newValue = newValue.replace(/\D/g, '');
570
+ }
571
+ if (newValue.length > 2) {
572
+ newValue = newValue.slice(0, 2);
573
+ }
574
+ if (segment === 'hour' || segment === 'minute' || segment === 'second') {
575
+ const numValue = Number.parseInt(newValue, 10);
576
+ if (!Number.isNaN(numValue) && newValue.length > 0) {
577
+ if (pendingDigit !== null && newValue.length === 1) {
578
+ const twoDigitValue = pendingDigit + newValue;
579
+ const combinedNum = Number.parseInt(twoDigitValue, 10);
580
+ if (!Number.isNaN(combinedNum)) {
581
+ const paddedValue = combinedNum.toString().padStart(2, '0');
582
+ setEditValue(paddedValue);
583
+ updateTimeValue(paddedValue, true);
584
+ setPendingDigit(null);
585
+ queueMicrotask(() => {
586
+ if (segment) {
587
+ const nextInputRef = inputGroupContext.getNextInput(segment);
588
+ if (nextInputRef?.current) {
589
+ nextInputRef.current.focus();
590
+ nextInputRef.current.select();
591
+ }
592
+ }
593
+ });
594
+ return;
595
+ }
596
+ }
597
+ const maxFirstDigit = segment === 'hour' ? (is12Hour ? 1 : 2) : 5;
598
+ const firstDigit = Number.parseInt(newValue[0] ?? '0', 10);
599
+ const shouldAutoAdvance = firstDigit > maxFirstDigit;
600
+ if (newValue.length === 1) {
601
+ if (shouldAutoAdvance) {
602
+ const paddedValue = numValue.toString().padStart(2, '0');
603
+ setEditValue(paddedValue);
604
+ updateTimeValue(paddedValue, true);
605
+ setPendingDigit(null);
606
+ queueMicrotask(() => {
607
+ if (segment) {
608
+ const nextInputRef = inputGroupContext.getNextInput(segment);
609
+ if (nextInputRef?.current) {
610
+ nextInputRef.current.focus();
611
+ nextInputRef.current.select();
612
+ }
613
+ }
614
+ });
615
+ }
616
+ else {
617
+ const paddedValue = numValue.toString().padStart(2, '0');
618
+ setEditValue(paddedValue);
619
+ setPendingDigit(newValue);
620
+ queueMicrotask(() => {
621
+ inputRef.current?.select();
622
+ });
623
+ }
624
+ }
625
+ else if (newValue.length === 2) {
626
+ const paddedValue = numValue.toString().padStart(2, '0');
627
+ setEditValue(paddedValue);
628
+ updateTimeValue(paddedValue, true);
629
+ setPendingDigit(null);
630
+ queueMicrotask(() => {
631
+ if (segment) {
632
+ const nextInputRef = inputGroupContext.getNextInput(segment);
633
+ if (nextInputRef?.current) {
634
+ nextInputRef.current.focus();
635
+ nextInputRef.current.select();
636
+ }
637
+ }
638
+ });
639
+ }
640
+ }
641
+ else if (newValue.length === 0) {
642
+ setEditValue('');
643
+ setPendingDigit(null);
644
+ }
645
+ }
646
+ }, [segment, updateTimeValue, onChangeProp, editValue, is12Hour, inputGroupContext, pendingDigit, segmentPlaceholder]);
647
+ const onClick = React.useCallback((event) => {
648
+ onClickProp?.(event);
649
+ if (event.defaultPrevented)
650
+ return;
651
+ event.currentTarget.select();
652
+ }, [onClickProp]);
653
+ const onFocus = React.useCallback((event) => {
654
+ onFocusProp?.(event);
655
+ if (event.defaultPrevented)
656
+ return;
657
+ setIsEditing(true);
658
+ setPendingDigit(null);
659
+ if (openOnFocus && !store.getState().open) {
660
+ store.setState('openedViaFocus', true);
661
+ store.setState('open', true);
662
+ }
663
+ queueMicrotask(() => event.target.select());
664
+ }, [onFocusProp, openOnFocus, store]);
665
+ const onKeyDown = React.useCallback((event) => {
666
+ onKeyDownProp?.(event);
667
+ if (event.defaultPrevented)
668
+ return;
669
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
670
+ event.preventDefault();
671
+ const goToPrevious = event.key === 'ArrowLeft';
672
+ const inputGroup = inputRef.current?.closest('[data-slot="time-picker-input-group"]');
673
+ if (inputGroup && inputRef.current) {
674
+ const allInputs = Array.from(inputGroup.querySelectorAll('input[type="text"]'));
675
+ const currentIdx = allInputs.indexOf(inputRef.current);
676
+ if (currentIdx !== -1) {
677
+ const targetIdx = goToPrevious
678
+ ? Math.max(0, currentIdx - 1)
679
+ : Math.min(allInputs.length - 1, currentIdx + 1);
680
+ const targetInput = allInputs[targetIdx];
681
+ if (targetInput && targetInput !== inputRef.current) {
682
+ targetInput.focus();
683
+ targetInput.select();
684
+ }
685
+ }
686
+ }
687
+ return;
688
+ }
689
+ if (event.key === 'Backspace' || event.key === 'Delete') {
690
+ const input = inputRef.current;
691
+ if (input && input.selectionStart === 0 && input.selectionEnd === input.value.length) {
692
+ event.preventDefault();
693
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
694
+ setEditValue(placeholder);
695
+ setPendingDigit(null);
696
+ if (timeValue) {
697
+ const newTime = { ...timeValue };
698
+ switch (segment) {
699
+ case 'hour':
700
+ delete newTime.hour;
701
+ break;
702
+ case 'minute':
703
+ delete newTime.minute;
704
+ break;
705
+ case 'second':
706
+ delete newTime.second;
707
+ break;
708
+ case 'period':
709
+ delete newTime.period;
710
+ break;
711
+ }
712
+ if (newTime.hour !== undefined ||
713
+ newTime.minute !== undefined ||
714
+ newTime.second !== undefined ||
715
+ newTime.period !== undefined) {
716
+ const newValue = formatTimeValue(newTime, showSeconds);
717
+ store.setState('value', newValue);
718
+ }
719
+ else {
720
+ store.setState('value', '');
721
+ }
722
+ }
723
+ else {
724
+ store.setState('value', '');
725
+ }
726
+ queueMicrotask(() => {
727
+ inputRef.current?.select();
728
+ });
729
+ return;
730
+ }
731
+ }
732
+ if (segment === 'period') {
733
+ const key = event.key.toLowerCase();
734
+ if (key === 'a' || key === 'p' || key === '1' || key === '2') {
735
+ event.preventDefault();
736
+ let newPeriod;
737
+ if (key === 'a' || key === '1') {
738
+ newPeriod = 'AM';
739
+ }
740
+ else {
741
+ newPeriod = 'PM';
742
+ }
743
+ setEditValue(newPeriod);
744
+ updateTimeValue(newPeriod, true);
745
+ queueMicrotask(() => {
746
+ inputRef.current?.select();
747
+ });
748
+ }
749
+ else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
750
+ event.preventDefault();
751
+ const placeholder = segmentPlaceholder.period;
752
+ const currentPeriod = editValue === placeholder || editValue === '' ? 'AM' : editValue;
753
+ const newPeriod = currentPeriod === 'AM' || currentPeriod === 'A' ? 'PM' : 'AM';
754
+ setEditValue(newPeriod);
755
+ updateTimeValue(newPeriod, true);
756
+ queueMicrotask(() => {
757
+ inputRef.current?.select();
758
+ });
759
+ }
760
+ return;
761
+ }
762
+ if (event.key === 'Tab') {
763
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
764
+ if (editValue && editValue.length > 0 && editValue !== placeholder) {
765
+ if (editValue.length === 2) {
766
+ updateTimeValue(editValue, true);
767
+ }
768
+ else if (editValue.length === 1) {
769
+ const numValue = Number.parseInt(editValue, 10);
770
+ if (!Number.isNaN(numValue)) {
771
+ const paddedValue = numValue.toString().padStart(2, '0');
772
+ updateTimeValue(paddedValue, true);
773
+ }
774
+ }
775
+ }
776
+ return;
777
+ }
778
+ if (event.key === 'Enter') {
779
+ event.preventDefault();
780
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
781
+ if (editValue && editValue.length > 0 && editValue !== placeholder) {
782
+ if (editValue.length === 2) {
783
+ updateTimeValue(editValue, true);
784
+ }
785
+ else if (editValue.length === 1) {
786
+ const numValue = Number.parseInt(editValue, 10);
787
+ if (!Number.isNaN(numValue)) {
788
+ const paddedValue = numValue.toString().padStart(2, '0');
789
+ updateTimeValue(paddedValue, true);
790
+ }
791
+ }
792
+ }
793
+ queueMicrotask(() => {
794
+ inputRef.current?.select();
795
+ });
796
+ }
797
+ if (event.key === 'Escape') {
798
+ event.preventDefault();
799
+ setEditValue(getSegmentValue());
800
+ inputRef.current?.blur();
801
+ }
802
+ if (event.key === 'ArrowUp') {
803
+ event.preventDefault();
804
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
805
+ if (editValue === placeholder || editValue === '') {
806
+ const defaultValue = segment === 'hour' ? (is12Hour ? 12 : 0) : 0;
807
+ const formattedValue = defaultValue.toString().padStart(2, '0');
808
+ setEditValue(formattedValue);
809
+ updateTimeValue(formattedValue, true);
810
+ queueMicrotask(() => {
811
+ inputRef.current?.select();
812
+ });
813
+ return;
814
+ }
815
+ const currentValue = Number.parseInt(editValue, 10);
816
+ if (!Number.isNaN(currentValue)) {
817
+ let newValue;
818
+ switch (segment) {
819
+ case 'hour':
820
+ if (is12Hour) {
821
+ newValue = currentValue === 12 ? 1 : currentValue + 1;
822
+ }
823
+ else {
824
+ newValue = currentValue === 23 ? 0 : currentValue + 1;
825
+ }
826
+ break;
827
+ case 'minute':
828
+ case 'second':
829
+ newValue = currentValue === 59 ? 0 : currentValue + 1;
830
+ break;
831
+ default:
832
+ return;
833
+ }
834
+ const formattedValue = newValue.toString().padStart(2, '0');
835
+ setEditValue(formattedValue);
836
+ updateTimeValue(formattedValue, true);
837
+ queueMicrotask(() => {
838
+ inputRef.current?.select();
839
+ });
840
+ }
841
+ }
842
+ if (event.key === 'ArrowDown') {
843
+ event.preventDefault();
844
+ const placeholder = segment ? segmentPlaceholder[segment] : DEFAULT_SEGMENT_PLACEHOLDER;
845
+ if (editValue === placeholder || editValue === '') {
846
+ const defaultValue = segment === 'hour' ? (is12Hour ? 12 : 23) : 59;
847
+ const formattedValue = defaultValue.toString().padStart(2, '0');
848
+ setEditValue(formattedValue);
849
+ updateTimeValue(formattedValue, true);
850
+ queueMicrotask(() => {
851
+ inputRef.current?.select();
852
+ });
853
+ return;
854
+ }
855
+ const currentValue = Number.parseInt(editValue, 10);
856
+ if (!Number.isNaN(currentValue)) {
857
+ let newValue;
858
+ switch (segment) {
859
+ case 'hour':
860
+ if (is12Hour) {
861
+ newValue = currentValue === 1 ? 12 : currentValue - 1;
862
+ }
863
+ else {
864
+ newValue = currentValue === 0 ? 23 : currentValue - 1;
865
+ }
866
+ break;
867
+ case 'minute':
868
+ case 'second':
869
+ newValue = currentValue === 0 ? 59 : currentValue - 1;
870
+ break;
871
+ default:
872
+ return;
873
+ }
874
+ const formattedValue = newValue.toString().padStart(2, '0');
875
+ setEditValue(formattedValue);
876
+ updateTimeValue(formattedValue, true);
877
+ queueMicrotask(() => {
878
+ inputRef.current?.select();
879
+ });
880
+ }
881
+ }
882
+ }, [
883
+ onKeyDownProp,
884
+ editValue,
885
+ segment,
886
+ is12Hour,
887
+ getSegmentValue,
888
+ updateTimeValue,
889
+ showSeconds,
890
+ timeValue,
891
+ store,
892
+ segmentPlaceholder,
893
+ ]);
894
+ const displayValue = isEditing ? editValue : getSegmentValue();
895
+ const segmentWidth = segment ? `var(--time-picker-${segment}-input-width)` : '2ch';
896
+ return (_jsx("input", { type: "text", inputMode: segment === 'period' ? 'text' : 'numeric', autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, translate: "no", ...inputProps, disabled: isDisabled, readOnly: isReadOnly, className: cn('inline-flex h-full items-center justify-center border-0 bg-transparent text-center text-sm tabular-nums outline-none transition-colors focus:bg-transparent disabled:cursor-not-allowed disabled:opacity-50', className), style: { width: segmentWidth, ...style }, ref: composedRef, value: displayValue, onBlur: onBlur, onChange: onChange, onClick: onClick, onFocus: onFocus, onKeyDown: onKeyDown }));
897
+ }
898
+ function TimePickerTrigger(props) {
899
+ const { className, children, disabled: disabledProp, ref, ...triggerProps } = props;
900
+ const { triggerId, disabled, triggerRef } = useTimePickerContext(TRIGGER_NAME);
901
+ const isDisabled = disabledProp || disabled;
902
+ const composedRef = useComposedRefs(ref, triggerRef);
903
+ return (_jsx(PopoverTrigger, { type: "button", id: triggerId, "data-slot": "time-picker-trigger", disabled: isDisabled, ref: composedRef, ...triggerProps, className: cn("ml-auto flex items-center text-muted-foreground transition-colors hover:text-foreground disabled:pointer-events-none [&>svg:not([class*='size-'])]:size-4", className), children: children ?? _jsx(Clock, {}) }));
904
+ }
905
+ const TimePickerGroupContext = React.createContext(null);
906
+ function useTimePickerGroupContext(consumerName) {
907
+ const context = React.useContext(TimePickerGroupContext);
908
+ if (!context) {
909
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
910
+ }
911
+ return context;
912
+ }
913
+ function TimePickerContent(props) {
914
+ const { side = 'bottom', align = 'start', sideOffset = 6, className, onOpenAutoFocus: onOpenAutoFocusProp, onInteractOutside: onInteractOutsideProp, ...contentProps } = props;
915
+ const store = useStoreContext(CONTENT_NAME);
916
+ const { openOnFocus, inputGroupRef } = useTimePickerContext(CONTENT_NAME);
917
+ const columnsRef = React.useRef(new Map());
918
+ const onColumnRegister = React.useCallback((column) => {
919
+ columnsRef.current.set(column.id, column);
920
+ }, []);
921
+ const onColumnUnregister = React.useCallback((id) => {
922
+ columnsRef.current.delete(id);
923
+ }, []);
924
+ const getColumns = React.useCallback(() => {
925
+ const columns = Array.from(columnsRef.current.entries())
926
+ .map(([id, { ref, getSelectedItemRef, getItems }]) => ({
927
+ id,
928
+ ref,
929
+ getSelectedItemRef,
930
+ getItems,
931
+ }))
932
+ .filter((c) => c.ref.current !== null);
933
+ return sortNodes(columns);
934
+ }, []);
935
+ const groupContextValue = React.useMemo(() => ({
936
+ getColumns,
937
+ onColumnRegister,
938
+ onColumnUnregister,
939
+ }), [getColumns, onColumnRegister, onColumnUnregister]);
940
+ const onOpenAutoFocus = React.useCallback((event) => {
941
+ onOpenAutoFocusProp?.(event);
942
+ if (event.defaultPrevented)
943
+ return;
944
+ event.preventDefault();
945
+ const { openedViaFocus } = store.getState();
946
+ if (openedViaFocus) {
947
+ store.setState('openedViaFocus', false);
948
+ return;
949
+ }
950
+ const columns = getColumns();
951
+ const firstColumn = columns[0];
952
+ if (!firstColumn)
953
+ return;
954
+ const items = firstColumn.getItems();
955
+ const selectedItem = items.find((item) => item.selected);
956
+ const candidateRefs = selectedItem
957
+ ? [selectedItem.ref, ...items.map((item) => item.ref)]
958
+ : items.map((item) => item.ref);
959
+ focusFirst(candidateRefs, false);
960
+ }, [onOpenAutoFocusProp, getColumns, store]);
961
+ const onInteractOutside = React.useCallback((event) => {
962
+ onInteractOutsideProp?.(event);
963
+ if (event.defaultPrevented)
964
+ return;
965
+ if (openOnFocus && inputGroupRef.current) {
966
+ const target = event.target;
967
+ if (!(target instanceof Node))
968
+ return;
969
+ const isInsideInputGroup = inputGroupRef.current.contains(target);
970
+ if (isInsideInputGroup) {
971
+ event.preventDefault();
972
+ }
973
+ }
974
+ }, [onInteractOutsideProp, openOnFocus, inputGroupRef]);
975
+ return (_jsx(TimePickerGroupContext.Provider, { value: groupContextValue, children: _jsx(PopoverContent, { "data-slot": "time-picker-content", side: side, align: align, sideOffset: sideOffset, ...contentProps, className: cn('flex w-auto max-w-(--radix-popover-trigger-width) p-0', className), onOpenAutoFocus: onOpenAutoFocus, onInteractOutside: onInteractOutside }) }));
976
+ }
977
+ const TimePickerColumnContext = React.createContext(null);
978
+ function useTimePickerColumnContext(consumerName) {
979
+ const context = React.useContext(TimePickerColumnContext);
980
+ if (!context) {
981
+ throw new Error(`\`${consumerName}\` must be used within a column`);
982
+ }
983
+ return context;
984
+ }
985
+ function TimePickerColumn(props) {
986
+ const { children, className, ref, ...columnProps } = props;
987
+ const columnId = React.useId();
988
+ const columnRef = React.useRef(null);
989
+ const composedRef = useComposedRefs(ref, columnRef);
990
+ const itemsRef = React.useRef(new Map());
991
+ const groupContext = useTimePickerGroupContext(COLUMN_NAME);
992
+ const onItemRegister = React.useCallback((value, ref, selected) => {
993
+ itemsRef.current.set(value, { ref, selected });
994
+ }, []);
995
+ const onItemUnregister = React.useCallback((value) => {
996
+ itemsRef.current.delete(value);
997
+ }, []);
998
+ const getItems = React.useCallback(() => {
999
+ const items = Array.from(itemsRef.current.entries())
1000
+ .map(([value, { ref, selected }]) => ({
1001
+ value,
1002
+ ref,
1003
+ selected,
1004
+ }))
1005
+ .filter((item) => item.ref.current);
1006
+ return sortNodes(items);
1007
+ }, []);
1008
+ const getSelectedItemRef = React.useCallback(() => {
1009
+ const items = getItems();
1010
+ return items.find((item) => item.selected)?.ref ?? null;
1011
+ }, [getItems]);
1012
+ useIsomorphicLayoutEffect(() => {
1013
+ groupContext.onColumnRegister({
1014
+ id: columnId,
1015
+ ref: columnRef,
1016
+ getSelectedItemRef,
1017
+ getItems,
1018
+ });
1019
+ return () => groupContext.onColumnUnregister(columnId);
1020
+ }, [groupContext, columnId, getSelectedItemRef, getItems]);
1021
+ const columnContextValue = React.useMemo(() => ({
1022
+ getItems,
1023
+ onItemRegister,
1024
+ onItemUnregister,
1025
+ }), [getItems, onItemRegister, onItemUnregister]);
1026
+ return (_jsx(TimePickerColumnContext.Provider, { value: columnContextValue, children: _jsx("div", { ref: composedRef, "data-slot": "time-picker-column", ...columnProps, className: cn('flex flex-col gap-1 not-last:border-r p-1', className), children: children }) }));
1027
+ }
1028
+ function TimePickerColumnItem(props) {
1029
+ const { value, selected = false, format = 'numeric', className, ref, ...itemProps } = props;
1030
+ const itemRef = React.useRef(null);
1031
+ const composedRef = useComposedRefs(ref, itemRef);
1032
+ const columnContext = useTimePickerColumnContext(COLUMN_ITEM_NAME);
1033
+ const groupContext = useTimePickerGroupContext(COLUMN_ITEM_NAME);
1034
+ useIsomorphicLayoutEffect(() => {
1035
+ columnContext.onItemRegister(value, itemRef, selected);
1036
+ return () => columnContext.onItemUnregister(value);
1037
+ }, [columnContext, value, selected]);
1038
+ useIsomorphicLayoutEffect(() => {
1039
+ if (selected && itemRef.current) {
1040
+ itemRef.current.scrollIntoView({ block: 'nearest' });
1041
+ }
1042
+ }, [selected]);
1043
+ const onClick = React.useCallback((event) => {
1044
+ itemProps.onClick?.(event);
1045
+ if (event.defaultPrevented)
1046
+ return;
1047
+ itemRef.current?.focus();
1048
+ }, [itemProps.onClick]);
1049
+ const onKeyDown = React.useCallback((event) => {
1050
+ itemProps.onKeyDown?.(event);
1051
+ if (event.defaultPrevented)
1052
+ return;
1053
+ if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
1054
+ event.preventDefault();
1055
+ const items = columnContext.getItems().sort((a, b) => {
1056
+ if (typeof a.value === 'number' && typeof b.value === 'number') {
1057
+ return a.value - b.value;
1058
+ }
1059
+ return 0;
1060
+ });
1061
+ const currentIndex = items.findIndex((item) => item.value === value);
1062
+ let nextIndex;
1063
+ if (event.key === 'ArrowUp') {
1064
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
1065
+ }
1066
+ else {
1067
+ nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
1068
+ }
1069
+ const nextItem = items[nextIndex];
1070
+ nextItem?.ref.current?.focus();
1071
+ nextItem?.ref.current?.click();
1072
+ }
1073
+ else if ((event.key === 'Tab' || event.key === 'ArrowLeft' || event.key === 'ArrowRight') && groupContext) {
1074
+ event.preventDefault();
1075
+ queueMicrotask(() => {
1076
+ const columns = groupContext.getColumns();
1077
+ if (columns.length === 0)
1078
+ return;
1079
+ const currentColumnIndex = columns.findIndex((c) => c.ref.current?.contains(itemRef.current) ?? false);
1080
+ if (currentColumnIndex === -1)
1081
+ return;
1082
+ const goToPrevious = event.key === 'ArrowLeft' || (event.key === 'Tab' && event.shiftKey);
1083
+ const nextColumnIndex = goToPrevious
1084
+ ? currentColumnIndex > 0
1085
+ ? currentColumnIndex - 1
1086
+ : columns.length - 1
1087
+ : currentColumnIndex < columns.length - 1
1088
+ ? currentColumnIndex + 1
1089
+ : 0;
1090
+ const nextColumn = columns[nextColumnIndex];
1091
+ if (nextColumn?.ref.current) {
1092
+ const items = nextColumn.getItems();
1093
+ const selectedItem = items.find((item) => item.selected);
1094
+ const candidateRefs = selectedItem
1095
+ ? [selectedItem.ref, ...items.map((item) => item.ref)]
1096
+ : items.map((item) => item.ref);
1097
+ focusFirst(candidateRefs, false);
1098
+ }
1099
+ });
1100
+ }
1101
+ }, [itemProps.onKeyDown, columnContext, groupContext, value]);
1102
+ const formattedValue = typeof value === 'number' && format === '2-digit' ? value.toString().padStart(2, '0') : value.toString();
1103
+ return (_jsx("button", { type: "button", ...itemProps, ref: composedRef, "data-selected": selected ? '' : undefined, className: cn('w-full rounded px-3 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground focus:border-ring focus:outline-none focus:ring-[3px] focus:ring-ring/50', 'data-selected:bg-primary data-selected:text-primary-foreground data-selected:hover:bg-primary data-selected:hover:text-primary-foreground', className), onClick: onClick, onKeyDown: onKeyDown, children: formattedValue }));
1104
+ }
1105
+ function TimePickerHour(props) {
1106
+ const { asChild, format = 'numeric', className, ...hourProps } = props;
1107
+ const { is12Hour, hourStep, showSeconds } = useTimePickerContext(HOUR_NAME);
1108
+ const store = useStoreContext(HOUR_NAME);
1109
+ const value = useStore((state) => state.value);
1110
+ const timeValue = parseTimeString(value);
1111
+ const hours = Array.from({
1112
+ length: is12Hour ? Math.ceil(12 / hourStep) : Math.ceil(24 / hourStep),
1113
+ }, (_, i) => {
1114
+ if (is12Hour) {
1115
+ const hour = (i * hourStep) % 12;
1116
+ return hour === 0 ? 12 : hour;
1117
+ }
1118
+ return i * hourStep;
1119
+ });
1120
+ const onHourSelect = React.useCallback((displayHour) => {
1121
+ const now = new Date();
1122
+ const currentTime = timeValue ?? {};
1123
+ let hour24 = displayHour;
1124
+ if (is12Hour) {
1125
+ let currentPeriod;
1126
+ if (timeValue?.period !== undefined) {
1127
+ currentPeriod = timeValue.period;
1128
+ }
1129
+ else if (timeValue?.hour !== undefined) {
1130
+ currentPeriod = to12Hour(timeValue.hour).period;
1131
+ }
1132
+ else {
1133
+ currentPeriod = to12Hour(now.getHours()).period;
1134
+ }
1135
+ hour24 = to24Hour(displayHour, currentPeriod);
1136
+ }
1137
+ const newTime = { ...currentTime, hour: hour24 };
1138
+ if (timeValue && timeValue.period !== undefined) {
1139
+ newTime.period = timeValue.period;
1140
+ }
1141
+ if (newTime.minute === undefined) {
1142
+ newTime.minute = now.getMinutes();
1143
+ }
1144
+ if (showSeconds && newTime.second === undefined) {
1145
+ newTime.second = now.getSeconds();
1146
+ }
1147
+ const newValue = formatTimeValue(newTime, showSeconds);
1148
+ store.setState('value', newValue);
1149
+ }, [timeValue, showSeconds, is12Hour, store]);
1150
+ const now = new Date();
1151
+ const referenceHour = timeValue?.hour ?? now.getHours();
1152
+ const displayHour = is12Hour ? to12Hour(referenceHour).hour : referenceHour;
1153
+ const HourPrimitive = asChild ? SlotPrimitive.Slot : TimePickerColumn;
1154
+ return (_jsx(HourPrimitive, { "data-slot": "time-picker-hour", ...hourProps, className: cn('scrollbar-none flex max-h-[200px] flex-col gap-1 overflow-y-auto p-1', className), children: hours.map((hour) => (_jsx(TimePickerColumnItem, { value: hour, selected: displayHour === hour, format: format, onClick: () => onHourSelect(hour) }, hour))) }));
1155
+ }
1156
+ function TimePickerMinute(props) {
1157
+ const { asChild, format = '2-digit', className, ...minuteProps } = props;
1158
+ const { minuteStep, showSeconds } = useTimePickerContext(MINUTE_NAME);
1159
+ const store = useStoreContext(MINUTE_NAME);
1160
+ const value = useStore((state) => state.value);
1161
+ const timeValue = parseTimeString(value);
1162
+ const minutes = Array.from({ length: Math.ceil(60 / minuteStep) }, (_, i) => i * minuteStep);
1163
+ const onMinuteSelect = React.useCallback((minute) => {
1164
+ const now = new Date();
1165
+ const currentTime = timeValue ?? {};
1166
+ const newTime = { ...currentTime, minute };
1167
+ if (newTime.hour === undefined) {
1168
+ newTime.hour = now.getHours();
1169
+ }
1170
+ if (showSeconds && newTime.second === undefined) {
1171
+ newTime.second = now.getSeconds();
1172
+ }
1173
+ const newValue = formatTimeValue(newTime, showSeconds);
1174
+ store.setState('value', newValue);
1175
+ }, [timeValue, showSeconds, store]);
1176
+ const MinutePrimitive = asChild ? SlotPrimitive.Slot : TimePickerColumn;
1177
+ const now = new Date();
1178
+ const referenceMinute = timeValue?.minute ?? now.getMinutes();
1179
+ return (_jsx(MinutePrimitive, { "data-slot": "time-picker-minute", ...minuteProps, className: cn('scrollbar-none flex max-h-[200px] flex-col gap-1 overflow-y-auto p-1', className), children: minutes.map((minute) => (_jsx(TimePickerColumnItem, { value: minute, selected: referenceMinute === minute, format: format, onClick: () => onMinuteSelect(minute) }, minute))) }));
1180
+ }
1181
+ function TimePickerSecond(props) {
1182
+ const { asChild, format = '2-digit', className, ...secondProps } = props;
1183
+ const { secondStep } = useTimePickerContext(SECOND_NAME);
1184
+ const store = useStoreContext(SECOND_NAME);
1185
+ const value = useStore((state) => state.value);
1186
+ const timeValue = parseTimeString(value);
1187
+ const seconds = Array.from({ length: Math.ceil(60 / secondStep) }, (_, i) => i * secondStep);
1188
+ const onSecondSelect = React.useCallback((second) => {
1189
+ const now = new Date();
1190
+ const currentTime = timeValue ?? {};
1191
+ const newTime = { ...currentTime, second };
1192
+ if (newTime.hour === undefined) {
1193
+ newTime.hour = now.getHours();
1194
+ }
1195
+ if (newTime.minute === undefined) {
1196
+ newTime.minute = now.getMinutes();
1197
+ }
1198
+ const newValue = formatTimeValue(newTime, true);
1199
+ store.setState('value', newValue);
1200
+ }, [timeValue, store]);
1201
+ const SecondPrimitive = asChild ? SlotPrimitive.Slot : TimePickerColumn;
1202
+ const now = new Date();
1203
+ const referenceSecond = timeValue?.second ?? now.getSeconds();
1204
+ return (_jsx(SecondPrimitive, { "data-slot": "time-picker-second", ...secondProps, className: cn('scrollbar-none flex max-h-[200px] flex-col gap-1 overflow-y-auto p-1', className), children: seconds.map((second) => (_jsx(TimePickerColumnItem, { value: second, selected: referenceSecond === second, format: format, onClick: () => onSecondSelect(second) }, second))) }));
1205
+ }
1206
+ function TimePickerPeriod(props) {
1207
+ const { asChild, className, ...periodProps } = props;
1208
+ const { is12Hour, showSeconds } = useTimePickerContext(PERIOD_NAME);
1209
+ const store = useStoreContext(PERIOD_NAME);
1210
+ const value = useStore((state) => state.value);
1211
+ const timeValue = parseTimeString(value);
1212
+ const onPeriodToggle = React.useCallback((period) => {
1213
+ const now = new Date();
1214
+ const currentTime = timeValue ?? {};
1215
+ const currentHour = currentTime.hour !== undefined ? currentTime.hour : now.getHours();
1216
+ const currentDisplay = to12Hour(currentHour);
1217
+ const new24Hour = to24Hour(currentDisplay.hour, period);
1218
+ const newTime = { ...currentTime, hour: new24Hour };
1219
+ if (newTime.minute === undefined) {
1220
+ newTime.minute = now.getMinutes();
1221
+ }
1222
+ if (showSeconds && newTime.second === undefined) {
1223
+ newTime.second = now.getSeconds();
1224
+ }
1225
+ const newValue = formatTimeValue(newTime, showSeconds);
1226
+ store.setState('value', newValue);
1227
+ }, [timeValue, showSeconds, store]);
1228
+ if (!is12Hour)
1229
+ return null;
1230
+ const now = new Date();
1231
+ const referenceHour = timeValue?.hour ?? now.getHours();
1232
+ const currentPeriod = to12Hour(referenceHour).period;
1233
+ const PeriodPrimitive = asChild ? SlotPrimitive.Slot : TimePickerColumn;
1234
+ return (_jsx(PeriodPrimitive, { "data-slot": "time-picker-period", ...periodProps, className: cn('flex flex-col gap-1 p-1', className), children: PERIODS.map((period) => (_jsx(TimePickerColumnItem, { value: period, selected: currentPeriod === period, onClick: () => onPeriodToggle(period) }, period))) }));
1235
+ }
1236
+ function TimePickerSeparator(props) {
1237
+ const { asChild, children, ...separatorProps } = props;
1238
+ const SeparatorPrimitive = asChild ? SlotPrimitive.Slot : 'span';
1239
+ return (_jsx(SeparatorPrimitive, { "aria-hidden": "true", "data-slot": "time-picker-separator", ...separatorProps, children: children ?? ':' }));
1240
+ }
1241
+ function TimePickerClear(props) {
1242
+ const { asChild, className, children, disabled: disabledProp, ...clearProps } = props;
1243
+ const { disabled, readOnly } = useTimePickerContext(CLEAR_NAME);
1244
+ const store = useStoreContext(CLEAR_NAME);
1245
+ const isDisabled = disabledProp || disabled;
1246
+ const onClick = React.useCallback((event) => {
1247
+ clearProps.onClick?.(event);
1248
+ if (event.defaultPrevented)
1249
+ return;
1250
+ event.preventDefault();
1251
+ if (disabled || readOnly)
1252
+ return;
1253
+ store.setState('value', '');
1254
+ }, [clearProps.onClick, disabled, readOnly, store]);
1255
+ const ClearPrimitive = asChild ? SlotPrimitive.Slot : 'button';
1256
+ return (_jsx(ClearPrimitive, { type: "button", "data-slot": "time-picker-clear", disabled: isDisabled, ...clearProps, className: cn('inline-flex items-center justify-center rounded-sm font-medium text-sm transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50', className), onClick: onClick, children: children ?? 'Clear' }));
1257
+ }
1258
+ export { TimePicker, TimePickerClear, TimePickerContent, TimePickerHour, TimePickerInput, TimePickerInputGroup, TimePickerLabel, TimePickerMinute, TimePickerPeriod, TimePickerSecond, TimePickerSeparator, TimePickerTrigger, useStore as useTimePicker, };