@zerodep-dev/vue-tsx-pro-ui 0.1.0 → 0.3.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 (470) hide show
  1. package/dist/base/Badge.js +3 -3
  2. package/dist/base/Badge.js.map +1 -1
  3. package/dist/base/Can.d.ts +12 -0
  4. package/dist/base/Can.js +20 -0
  5. package/dist/base/Can.js.map +1 -0
  6. package/dist/base/ClientOnly.d.ts +10 -0
  7. package/dist/base/ClientOnly.js +18 -0
  8. package/dist/base/ClientOnly.js.map +1 -0
  9. package/dist/base/CloseButton.js +3 -3
  10. package/dist/base/CloseButton.js.map +1 -1
  11. package/dist/base/CodeBlock.js +5 -5
  12. package/dist/base/CodeBlock.js.map +1 -1
  13. package/dist/base/CopyButton.js +3 -3
  14. package/dist/base/CopyButton.js.map +1 -1
  15. package/dist/base/Icon.js +3 -3
  16. package/dist/base/Icon.js.map +1 -1
  17. package/dist/base/Indicator.js +3 -3
  18. package/dist/base/Indicator.js.map +1 -1
  19. package/dist/base/StatusDot.js +3 -3
  20. package/dist/base/StatusDot.js.map +1 -1
  21. package/dist/base/Tag.js +5 -5
  22. package/dist/base/Tag.js.map +1 -1
  23. package/dist/base/button-core.js +4 -4
  24. package/dist/base/button-core.js.map +1 -1
  25. package/dist/charts/AreaChart.js +3 -3
  26. package/dist/charts/AreaChart.js.map +1 -1
  27. package/dist/charts/BarChart.js +3 -3
  28. package/dist/charts/BarChart.js.map +1 -1
  29. package/dist/charts/ChordChart.js +3 -3
  30. package/dist/charts/ChordChart.js.map +1 -1
  31. package/dist/charts/ComboChart.js +3 -3
  32. package/dist/charts/ComboChart.js.map +1 -1
  33. package/dist/charts/DonutChart.js +3 -3
  34. package/dist/charts/DonutChart.js.map +1 -1
  35. package/dist/charts/FunnelChart.js +5 -5
  36. package/dist/charts/FunnelChart.js.map +1 -1
  37. package/dist/charts/GraphChart.js +3 -3
  38. package/dist/charts/GraphChart.js.map +1 -1
  39. package/dist/charts/LineChart.js +3 -3
  40. package/dist/charts/LineChart.js.map +1 -1
  41. package/dist/charts/MapChart.js +7 -7
  42. package/dist/charts/MapChart.js.map +1 -1
  43. package/dist/charts/RadarChart.js +16 -15
  44. package/dist/charts/RadarChart.js.map +1 -1
  45. package/dist/charts/SankeyChart.js +3 -3
  46. package/dist/charts/SankeyChart.js.map +1 -1
  47. package/dist/charts/ScatterChart.js +3 -3
  48. package/dist/charts/ScatterChart.js.map +1 -1
  49. package/dist/charts/TimelineChart.js +6 -5
  50. package/dist/charts/TimelineChart.js.map +1 -1
  51. package/dist/charts/TreemapChart.js +3 -3
  52. package/dist/charts/TreemapChart.js.map +1 -1
  53. package/dist/charts/WaterfallChart.js +3 -3
  54. package/dist/charts/WaterfallChart.js.map +1 -1
  55. package/dist/charts/XYChart.js +9 -7
  56. package/dist/charts/XYChart.js.map +1 -1
  57. package/dist/charts/frame.js +10 -8
  58. package/dist/charts/frame.js.map +1 -1
  59. package/dist/charts/single.js +4 -3
  60. package/dist/charts/single.js.map +1 -1
  61. package/dist/code-editor/CodeEditor.d.ts +18 -0
  62. package/dist/code-editor/CodeEditor.js +57 -0
  63. package/dist/code-editor/CodeEditor.js.map +1 -0
  64. package/dist/code-editor/editor.d.ts +52 -0
  65. package/dist/code-editor/editor.js +225 -0
  66. package/dist/code-editor/editor.js.map +1 -0
  67. package/dist/code-editor/index.d.ts +9 -0
  68. package/dist/code-editor/index.js +3 -0
  69. package/dist/config/Provider.d.ts +3 -1
  70. package/dist/config/Provider.js +9 -4
  71. package/dist/config/Provider.js.map +1 -1
  72. package/dist/config/context.d.ts +18 -0
  73. package/dist/config/context.js +16 -1
  74. package/dist/config/context.js.map +1 -1
  75. package/dist/config/createUi.d.ts +20 -3
  76. package/dist/config/createUi.js +80 -49
  77. package/dist/config/createUi.js.map +1 -1
  78. package/dist/config/lang/en-US.js +21 -3
  79. package/dist/config/lang/en-US.js.map +1 -1
  80. package/dist/config/lang/format.d.ts +2 -1
  81. package/dist/config/lang/format.js +9 -2
  82. package/dist/config/lang/format.js.map +1 -1
  83. package/dist/config/lang/lang.d.ts +19 -6
  84. package/dist/config/lang/lang.js +11 -2
  85. package/dist/config/lang/lang.js.map +1 -1
  86. package/dist/config/lang/zh-CN.js +21 -3
  87. package/dist/config/lang/zh-CN.js.map +1 -1
  88. package/dist/config/layout/preference.d.ts +43 -0
  89. package/dist/config/layout/preference.js +108 -0
  90. package/dist/config/layout/preference.js.map +1 -0
  91. package/dist/date/Calendar.js +3 -3
  92. package/dist/date/Calendar.js.map +1 -1
  93. package/dist/date/CalendarBoard.js +9 -9
  94. package/dist/date/CalendarBoard.js.map +1 -1
  95. package/dist/date/CalendarView.js +7 -7
  96. package/dist/date/CalendarView.js.map +1 -1
  97. package/dist/date/DateField.js +3 -3
  98. package/dist/date/DateField.js.map +1 -1
  99. package/dist/date/DatePicker.js +5 -5
  100. package/dist/date/DatePicker.js.map +1 -1
  101. package/dist/date/DateRangePicker.js +5 -5
  102. package/dist/date/DateRangePicker.js.map +1 -1
  103. package/dist/date/DateSegmentGroup.js +5 -5
  104. package/dist/date/DateSegmentGroup.js.map +1 -1
  105. package/dist/date/QuarterCalendar.js +6 -6
  106. package/dist/date/QuarterCalendar.js.map +1 -1
  107. package/dist/date/RangeCalendar.js +3 -3
  108. package/dist/date/RangeCalendar.js.map +1 -1
  109. package/dist/date/SegmentedField.js +3 -3
  110. package/dist/date/SegmentedField.js.map +1 -1
  111. package/dist/date/TimeField.js +3 -3
  112. package/dist/date/TimeField.js.map +1 -1
  113. package/dist/date/TimePicker.js +4 -4
  114. package/dist/date/TimePicker.js.map +1 -1
  115. package/dist/date/date-segments.js +1 -1
  116. package/dist/date/date-segments.js.map +1 -1
  117. package/dist/date/picker-popover.js +3 -2
  118. package/dist/date/picker-popover.js.map +1 -1
  119. package/dist/diagram/Diagram.js +12 -12
  120. package/dist/diagram/Diagram.js.map +1 -1
  121. package/dist/diagram/DiagramLanes.js +3 -3
  122. package/dist/diagram/DiagramLanes.js.map +1 -1
  123. package/dist/diagram/DiagramMinimap.js +4 -4
  124. package/dist/diagram/DiagramMinimap.js.map +1 -1
  125. package/dist/diagram/index.d.ts +2 -1
  126. package/dist/diagram/index.js +2 -1
  127. package/dist/diagram/layout.d.ts +57 -0
  128. package/dist/diagram/layout.js +50 -0
  129. package/dist/diagram/layout.js.map +1 -0
  130. package/dist/display/Accordion.js +6 -6
  131. package/dist/display/Accordion.js.map +1 -1
  132. package/dist/display/AnimatedNumber.js +4 -4
  133. package/dist/display/AnimatedNumber.js.map +1 -1
  134. package/dist/display/Avatar.js +4 -4
  135. package/dist/display/Avatar.js.map +1 -1
  136. package/dist/display/Checklist.js +7 -7
  137. package/dist/display/Checklist.js.map +1 -1
  138. package/dist/display/Collapse.js +8 -5
  139. package/dist/display/Collapse.js.map +1 -1
  140. package/dist/display/Collapsible.js +3 -3
  141. package/dist/display/Collapsible.js.map +1 -1
  142. package/dist/display/Descriptions.js +5 -5
  143. package/dist/display/Descriptions.js.map +1 -1
  144. package/dist/display/Ellipsis.js +3 -3
  145. package/dist/display/Ellipsis.js.map +1 -1
  146. package/dist/display/FieldCompare.js +4 -4
  147. package/dist/display/FieldCompare.js.map +1 -1
  148. package/dist/display/Gauge.js +11 -11
  149. package/dist/display/Gauge.js.map +1 -1
  150. package/dist/display/Image.js +4 -4
  151. package/dist/display/Image.js.map +1 -1
  152. package/dist/display/Marquee.js +3 -3
  153. package/dist/display/Marquee.js.map +1 -1
  154. package/dist/display/ProportionBar.js +4 -4
  155. package/dist/display/ProportionBar.js.map +1 -1
  156. package/dist/display/Sortable.js +4 -4
  157. package/dist/display/Sortable.js.map +1 -1
  158. package/dist/display/Sparkline.js +6 -6
  159. package/dist/display/Sparkline.js.map +1 -1
  160. package/dist/display/Stat.js +3 -3
  161. package/dist/display/Stat.js.map +1 -1
  162. package/dist/display/Timeline.js +7 -7
  163. package/dist/display/Timeline.js.map +1 -1
  164. package/dist/display/Tree.js +10 -10
  165. package/dist/display/Tree.js.map +1 -1
  166. package/dist/display/VirtualList.js +7 -7
  167. package/dist/display/VirtualList.js.map +1 -1
  168. package/dist/display/Watermark.js +3 -3
  169. package/dist/display/Watermark.js.map +1 -1
  170. package/dist/docs-kit/CodeGroup.js +5 -5
  171. package/dist/docs-kit/CodeGroup.js.map +1 -1
  172. package/dist/docs-kit/CodePreview.js +6 -6
  173. package/dist/docs-kit/CodePreview.js.map +1 -1
  174. package/dist/docs-kit/PropsTable.js +4 -4
  175. package/dist/docs-kit/PropsTable.js.map +1 -1
  176. package/dist/feedback/Alert.js +5 -5
  177. package/dist/feedback/Alert.js.map +1 -1
  178. package/dist/feedback/Banner.js +5 -5
  179. package/dist/feedback/Banner.js.map +1 -1
  180. package/dist/feedback/Empty.js +4 -4
  181. package/dist/feedback/Empty.js.map +1 -1
  182. package/dist/feedback/LoadingBar.js +20 -13
  183. package/dist/feedback/LoadingBar.js.map +1 -1
  184. package/dist/feedback/LoadingOverlay.js +3 -3
  185. package/dist/feedback/LoadingOverlay.js.map +1 -1
  186. package/dist/feedback/Progress.js +14 -14
  187. package/dist/feedback/Progress.js.map +1 -1
  188. package/dist/feedback/Result.js +4 -4
  189. package/dist/feedback/Result.js.map +1 -1
  190. package/dist/feedback/SkeletonText.js +3 -3
  191. package/dist/feedback/SkeletonText.js.map +1 -1
  192. package/dist/feedback/Toast.js +6 -6
  193. package/dist/feedback/Toast.js.map +1 -1
  194. package/dist/form/Field.d.ts +7 -0
  195. package/dist/form/Field.js +20 -9
  196. package/dist/form/Field.js.map +1 -1
  197. package/dist/form/Form.js +3 -3
  198. package/dist/form/Form.js.map +1 -1
  199. package/dist/form/FormErrorSummary.js +3 -3
  200. package/dist/form/FormErrorSummary.js.map +1 -1
  201. package/dist/form/FormSection.js +6 -6
  202. package/dist/form/FormSection.js.map +1 -1
  203. package/dist/form/useForm.d.ts +4 -1
  204. package/dist/form/useForm.js +35 -13
  205. package/dist/form/useForm.js.map +1 -1
  206. package/dist/index.d.ts +18 -10
  207. package/dist/index.js +17 -9
  208. package/dist/input/Autocomplete.js +3 -3
  209. package/dist/input/Autocomplete.js.map +1 -1
  210. package/dist/input/Cascader.js +7 -7
  211. package/dist/input/Cascader.js.map +1 -1
  212. package/dist/input/CharacterCount.js +3 -3
  213. package/dist/input/CharacterCount.js.map +1 -1
  214. package/dist/input/Checkbox.js +5 -5
  215. package/dist/input/Checkbox.js.map +1 -1
  216. package/dist/input/ColorField.js +4 -4
  217. package/dist/input/ColorField.js.map +1 -1
  218. package/dist/input/Combobox.js +5 -5
  219. package/dist/input/Combobox.js.map +1 -1
  220. package/dist/input/ConditionBuilder.js +15 -14
  221. package/dist/input/ConditionBuilder.js.map +1 -1
  222. package/dist/input/FileDrop.js +3 -3
  223. package/dist/input/FileDrop.js.map +1 -1
  224. package/dist/input/Listbox.js +9 -9
  225. package/dist/input/Listbox.js.map +1 -1
  226. package/dist/input/Mentions.js +4 -4
  227. package/dist/input/Mentions.js.map +1 -1
  228. package/dist/input/NumberField.js +3 -3
  229. package/dist/input/NumberField.js.map +1 -1
  230. package/dist/input/NumberRangeField.js +5 -5
  231. package/dist/input/NumberRangeField.js.map +1 -1
  232. package/dist/input/OtpField.js +5 -5
  233. package/dist/input/OtpField.js.map +1 -1
  234. package/dist/input/PeoplePicker.js +6 -6
  235. package/dist/input/PeoplePicker.js.map +1 -1
  236. package/dist/input/PeoplePickerPanel.js +15 -15
  237. package/dist/input/PeoplePickerPanel.js.map +1 -1
  238. package/dist/input/Radio.js +4 -4
  239. package/dist/input/Radio.js.map +1 -1
  240. package/dist/input/Rating.js +5 -5
  241. package/dist/input/Rating.js.map +1 -1
  242. package/dist/input/Select.js +5 -5
  243. package/dist/input/Select.js.map +1 -1
  244. package/dist/input/SelectedTags.js +4 -4
  245. package/dist/input/SelectedTags.js.map +1 -1
  246. package/dist/input/Slider.js +6 -6
  247. package/dist/input/Slider.js.map +1 -1
  248. package/dist/input/Switch.js +3 -3
  249. package/dist/input/Switch.js.map +1 -1
  250. package/dist/input/TagsInput.js +5 -5
  251. package/dist/input/TagsInput.js.map +1 -1
  252. package/dist/input/TextField.js +5 -5
  253. package/dist/input/TextField.js.map +1 -1
  254. package/dist/input/Textarea.js +4 -4
  255. package/dist/input/Textarea.js.map +1 -1
  256. package/dist/input/ToggleGroup.js +4 -4
  257. package/dist/input/ToggleGroup.js.map +1 -1
  258. package/dist/input/Transfer.js +8 -8
  259. package/dist/input/Transfer.js.map +1 -1
  260. package/dist/input/TreeSelect.js +7 -7
  261. package/dist/input/TreeSelect.js.map +1 -1
  262. package/dist/input/Upload.js +10 -9
  263. package/dist/input/Upload.js.map +1 -1
  264. package/dist/input/condition.d.ts +1 -1
  265. package/dist/input/condition.js +32 -14
  266. package/dist/input/condition.js.map +1 -1
  267. package/dist/input/people.d.ts +15 -14
  268. package/dist/input/people.js +5 -5
  269. package/dist/input/people.js.map +1 -1
  270. package/dist/input/remote-items.d.ts +4 -2
  271. package/dist/input/remote-items.js +7 -2
  272. package/dist/input/remote-items.js.map +1 -1
  273. package/dist/layout/Affix.js +4 -4
  274. package/dist/layout/Affix.js.map +1 -1
  275. package/dist/layout/ResizeHandle.d.ts +6 -2
  276. package/dist/layout/ResizeHandle.js +32 -9
  277. package/dist/layout/ResizeHandle.js.map +1 -1
  278. package/dist/layout/ScrollArea.js +3 -3
  279. package/dist/layout/ScrollArea.js.map +1 -1
  280. package/dist/layout/Separator.js +3 -3
  281. package/dist/layout/Separator.js.map +1 -1
  282. package/dist/layout/Splitter.js +3 -3
  283. package/dist/layout/Splitter.js.map +1 -1
  284. package/dist/layout/ViewportFill.d.ts +2 -2
  285. package/dist/layout/ViewportFill.js +4 -4
  286. package/dist/layout/ViewportFill.js.map +1 -1
  287. package/dist/navigation/Breadcrumbs.js +4 -4
  288. package/dist/navigation/Breadcrumbs.js.map +1 -1
  289. package/dist/navigation/NavBar.js +6 -6
  290. package/dist/navigation/NavBar.js.map +1 -1
  291. package/dist/navigation/NavList.d.ts +1 -0
  292. package/dist/navigation/NavList.js +20 -12
  293. package/dist/navigation/NavList.js.map +1 -1
  294. package/dist/navigation/NavMenu.d.ts +27 -0
  295. package/dist/navigation/NavMenu.js +54 -0
  296. package/dist/navigation/NavMenu.js.map +1 -0
  297. package/dist/navigation/PageJump.js +3 -3
  298. package/dist/navigation/PageJump.js.map +1 -1
  299. package/dist/navigation/PageSizeSelect.js +4 -4
  300. package/dist/navigation/PageSizeSelect.js.map +1 -1
  301. package/dist/navigation/Pagination.js +6 -6
  302. package/dist/navigation/Pagination.js.map +1 -1
  303. package/dist/navigation/PaginationBar.js +5 -5
  304. package/dist/navigation/PaginationBar.js.map +1 -1
  305. package/dist/navigation/Steps.js +4 -4
  306. package/dist/navigation/Steps.js.map +1 -1
  307. package/dist/navigation/TableOfContents.js +5 -5
  308. package/dist/navigation/TableOfContents.js.map +1 -1
  309. package/dist/navigation/Tabs.js +7 -7
  310. package/dist/navigation/Tabs.js.map +1 -1
  311. package/dist/navigation/Toolbar.js +3 -3
  312. package/dist/navigation/Toolbar.js.map +1 -1
  313. package/dist/overlay/AlertDialog.js +4 -4
  314. package/dist/overlay/AlertDialog.js.map +1 -1
  315. package/dist/overlay/CommandPalette.js +4 -4
  316. package/dist/overlay/CommandPalette.js.map +1 -1
  317. package/dist/overlay/ContextMenu.js +3 -3
  318. package/dist/overlay/ContextMenu.js.map +1 -1
  319. package/dist/overlay/Dialog.js +4 -4
  320. package/dist/overlay/Dialog.js.map +1 -1
  321. package/dist/overlay/Drawer.js +5 -5
  322. package/dist/overlay/Drawer.js.map +1 -1
  323. package/dist/overlay/HoverCard.js +5 -3
  324. package/dist/overlay/HoverCard.js.map +1 -1
  325. package/dist/overlay/Lightbox.js +5 -5
  326. package/dist/overlay/Lightbox.js.map +1 -1
  327. package/dist/overlay/Menu.js +7 -7
  328. package/dist/overlay/Menu.js.map +1 -1
  329. package/dist/overlay/ModalCore.js +9 -9
  330. package/dist/overlay/ModalCore.js.map +1 -1
  331. package/dist/overlay/Popconfirm.js +6 -6
  332. package/dist/overlay/Popconfirm.js.map +1 -1
  333. package/dist/overlay/Popover.js +5 -3
  334. package/dist/overlay/Popover.js.map +1 -1
  335. package/dist/overlay/Tooltip.js +5 -3
  336. package/dist/overlay/Tooltip.js.map +1 -1
  337. package/dist/overlay/Tour.js +8 -8
  338. package/dist/overlay/Tour.js.map +1 -1
  339. package/dist/overlay/detached.d.ts +2 -0
  340. package/dist/overlay/detached.js +73 -42
  341. package/dist/overlay/detached.js.map +1 -1
  342. package/dist/patterns/ActionBar.js +3 -3
  343. package/dist/patterns/ActionBar.js.map +1 -1
  344. package/dist/patterns/AppShell.d.ts +28 -1
  345. package/dist/patterns/AppShell.js +158 -52
  346. package/dist/patterns/AppShell.js.map +1 -1
  347. package/dist/patterns/AuthLayout.d.ts +28 -0
  348. package/dist/patterns/AuthLayout.js +77 -0
  349. package/dist/patterns/AuthLayout.js.map +1 -0
  350. package/dist/patterns/CommentThread.js +9 -9
  351. package/dist/patterns/CommentThread.js.map +1 -1
  352. package/dist/patterns/DataImport.js +4 -4
  353. package/dist/patterns/DataImport.js.map +1 -1
  354. package/dist/patterns/DeadlineBadge.js +3 -3
  355. package/dist/patterns/DeadlineBadge.js.map +1 -1
  356. package/dist/patterns/FilterBar.d.ts +11 -1
  357. package/dist/patterns/FilterBar.js +39 -10
  358. package/dist/patterns/FilterBar.js.map +1 -1
  359. package/dist/patterns/FormDialog.d.ts +18 -0
  360. package/dist/patterns/FormDialog.js +46 -0
  361. package/dist/patterns/FormDialog.js.map +1 -0
  362. package/dist/patterns/KanbanBoard.js +8 -8
  363. package/dist/patterns/KanbanBoard.js.map +1 -1
  364. package/dist/patterns/LayoutSwitcher.d.ts +12 -0
  365. package/dist/patterns/LayoutSwitcher.js +79 -0
  366. package/dist/patterns/LayoutSwitcher.js.map +1 -0
  367. package/dist/patterns/NotificationCenter.js +8 -8
  368. package/dist/patterns/NotificationCenter.js.map +1 -1
  369. package/dist/patterns/PageTabs.d.ts +12 -7
  370. package/dist/patterns/PageTabs.js +41 -29
  371. package/dist/patterns/PageTabs.js.map +1 -1
  372. package/dist/patterns/QueryTable.d.ts +10 -1
  373. package/dist/patterns/QueryTable.js +128 -68
  374. package/dist/patterns/QueryTable.js.map +1 -1
  375. package/dist/patterns/SlideCaptcha.d.ts +80 -0
  376. package/dist/patterns/SlideCaptcha.js +354 -0
  377. package/dist/patterns/SlideCaptcha.js.map +1 -0
  378. package/dist/patterns/StepsForm.js +7 -7
  379. package/dist/patterns/StepsForm.js.map +1 -1
  380. package/dist/patterns/ThemeSwitcher.js +3 -3
  381. package/dist/patterns/ThemeSwitcher.js.map +1 -1
  382. package/dist/patterns/index.d.ts +7 -3
  383. package/dist/patterns/index.js +5 -1
  384. package/dist/patterns/messages.d.ts +39 -1
  385. package/dist/patterns/messages.js +40 -2
  386. package/dist/patterns/messages.js.map +1 -1
  387. package/dist/table/ColumnHeaderActions.js +3 -3
  388. package/dist/table/ColumnHeaderActions.js.map +1 -1
  389. package/dist/table/ColumnResizer.js +3 -3
  390. package/dist/table/ColumnResizer.js.map +1 -1
  391. package/dist/table/ColumnSettings.js +5 -5
  392. package/dist/table/ColumnSettings.js.map +1 -1
  393. package/dist/table/ColumnTable.js +8 -8
  394. package/dist/table/ColumnTable.js.map +1 -1
  395. package/dist/table/DataTable.js +8 -8
  396. package/dist/table/DataTable.js.map +1 -1
  397. package/dist/table/DataTableView.js +21 -21
  398. package/dist/table/DataTableView.js.map +1 -1
  399. package/dist/table/PivotTable.js +3 -3
  400. package/dist/table/PivotTable.js.map +1 -1
  401. package/dist/table/SelectionBar.js +4 -4
  402. package/dist/table/SelectionBar.js.map +1 -1
  403. package/dist/table/TreeDataTable.js +5 -5
  404. package/dist/table/TreeDataTable.js.map +1 -1
  405. package/dist/theme-customize/ThemeCustomizer.js +7 -6
  406. package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
  407. package/dist/theme-customize/ThemeThumbnail.js +3 -3
  408. package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
  409. package/dist/three/background/AuroraBackground.js +3 -3
  410. package/dist/three/background/AuroraBackground.js.map +1 -1
  411. package/dist/three/background/MeshGradient.js +3 -3
  412. package/dist/three/background/MeshGradient.js.map +1 -1
  413. package/dist/three/background/ShaderBackground.js +3 -3
  414. package/dist/three/background/ShaderBackground.js.map +1 -1
  415. package/dist/three/core/EffectSurface.js +3 -3
  416. package/dist/three/core/EffectSurface.js.map +1 -1
  417. package/dist/three/core/ThreeCanvas.js +4 -4
  418. package/dist/three/core/ThreeCanvas.js.map +1 -1
  419. package/dist/three/effects/Confetti.js +3 -3
  420. package/dist/three/effects/Confetti.js.map +1 -1
  421. package/dist/three/effects/ParticleField.js +3 -3
  422. package/dist/three/effects/ParticleField.js.map +1 -1
  423. package/dist/three/effects/WaveGrid.js +3 -3
  424. package/dist/three/effects/WaveGrid.js.map +1 -1
  425. package/dist/three/globe/Globe.js +3 -3
  426. package/dist/three/globe/Globe.js.map +1 -1
  427. package/dist/three/model/ModelViewer.js +3 -3
  428. package/dist/three/model/ModelViewer.js.map +1 -1
  429. package/dist/utils/data/clone.d.ts +8 -0
  430. package/dist/utils/data/clone.js +21 -0
  431. package/dist/utils/data/clone.js.map +1 -0
  432. package/dist/utils/data/date.d.ts +10 -0
  433. package/dist/utils/data/date.js +13 -1
  434. package/dist/utils/data/date.js.map +1 -1
  435. package/dist/utils/data/number.d.ts +5 -0
  436. package/dist/utils/data/number.js +8 -1
  437. package/dist/utils/data/number.js.map +1 -1
  438. package/dist/utils/data/numeric.d.ts +7 -0
  439. package/dist/utils/data/numeric.js +46 -1
  440. package/dist/utils/data/numeric.js.map +1 -1
  441. package/dist/utils/dom/download.d.ts +8 -1
  442. package/dist/utils/dom/download.js +19 -2
  443. package/dist/utils/dom/download.js.map +1 -1
  444. package/dist/utils/dom/element.d.ts +3 -1
  445. package/dist/utils/dom/element.js +8 -4
  446. package/dist/utils/dom/element.js.map +1 -1
  447. package/dist/utils/dom/fullscreen.d.ts +1 -1
  448. package/dist/utils/dom/fullscreen.js +12 -8
  449. package/dist/utils/dom/fullscreen.js.map +1 -1
  450. package/dist/utils/dom/mounted.d.ts +7 -0
  451. package/dist/utils/dom/mounted.js +16 -0
  452. package/dist/utils/dom/mounted.js.map +1 -0
  453. package/dist/utils/dom/overflow.js +2 -1
  454. package/dist/utils/dom/overflow.js.map +1 -1
  455. package/dist/utils/dom/pan-zoom.js +2 -1
  456. package/dist/utils/dom/pan-zoom.js.map +1 -1
  457. package/dist/utils/props.js +3 -13
  458. package/dist/utils/props.js.map +1 -1
  459. package/dist/utils/request/error-message.d.ts +17 -0
  460. package/dist/utils/request/error-message.js +50 -0
  461. package/dist/utils/request/error-message.js.map +1 -0
  462. package/dist/utils/request/http.d.ts +80 -4
  463. package/dist/utils/request/http.js +121 -24
  464. package/dist/utils/request/http.js.map +1 -1
  465. package/dist/utils/request/use-autosave.d.ts +35 -0
  466. package/dist/utils/request/use-autosave.js +69 -0
  467. package/dist/utils/request/use-autosave.js.map +1 -0
  468. package/dist/utils/request/use-request.js +4 -2
  469. package/dist/utils/request/use-request.js.map +1 -1
  470. package/package.json +57 -4
@@ -8,8 +8,8 @@ import { FormValue } from "../form/FormValue.js";
8
8
  import { useDateLocale } from "./date-locale.js";
9
9
  import { fieldsToIso, isoToFields, useDateSegments } from "./date-segments.js";
10
10
  import { DateSegmentGroup } from "./DateSegmentGroup.js";
11
- import { createVNode, mergeProps, shallowRef } from "vue";
12
- import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
11
+ import { createVNode, shallowRef } from "vue";
12
+ import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
13
13
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
14
14
  import { now } from "@internationalized/date";
15
15
  //#region src/date/SegmentedField.tsx
@@ -112,7 +112,7 @@ var SegmentedField = /*#__PURE__*/ _component((_props, _ctx) => {
112
112
  ...state,
113
113
  invalid: bad
114
114
  });
115
- return createVNode("div", mergeProps(mergeAttrs(s.root, propsRoot.value, { onPointerdown: state.disabled ? void 0 : focusOnShell(firstSegment) }), {
115
+ return createVNode("div", mergeJsxProps(mergeAttrs(s.root, propsRoot.value, { onPointerdown: state.disabled ? void 0 : focusOnShell(firstSegment) }), {
116
116
  "data-invalid": bad || void 0,
117
117
  "data-disabled": state.disabled || void 0
118
118
  }), [
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/SegmentedField.tsx"],"sourcesContent":["/**\n * 分段输入框:输入框外壳(同 TextField)里放一组日期分段、可选的前置图标、清空按钮与尾部内容。\n * DateField、TimeField 是它的两种用法(只差有哪些段与怎样校验);日期选择器把打开日历的按钮放在 suffix 里。\n *\n * <SegmentedField fields={['hour', 'minute']} _value={time} />\n *\n * 值是 ISO 字符串(fieldsToIso);所有段都填了才写回,删掉一段写回 null。写了 name 时用隐藏的 input 随表单提交。\n * 点外壳的空白处时焦点进第一个没填的段。\n *\n * 部件:Root(外壳)、Input(DateSegmentGroup,主元素)、Segment、Literal、Icon、Clear。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { useLang } from '../config/context';\nimport type { HourCycles } from '../config/lang/lang';\nimport { useFieldControl, useFormReset } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport { isoWeekOf } from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { fieldsToIso, isoToFields, useDateSegments, type DateSegmentType } from './date-segments';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\n\n/** 由组件管理:角色与关联 */\nexport type SegmentedFieldManaged = 'role' | 'aria-describedby';\n\n/** 分段输入框共有的属性(DateField、TimeField 都有);未声明的属性落到这组分段上(主元素) */\nexport interface SegmentedFieldOptions\n extends\n PartProps<'div', SegmentedFieldManaged>,\n ControlOptions,\n ControlIconOptions,\n Pick<DateSegmentGroupProps, 'propsSegment' | 'propsLiteral'> {\n /** 12 / 24 小时制(有时的段时);不写时按语言 */\n hourCycle?: keyof HourCycles;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时值超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 表单提交时的 name(用隐藏的 input,值是 ISO 字符串) */\n name?: string;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 框里最后的内容:日期选择器打开日历的按钮 */\n suffix?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n}\n\n/** 未声明的属性落到这组分段上 */\nexport interface SegmentedFieldProps extends SegmentedFieldOptions {\n /** 值(ISO 字符串):父级写 _value={x};没填全时 null */\n _value?: string | null;\n /** 有哪些段,按年 → 秒的顺序(显示顺序按语言) */\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 值超出范围、不可选(有值时调用):外壳显示出错 */\n outOfRange?: (value: string) => boolean;\n}\n\n/**\n * 一组分段的状态,按当前语言(段的顺序、小时制、占位文字,没填时占位的是此刻);值是 ISO 字符串,填全了才写回。\n * SegmentedField 与 DateRangePicker 的开始、结束两组分段用它。在组件 setup 里调用\n */\nexport function useFieldSegments(\n read: () => {\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n value: string | null;\n hourCycle?: keyof HourCycles;\n readonly: boolean;\n },\n onChange: (value: string | null) => void,\n onExit?: (direction: 1 | -1) => void,\n) {\n const lang = useLang();\n const locale = useDateLocale();\n const segments = useDateSegments({\n fields: () => read().fields,\n locale: () => lang.code,\n hourCycle: () => read().hourCycle ?? lang.hourCycle,\n value: () => isoToFields(read().value, read().fields),\n onChange: (next) => onChange(next ? fieldsToIso(next, read().fields) : null),\n placeholderValue: () => {\n const current = now(locale.timeZone);\n // 选周时从这一周所属的年起步(12 月底的那周可能已经算明年的第 1 周)\n const week = isoWeekOf(current);\n return {\n year: read().fields.includes('week') ? week.year : current.year,\n month: current.month,\n day: current.day,\n quarter: Math.ceil(current.month / 3),\n week: week.week,\n hour: current.hour,\n minute: current.minute,\n second: 0,\n };\n },\n placeholders: () => lang.dateFieldPlaceholders,\n periodPatterns: () => lang.dateFieldPeriodPatterns,\n readonly: () => read().readonly,\n onExit,\n });\n useFormReset(() => segments.reset());\n return segments;\n}\n\n/** 一组分段里第一个没填的段(都填了时第一段):点外壳空白处、清空后焦点去这里 */\nexport const firstSegmentOf = (group: Element | null | undefined) =>\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"][data-placeholder]') ??\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"]') ??\n null;\n\n/** SegmentedField 的样式:input */\nexport const segmentedFieldStyles = css.create({\n // 分段占满剩下的宽度:清空按钮、尾部内容贴着外壳的结束边\n input: { flexGrow: 1 },\n});\n\n/** 分段输入框:外壳 + 一组日期分段 */\nexport const SegmentedField = _component(\n ({\n _value: value = _bindable<string | null>(null),\n fields,\n outOfRange,\n hourCycle,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n name,\n clearable = false,\n icon,\n suffix,\n id,\n propsRoot,\n propsIcon,\n propsClear,\n propsSegment,\n propsLiteral,\n ...rest\n }: SegmentedFieldProps) => {\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let group = _state.raw<HTMLElement | null>(null);\n\n const segments = useFieldSegments(\n () => ({\n fields,\n value,\n hourCycle,\n readonly: control().disabled || control().readonly,\n }),\n (next) => (value = next),\n );\n const firstSegment = () => firstSegmentOf(group);\n\n function clear() {\n segments.clear();\n value = null;\n firstSegment()?.focus();\n }\n\n return () => {\n const state = control();\n const bad = state.invalid || (value != null && (outOfRange?.(value) ?? false));\n const filled = value != null || segments.partial;\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(firstSegment),\n })}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n sx: segmentedFieldStyles.input,\n segments,\n labelledBy: state.labelledBy,\n describedBy: state.describedBy,\n },\n rest,\n {\n ref: (instance: unknown) => (group = toElement(instance)),\n id: state.id,\n segments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n propsSegment,\n propsLiteral,\n },\n )}\n />\n {clearable &&\n filled &&\n !state.disabled &&\n !state.readonly &&\n controlClear(s, propsClear, clear)}\n {suffix}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"SegmentedField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/SegmentedField.tsx"],"sourcesContent":["/**\n * 分段输入框:输入框外壳(同 TextField)里放一组日期分段、可选的前置图标、清空按钮与尾部内容。\n * DateField、TimeField 是它的两种用法(只差有哪些段与怎样校验);日期选择器把打开日历的按钮放在 suffix 里。\n *\n * <SegmentedField fields={['hour', 'minute']} _value={time} />\n *\n * 值是 ISO 字符串(fieldsToIso);所有段都填了才写回,删掉一段写回 null。写了 name 时用隐藏的 input 随表单提交。\n * 点外壳的空白处时焦点进第一个没填的段。\n *\n * 部件:Root(外壳)、Input(DateSegmentGroup,主元素)、Segment、Literal、Icon、Clear。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { useLang } from '../config/context';\nimport type { HourCycles } from '../config/lang/lang';\nimport { useFieldControl, useFormReset } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport { isoWeekOf } from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { fieldsToIso, isoToFields, useDateSegments, type DateSegmentType } from './date-segments';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\n\n/** 由组件管理:角色与关联 */\nexport type SegmentedFieldManaged = 'role' | 'aria-describedby';\n\n/** 分段输入框共有的属性(DateField、TimeField 都有);未声明的属性落到这组分段上(主元素) */\nexport interface SegmentedFieldOptions\n extends\n PartProps<'div', SegmentedFieldManaged>,\n ControlOptions,\n ControlIconOptions,\n Pick<DateSegmentGroupProps, 'propsSegment' | 'propsLiteral'> {\n /** 12 / 24 小时制(有时的段时);不写时按语言 */\n hourCycle?: keyof HourCycles;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时值超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 表单提交时的 name(用隐藏的 input,值是 ISO 字符串) */\n name?: string;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 框里最后的内容:日期选择器打开日历的按钮 */\n suffix?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n}\n\n/** 未声明的属性落到这组分段上 */\nexport interface SegmentedFieldProps extends SegmentedFieldOptions {\n /** 值(ISO 字符串):父级写 _value={x};没填全时 null */\n _value?: string | null;\n /** 有哪些段,按年 → 秒的顺序(显示顺序按语言) */\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 值超出范围、不可选(有值时调用):外壳显示出错 */\n outOfRange?: (value: string) => boolean;\n}\n\n/**\n * 一组分段的状态,按当前语言(段的顺序、小时制、占位文字,没填时占位的是此刻);值是 ISO 字符串,填全了才写回。\n * SegmentedField 与 DateRangePicker 的开始、结束两组分段用它。在组件 setup 里调用\n */\nexport function useFieldSegments(\n read: () => {\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n value: string | null;\n hourCycle?: keyof HourCycles;\n readonly: boolean;\n },\n onChange: (value: string | null) => void,\n onExit?: (direction: 1 | -1) => void,\n) {\n const lang = useLang();\n const locale = useDateLocale();\n const segments = useDateSegments({\n fields: () => read().fields,\n locale: () => lang.code,\n hourCycle: () => read().hourCycle ?? lang.hourCycle,\n value: () => isoToFields(read().value, read().fields),\n onChange: (next) => onChange(next ? fieldsToIso(next, read().fields) : null),\n placeholderValue: () => {\n const current = now(locale.timeZone);\n // 选周时从这一周所属的年起步(12 月底的那周可能已经算明年的第 1 周)\n const week = isoWeekOf(current);\n return {\n year: read().fields.includes('week') ? week.year : current.year,\n month: current.month,\n day: current.day,\n quarter: Math.ceil(current.month / 3),\n week: week.week,\n hour: current.hour,\n minute: current.minute,\n second: 0,\n };\n },\n placeholders: () => lang.dateFieldPlaceholders,\n periodPatterns: () => lang.dateFieldPeriodPatterns,\n readonly: () => read().readonly,\n onExit,\n });\n useFormReset(() => segments.reset());\n return segments;\n}\n\n/** 一组分段里第一个没填的段(都填了时第一段):点外壳空白处、清空后焦点去这里 */\nexport const firstSegmentOf = (group: Element | null | undefined) =>\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"][data-placeholder]') ??\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"]') ??\n null;\n\n/** SegmentedField 的样式:input */\nexport const segmentedFieldStyles = css.create({\n // 分段占满剩下的宽度:清空按钮、尾部内容贴着外壳的结束边\n input: { flexGrow: 1 },\n});\n\n/** 分段输入框:外壳 + 一组日期分段 */\nexport const SegmentedField = _component(\n ({\n _value: value = _bindable<string | null>(null),\n fields,\n outOfRange,\n hourCycle,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n name,\n clearable = false,\n icon,\n suffix,\n id,\n propsRoot,\n propsIcon,\n propsClear,\n propsSegment,\n propsLiteral,\n ...rest\n }: SegmentedFieldProps) => {\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let group = _state.raw<HTMLElement | null>(null);\n\n const segments = useFieldSegments(\n () => ({\n fields,\n value,\n hourCycle,\n readonly: control().disabled || control().readonly,\n }),\n (next) => (value = next),\n );\n const firstSegment = () => firstSegmentOf(group);\n\n function clear() {\n segments.clear();\n value = null;\n firstSegment()?.focus();\n }\n\n return () => {\n const state = control();\n const bad = state.invalid || (value != null && (outOfRange?.(value) ?? false));\n const filled = value != null || segments.partial;\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(firstSegment),\n })}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n sx: segmentedFieldStyles.input,\n segments,\n labelledBy: state.labelledBy,\n describedBy: state.describedBy,\n },\n rest,\n {\n ref: (instance: unknown) => (group = toElement(instance)),\n id: state.id,\n segments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n propsSegment,\n propsLiteral,\n },\n )}\n />\n {clearable &&\n filled &&\n !state.disabled &&\n !state.readonly &&\n controlClear(s, propsClear, clear)}\n {suffix}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { parseIsoTime, toIsoTime } from "../utils/data/date.js";
2
2
  import { segmentFields } from "./date-segments.js";
3
3
  import { SegmentedField } from "./SegmentedField.js";
4
- import { computed, createVNode, mergeProps } from "vue";
5
- import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
4
+ import { computed, createVNode } from "vue";
5
+ import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
6
6
  //#region src/date/TimeField.tsx
7
7
  /** 时间精确到哪一段 */
8
8
  /** 时间输入框接受的值:'HH:mm[:ss]' 字符串,或 @internationalized/date 的 Time */
@@ -32,7 +32,7 @@ var TimeField = /*#__PURE__*/ _component((_props, _ctx) => {
32
32
  const asTime = lastLike != null ? typeof lastLike !== "string" : valueType.value === "dateValue";
33
33
  value.value = next != null && asTime ? parseIsoTime(next) : next;
34
34
  }
35
- return () => createVNode(SegmentedField, mergeProps(rest, {
35
+ return () => createVNode(SegmentedField, mergeJsxProps(rest, {
36
36
  "onUpdate:_value": write,
37
37
  "_value": iso.value,
38
38
  "fields": segmentFields(granularity.value, true),
@@ -1 +1 @@
1
- {"version":3,"file":"TimeField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_mergeProps"],"sources":["../../src/date/TimeField.tsx"],"sourcesContent":["/**\n * 时间输入框:分段输入时、分(可选秒),12 / 24 小时制跟随语言(zh-CN 24 小时,en-US 12 小时加 AM / PM),也可以用 hourCycle 指定。\n * 参考 React Aria TimeField、原生 input type=\"time\"。要从按步长列出的时间里点选用 TimePicker。\n *\n * <Field label=\"提醒时间\"><TimeField _value={time} /></Field>\n * <TimeField granularity=\"second\" hourCycle=\"h12\" _value={at} aria-label=\"打卡时间\" />\n *\n * 值是 'HH:mm'(granularity 为 second 时 'HH:mm:ss'),时总是 24 小时制,与原生 input type=\"time\" 一致;\n * 也可以是 @internationalized/date 的 Time,写回时保持同一种类型。\n * 键盘同 DateField;12 小时制时在上午 / 下午那段打 a、p 切换。部件见 SegmentedField。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport type { Time } from '@internationalized/date';\nimport { parseIsoTime, toIsoTime } from '../utils/data/date';\nimport type { DateValueTypes } from './date-locale';\nimport { segmentFields } from './date-segments';\nimport { SegmentedField, type SegmentedFieldOptions } from './SegmentedField';\n\n/** 时间精确到哪一段 */\nexport interface TimeFieldGranularities {\n /** 只有时:'14:00' */\n hour: unknown;\n /** 时分(默认):'14:30' */\n minute: unknown;\n /** 时分秒:'14:30:15' */\n second: unknown;\n}\n\n/** 时间输入框接受的值:'HH:mm[:ss]' 字符串,或 @internationalized/date 的 Time */\nexport type TimeInput = string | Time;\n\n/** TimeInput → Time:ISO 字符串按 'HH:mm[:ss]' 解析,空值或格式不对时为 null */\nexport const toTime = (input: TimeInput | null | undefined): Time | null =>\n typeof input === 'string' || input == null ? parseIsoTime(input) : input;\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface TimeFieldProps<V extends TimeInput = string> extends SegmentedFieldOptions {\n /** 值('HH:mm' 或 'HH:mm:ss',24 小时制;或 Time,写回时保持同一种类型):父级写 _value={x};没填全时 null */\n _value?: V | null;\n /** 值为空、推不出类型时写回哪一种,默认 iso(字符串);dateValue 写 Time */\n valueType?: keyof DateValueTypes;\n /** 精确到哪一段,默认 minute */\n granularity?: keyof TimeFieldGranularities;\n /** 最早的时间('09:00' 或 Time):早于它显示出错 */\n min?: TimeInput;\n /** 最晚的时间('18:00' 或 Time):晚于它显示出错 */\n max?: TimeInput;\n /**\n * 不可选的时间(午休、已约满的时段):键入时显示出错,TimePicker 的列表里不可用。\n * 第一个参数是 'HH:mm',第二个是同一时刻的 Time:`(_, time) => time.hour === 12`\n */\n isTimeUnavailable?: (time: string, value: Time) => boolean;\n}\n\n/** 时间输入框:分段输入 */\nexport const TimeField = _component(\n <V extends TimeInput>({\n _value: value = _bindable<V | null>(null),\n granularity = 'minute',\n valueType = 'iso',\n min,\n max,\n isTimeUnavailable,\n ...rest\n }: TimeFieldProps<V>) => {\n const outOfRange = (iso: string) => {\n const time = parseIsoTime(iso);\n if (time == null) return false;\n const low = toTime(min);\n const high = toTime(max);\n return (\n (low != null && time.compare(low) < 0) ||\n (high != null && time.compare(high) > 0) ||\n (isTimeUnavailable?.(toIsoTime(time), time) ?? false)\n );\n };\n const iso = _derived(\n value == null || typeof value === 'string'\n ? value\n : toIsoTime(value, granularity === 'second'),\n );\n // 值清空后再填:仍按清空前的类型写回\n let lastLike: V | undefined;\n function write(next: string | null) {\n lastLike = value ?? lastLike;\n const asTime = lastLike != null ? typeof lastLike !== 'string' : valueType === 'dateValue';\n value = (next != null && asTime ? parseIsoTime(next) : next) as V | null;\n }\n return () => (\n <SegmentedField\n {...rest}\n onUpdate:_value={write}\n _value={iso}\n fields={segmentFields(granularity, true)}\n outOfRange={outOfRange}\n />\n );\n },\n);\n"],"mappings":";;;;;;;;;AAgCA,IAAa,UAAU,UACrB,OAAO,UAAU,YAAY,SAAS,OAAO,aAAa,KAAK,IAAI;;;AAsBrE,IAAa,YAAY,0BACvB,QAAA,SAQyB;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAPa,MAAI,KAAA,IAAA;CAAA,MAAA,cAAAC,aAAA,QAAA,eAC1B,QAAQ;CAAA,MAAA,YAAAA,aAAA,QAAA,aACV,KAAK;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,oBAAAA,aAAA,QAAA,mBAAA;CAAA,MAId,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,cAAc,QAAgB;EAClC,MAAM,OAAO,aAAa,GAAG;EAC7B,IAAI,QAAQ,MAAM,OAAO;EACzB,MAAM,MAAM,OAAM,IAAA,KAAI;EACtB,MAAM,OAAO,OAAM,IAAA,KAAI;EACvB,OACG,OAAO,QAAQ,KAAK,QAAQ,GAAG,IAAI,KACnC,QAAQ,QAAQ,KAAK,QAAQ,IAAI,IAAI,MACrC,kBAAA,QAAoB,UAAU,IAAI,GAAG,IAAI,KAAK;CAEnD;CACA,MAAM,MAAGC,eACP,MAAA,SAAS,QAAQ,OAAA,MAAA,UAAiB,WAAQ,MAAA,QAEtC,UAAS,MAAA,OAAQ,YAAA,UAAgB,QAAQ,CAAC;CAGhD,IAAI;CACJ,SAAS,MAAM,MAAqB;EAClC,WAAW,MAAA,SAAS;EACpB,MAAM,SAAS,YAAY,OAAO,OAAO,aAAa,WAAW,UAAA,UAAc;EAC/E,MAAA,QAAS,QAAQ,QAAQ,SAAS,aAAa,IAAI,IAAI;CACzD;CACA,aAAOC,YAAA,gBAAAC,WAEC,MAAI;EAAA,mBACS;EAAK,UAAA,IAAA;EAAA,UAEd,cAAa,YAAA,OAAc,IAAI;EAAC,cAC5B;CAAU,CAAA,GAAA,IAAA;AAG5B,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
1
+ {"version":3,"file":"TimeField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_mergeProps"],"sources":["../../src/date/TimeField.tsx"],"sourcesContent":["/**\n * 时间输入框:分段输入时、分(可选秒),12 / 24 小时制跟随语言(zh-CN 24 小时,en-US 12 小时加 AM / PM),也可以用 hourCycle 指定。\n * 参考 React Aria TimeField、原生 input type=\"time\"。要从按步长列出的时间里点选用 TimePicker。\n *\n * <Field label=\"提醒时间\"><TimeField _value={time} /></Field>\n * <TimeField granularity=\"second\" hourCycle=\"h12\" _value={at} aria-label=\"打卡时间\" />\n *\n * 值是 'HH:mm'(granularity 为 second 时 'HH:mm:ss'),时总是 24 小时制,与原生 input type=\"time\" 一致;\n * 也可以是 @internationalized/date 的 Time,写回时保持同一种类型。\n * 键盘同 DateField;12 小时制时在上午 / 下午那段打 a、p 切换。部件见 SegmentedField。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport type { Time } from '@internationalized/date';\nimport { parseIsoTime, toIsoTime } from '../utils/data/date';\nimport type { DateValueTypes } from './date-locale';\nimport { segmentFields } from './date-segments';\nimport { SegmentedField, type SegmentedFieldOptions } from './SegmentedField';\n\n/** 时间精确到哪一段 */\nexport interface TimeFieldGranularities {\n /** 只有时:'14:00' */\n hour: unknown;\n /** 时分(默认):'14:30' */\n minute: unknown;\n /** 时分秒:'14:30:15' */\n second: unknown;\n}\n\n/** 时间输入框接受的值:'HH:mm[:ss]' 字符串,或 @internationalized/date 的 Time */\nexport type TimeInput = string | Time;\n\n/** TimeInput → Time:ISO 字符串按 'HH:mm[:ss]' 解析,空值或格式不对时为 null */\nexport const toTime = (input: TimeInput | null | undefined): Time | null =>\n typeof input === 'string' || input == null ? parseIsoTime(input) : input;\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface TimeFieldProps<V extends TimeInput = string> extends SegmentedFieldOptions {\n /** 值('HH:mm' 或 'HH:mm:ss',24 小时制;或 Time,写回时保持同一种类型):父级写 _value={x};没填全时 null */\n _value?: V | null;\n /** 值为空、推不出类型时写回哪一种,默认 iso(字符串);dateValue 写 Time */\n valueType?: keyof DateValueTypes;\n /** 精确到哪一段,默认 minute */\n granularity?: keyof TimeFieldGranularities;\n /** 最早的时间('09:00' 或 Time):早于它显示出错 */\n min?: TimeInput;\n /** 最晚的时间('18:00' 或 Time):晚于它显示出错 */\n max?: TimeInput;\n /**\n * 不可选的时间(午休、已约满的时段):键入时显示出错,TimePicker 的列表里不可用。\n * 第一个参数是 'HH:mm',第二个是同一时刻的 Time:`(_, time) => time.hour === 12`\n */\n isTimeUnavailable?: (time: string, value: Time) => boolean;\n}\n\n/** 时间输入框:分段输入 */\nexport const TimeField = _component(\n <V extends TimeInput>({\n _value: value = _bindable<V | null>(null),\n granularity = 'minute',\n valueType = 'iso',\n min,\n max,\n isTimeUnavailable,\n ...rest\n }: TimeFieldProps<V>) => {\n const outOfRange = (iso: string) => {\n const time = parseIsoTime(iso);\n if (time == null) return false;\n const low = toTime(min);\n const high = toTime(max);\n return (\n (low != null && time.compare(low) < 0) ||\n (high != null && time.compare(high) > 0) ||\n (isTimeUnavailable?.(toIsoTime(time), time) ?? false)\n );\n };\n const iso = _derived(\n value == null || typeof value === 'string'\n ? value\n : toIsoTime(value, granularity === 'second'),\n );\n // 值清空后再填:仍按清空前的类型写回\n let lastLike: V | undefined;\n function write(next: string | null) {\n lastLike = value ?? lastLike;\n const asTime = lastLike != null ? typeof lastLike !== 'string' : valueType === 'dateValue';\n value = (next != null && asTime ? parseIsoTime(next) : next) as V | null;\n }\n return () => (\n <SegmentedField\n {...rest}\n onUpdate:_value={write}\n _value={iso}\n fields={segmentFields(granularity, true)}\n outOfRange={outOfRange}\n />\n );\n },\n);\n"],"mappings":";;;;;;;;;AAgCA,IAAa,UAAU,UACrB,OAAO,UAAU,YAAY,SAAS,OAAO,aAAa,KAAK,IAAI;;;AAsBrE,IAAa,YAAY,0BACvB,QAAA,SAQyB;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAPa,MAAI,KAAA,IAAA;CAAA,MAAA,cAAAC,aAAA,QAAA,eAC1B,QAAQ;CAAA,MAAA,YAAAA,aAAA,QAAA,aACV,KAAK;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,oBAAAA,aAAA,QAAA,mBAAA;CAAA,MAId,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,cAAc,QAAgB;EAClC,MAAM,OAAO,aAAa,GAAG;EAC7B,IAAI,QAAQ,MAAM,OAAO;EACzB,MAAM,MAAM,OAAM,IAAA,KAAI;EACtB,MAAM,OAAO,OAAM,IAAA,KAAI;EACvB,OACG,OAAO,QAAQ,KAAK,QAAQ,GAAG,IAAI,KACnC,QAAQ,QAAQ,KAAK,QAAQ,IAAI,IAAI,MACrC,kBAAA,QAAoB,UAAU,IAAI,GAAG,IAAI,KAAK;CAEnD;CACA,MAAM,MAAGC,eACP,MAAA,SAAS,QAAQ,OAAA,MAAA,UAAiB,WAAQ,MAAA,QAEtC,UAAS,MAAA,OAAQ,YAAA,UAAgB,QAAQ,CAAC;CAGhD,IAAI;CACJ,SAAS,MAAM,MAAqB;EAClC,WAAW,MAAA,SAAS;EACpB,MAAM,SAAS,YAAY,OAAO,OAAO,aAAa,WAAW,UAAA,UAAc;EAC/E,MAAA,QAAS,QAAQ,QAAQ,SAAS,aAAa,IAAI,IAAI;CACzD;CACA,aAAOC,YAAA,gBAAAC,cAEC,MAAI;EAAA,mBACS;EAAK,UAAA,IAAA;EAAA,UAEd,cAAa,YAAA,OAAc,IAAI;EAAC,cAC5B;CAAU,CAAA,GAAA,IAAA;AAG5B,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -9,8 +9,8 @@ import { Listbox } from "../input/Listbox.js";
9
9
  import { useDateLocale } from "./date-locale.js";
10
10
  import { usePickerPopover } from "./picker-popover.js";
11
11
  import { TimeField, toTime } from "./TimeField.js";
12
- import { Fragment, computed, createVNode, mergeProps } from "vue";
13
- import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
12
+ import { Fragment, computed, createVNode } from "vue";
13
+ import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
14
14
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
15
  import { Clock } from "@lucide/icons";
16
16
  import { Time, now } from "@internationalized/date";
@@ -129,7 +129,7 @@ var TimePicker = /*#__PURE__*/ _component((_props, _ctx) => {
129
129
  const high = toTime(max.value);
130
130
  return !(low != null && time.compare(low) < 0 || high != null && time.compare(high) > 0 || (isTimeUnavailable.value?.(toIsoTime(time), time) ?? false));
131
131
  }
132
- return () => createVNode(Fragment, null, [createVNode(TimeField, mergeProps(rest, {
132
+ return () => createVNode(Fragment, null, [createVNode(TimeField, mergeJsxProps(rest, {
133
133
  "_value": value.value,
134
134
  "onUpdate:_value": _cache[0] || (_cache[0] = ($event) => value.value = $event),
135
135
  "granularity": granularity.value,
@@ -159,7 +159,7 @@ var TimePicker = /*#__PURE__*/ _component((_props, _ctx) => {
159
159
  _value: selected.value,
160
160
  onPick: (iso) => write(parseIsoTime(iso)),
161
161
  required: true
162
- }), null), createVNode(Button, mergeProps(mergePartProps({
162
+ }), null), createVNode(Button, mergeJsxProps(mergePartProps({
163
163
  sx: timePickerStyles.now,
164
164
  variant: "ghost",
165
165
  size: "sm",
@@ -1 +1 @@
1
- {"version":3,"file":"TimePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/date/TimePicker.tsx"],"sourcesContent":["/**\n * 时间选择器:TimeField 加一个打开时间列表的按钮,按 step 列出可选的时间(同 Google 日历的时间下拉);可以直接键入,也可以点选。\n * 参考 Mantine TimePicker 的 presets、MUI 的 digital clock;列表是 Listbox(↑↓、Home / End、按数字跳转)。\n *\n * <Field label=\"开会时间\"><TimePicker _value={time} min=\"09:00\" max=\"18:00\" /></Field>\n * <TimePicker step={15} _value={time} aria-label=\"提醒时间\" />\n *\n * 值同 TimeField('HH:mm',或 Time)。列表从 min(默认 00:00)起每 step 分钟一项,到 max 为止,按语言的 12 / 24 小时制显示;\n * 不在列表里的时间(14:47)照样能键入;isTimeUnavailable 的时间在列表里不可用、键入时显示出错。\n * 列表下方“此刻”选当前时间(此刻不可选时不可用)。选好后关闭,焦点回到按钮;Esc、点外部关闭,分段里 Alt + ↓ 打开。\n *\n * 部件:同 TimeField,另有 Button(打开按钮)、Popover(弹层)、List(Listbox)、Now(“此刻”按钮)。\n */\nimport { Clock } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now, Time } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { useLang } from '../config/context';\nimport { useFormat } from '../config/lang/format';\nimport { useFieldControl } from '../form/Field';\nimport { Listbox, type ListboxProps } from '../input/Listbox';\nimport type { ListboxOption } from '../input/list-state';\nimport { parseIsoTime, toIsoTime } from '../utils/data/date';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { usePickerPopover, type PickerPopoverParts } from './picker-popover';\nimport { TimeField, toTime, type TimeFieldProps, type TimeInput } from './TimeField';\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface TimePickerProps<V extends TimeInput = string>\n extends TimeFieldProps<V>, PickerPopoverParts, OpenChangeProps {\n /** 列表是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 列表里相邻两项相隔几分钟,默认 30 */\n step?: number;\n /** 时间列表的部件属性 */\n propsList?: Omit<Partial<ListboxProps>, 'items' | '_value' | 'onPick'>;\n /** “此刻”按钮的部件属性 */\n propsNow?: Omit<Partial<ButtonProps>, 'onClick'>;\n}\n\n/** TimePicker 的样式:popover、list、now */\nexport const timePickerStyles = css.create({\n popover: { display: 'flex', flexDirection: 'column', padding: '_xs' },\n // 弹层与输入框同宽,列表最多十来项高,其余滚动\n list: { maxHeight: '16em' },\n now: { marginTop: '_xs' },\n});\n\nconst minutesOf = (time: Time) => time.hour * 60 + time.minute;\n\n/** 时间选择器:分段输入 + 按步长列出的时间 */\nexport const TimePicker = _component(\n <V extends TimeInput>({\n _value: value = _bindable<V | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n step = 30,\n granularity = 'minute',\n valueType = 'iso',\n min,\n max,\n isTimeUnavailable,\n hourCycle,\n placement,\n id,\n disabled,\n readonly,\n invalid,\n required,\n propsRoot,\n propsButton,\n propsPopover,\n propsList,\n propsNow,\n onKeydown,\n ...rest\n }: TimePickerProps<V>) => {\n const lang = useLang();\n const format = useFormat();\n const locale = useDateLocale();\n // 输入由里面的 TimeField 接 Field;这里只读状态决定能不能打开面板\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }), {\n delegate: true,\n });\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n matchWidth: true,\n editable: !control().disabled && !control().readonly,\n label: lang.timePickerOpen,\n size: rest.size,\n }),\n {\n toggle: setOpen,\n shown: (panel) => panel.querySelector<HTMLElement>('[role=\"listbox\"]')?.focus(),\n },\n );\n\n /** 列表的选项:min 到 max,每 step 分钟一项,按语言的小时制显示 */\n const options = _derived.by((): ListboxOption[] => {\n const first = minutesOf(toTime(min) ?? new Time(0, 0));\n const last = minutesOf(toTime(max) ?? new Time(23, 59));\n const result: ListboxOption[] = [];\n for (let minutes = first; minutes <= last; minutes += Math.max(step, 1)) {\n const time = new Time(Math.floor(minutes / 60), minutes % 60);\n const iso = toIsoTime(time);\n result.push({\n value: iso,\n label: format.date(iso, { timeStyle: 'short', hourCycle }),\n disabled: isTimeUnavailable?.(iso, time) ?? false,\n });\n }\n return result;\n });\n\n // 当前值正好是列表里的一项时高亮它(只比时分)\n const selected = _derived.by(() => {\n const time = toTime(value);\n return time ? toIsoTime(time) : undefined;\n });\n\n /** 写回:和当前值同一种类型(Time 或字符串),精确到秒时补 :00 */\n function write(time: Time, event?: Event) {\n const asTime = (value != null && typeof value !== 'string') || valueType === 'dateValue';\n value = (asTime ? time : toIsoTime(time, granularity === 'second')) as V;\n setOpen(false, 'select', event);\n }\n\n /** 此刻(精确到分) */\n const nowTime = () => {\n const current = now(locale.timeZone);\n return new Time(current.hour, current.minute);\n };\n /** 此刻能不能选:在 min–max 之内,不是不可选的时间 */\n function nowAvailable() {\n const time = nowTime();\n const low = toTime(min);\n const high = toTime(max);\n return !(\n (low != null && time.compare(low) < 0) ||\n (high != null && time.compare(high) > 0) ||\n (isTimeUnavailable?.(toIsoTime(time), time) ?? false)\n );\n }\n\n return () => (\n <>\n <TimeField\n {...rest}\n _value={value}\n granularity={granularity}\n valueType={valueType}\n min={min}\n max={max}\n isTimeUnavailable={isTimeUnavailable}\n hourCycle={hourCycle}\n id={id}\n disabled={disabled}\n readonly={readonly}\n invalid={invalid}\n required={required}\n onKeydown={(event) => {\n onKeydown?.(event);\n picker.onKeydown(event);\n }}\n propsRoot={mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: picker.anchorRef })}\n suffix={picker.button(Clock, propsButton)}\n />\n {picker.panel(\n timePickerStyles.popover,\n propsPopover,\n open && [\n <Listbox\n {...mergePartProps<ListboxProps>(\n { sx: timePickerStyles.list, 'aria-label': lang.timePickerOpen, items: options },\n propsList,\n // 在 Field 里时 Listbox 默认取 Field 的控件 id:那是输入框的,列表要自己的 id\n {\n id: `${picker.id}-list`,\n items: options,\n _value: selected,\n onPick: (iso) => write(parseIsoTime(iso)!),\n required: true,\n },\n )}\n />,\n <Button\n {...mergePartProps<ButtonProps>(\n { sx: timePickerStyles.now, variant: 'ghost', size: 'sm', fullWidth: true },\n propsNow,\n {\n disabled: !nowAvailable(),\n onClick: (event: MouseEvent) => write(nowTime(), event),\n },\n )}\n >\n {lang.timePickerNow}\n </Button>,\n ],\n )}\n </>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"TimePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/date/TimePicker.tsx"],"sourcesContent":["/**\n * 时间选择器:TimeField 加一个打开时间列表的按钮,按 step 列出可选的时间(同 Google 日历的时间下拉);可以直接键入,也可以点选。\n * 参考 Mantine TimePicker 的 presets、MUI 的 digital clock;列表是 Listbox(↑↓、Home / End、按数字跳转)。\n *\n * <Field label=\"开会时间\"><TimePicker _value={time} min=\"09:00\" max=\"18:00\" /></Field>\n * <TimePicker step={15} _value={time} aria-label=\"提醒时间\" />\n *\n * 值同 TimeField('HH:mm',或 Time)。列表从 min(默认 00:00)起每 step 分钟一项,到 max 为止,按语言的 12 / 24 小时制显示;\n * 不在列表里的时间(14:47)照样能键入;isTimeUnavailable 的时间在列表里不可用、键入时显示出错。\n * 列表下方“此刻”选当前时间(此刻不可选时不可用)。选好后关闭,焦点回到按钮;Esc、点外部关闭,分段里 Alt + ↓ 打开。\n *\n * 部件:同 TimeField,另有 Button(打开按钮)、Popover(弹层)、List(Listbox)、Now(“此刻”按钮)。\n */\nimport { Clock } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now, Time } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { useLang } from '../config/context';\nimport { useFormat } from '../config/lang/format';\nimport { useFieldControl } from '../form/Field';\nimport { Listbox, type ListboxProps } from '../input/Listbox';\nimport type { ListboxOption } from '../input/list-state';\nimport { parseIsoTime, toIsoTime } from '../utils/data/date';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { usePickerPopover, type PickerPopoverParts } from './picker-popover';\nimport { TimeField, toTime, type TimeFieldProps, type TimeInput } from './TimeField';\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface TimePickerProps<V extends TimeInput = string>\n extends TimeFieldProps<V>, PickerPopoverParts, OpenChangeProps {\n /** 列表是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 列表里相邻两项相隔几分钟,默认 30 */\n step?: number;\n /** 时间列表的部件属性 */\n propsList?: Omit<Partial<ListboxProps>, 'items' | '_value' | 'onPick'>;\n /** “此刻”按钮的部件属性 */\n propsNow?: Omit<Partial<ButtonProps>, 'onClick'>;\n}\n\n/** TimePicker 的样式:popover、list、now */\nexport const timePickerStyles = css.create({\n popover: { display: 'flex', flexDirection: 'column', padding: '_xs' },\n // 弹层与输入框同宽,列表最多十来项高,其余滚动\n list: { maxHeight: '16em' },\n now: { marginTop: '_xs' },\n});\n\nconst minutesOf = (time: Time) => time.hour * 60 + time.minute;\n\n/** 时间选择器:分段输入 + 按步长列出的时间 */\nexport const TimePicker = _component(\n <V extends TimeInput>({\n _value: value = _bindable<V | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n step = 30,\n granularity = 'minute',\n valueType = 'iso',\n min,\n max,\n isTimeUnavailable,\n hourCycle,\n placement,\n id,\n disabled,\n readonly,\n invalid,\n required,\n propsRoot,\n propsButton,\n propsPopover,\n propsList,\n propsNow,\n onKeydown,\n ...rest\n }: TimePickerProps<V>) => {\n const lang = useLang();\n const format = useFormat();\n const locale = useDateLocale();\n // 输入由里面的 TimeField 接 Field;这里只读状态决定能不能打开面板\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }), {\n delegate: true,\n });\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n matchWidth: true,\n editable: !control().disabled && !control().readonly,\n label: lang.timePickerOpen,\n size: rest.size,\n }),\n {\n toggle: setOpen,\n shown: (panel) => panel.querySelector<HTMLElement>('[role=\"listbox\"]')?.focus(),\n },\n );\n\n /** 列表的选项:min 到 max,每 step 分钟一项,按语言的小时制显示 */\n const options = _derived.by((): ListboxOption[] => {\n const first = minutesOf(toTime(min) ?? new Time(0, 0));\n const last = minutesOf(toTime(max) ?? new Time(23, 59));\n const result: ListboxOption[] = [];\n for (let minutes = first; minutes <= last; minutes += Math.max(step, 1)) {\n const time = new Time(Math.floor(minutes / 60), minutes % 60);\n const iso = toIsoTime(time);\n result.push({\n value: iso,\n label: format.date(iso, { timeStyle: 'short', hourCycle }),\n disabled: isTimeUnavailable?.(iso, time) ?? false,\n });\n }\n return result;\n });\n\n // 当前值正好是列表里的一项时高亮它(只比时分)\n const selected = _derived.by(() => {\n const time = toTime(value);\n return time ? toIsoTime(time) : undefined;\n });\n\n /** 写回:和当前值同一种类型(Time 或字符串),精确到秒时补 :00 */\n function write(time: Time, event?: Event) {\n const asTime = (value != null && typeof value !== 'string') || valueType === 'dateValue';\n value = (asTime ? time : toIsoTime(time, granularity === 'second')) as V;\n setOpen(false, 'select', event);\n }\n\n /** 此刻(精确到分) */\n const nowTime = () => {\n const current = now(locale.timeZone);\n return new Time(current.hour, current.minute);\n };\n /** 此刻能不能选:在 min–max 之内,不是不可选的时间 */\n function nowAvailable() {\n const time = nowTime();\n const low = toTime(min);\n const high = toTime(max);\n return !(\n (low != null && time.compare(low) < 0) ||\n (high != null && time.compare(high) > 0) ||\n (isTimeUnavailable?.(toIsoTime(time), time) ?? false)\n );\n }\n\n return () => (\n <>\n <TimeField\n {...rest}\n _value={value}\n granularity={granularity}\n valueType={valueType}\n min={min}\n max={max}\n isTimeUnavailable={isTimeUnavailable}\n hourCycle={hourCycle}\n id={id}\n disabled={disabled}\n readonly={readonly}\n invalid={invalid}\n required={required}\n onKeydown={(event) => {\n onKeydown?.(event);\n picker.onKeydown(event);\n }}\n propsRoot={mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: picker.anchorRef })}\n suffix={picker.button(Clock, propsButton)}\n />\n {picker.panel(\n timePickerStyles.popover,\n propsPopover,\n open && [\n <Listbox\n {...mergePartProps<ListboxProps>(\n { sx: timePickerStyles.list, 'aria-label': lang.timePickerOpen, items: options },\n propsList,\n // 在 Field 里时 Listbox 默认取 Field 的控件 id:那是输入框的,列表要自己的 id\n {\n id: `${picker.id}-list`,\n items: options,\n _value: selected,\n onPick: (iso) => write(parseIsoTime(iso)!),\n required: true,\n },\n )}\n />,\n <Button\n {...mergePartProps<ButtonProps>(\n { sx: timePickerStyles.now, variant: 'ghost', size: 'sm', fullWidth: true },\n propsNow,\n {\n disabled: !nowAvailable(),\n onClick: (event: MouseEvent) => write(nowTime(), event),\n },\n )}\n >\n {lang.timePickerNow}\n </Button>,\n ],\n )}\n </>\n );\n },\n);\n"],"mappings":"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"}
@@ -71,7 +71,7 @@ function useDateSegments(config) {
71
71
  const wanted = new Set(fields.value);
72
72
  return parts.filter((part) => part.type === "literal" || wanted.has(part.type)).map((part) => ({
73
73
  type: part.type,
74
- literal: part.value
74
+ literal: part.type === "literal" ? part.value.replace(/[   ]/g, " ") : part.value
75
75
  })).filter((part, index, all) => part.type !== "literal" || part.literal.trim() !== "" || index > 0 && index < all.length - 1);
76
76
  });
77
77
  const labels = computed(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"date-segments.js","names":[],"sources":["../../src/date/date-segments.ts"],"sourcesContent":["/**\n * 分段输入的状态(年、月、日、时、分、秒、上午 / 下午):DateField、TimeField 共用。参考 React Aria 的 useDateFieldState。\n * 不碰 DOM:组件把每段渲染成 role=\"spinbutton\" 的可聚焦元素,按键、输入交给这里,焦点该去哪一段由 focusedSegment 告诉组件。\n *\n * - 段的顺序、分隔符取自 Intl(zh-CN 年/月/日,en-US 月/日/年,de-DE 日.月.年),12 / 24 小时制按语言或配置;\n * - 逐段输入:打一个数字后,再打一个就超出范围时直接跳到下一段(月份打 3 → 03 跳走,打 1 → 等第二位);\n * - ↑↓ 加减(到头时回绕),Page Up / Down 大步,Home / End 到最小 / 最大,Backspace 删一位、删空后回到上一段;\n * - 所有段都填了才写回值;填好的值删掉一段时写回 null。认全角数字与阿拉伯-印度数字。\n *\n * const segments = useDateSegments({ fields: () => ['year', 'month', 'day'], value: () => fields, onChange, … });\n */\nimport { computed, ref, shallowRef, watch } from 'vue';\nimport type { HourCycles } from '../config/lang/lang';\nimport { isoWeeksInYear } from '../utils/data/date';\n\n/** 可以输入的段 */\nexport interface DateSegmentTypes {\n /** 年 */\n year: unknown;\n /** 月 */\n month: unknown;\n /** 日 */\n day: unknown;\n /** 季度(1–4) */\n quarter: unknown;\n /** 一年里的第几周(ISO 8601:周一开始,含 1 月 4 日的那周是第 1 周) */\n week: unknown;\n /** 时(内部总是 0–23,12 小时制时显示 1–12) */\n hour: unknown;\n /** 分 */\n minute: unknown;\n /** 秒 */\n second: unknown;\n /** 上午 / 下午(12 小时制时自动加上) */\n dayPeriod: unknown;\n}\n\n/** 一段的类型 */\nexport type DateSegmentType = keyof DateSegmentTypes;\n\n/** 值的各个字段:时是 0–23 */\nexport type DateFieldValues = Partial<Record<Exclude<DateSegmentType, 'dayPeriod'>, number>>;\n\n/** 渲染用的一段 */\nexport interface DateSegment {\n /** 段的类型;literal 是分隔符(/、:、年) */\n type: DateSegmentType | 'literal';\n /** 显示的文字:值、正在输入的数字,或占位文字 */\n text: string;\n /** 还没填:显示的是占位文字 */\n placeholder: boolean;\n /** 当前值(dayPeriod 是 0 上午 / 1 下午);没填时 null */\n value: number | null;\n /** 最小值(aria-valuemin) */\n min: number;\n /** 最大值(aria-valuemax) */\n max: number;\n /** 段的名称(取自 Intl.DisplayNames:年、月、日 / year、month、day),给 aria-label */\n label: string;\n}\n\n/** useDateSegments 的选项 */\nexport interface DateSegmentsOptions {\n /** 有哪些段(不含 dayPeriod,12 小时制时自动加) */\n fields: () => readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 语言:段的顺序、分隔符、数字的写法 */\n locale: () => string;\n /** 12 / 24 小时制;不写时按语言 */\n hourCycle?: () => keyof HourCycles | undefined;\n /** 完整的值(外部传入);没有时 null */\n value: () => DateFieldValues | null;\n /** 所有段都填了时写回完整的值,填好的值删掉一段时写回 null */\n onChange: (value: DateFieldValues | null) => void;\n /** ↑↓ 从空段开始加减时的起点(一般是现在) */\n placeholderValue: () => DateFieldValues;\n /** 各段的占位文字(年、月、日 / yyyy、mm、dd) */\n placeholders: () => Partial<Record<DateSegmentType, string>>;\n /** 季度、周这两种段的排法(Intl 不排它们),如 `'{year}年第{quarter}季度'`;不写时是 `'{year}-{quarter}'` */\n periodPatterns?: () => Partial<Record<'quarter' | 'week', string>>;\n /** 只读或不可用:不响应输入 */\n readonly?: () => boolean;\n /** 焦点要越过这组的两端时(最后一段输入满了;第一段删空后再删):DateRangePicker 把焦点交给另一组 */\n onExit?: (direction: 1 | -1) => void;\n}\n\n/** 分段输入的状态与操作 */\nexport interface DateSegmentsState {\n /** 各段,含分隔符,按语言的顺序 */\n readonly segments: readonly DateSegment[];\n /** 可以输入的段(不含分隔符),Tab 与 ←→ 的顺序 */\n readonly editable: readonly DateSegment[];\n /** 焦点应该在的段:输入满了跳到下一段、Backspace 删空回到上一段时变化 */\n readonly focusedSegment: DateSegmentType | null;\n /** 有段填了、但还没填全 */\n readonly partial: boolean;\n /** 焦点进了某一段(组件的 focusin) */\n setFocused(type: DateSegmentType | null): void;\n /** 在焦点段输入文字(数字、a / p):逐个字符处理 */\n type(text: string): void;\n /** 焦点段加减 */\n increment(amount: number): void;\n /** 焦点段设成最小 / 最大值 */\n toEdge(edge: 'min' | 'max'): void;\n /** 删掉焦点段的最后一位;已经空了时焦点回到上一段 */\n backspace(): void;\n /** 清空所有段 */\n clear(): void;\n /** 丢掉还没写回的输入(打了一半的段),回到当前的值:表单重置时 */\n reset(): void;\n /** 写回还没写回的年份(没打满四位时先不写回):离开这一段、按 Enter 提交时 */\n commit(): void;\n /** 焦点移到相邻的段 */\n moveFocus(direction: 1 | -1): void;\n}\n\n/** Page Up / Down 的步长(同 React Aria) */\nconst BIG_STEPS: Record<DateSegmentType, number> = {\n year: 5,\n month: 2,\n day: 7,\n quarter: 2,\n week: 4,\n hour: 2,\n minute: 15,\n second: 15,\n dayPeriod: 1,\n};\n\n/** 全角数字、阿拉伯-印度数字 → 半角 */\nfunction normalizeDigits(text: string): string {\n return text\n .replace(/[0-9]/g, (char) => String.fromCharCode(char.charCodeAt(0) - 0xfee0))\n .replace(/[\\u0660-\\u0669]/g, (char) => String(char.charCodeAt(0) - 0x0660))\n .replace(/[\\u06f0-\\u06f9]/g, (char) => String(char.charCodeAt(0) - 0x06f0));\n}\n\nconst daysInMonth = (year: number | undefined, month: number | undefined) =>\n month == null ? 31 : new Date(Date.UTC(year ?? 2000, month, 0)).getUTCDate();\n\n/** 分段输入的状态(组件 setup 里调用) */\nexport function useDateSegments(config: DateSegmentsOptions): DateSegmentsState {\n // 正在编辑的各字段:可以只填了一部分\n const draft = ref<DateFieldValues>({ ...config.value() });\n // 当前段已经打了的数字(还可能接着打第二位)\n const buffer = ref('');\n // 年份没打满四位:草稿里有了,先不写回(逐位打 2、0、2、6 时不写出 0002、0020、0202)\n let pendingYear = false;\n const focusedSegment = shallowRef<DateSegmentType | null>(null);\n\n // 外部的值变了(父级改了、清空了)时以它为准;自己写回的值也会回到这里,结果相同\n watch(\n () => config.value(),\n (value) => {\n if (sameFields(value, complete.value ? draft.value : null)) return;\n draft.value = { ...value };\n buffer.value = '';\n },\n );\n\n const hour12 = computed(() => {\n const cycle = config.hourCycle?.() ?? resolvedHourCycle(config.locale());\n return cycle === 'h12';\n });\n\n const fields = computed(() => {\n const list: DateSegmentType[] = [...config.fields()];\n if (hour12.value && list.includes('hour')) list.push('dayPeriod');\n return list;\n });\n\n const complete = computed(() => config.fields().every((field) => draft.value[field] != null));\n\n /** 按语言的顺序排好的段(含分隔符):只取格式化结果的结构,值另外填 */\n const layout = computed(() => {\n // 季度、周:Intl 不排这两种段,按语言包的排法\n const period = config.fields().find((field) => field === 'quarter' || field === 'week');\n if (period) {\n const pattern = config.periodPatterns?.()[period] ?? `{year}-{${period}}`;\n return pattern\n .split(/(\\{(?:year|quarter|week)\\})/)\n .filter(Boolean)\n .map((part) => {\n const field = /^\\{(year|quarter|week)\\}$/.exec(part)?.[1];\n return field\n ? { type: field as DateSegment['type'], literal: '' }\n : { type: 'literal' as const, literal: part };\n });\n }\n const options: Intl.DateTimeFormatOptions = {\n hourCycle: hour12.value ? 'h12' : 'h23',\n timeZone: 'UTC',\n };\n // 到这里的只有 Intl 认识的段(季度、周在上面已经返回了)\n for (const field of config.fields() as readonly Exclude<ValueField, 'quarter' | 'week'>[]) {\n options[field] = field === 'year' ? 'numeric' : '2-digit';\n }\n const parts = new Intl.DateTimeFormat(config.locale(), options).formatToParts(SAMPLE);\n const wanted = new Set(fields.value);\n return (\n parts\n .filter((part) => part.type === 'literal' || wanted.has(part.type as DateSegmentType))\n .map((part) => ({ type: part.type as DateSegment['type'], literal: part.value }))\n // 首尾只有空白的分隔符没有意义;“2026年10月”结尾的“月”要留着\n .filter(\n (part, index, all) =>\n part.type !== 'literal' ||\n part.literal.trim() !== '' ||\n (index > 0 && index < all.length - 1),\n )\n );\n });\n\n const labels = computed(() => {\n const names = new Intl.DisplayNames(config.locale(), { type: 'dateTimeField' });\n return Object.fromEntries(\n // Intl 的字段名里周叫 weekOfYear\n fields.value.map((field) => [\n field,\n names.of(field === 'week' ? 'weekOfYear' : field) ?? field,\n ]),\n ) as Record<DateSegmentType, string>;\n });\n\n const digits = computed(() => {\n const locale = config.locale();\n const format = (width: number) =>\n new Intl.NumberFormat(locale, { useGrouping: false, minimumIntegerDigits: width });\n return { 1: format(1), 2: format(2), 4: format(4) } as Record<1 | 2 | 4, Intl.NumberFormat>;\n });\n\n const periods = computed(() => {\n const formatter = new Intl.DateTimeFormat(config.locale(), {\n hour: 'numeric',\n hourCycle: 'h12',\n timeZone: 'UTC',\n });\n const period = (hour: number) =>\n formatter.formatToParts(Date.UTC(2000, 0, 1, hour)).find((part) => part.type === 'dayPeriod')\n ?.value ?? (hour < 12 ? 'AM' : 'PM');\n return [period(0), period(12)] as const;\n });\n\n function range(type: DateSegmentType): [number, number] {\n switch (type) {\n case 'year':\n return [1, 9999];\n case 'month':\n return [1, 12];\n case 'day':\n return [1, daysInMonth(draft.value.year, draft.value.month)];\n case 'quarter':\n return [1, 4];\n case 'week':\n return [1, draft.value.year == null ? 53 : isoWeeksInYear(draft.value.year)];\n case 'hour':\n return hour12.value ? [1, 12] : [0, 23];\n case 'minute':\n case 'second':\n return [0, 59];\n case 'dayPeriod':\n return [0, 1];\n }\n }\n\n /** 段上显示的值:12 小时制的时显示 1–12,上午 / 下午是 0 / 1 */\n function shown(type: DateSegmentType): number | null {\n const hour = draft.value.hour;\n if (type === 'dayPeriod') return hour == null ? null : hour >= 12 ? 1 : 0;\n if (type === 'hour' && hour12.value && hour != null) return hour % 12 || 12;\n return draft.value[type] ?? null;\n }\n\n function text(type: DateSegmentType, value: number | null): string {\n if (type === 'dayPeriod') return value == null ? '' : periods.value[value as 0 | 1];\n if (buffer.value && focusedSegment.value === type)\n return digits.value[1].format(Number(buffer.value));\n if (value == null) return '';\n const width =\n type === 'year' ? 4 : type === 'quarter' || (type === 'hour' && hour12.value) ? 1 : 2;\n return digits.value[width].format(value);\n }\n\n /**\n * 空段的占位:语言包里的单位字(年、月、日);后面紧跟的文字已经是这个单位时(中文的“2026年”)改用横线,\n * 显示成“––年”,否则会是“年年”\n */\n function placeholderOf(type: DateSegmentType, next: string | undefined): string {\n const unit = config.placeholders()[type];\n return !unit || next?.trimStart().startsWith(unit) ? '––' : unit;\n }\n\n const segments = computed((): DateSegment[] =>\n layout.value.map(({ type, literal }, index) => {\n if (type === 'literal')\n return { type, text: literal, placeholder: false, value: null, min: 0, max: 0, label: '' };\n const value = shown(type);\n const [min, max] = range(type);\n const filled = text(type, value);\n const following = layout.value[index + 1];\n return {\n type,\n text: filled || placeholderOf(type, following?.literal),\n placeholder: !filled,\n value,\n min,\n max,\n label: labels.value[type],\n };\n }),\n );\n const editable = computed(() => segments.value.filter((segment) => segment.type !== 'literal'));\n\n /** 写一段的值(显示值:12 小时制的时是 1–12);写完检查是否填全,emit 为 false 时只改草稿 */\n function write(type: DateSegmentType, value: number | null, emit = true) {\n const next = { ...draft.value };\n if (type === 'dayPeriod') {\n if (next.hour == null || value == null) return;\n next.hour = (next.hour % 12) + value * 12;\n } else if (type === 'hour' && hour12.value && value != null) {\n const afternoon = (draft.value.hour ?? config.placeholderValue().hour ?? 0) >= 12;\n next.hour = (value % 12) + (afternoon ? 12 : 0);\n } else if (value == null) delete next[type];\n else next[type] = value;\n const wasComplete = complete.value;\n draft.value = next;\n pendingYear = !emit;\n if (!emit) return;\n if (complete.value) config.onChange(constrained(next));\n else if (wasComplete) config.onChange(null);\n }\n\n function commit() {\n if (!pendingYear) return;\n pendingYear = false;\n if (complete.value) config.onChange(constrained(draft.value));\n }\n\n // 日超过了这个月的天数(先填了 31 再把月改成 2 月):写回时取这个月的最后一天;周同理(这一年只有 52 周时)\n function constrained(values: DateFieldValues): DateFieldValues {\n if (values.week != null && values.year != null)\n return { ...values, week: Math.min(values.week, isoWeeksInYear(values.year)) };\n if (values.day == null) return values;\n return { ...values, day: Math.min(values.day, daysInMonth(values.year, values.month)) };\n }\n\n const current = () => focusedSegment.value;\n\n const state: DateSegmentsState = {\n get segments() {\n return segments.value;\n },\n get editable() {\n return editable.value;\n },\n get focusedSegment() {\n return focusedSegment.value;\n },\n get partial() {\n return !complete.value && config.fields().some((field) => draft.value[field] != null);\n },\n setFocused(type) {\n if (type !== focusedSegment.value) {\n commit();\n buffer.value = '';\n }\n focusedSegment.value = type;\n },\n type(input) {\n if (!current() || config.readonly?.()) return;\n for (const char of normalizeDigits(input)) {\n const segment = current();\n if (!segment) return;\n if (segment === 'dayPeriod') {\n const lower = char.toLocaleLowerCase();\n const [am, pm] = periods.value.map((label) => label.toLocaleLowerCase());\n if (lower === 'a' || am!.startsWith(lower)) write('dayPeriod', 0);\n else if (lower === 'p' || pm!.startsWith(lower)) write('dayPeriod', 1);\n else continue;\n state.moveFocus(1);\n continue;\n }\n if (!/\\d/.test(char)) continue;\n const [min, max] = range(segment);\n let next = buffer.value + char;\n // 打了这一位就超出范围:从这一位重新开始\n if (Number(next) > max) next = char;\n buffer.value = next;\n const number = Number(next);\n // 0 还不是合法值(月、日、12 小时制的时):先记着,等下一位;年份打满四位才写回\n if (number >= min) write(segment, number, segment !== 'year' || next.length >= 4);\n const maxDigits = String(max).length;\n if (next.length >= maxDigits || number * 10 > max) {\n buffer.value = '';\n if (number < min) write(segment, min);\n state.moveFocus(1);\n }\n }\n },\n increment(amount) {\n const type = current();\n if (!type || config.readonly?.()) return;\n buffer.value = '';\n const [min, max] = range(type);\n const value = shown(type);\n if (value == null) {\n const start = config.placeholderValue();\n if (type === 'dayPeriod') {\n if (draft.value.hour == null)\n write('hour', hour12.value ? (start.hour ?? 0) % 12 || 12 : (start.hour ?? 0));\n write('dayPeriod', (start.hour ?? 0) >= 12 ? 1 : 0);\n return;\n }\n const initial =\n type === 'hour' && hour12.value ? (start.hour ?? 0) % 12 || 12 : (start[type] ?? min);\n write(type, initial);\n return;\n }\n const size = max - min + 1;\n write(type, ((((value - min + amount) % size) + size) % size) + min);\n },\n toEdge(edge) {\n const type = current();\n if (!type || config.readonly?.()) return;\n buffer.value = '';\n const [min, max] = range(type);\n write(type, edge === 'min' ? min : max);\n },\n backspace() {\n const type = current();\n if (!type || config.readonly?.()) return;\n const value = shown(type);\n if (value == null && !buffer.value) {\n state.moveFocus(-1);\n return;\n }\n const digitsLeft = type === 'dayPeriod' ? '' : (buffer.value || String(value)).slice(0, -1);\n buffer.value = digitsLeft;\n const [min] = range(type);\n if (type === 'dayPeriod' || !digitsLeft) {\n if (type === 'dayPeriod' || type === 'hour') {\n // 删掉上午 / 下午或时:时没有了,两段一起清空\n const next = { ...draft.value };\n delete next.hour;\n const wasComplete = complete.value;\n draft.value = next;\n if (wasComplete) config.onChange(null);\n return;\n }\n write(type, null);\n return;\n }\n if (Number(digitsLeft) >= min) write(type, Number(digitsLeft));\n },\n clear() {\n buffer.value = '';\n pendingYear = false;\n const wasComplete = complete.value;\n draft.value = {};\n if (wasComplete) config.onChange(null);\n },\n reset() {\n buffer.value = '';\n pendingYear = false;\n draft.value = { ...config.value() };\n },\n commit,\n moveFocus(direction) {\n const list = editable.value;\n const index = list.findIndex((segment) => segment.type === current());\n const next = list[index + direction];\n if (next) state.setFocused(next.type as DateSegmentType);\n else config.onExit?.(direction);\n },\n };\n return state;\n}\n\n/**\n * 分段输入的键盘操作:↑↓ 加减、Page Up / Down 大步、Home / End 最小 / 最大、Backspace / Delete 删除、\n * ←→ 换段(从右到左排版时反过来)。数字与字母走 beforeinput(软键盘、输入法也能输入),这里不处理。\n * 返回是否处理了这个按键(处理了就该 preventDefault)\n */\nexport function handleSegmentKeydown(\n state: DateSegmentsState,\n event: KeyboardEvent,\n rtl = false,\n): boolean {\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n const type = state.focusedSegment;\n if (!type) return false;\n const forward = rtl ? -1 : 1;\n const actions: Record<string, () => void> = {\n ArrowUp: () => state.increment(1),\n ArrowDown: () => state.increment(-1),\n PageUp: () => state.increment(BIG_STEPS[type]),\n PageDown: () => state.increment(-BIG_STEPS[type]),\n Home: () => state.toEdge('min'),\n End: () => state.toEdge('max'),\n Backspace: () => state.backspace(),\n Delete: () => state.backspace(),\n ArrowRight: () => state.moveFocus(forward as 1 | -1),\n ArrowLeft: () => state.moveFocus(-forward as 1 | -1),\n };\n const action = actions[event.key];\n if (!action) return false;\n action();\n return true;\n}\n\n// ───────── 内部实现 ─────────\n\n/** 取段的顺序用的任意时刻(各段都是两位数,排版不受值影响) */\nconst SAMPLE = Date.UTC(2000, 10, 22, 13, 44, 55);\n\n/** 语言默认的小时制 */\nfunction resolvedHourCycle(locale: string): keyof HourCycles {\n const cycle = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).resolvedOptions().hourCycle;\n return cycle === 'h11' || cycle === 'h12' ? 'h12' : 'h23';\n}\n\nfunction sameFields(a: DateFieldValues | null, b: DateFieldValues | null): boolean {\n if (a == null || b == null) return a === b;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]) as Set<keyof DateFieldValues>;\n return [...keys].every((key) => a[key] === b[key]);\n}\n\n// ───────── 值与 ISO 字符串 ─────────\n\n/** 日期类分段的粒度:DateField 精确到哪一段(到时、分、秒时是日期加时间) */\nexport interface DateFieldGranularities {\n /** 只有年:'2026' */\n year: unknown;\n /** 年月:'2026-10'(同原生 input type=\"month\") */\n month: unknown;\n /** 年月日(默认):'2026-10-20' */\n day: unknown;\n /** 年与季度:'2026-Q4' */\n quarter: unknown;\n /** 年与周(ISO 8601,周一开始):'2026-W43'(同原生 input type=\"week\") */\n week: unknown;\n /** 日期加时:'2026-10-20T14:00' */\n hour: unknown;\n /** 日期加时分:'2026-10-20T14:30'(同原生 input type=\"datetime-local\") */\n minute: unknown;\n /** 日期加时分秒:'2026-10-20T14:30:15' */\n second: unknown;\n}\n\n/** 分段输入精确到哪一段 */\nexport type DateFieldGranularity = keyof DateFieldGranularities;\n\ntype ValueField = Exclude<DateSegmentType, 'dayPeriod'>;\n\nconst ALL_FIELDS: readonly ValueField[] = ['year', 'month', 'day', 'hour', 'minute', 'second'];\n\n/** 日期分段:从年到 granularity;time 时只取时间的部分(TimeField) */\nexport function segmentFields(granularity: DateFieldGranularity, time = false): ValueField[] {\n if (granularity === 'quarter' || granularity === 'week') return time ? [] : ['year', granularity];\n const fields = ALL_FIELDS.slice(0, ALL_FIELDS.indexOf(granularity) + 1);\n return time\n ? fields.filter((field) => field === 'hour' || field === 'minute' || field === 'second')\n : fields;\n}\n\nconst pad = (value: number, width = 2) => String(value).padStart(width, '0');\n\n/** 各段的值 → ISO 字符串(按有哪些段:'2026'、'2026-10'、'2026-10-20'、'2026-10-20T14:30'、'14:30') */\nexport function fieldsToIso(values: DateFieldValues, fields: readonly ValueField[]): string {\n if (fields.includes('quarter')) return `${pad(values.year ?? 0, 4)}-Q${values.quarter ?? 1}`;\n if (fields.includes('week')) return `${pad(values.year ?? 0, 4)}-W${pad(values.week ?? 1)}`;\n const date = [\n values.year != null && pad(values.year, 4),\n fields.includes('month') && pad(values.month ?? 1),\n fields.includes('day') && pad(values.day ?? 1),\n ]\n .filter((part) => part !== false)\n .join('-');\n if (!fields.includes('hour')) return date;\n const time = [\n pad(values.hour ?? 0),\n pad(values.minute ?? 0),\n fields.includes('second') && pad(values.second ?? 0),\n ]\n .filter((part) => part !== false)\n .join(':');\n return fields.includes('year') ? `${date}T${time}` : time;\n}\n\n/** ISO 字符串 → 各段的值;格式不对时 null。只取 fields 里有的段('2026-10-20T14:30' 给 DateField 时只要日期) */\nexport function isoToFields(\n value: string | null | undefined,\n fields: readonly ValueField[],\n): DateFieldValues | null {\n if (!value) return null;\n const period = /^(\\d{4})-(?:Q([1-4])|W(\\d{2}))$/.exec(value);\n if (period) {\n const parsed: DateFieldValues = { year: Number(period[1]) };\n if (period[2] != null) parsed.quarter = Number(period[2]);\n if (period[3] != null) parsed.week = Number(period[3]);\n return fields.every((field) => parsed[field] != null) ? parsed : null;\n }\n const match = /^(?:(\\d{4})(?:-(\\d{2})(?:-(\\d{2}))?)?)?(?:T?(\\d{2}):(\\d{2})(?::(\\d{2}))?)?$/.exec(\n value,\n );\n if (!match) return null;\n const parsed: DateFieldValues = {};\n ALL_FIELDS.forEach((field, index) => {\n const text = match[index + 1];\n if (fields.includes(field) && text != null) parsed[field] = Number(text);\n });\n return fields.every((field) => parsed[field] != null) ? parsed : null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"date-segments.js","names":[],"sources":["../../src/date/date-segments.ts"],"sourcesContent":["/**\n * 分段输入的状态(年、月、日、时、分、秒、上午 / 下午):DateField、TimeField 共用。参考 React Aria 的 useDateFieldState。\n * 不碰 DOM:组件把每段渲染成 role=\"spinbutton\" 的可聚焦元素,按键、输入交给这里,焦点该去哪一段由 focusedSegment 告诉组件。\n *\n * - 段的顺序、分隔符取自 Intl(zh-CN 年/月/日,en-US 月/日/年,de-DE 日.月.年),12 / 24 小时制按语言或配置;\n * - 逐段输入:打一个数字后,再打一个就超出范围时直接跳到下一段(月份打 3 → 03 跳走,打 1 → 等第二位);\n * - ↑↓ 加减(到头时回绕),Page Up / Down 大步,Home / End 到最小 / 最大,Backspace 删一位、删空后回到上一段;\n * - 所有段都填了才写回值;填好的值删掉一段时写回 null。认全角数字与阿拉伯-印度数字。\n *\n * const segments = useDateSegments({ fields: () => ['year', 'month', 'day'], value: () => fields, onChange, … });\n */\nimport { computed, ref, shallowRef, watch } from 'vue';\nimport type { HourCycles } from '../config/lang/lang';\nimport { isoWeeksInYear } from '../utils/data/date';\n\n/** 可以输入的段 */\nexport interface DateSegmentTypes {\n /** 年 */\n year: unknown;\n /** 月 */\n month: unknown;\n /** 日 */\n day: unknown;\n /** 季度(1–4) */\n quarter: unknown;\n /** 一年里的第几周(ISO 8601:周一开始,含 1 月 4 日的那周是第 1 周) */\n week: unknown;\n /** 时(内部总是 0–23,12 小时制时显示 1–12) */\n hour: unknown;\n /** 分 */\n minute: unknown;\n /** 秒 */\n second: unknown;\n /** 上午 / 下午(12 小时制时自动加上) */\n dayPeriod: unknown;\n}\n\n/** 一段的类型 */\nexport type DateSegmentType = keyof DateSegmentTypes;\n\n/** 值的各个字段:时是 0–23 */\nexport type DateFieldValues = Partial<Record<Exclude<DateSegmentType, 'dayPeriod'>, number>>;\n\n/** 渲染用的一段 */\nexport interface DateSegment {\n /** 段的类型;literal 是分隔符(/、:、年) */\n type: DateSegmentType | 'literal';\n /** 显示的文字:值、正在输入的数字,或占位文字 */\n text: string;\n /** 还没填:显示的是占位文字 */\n placeholder: boolean;\n /** 当前值(dayPeriod 是 0 上午 / 1 下午);没填时 null */\n value: number | null;\n /** 最小值(aria-valuemin) */\n min: number;\n /** 最大值(aria-valuemax) */\n max: number;\n /** 段的名称(取自 Intl.DisplayNames:年、月、日 / year、month、day),给 aria-label */\n label: string;\n}\n\n/** useDateSegments 的选项 */\nexport interface DateSegmentsOptions {\n /** 有哪些段(不含 dayPeriod,12 小时制时自动加) */\n fields: () => readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 语言:段的顺序、分隔符、数字的写法 */\n locale: () => string;\n /** 12 / 24 小时制;不写时按语言 */\n hourCycle?: () => keyof HourCycles | undefined;\n /** 完整的值(外部传入);没有时 null */\n value: () => DateFieldValues | null;\n /** 所有段都填了时写回完整的值,填好的值删掉一段时写回 null */\n onChange: (value: DateFieldValues | null) => void;\n /** ↑↓ 从空段开始加减时的起点(一般是现在) */\n placeholderValue: () => DateFieldValues;\n /** 各段的占位文字(年、月、日 / yyyy、mm、dd) */\n placeholders: () => Partial<Record<DateSegmentType, string>>;\n /** 季度、周这两种段的排法(Intl 不排它们),如 `'{year}年第{quarter}季度'`;不写时是 `'{year}-{quarter}'` */\n periodPatterns?: () => Partial<Record<'quarter' | 'week', string>>;\n /** 只读或不可用:不响应输入 */\n readonly?: () => boolean;\n /** 焦点要越过这组的两端时(最后一段输入满了;第一段删空后再删):DateRangePicker 把焦点交给另一组 */\n onExit?: (direction: 1 | -1) => void;\n}\n\n/** 分段输入的状态与操作 */\nexport interface DateSegmentsState {\n /** 各段,含分隔符,按语言的顺序 */\n readonly segments: readonly DateSegment[];\n /** 可以输入的段(不含分隔符),Tab 与 ←→ 的顺序 */\n readonly editable: readonly DateSegment[];\n /** 焦点应该在的段:输入满了跳到下一段、Backspace 删空回到上一段时变化 */\n readonly focusedSegment: DateSegmentType | null;\n /** 有段填了、但还没填全 */\n readonly partial: boolean;\n /** 焦点进了某一段(组件的 focusin) */\n setFocused(type: DateSegmentType | null): void;\n /** 在焦点段输入文字(数字、a / p):逐个字符处理 */\n type(text: string): void;\n /** 焦点段加减 */\n increment(amount: number): void;\n /** 焦点段设成最小 / 最大值 */\n toEdge(edge: 'min' | 'max'): void;\n /** 删掉焦点段的最后一位;已经空了时焦点回到上一段 */\n backspace(): void;\n /** 清空所有段 */\n clear(): void;\n /** 丢掉还没写回的输入(打了一半的段),回到当前的值:表单重置时 */\n reset(): void;\n /** 写回还没写回的年份(没打满四位时先不写回):离开这一段、按 Enter 提交时 */\n commit(): void;\n /** 焦点移到相邻的段 */\n moveFocus(direction: 1 | -1): void;\n}\n\n/** Page Up / Down 的步长(同 React Aria) */\nconst BIG_STEPS: Record<DateSegmentType, number> = {\n year: 5,\n month: 2,\n day: 7,\n quarter: 2,\n week: 4,\n hour: 2,\n minute: 15,\n second: 15,\n dayPeriod: 1,\n};\n\n/** 全角数字、阿拉伯-印度数字 → 半角 */\nfunction normalizeDigits(text: string): string {\n return text\n .replace(/[0-9]/g, (char) => String.fromCharCode(char.charCodeAt(0) - 0xfee0))\n .replace(/[\\u0660-\\u0669]/g, (char) => String(char.charCodeAt(0) - 0x0660))\n .replace(/[\\u06f0-\\u06f9]/g, (char) => String(char.charCodeAt(0) - 0x06f0));\n}\n\nconst daysInMonth = (year: number | undefined, month: number | undefined) =>\n month == null ? 31 : new Date(Date.UTC(year ?? 2000, month, 0)).getUTCDate();\n\n/** 分段输入的状态(组件 setup 里调用) */\nexport function useDateSegments(config: DateSegmentsOptions): DateSegmentsState {\n // 正在编辑的各字段:可以只填了一部分\n const draft = ref<DateFieldValues>({ ...config.value() });\n // 当前段已经打了的数字(还可能接着打第二位)\n const buffer = ref('');\n // 年份没打满四位:草稿里有了,先不写回(逐位打 2、0、2、6 时不写出 0002、0020、0202)\n let pendingYear = false;\n const focusedSegment = shallowRef<DateSegmentType | null>(null);\n\n // 外部的值变了(父级改了、清空了)时以它为准;自己写回的值也会回到这里,结果相同\n watch(\n () => config.value(),\n (value) => {\n if (sameFields(value, complete.value ? draft.value : null)) return;\n draft.value = { ...value };\n buffer.value = '';\n },\n );\n\n const hour12 = computed(() => {\n const cycle = config.hourCycle?.() ?? resolvedHourCycle(config.locale());\n return cycle === 'h12';\n });\n\n const fields = computed(() => {\n const list: DateSegmentType[] = [...config.fields()];\n if (hour12.value && list.includes('hour')) list.push('dayPeriod');\n return list;\n });\n\n const complete = computed(() => config.fields().every((field) => draft.value[field] != null));\n\n /** 按语言的顺序排好的段(含分隔符):只取格式化结果的结构,值另外填 */\n const layout = computed(() => {\n // 季度、周:Intl 不排这两种段,按语言包的排法\n const period = config.fields().find((field) => field === 'quarter' || field === 'week');\n if (period) {\n const pattern = config.periodPatterns?.()[period] ?? `{year}-{${period}}`;\n return pattern\n .split(/(\\{(?:year|quarter|week)\\})/)\n .filter(Boolean)\n .map((part) => {\n const field = /^\\{(year|quarter|week)\\}$/.exec(part)?.[1];\n return field\n ? { type: field as DateSegment['type'], literal: '' }\n : { type: 'literal' as const, literal: part };\n });\n }\n const options: Intl.DateTimeFormatOptions = {\n hourCycle: hour12.value ? 'h12' : 'h23',\n timeZone: 'UTC',\n };\n // 到这里的只有 Intl 认识的段(季度、周在上面已经返回了)\n for (const field of config.fields() as readonly Exclude<ValueField, 'quarter' | 'week'>[]) {\n options[field] = field === 'year' ? 'numeric' : '2-digit';\n }\n const parts = new Intl.DateTimeFormat(config.locale(), options).formatToParts(SAMPLE);\n const wanted = new Set(fields.value);\n return (\n parts\n .filter((part) => part.type === 'literal' || wanted.has(part.type as DateSegmentType))\n // 分隔符里的各种空白(不换行空格、窄不换行空格)统一成普通空格:各平台的 Intl 给的不一样,\n // 服务端渲染与浏览器的文字对不上;显示上没有区别\n .map((part) => ({\n type: part.type as DateSegment['type'],\n literal: part.type === 'literal' ? part.value.replace(/[   ]/g, ' ') : part.value,\n }))\n // 首尾只有空白的分隔符没有意义;“2026年10月”结尾的“月”要留着\n .filter(\n (part, index, all) =>\n part.type !== 'literal' ||\n part.literal.trim() !== '' ||\n (index > 0 && index < all.length - 1),\n )\n );\n });\n\n const labels = computed(() => {\n const names = new Intl.DisplayNames(config.locale(), { type: 'dateTimeField' });\n return Object.fromEntries(\n // Intl 的字段名里周叫 weekOfYear\n fields.value.map((field) => [\n field,\n names.of(field === 'week' ? 'weekOfYear' : field) ?? field,\n ]),\n ) as Record<DateSegmentType, string>;\n });\n\n const digits = computed(() => {\n const locale = config.locale();\n const format = (width: number) =>\n new Intl.NumberFormat(locale, { useGrouping: false, minimumIntegerDigits: width });\n return { 1: format(1), 2: format(2), 4: format(4) } as Record<1 | 2 | 4, Intl.NumberFormat>;\n });\n\n const periods = computed(() => {\n const formatter = new Intl.DateTimeFormat(config.locale(), {\n hour: 'numeric',\n hourCycle: 'h12',\n timeZone: 'UTC',\n });\n const period = (hour: number) =>\n formatter.formatToParts(Date.UTC(2000, 0, 1, hour)).find((part) => part.type === 'dayPeriod')\n ?.value ?? (hour < 12 ? 'AM' : 'PM');\n return [period(0), period(12)] as const;\n });\n\n function range(type: DateSegmentType): [number, number] {\n switch (type) {\n case 'year':\n return [1, 9999];\n case 'month':\n return [1, 12];\n case 'day':\n return [1, daysInMonth(draft.value.year, draft.value.month)];\n case 'quarter':\n return [1, 4];\n case 'week':\n return [1, draft.value.year == null ? 53 : isoWeeksInYear(draft.value.year)];\n case 'hour':\n return hour12.value ? [1, 12] : [0, 23];\n case 'minute':\n case 'second':\n return [0, 59];\n case 'dayPeriod':\n return [0, 1];\n }\n }\n\n /** 段上显示的值:12 小时制的时显示 1–12,上午 / 下午是 0 / 1 */\n function shown(type: DateSegmentType): number | null {\n const hour = draft.value.hour;\n if (type === 'dayPeriod') return hour == null ? null : hour >= 12 ? 1 : 0;\n if (type === 'hour' && hour12.value && hour != null) return hour % 12 || 12;\n return draft.value[type] ?? null;\n }\n\n function text(type: DateSegmentType, value: number | null): string {\n if (type === 'dayPeriod') return value == null ? '' : periods.value[value as 0 | 1];\n if (buffer.value && focusedSegment.value === type)\n return digits.value[1].format(Number(buffer.value));\n if (value == null) return '';\n const width =\n type === 'year' ? 4 : type === 'quarter' || (type === 'hour' && hour12.value) ? 1 : 2;\n return digits.value[width].format(value);\n }\n\n /**\n * 空段的占位:语言包里的单位字(年、月、日);后面紧跟的文字已经是这个单位时(中文的“2026年”)改用横线,\n * 显示成“––年”,否则会是“年年”\n */\n function placeholderOf(type: DateSegmentType, next: string | undefined): string {\n const unit = config.placeholders()[type];\n return !unit || next?.trimStart().startsWith(unit) ? '––' : unit;\n }\n\n const segments = computed((): DateSegment[] =>\n layout.value.map(({ type, literal }, index) => {\n if (type === 'literal')\n return { type, text: literal, placeholder: false, value: null, min: 0, max: 0, label: '' };\n const value = shown(type);\n const [min, max] = range(type);\n const filled = text(type, value);\n const following = layout.value[index + 1];\n return {\n type,\n text: filled || placeholderOf(type, following?.literal),\n placeholder: !filled,\n value,\n min,\n max,\n label: labels.value[type],\n };\n }),\n );\n const editable = computed(() => segments.value.filter((segment) => segment.type !== 'literal'));\n\n /** 写一段的值(显示值:12 小时制的时是 1–12);写完检查是否填全,emit 为 false 时只改草稿 */\n function write(type: DateSegmentType, value: number | null, emit = true) {\n const next = { ...draft.value };\n if (type === 'dayPeriod') {\n if (next.hour == null || value == null) return;\n next.hour = (next.hour % 12) + value * 12;\n } else if (type === 'hour' && hour12.value && value != null) {\n const afternoon = (draft.value.hour ?? config.placeholderValue().hour ?? 0) >= 12;\n next.hour = (value % 12) + (afternoon ? 12 : 0);\n } else if (value == null) delete next[type];\n else next[type] = value;\n const wasComplete = complete.value;\n draft.value = next;\n pendingYear = !emit;\n if (!emit) return;\n if (complete.value) config.onChange(constrained(next));\n else if (wasComplete) config.onChange(null);\n }\n\n function commit() {\n if (!pendingYear) return;\n pendingYear = false;\n if (complete.value) config.onChange(constrained(draft.value));\n }\n\n // 日超过了这个月的天数(先填了 31 再把月改成 2 月):写回时取这个月的最后一天;周同理(这一年只有 52 周时)\n function constrained(values: DateFieldValues): DateFieldValues {\n if (values.week != null && values.year != null)\n return { ...values, week: Math.min(values.week, isoWeeksInYear(values.year)) };\n if (values.day == null) return values;\n return { ...values, day: Math.min(values.day, daysInMonth(values.year, values.month)) };\n }\n\n const current = () => focusedSegment.value;\n\n const state: DateSegmentsState = {\n get segments() {\n return segments.value;\n },\n get editable() {\n return editable.value;\n },\n get focusedSegment() {\n return focusedSegment.value;\n },\n get partial() {\n return !complete.value && config.fields().some((field) => draft.value[field] != null);\n },\n setFocused(type) {\n if (type !== focusedSegment.value) {\n commit();\n buffer.value = '';\n }\n focusedSegment.value = type;\n },\n type(input) {\n if (!current() || config.readonly?.()) return;\n for (const char of normalizeDigits(input)) {\n const segment = current();\n if (!segment) return;\n if (segment === 'dayPeriod') {\n const lower = char.toLocaleLowerCase();\n const [am, pm] = periods.value.map((label) => label.toLocaleLowerCase());\n if (lower === 'a' || am!.startsWith(lower)) write('dayPeriod', 0);\n else if (lower === 'p' || pm!.startsWith(lower)) write('dayPeriod', 1);\n else continue;\n state.moveFocus(1);\n continue;\n }\n if (!/\\d/.test(char)) continue;\n const [min, max] = range(segment);\n let next = buffer.value + char;\n // 打了这一位就超出范围:从这一位重新开始\n if (Number(next) > max) next = char;\n buffer.value = next;\n const number = Number(next);\n // 0 还不是合法值(月、日、12 小时制的时):先记着,等下一位;年份打满四位才写回\n if (number >= min) write(segment, number, segment !== 'year' || next.length >= 4);\n const maxDigits = String(max).length;\n if (next.length >= maxDigits || number * 10 > max) {\n buffer.value = '';\n if (number < min) write(segment, min);\n state.moveFocus(1);\n }\n }\n },\n increment(amount) {\n const type = current();\n if (!type || config.readonly?.()) return;\n buffer.value = '';\n const [min, max] = range(type);\n const value = shown(type);\n if (value == null) {\n const start = config.placeholderValue();\n if (type === 'dayPeriod') {\n if (draft.value.hour == null)\n write('hour', hour12.value ? (start.hour ?? 0) % 12 || 12 : (start.hour ?? 0));\n write('dayPeriod', (start.hour ?? 0) >= 12 ? 1 : 0);\n return;\n }\n const initial =\n type === 'hour' && hour12.value ? (start.hour ?? 0) % 12 || 12 : (start[type] ?? min);\n write(type, initial);\n return;\n }\n const size = max - min + 1;\n write(type, ((((value - min + amount) % size) + size) % size) + min);\n },\n toEdge(edge) {\n const type = current();\n if (!type || config.readonly?.()) return;\n buffer.value = '';\n const [min, max] = range(type);\n write(type, edge === 'min' ? min : max);\n },\n backspace() {\n const type = current();\n if (!type || config.readonly?.()) return;\n const value = shown(type);\n if (value == null && !buffer.value) {\n state.moveFocus(-1);\n return;\n }\n const digitsLeft = type === 'dayPeriod' ? '' : (buffer.value || String(value)).slice(0, -1);\n buffer.value = digitsLeft;\n const [min] = range(type);\n if (type === 'dayPeriod' || !digitsLeft) {\n if (type === 'dayPeriod' || type === 'hour') {\n // 删掉上午 / 下午或时:时没有了,两段一起清空\n const next = { ...draft.value };\n delete next.hour;\n const wasComplete = complete.value;\n draft.value = next;\n if (wasComplete) config.onChange(null);\n return;\n }\n write(type, null);\n return;\n }\n if (Number(digitsLeft) >= min) write(type, Number(digitsLeft));\n },\n clear() {\n buffer.value = '';\n pendingYear = false;\n const wasComplete = complete.value;\n draft.value = {};\n if (wasComplete) config.onChange(null);\n },\n reset() {\n buffer.value = '';\n pendingYear = false;\n draft.value = { ...config.value() };\n },\n commit,\n moveFocus(direction) {\n const list = editable.value;\n const index = list.findIndex((segment) => segment.type === current());\n const next = list[index + direction];\n if (next) state.setFocused(next.type as DateSegmentType);\n else config.onExit?.(direction);\n },\n };\n return state;\n}\n\n/**\n * 分段输入的键盘操作:↑↓ 加减、Page Up / Down 大步、Home / End 最小 / 最大、Backspace / Delete 删除、\n * ←→ 换段(从右到左排版时反过来)。数字与字母走 beforeinput(软键盘、输入法也能输入),这里不处理。\n * 返回是否处理了这个按键(处理了就该 preventDefault)\n */\nexport function handleSegmentKeydown(\n state: DateSegmentsState,\n event: KeyboardEvent,\n rtl = false,\n): boolean {\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n const type = state.focusedSegment;\n if (!type) return false;\n const forward = rtl ? -1 : 1;\n const actions: Record<string, () => void> = {\n ArrowUp: () => state.increment(1),\n ArrowDown: () => state.increment(-1),\n PageUp: () => state.increment(BIG_STEPS[type]),\n PageDown: () => state.increment(-BIG_STEPS[type]),\n Home: () => state.toEdge('min'),\n End: () => state.toEdge('max'),\n Backspace: () => state.backspace(),\n Delete: () => state.backspace(),\n ArrowRight: () => state.moveFocus(forward as 1 | -1),\n ArrowLeft: () => state.moveFocus(-forward as 1 | -1),\n };\n const action = actions[event.key];\n if (!action) return false;\n action();\n return true;\n}\n\n// ───────── 内部实现 ─────────\n\n/** 取段的顺序用的任意时刻(各段都是两位数,排版不受值影响) */\nconst SAMPLE = Date.UTC(2000, 10, 22, 13, 44, 55);\n\n/** 语言默认的小时制 */\nfunction resolvedHourCycle(locale: string): keyof HourCycles {\n const cycle = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).resolvedOptions().hourCycle;\n return cycle === 'h11' || cycle === 'h12' ? 'h12' : 'h23';\n}\n\nfunction sameFields(a: DateFieldValues | null, b: DateFieldValues | null): boolean {\n if (a == null || b == null) return a === b;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]) as Set<keyof DateFieldValues>;\n return [...keys].every((key) => a[key] === b[key]);\n}\n\n// ───────── 值与 ISO 字符串 ─────────\n\n/** 日期类分段的粒度:DateField 精确到哪一段(到时、分、秒时是日期加时间) */\nexport interface DateFieldGranularities {\n /** 只有年:'2026' */\n year: unknown;\n /** 年月:'2026-10'(同原生 input type=\"month\") */\n month: unknown;\n /** 年月日(默认):'2026-10-20' */\n day: unknown;\n /** 年与季度:'2026-Q4' */\n quarter: unknown;\n /** 年与周(ISO 8601,周一开始):'2026-W43'(同原生 input type=\"week\") */\n week: unknown;\n /** 日期加时:'2026-10-20T14:00' */\n hour: unknown;\n /** 日期加时分:'2026-10-20T14:30'(同原生 input type=\"datetime-local\") */\n minute: unknown;\n /** 日期加时分秒:'2026-10-20T14:30:15' */\n second: unknown;\n}\n\n/** 分段输入精确到哪一段 */\nexport type DateFieldGranularity = keyof DateFieldGranularities;\n\ntype ValueField = Exclude<DateSegmentType, 'dayPeriod'>;\n\nconst ALL_FIELDS: readonly ValueField[] = ['year', 'month', 'day', 'hour', 'minute', 'second'];\n\n/** 日期分段:从年到 granularity;time 时只取时间的部分(TimeField) */\nexport function segmentFields(granularity: DateFieldGranularity, time = false): ValueField[] {\n if (granularity === 'quarter' || granularity === 'week') return time ? [] : ['year', granularity];\n const fields = ALL_FIELDS.slice(0, ALL_FIELDS.indexOf(granularity) + 1);\n return time\n ? fields.filter((field) => field === 'hour' || field === 'minute' || field === 'second')\n : fields;\n}\n\nconst pad = (value: number, width = 2) => String(value).padStart(width, '0');\n\n/** 各段的值 → ISO 字符串(按有哪些段:'2026'、'2026-10'、'2026-10-20'、'2026-10-20T14:30'、'14:30') */\nexport function fieldsToIso(values: DateFieldValues, fields: readonly ValueField[]): string {\n if (fields.includes('quarter')) return `${pad(values.year ?? 0, 4)}-Q${values.quarter ?? 1}`;\n if (fields.includes('week')) return `${pad(values.year ?? 0, 4)}-W${pad(values.week ?? 1)}`;\n const date = [\n values.year != null && pad(values.year, 4),\n fields.includes('month') && pad(values.month ?? 1),\n fields.includes('day') && pad(values.day ?? 1),\n ]\n .filter((part) => part !== false)\n .join('-');\n if (!fields.includes('hour')) return date;\n const time = [\n pad(values.hour ?? 0),\n pad(values.minute ?? 0),\n fields.includes('second') && pad(values.second ?? 0),\n ]\n .filter((part) => part !== false)\n .join(':');\n return fields.includes('year') ? `${date}T${time}` : time;\n}\n\n/** ISO 字符串 → 各段的值;格式不对时 null。只取 fields 里有的段('2026-10-20T14:30' 给 DateField 时只要日期) */\nexport function isoToFields(\n value: string | null | undefined,\n fields: readonly ValueField[],\n): DateFieldValues | null {\n if (!value) return null;\n const period = /^(\\d{4})-(?:Q([1-4])|W(\\d{2}))$/.exec(value);\n if (period) {\n const parsed: DateFieldValues = { year: Number(period[1]) };\n if (period[2] != null) parsed.quarter = Number(period[2]);\n if (period[3] != null) parsed.week = Number(period[3]);\n return fields.every((field) => parsed[field] != null) ? parsed : null;\n }\n const match = /^(?:(\\d{4})(?:-(\\d{2})(?:-(\\d{2}))?)?)?(?:T?(\\d{2}):(\\d{2})(?::(\\d{2}))?)?$/.exec(\n value,\n );\n if (!match) return null;\n const parsed: DateFieldValues = {};\n ALL_FIELDS.forEach((field, index) => {\n const text = match[index + 1];\n if (fields.includes(field) && text != null) parsed[field] = Number(text);\n });\n return fields.every((field) => parsed[field] != null) ? parsed : null;\n}\n"],"mappings":"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"}
@@ -6,7 +6,8 @@ import { focusFirst } from "../utils/dom/focus.js";
6
6
  import { toElement } from "../utils/dom/element.js";
7
7
  import { anchoredPanelSx, useAnchoredPopover } from "../utils/dom/floating.js";
8
8
  import { inputRecipe } from "../input/control.js";
9
- import { createVNode, mergeProps, shallowRef, useId } from "vue";
9
+ import { createVNode, shallowRef, useId } from "vue";
10
+ import { mergeJsxProps } from "@zerodep-dev/vue-tsx-pro-tsx";
10
11
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
11
12
  //#region src/date/picker-popover.tsx
12
13
  /** 选择器上的打开按钮与弹层的部件属性 */
@@ -70,7 +71,7 @@ function usePickerPopover(read, events) {
70
71
  /** 弹层:内容只在打开时渲染(由调用方按 open 给) */
71
72
  panel(sx, user, children) {
72
73
  const { open, label, size } = read();
73
- return createVNode("div", mergeProps(mergeAttrs({
74
+ return createVNode("div", mergeJsxProps(mergeAttrs({
74
75
  sx: [anchoredPanelSx(size), sx],
75
76
  "aria-label": label
76
77
  }, user, {
@@ -1 +1 @@
1
- {"version":3,"file":"picker-popover.js","names":["_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/picker-popover.tsx"],"sourcesContent":["/**\n * 日期、时间选择器共用的打开按钮与弹层(DatePicker、DateRangePicker、TimePicker),以及日历旁边的快捷选项:\n * 输入框外壳是定位的锚点,后缀里的按钮打开,弹层是 role=\"dialog\" 的原生 popover(Esc、点外部关闭);\n * 关闭时焦点还给按钮(外壳不可聚焦);分段里按 Alt + ↓ 打开(同原生 select)。在组件 setup 里调用。\n *\n * const picker = usePickerPopover(() => ({ open, editable, label: lang.datePickerOpen }), {\n * toggle: setOpen,\n * shown: (panel) => panel.querySelector('…')?.focus(),\n * });\n * <DateField propsRoot={{ ref: picker.anchorRef }} onKeydown={picker.onKeydown} suffix={picker.button(CalendarDays, propsButton)} />\n * {picker.panel(sx, propsPopover, open && <Calendar … />)}\n */\nimport { useId, type VNodeChild } from 'vue';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button } from '../base/Button';\nimport type { IconData } from '../base/Icon';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useRecipe } from '../config/styles';\nimport { inputRecipe } from '../input/control';\nimport { anchoredPanelSx, useAnchoredPopover, type FloatingPlacement } from '../utils/dom/floating';\nimport { focusFirst } from '../utils/dom/focus';\nimport type { SetOpen } from '../utils/dom/open-change';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport type { TextSize } from '../utils/style/typography';\n\n/** 选择器上的打开按钮与弹层的部件属性 */\nexport interface PickerPopoverParts {\n /** 弹出位置,默认 bottom-start;空间不够时自动翻转 */\n placement?: FloatingPlacement;\n /** 打开按钮的部件属性 */\n propsButton?: Omit<Partial<IconButtonProps>, 'onClick' | 'aria-expanded' | 'aria-controls'>;\n /** 弹层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover' | 'role'>;\n}\n\n/** usePickerPopover 每次渲染读取的状态 */\nexport interface PickerPopoverState {\n /** 是否打开 */\n open: boolean;\n /** 能不能打开:不可用、只读时按钮也不可用 */\n editable: boolean;\n /** 按钮与弹层的名称(“选择日期”) */\n label: string;\n /** 弹出位置 */\n placement?: FloatingPlacement;\n /** 弹层与输入框同宽(时间列表) */\n matchWidth?: boolean;\n /** 控件的字号档位:弹层渲染在顶层、不继承输入框的字号,按它设置 */\n size?: TextSize;\n}\n\n/** usePickerPopover 的回调 */\nexport interface PickerPopoverEvents {\n /** 打开或关闭(按钮、Alt + ↓、Esc、点外部):写回组件的 open 并通知 onOpenChange,一般是组件的 openSetter */\n toggle: SetOpen;\n /** 打开后、第一次定位完成时:把焦点交给弹层里合适的元素 */\n shown: (panel: HTMLElement) => void;\n}\n\n/** 选择器的打开按钮与弹层 */\nexport function usePickerPopover(read: () => PickerPopoverState, events: PickerPopoverEvents) {\n const id = useId();\n let anchor = _state.raw<HTMLElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n let trigger = _state.raw<HTMLElement | null>(null);\n // 打开按钮放在输入框外壳里:用外壳配方的 button 部件(带 styles.Input 的定制)\n const shell = useRecipe(inputRecipe);\n\n const { onToggle } = useAnchoredPopover(\n () => {\n const { open, placement = 'bottom-start', matchWidth } = read();\n return { open, anchor, panel, floating: { placement, matchWidth }, restoreFocus: trigger };\n },\n { close: (reason, event) => events.toggle(false, reason, event), shown: events.shown },\n );\n\n return {\n /** 弹层的 id(按钮的 aria-controls);弹层里的元素可以据此派生自己的 id */\n id,\n /** 输入框外壳(锚点):放进 propsRoot 的 ref */\n anchorRef: (element: unknown) => (anchor = toElement(element)),\n /** 输入框外壳:选完日期后把焦点交给其中的某一段 */\n get anchor() {\n return anchor;\n },\n /** 分段上的 keydown:Alt + ↓ 打开 */\n onKeydown: (event: KeyboardEvent) => {\n if (!event.altKey || event.key !== 'ArrowDown' || !read().editable) return;\n event.preventDefault();\n events.toggle(true, 'trigger', event);\n },\n /** 输入框后缀里的打开按钮 */\n button(icon: IconData, user?: PickerPopoverParts['propsButton']) {\n const { open, editable, label } = read();\n return (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n { ...shell().button, radius: 'full', icon, 'aria-label': label },\n user,\n {\n ref: (element: unknown) => (trigger = toElement(element)),\n disabled: !editable,\n 'aria-haspopup': 'dialog',\n 'aria-expanded': open,\n 'aria-controls': id,\n onClick: (event: MouseEvent) => events.toggle(!open, 'trigger', event),\n },\n )}\n />\n );\n },\n /** 弹层:内容只在打开时渲染(由调用方按 open 给) */\n panel(sx: css.SxStyles, user: PickerPopoverParts['propsPopover'], children: VNodeChild) {\n const { open, label, size } = read();\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [anchoredPanelSx(size), sx],\n 'aria-label': label,\n },\n user,\n { ref: _toRef(panel), id, popover: 'auto', role: 'dialog', onToggle },\n )}\n data-state={open ? 'open' : 'closed'}\n >\n {children}\n </div>\n );\n },\n };\n}\n\n/** 弹层里是日历时:焦点进日历当前的那一格(已选或今天),不是“上个月”按钮 */\nexport function focusCalendar(panel: HTMLElement): void {\n const cell = panel.querySelector<HTMLElement>('[role=\"grid\"] [tabindex=\"0\"]');\n if (cell) cell.focus();\n else focusFirst(panel);\n}\n\n/** 弹层里的一个快捷选项(“今天”“最近 7 天”) */\nexport interface PickerPreset {\n /** 列表里的 key */\n key: string;\n /** 按钮上的文字 */\n label: string;\n /** 当前值就是它:按钮按下(aria-pressed) */\n active: boolean;\n /** 超出可选范围:不可用 */\n disabled?: boolean;\n /** 点了 */\n onPick: () => void;\n}\n\n/** 快捷选项的样式:presets(一列,靠日历那边有分隔线)、preset(按钮文字靠左) */\nexport const pickerPresetStyles = css.create({\n presets: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_xs',\n paddingInlineEnd: '_sm',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: '_borderMuted',\n },\n preset: { justifyContent: 'flex-start' },\n});\n\n/** 日历旁边的一列快捷选项(DatePicker、DateRangePicker 共用):一组按钮,当前值对应的那一项按下 */\nexport function renderPickerPresets(\n presets: readonly PickerPreset[],\n label: string,\n user?: PartProps<'div', 'role'>,\n): VNodeChild {\n if (presets.length === 0) return null;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: pickerPresetStyles.presets }, user, {\n role: 'group',\n 'aria-label': label,\n })}\n >\n {presets.map((preset) => (\n <Button\n key={preset.key}\n sx={pickerPresetStyles.preset}\n size=\"sm\"\n variant={preset.active ? 'soft' : 'ghost'}\n tone=\"neutral\"\n aria-pressed={preset.active}\n disabled={preset.disabled}\n onClick={preset.onPick}\n >\n {preset.label}\n </Button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA6DA,SAAgB,iBAAiB,MAAgC,QAA6B;CAC5F,MAAM,KAAK,MAAM;CACjB,IAAI,SAAMA,WAAkC,IAAI;CAChD,IAAI,QAAKA,WAAkC,IAAI;CAC/C,IAAI,UAAOA,WAAkC,IAAI;CAEjD,MAAM,QAAQ,UAAU,WAAW;CAEnC,MAAM,EAAE,aAAa,yBACb;EACJ,MAAM,EAAE,MAAM,YAAY,gBAAgB,eAAe,KAAK;EAC9D,OAAO;GAAE;GAAM,QAAM,OAAA;GAAE,OAAK,MAAA;GAAE,UAAU;IAAE;IAAW;GAAW;GAAG,cAAY,QAAA;EAAU;CAC3F,GACA;EAAE,QAAQ,QAAQ,UAAU,OAAO,OAAO,OAAO,QAAQ,KAAK;EAAG,OAAO,OAAO;CAAM,CACvF;CAEA,OAAO;;EAEL;;EAEA,YAAY,YAAsB,OAAA,QAAS,UAAU,OAAO;;EAE5D,IAAI,SAAS;GACX,OAAA,OAAA;EACF;;EAEA,YAAY,UAAyB;GACnC,IAAI,CAAC,MAAM,UAAU,MAAM,QAAQ,eAAe,CAAC,KAAK,CAAC,CAAC,UAAU;GACpE,MAAM,eAAe;GACrB,OAAO,OAAO,MAAM,WAAW,KAAK;EACtC;;EAEA,OAAO,MAAgB,MAA0C;GAC/D,MAAM,EAAE,MAAM,UAAU,UAAU,KAAK;GACvC,OAAAC,YAAA,YAEQ,eACF;IAAE,GAAG,MAAM,CAAC,CAAC;IAAQ,QAAQ;IAAQ;IAAM,cAAc;GAAM,GAC/D,MACA;IACE,MAAM,YAAsB,QAAA,QAAU,UAAU,OAAO;IACvD,UAAU,CAAC;IACX,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,UAAU,UAAsB,OAAO,OAAO,CAAC,MAAM,WAAW,KAAK;GACvE,CACF,GAAC,IAAA;EAGP;;EAEA,MAAM,IAAkB,MAA0C,UAAsB;GACtF,MAAM,EAAE,MAAM,OAAO,SAAS,KAAK;GACnC,OAAAA,YAAA,OAAAC,WAEQ,WACF;IACE,IAAI,CAAC,gBAAgB,IAAI,GAAG,EAAE;IAC9B,cAAc;GAChB,GACA,MACA;IAAE,KAAG;IAAiB;IAAI,SAAS;IAAQ,MAAM;IAAU;GAAS,CACtE,GAAC,EAAA,cACW,OAAO,SAAS,SAAQ,CAAA,GAAA,CAEnC,QAAQ,CAAA;EAGf;CACF;AACF;;AAGA,SAAgB,cAAc,OAA0B;CACtD,MAAM,OAAO,MAAM,cAA2B,kCAA8B;CAC5E,IAAI,MAAM,KAAK,MAAM;MAChB,WAAW,KAAK;AACvB;;;AAiBA,IAAa,qBAAqB,IAAI,OAAO;CAC3C,SAAS;EACP,SAAS;EACT,eAAe;EACf,KAAK;EACL,kBAAkB;EAClB,sBAAsB;EACtB,sBAAsB;EACtB,sBAAsB;CACxB;CACA,QAAQ,EAAE,gBAAgB,aAAa;AACzC,CAAC;;AAGD,SAAgB,oBACd,SACA,OACA,MACY;CACZ,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,OAAAD,YAAA,OAEQ,WAAkB,EAAE,IAAI,mBAAmB,QAAQ,GAAG,MAAM;EAC9D,MAAM;EACN,cAAc;CAChB,CAAC,GAAC,CAED,QAAQ,KAAK,WAAMA,YAAA,QAAA;EAAA,OAEX,OAAO;EAAG,MACX,mBAAmB;EAAM,QAAA;EAAA,WAEpB,OAAO,SAAS,SAAS;EAAO,QAAA;EAAA,gBAE3B,OAAO;EAAM,YACjB,OAAO;EAAQ,WAChB,OAAO;CAAM,GAAA,EAAA,eAAA,CAErB,OAAO,KAAK,EAAA,CAAA,CAEhB,CAAC,CAAA;AAGR"}
1
+ {"version":3,"file":"picker-popover.js","names":["_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/picker-popover.tsx"],"sourcesContent":["/**\n * 日期、时间选择器共用的打开按钮与弹层(DatePicker、DateRangePicker、TimePicker),以及日历旁边的快捷选项:\n * 输入框外壳是定位的锚点,后缀里的按钮打开,弹层是 role=\"dialog\" 的原生 popover(Esc、点外部关闭);\n * 关闭时焦点还给按钮(外壳不可聚焦);分段里按 Alt + ↓ 打开(同原生 select)。在组件 setup 里调用。\n *\n * const picker = usePickerPopover(() => ({ open, editable, label: lang.datePickerOpen }), {\n * toggle: setOpen,\n * shown: (panel) => panel.querySelector('…')?.focus(),\n * });\n * <DateField propsRoot={{ ref: picker.anchorRef }} onKeydown={picker.onKeydown} suffix={picker.button(CalendarDays, propsButton)} />\n * {picker.panel(sx, propsPopover, open && <Calendar … />)}\n */\nimport { useId, type VNodeChild } from 'vue';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button } from '../base/Button';\nimport type { IconData } from '../base/Icon';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useRecipe } from '../config/styles';\nimport { inputRecipe } from '../input/control';\nimport { anchoredPanelSx, useAnchoredPopover, type FloatingPlacement } from '../utils/dom/floating';\nimport { focusFirst } from '../utils/dom/focus';\nimport type { SetOpen } from '../utils/dom/open-change';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport type { TextSize } from '../utils/style/typography';\n\n/** 选择器上的打开按钮与弹层的部件属性 */\nexport interface PickerPopoverParts {\n /** 弹出位置,默认 bottom-start;空间不够时自动翻转 */\n placement?: FloatingPlacement;\n /** 打开按钮的部件属性 */\n propsButton?: Omit<Partial<IconButtonProps>, 'onClick' | 'aria-expanded' | 'aria-controls'>;\n /** 弹层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover' | 'role'>;\n}\n\n/** usePickerPopover 每次渲染读取的状态 */\nexport interface PickerPopoverState {\n /** 是否打开 */\n open: boolean;\n /** 能不能打开:不可用、只读时按钮也不可用 */\n editable: boolean;\n /** 按钮与弹层的名称(“选择日期”) */\n label: string;\n /** 弹出位置 */\n placement?: FloatingPlacement;\n /** 弹层与输入框同宽(时间列表) */\n matchWidth?: boolean;\n /** 控件的字号档位:弹层渲染在顶层、不继承输入框的字号,按它设置 */\n size?: TextSize;\n}\n\n/** usePickerPopover 的回调 */\nexport interface PickerPopoverEvents {\n /** 打开或关闭(按钮、Alt + ↓、Esc、点外部):写回组件的 open 并通知 onOpenChange,一般是组件的 openSetter */\n toggle: SetOpen;\n /** 打开后、第一次定位完成时:把焦点交给弹层里合适的元素 */\n shown: (panel: HTMLElement) => void;\n}\n\n/** 选择器的打开按钮与弹层 */\nexport function usePickerPopover(read: () => PickerPopoverState, events: PickerPopoverEvents) {\n const id = useId();\n let anchor = _state.raw<HTMLElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n let trigger = _state.raw<HTMLElement | null>(null);\n // 打开按钮放在输入框外壳里:用外壳配方的 button 部件(带 styles.Input 的定制)\n const shell = useRecipe(inputRecipe);\n\n const { onToggle } = useAnchoredPopover(\n () => {\n const { open, placement = 'bottom-start', matchWidth } = read();\n return { open, anchor, panel, floating: { placement, matchWidth }, restoreFocus: trigger };\n },\n { close: (reason, event) => events.toggle(false, reason, event), shown: events.shown },\n );\n\n return {\n /** 弹层的 id(按钮的 aria-controls);弹层里的元素可以据此派生自己的 id */\n id,\n /** 输入框外壳(锚点):放进 propsRoot 的 ref */\n anchorRef: (element: unknown) => (anchor = toElement(element)),\n /** 输入框外壳:选完日期后把焦点交给其中的某一段 */\n get anchor() {\n return anchor;\n },\n /** 分段上的 keydown:Alt + ↓ 打开 */\n onKeydown: (event: KeyboardEvent) => {\n if (!event.altKey || event.key !== 'ArrowDown' || !read().editable) return;\n event.preventDefault();\n events.toggle(true, 'trigger', event);\n },\n /** 输入框后缀里的打开按钮 */\n button(icon: IconData, user?: PickerPopoverParts['propsButton']) {\n const { open, editable, label } = read();\n return (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n { ...shell().button, radius: 'full', icon, 'aria-label': label },\n user,\n {\n ref: (element: unknown) => (trigger = toElement(element)),\n disabled: !editable,\n 'aria-haspopup': 'dialog',\n 'aria-expanded': open,\n 'aria-controls': id,\n onClick: (event: MouseEvent) => events.toggle(!open, 'trigger', event),\n },\n )}\n />\n );\n },\n /** 弹层:内容只在打开时渲染(由调用方按 open 给) */\n panel(sx: css.SxStyles, user: PickerPopoverParts['propsPopover'], children: VNodeChild) {\n const { open, label, size } = read();\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [anchoredPanelSx(size), sx],\n 'aria-label': label,\n },\n user,\n { ref: _toRef(panel), id, popover: 'auto', role: 'dialog', onToggle },\n )}\n data-state={open ? 'open' : 'closed'}\n >\n {children}\n </div>\n );\n },\n };\n}\n\n/** 弹层里是日历时:焦点进日历当前的那一格(已选或今天),不是“上个月”按钮 */\nexport function focusCalendar(panel: HTMLElement): void {\n const cell = panel.querySelector<HTMLElement>('[role=\"grid\"] [tabindex=\"0\"]');\n if (cell) cell.focus();\n else focusFirst(panel);\n}\n\n/** 弹层里的一个快捷选项(“今天”“最近 7 天”) */\nexport interface PickerPreset {\n /** 列表里的 key */\n key: string;\n /** 按钮上的文字 */\n label: string;\n /** 当前值就是它:按钮按下(aria-pressed) */\n active: boolean;\n /** 超出可选范围:不可用 */\n disabled?: boolean;\n /** 点了 */\n onPick: () => void;\n}\n\n/** 快捷选项的样式:presets(一列,靠日历那边有分隔线)、preset(按钮文字靠左) */\nexport const pickerPresetStyles = css.create({\n presets: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_xs',\n paddingInlineEnd: '_sm',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: '_borderMuted',\n },\n preset: { justifyContent: 'flex-start' },\n});\n\n/** 日历旁边的一列快捷选项(DatePicker、DateRangePicker 共用):一组按钮,当前值对应的那一项按下 */\nexport function renderPickerPresets(\n presets: readonly PickerPreset[],\n label: string,\n user?: PartProps<'div', 'role'>,\n): VNodeChild {\n if (presets.length === 0) return null;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: pickerPresetStyles.presets }, user, {\n role: 'group',\n 'aria-label': label,\n })}\n >\n {presets.map((preset) => (\n <Button\n key={preset.key}\n sx={pickerPresetStyles.preset}\n size=\"sm\"\n variant={preset.active ? 'soft' : 'ghost'}\n tone=\"neutral\"\n aria-pressed={preset.active}\n disabled={preset.disabled}\n onClick={preset.onPick}\n >\n {preset.label}\n </Button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6DA,SAAgB,iBAAiB,MAAgC,QAA6B;CAC5F,MAAM,KAAK,MAAM;CACjB,IAAI,SAAMA,WAAkC,IAAI;CAChD,IAAI,QAAKA,WAAkC,IAAI;CAC/C,IAAI,UAAOA,WAAkC,IAAI;CAEjD,MAAM,QAAQ,UAAU,WAAW;CAEnC,MAAM,EAAE,aAAa,yBACb;EACJ,MAAM,EAAE,MAAM,YAAY,gBAAgB,eAAe,KAAK;EAC9D,OAAO;GAAE;GAAM,QAAM,OAAA;GAAE,OAAK,MAAA;GAAE,UAAU;IAAE;IAAW;GAAW;GAAG,cAAY,QAAA;EAAU;CAC3F,GACA;EAAE,QAAQ,QAAQ,UAAU,OAAO,OAAO,OAAO,QAAQ,KAAK;EAAG,OAAO,OAAO;CAAM,CACvF;CAEA,OAAO;;EAEL;;EAEA,YAAY,YAAsB,OAAA,QAAS,UAAU,OAAO;;EAE5D,IAAI,SAAS;GACX,OAAA,OAAA;EACF;;EAEA,YAAY,UAAyB;GACnC,IAAI,CAAC,MAAM,UAAU,MAAM,QAAQ,eAAe,CAAC,KAAK,CAAC,CAAC,UAAU;GACpE,MAAM,eAAe;GACrB,OAAO,OAAO,MAAM,WAAW,KAAK;EACtC;;EAEA,OAAO,MAAgB,MAA0C;GAC/D,MAAM,EAAE,MAAM,UAAU,UAAU,KAAK;GACvC,OAAAC,YAAA,YAEQ,eACF;IAAE,GAAG,MAAM,CAAC,CAAC;IAAQ,QAAQ;IAAQ;IAAM,cAAc;GAAM,GAC/D,MACA;IACE,MAAM,YAAsB,QAAA,QAAU,UAAU,OAAO;IACvD,UAAU,CAAC;IACX,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,UAAU,UAAsB,OAAO,OAAO,CAAC,MAAM,WAAW,KAAK;GACvE,CACF,GAAC,IAAA;EAGP;;EAEA,MAAM,IAAkB,MAA0C,UAAsB;GACtF,MAAM,EAAE,MAAM,OAAO,SAAS,KAAK;GACnC,OAAAA,YAAA,OAAAC,cAEQ,WACF;IACE,IAAI,CAAC,gBAAgB,IAAI,GAAG,EAAE;IAC9B,cAAc;GAChB,GACA,MACA;IAAE,KAAG;IAAiB;IAAI,SAAS;IAAQ,MAAM;IAAU;GAAS,CACtE,GAAC,EAAA,cACW,OAAO,SAAS,SAAQ,CAAA,GAAA,CAEnC,QAAQ,CAAA;EAGf;CACF;AACF;;AAGA,SAAgB,cAAc,OAA0B;CACtD,MAAM,OAAO,MAAM,cAA2B,kCAA8B;CAC5E,IAAI,MAAM,KAAK,MAAM;MAChB,WAAW,KAAK;AACvB;;;AAiBA,IAAa,qBAAqB,IAAI,OAAO;CAC3C,SAAS;EACP,SAAS;EACT,eAAe;EACf,KAAK;EACL,kBAAkB;EAClB,sBAAsB;EACtB,sBAAsB;EACtB,sBAAsB;CACxB;CACA,QAAQ,EAAE,gBAAgB,aAAa;AACzC,CAAC;;AAGD,SAAgB,oBACd,SACA,OACA,MACY;CACZ,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,OAAAD,YAAA,OAEQ,WAAkB,EAAE,IAAI,mBAAmB,QAAQ,GAAG,MAAM;EAC9D,MAAM;EACN,cAAc;CAChB,CAAC,GAAC,CAED,QAAQ,KAAK,WAAMA,YAAA,QAAA;EAAA,OAEX,OAAO;EAAG,MACX,mBAAmB;EAAM,QAAA;EAAA,WAEpB,OAAO,SAAS,SAAS;EAAO,QAAA;EAAA,gBAE3B,OAAO;EAAM,YACjB,OAAO;EAAQ,WAChB,OAAO;CAAM,GAAA,EAAA,eAAA,CAErB,OAAO,KAAK,EAAA,CAAA,CAEhB,CAAC,CAAA;AAGR"}
@@ -9,8 +9,8 @@ import { DiagramNode } from "./DiagramNode.js";
9
9
  import { alignToGuides, arrowHead, boundsOf, polylineMidpoint, polylinePath, rectAt, rectContains, rectFromCorners, rectsIntersect, trimEnd } from "./geometry.js";
10
10
  import { diagramMessages } from "./messages.js";
11
11
  import { nearestSide, routeEdges, sidePoint, straightRoute } from "./route.js";
12
- import { computed, createVNode, mergeProps, shallowRef } from "vue";
13
- import { _component, bindable, childrenProp, createContext, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
12
+ import { computed, createVNode, shallowRef } from "vue";
13
+ import { _component, bindable, childrenProp, createContext, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
14
14
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
15
  //#region src/diagram/Diagram.tsx
16
16
  /** 画布上的一个节点:位置与大小(画布坐标),其余字段使用方自己用 */
@@ -382,7 +382,7 @@ var NodeView = /*#__PURE__*/ _component((_props, _ctx) => {
382
382
  height: item.value.height
383
383
  }, event)
384
384
  } : { role: "img" }
385
- }), [render.value(item.value, state), ports.value && SIDES.map((side) => createVNode("span", mergeProps({ "key": side }, mergeAttrs({ sx: [diagramStyles.port, portStyles[side]] }, portPart.value, {
385
+ }), [render.value(item.value, state), ports.value && SIDES.map((side) => createVNode("span", mergeJsxProps({ "key": side }, mergeAttrs({ sx: [diagramStyles.port, portStyles[side]] }, portPart.value, {
386
386
  ...dataAttrs({ "data-diagram-port": side }),
387
387
  "aria-hidden": "true",
388
388
  onPointerdown: (event) => actions.value.portDown(id, side, event)
@@ -445,9 +445,9 @@ var EdgeView = /*#__PURE__*/ _component((_props2, _ctx2) => {
445
445
  onFocus: (event) => actions.value.focus(boundsOf([], points.value), event)
446
446
  } : {}
447
447
  }), [
448
- selectable.value && createVNode("path", mergeProps({ "d": path }, css.attrs(diagramStyles.edgeHit)), null),
449
- createVNode("path", mergeProps({ "d": path }, css.attrs(diagramStyles.edgeLine)), null),
450
- createVNode("polygon", mergeProps({ "points": arrowHead(points.value, ARROW) }, css.attrs(diagramStyles.edgeArrow)), null)
448
+ selectable.value && createVNode("path", mergeJsxProps({ "d": path }, css.attrs(diagramStyles.edgeHit)), null),
449
+ createVNode("path", mergeJsxProps({ "d": path }, css.attrs(diagramStyles.edgeLine)), null),
450
+ createVNode("polygon", mergeJsxProps({ "points": arrowHead(points.value, ARROW) }, css.attrs(diagramStyles.edgeArrow)), null)
451
451
  ]);
452
452
  };
453
453
  }, {
@@ -996,7 +996,7 @@ var Diagram = /*#__PURE__*/ _component((_props4, _ctx4) => {
996
996
  "actions": actions
997
997
  }, null);
998
998
  }),
999
- createVNode("svg", mergeProps(css.attrs(diagramStyles.edges), {
999
+ createVNode("svg", mergeJsxProps(css.attrs(diagramStyles.edges), {
1000
1000
  "width": "1",
1001
1001
  "height": "1",
1002
1002
  "aria-hidden": selectable.value ? void 0 : "true"
@@ -1029,13 +1029,13 @@ var Diagram = /*#__PURE__*/ _component((_props4, _ctx4) => {
1029
1029
  "part": propsEdgeText.value
1030
1030
  }, null);
1031
1031
  }),
1032
- (!!drag.value?.guides.length || !!link.value || ends.length > 0) && createVNode("svg", mergeProps(css.attrs(diagramStyles.edges, diagramStyles.above), {
1032
+ (!!drag.value?.guides.length || !!link.value || ends.length > 0) && createVNode("svg", mergeJsxProps(css.attrs(diagramStyles.edges, diagramStyles.above), {
1033
1033
  "width": "1",
1034
1034
  "height": "1",
1035
1035
  "aria-hidden": "true",
1036
1036
  "data-diagram-transient": ""
1037
1037
  }), [
1038
- drag.value?.guides.map((guide, index) => createVNode("line", mergeProps({ "key": index }, mergeAttrs({ sx: diagramStyles.guide }, propsGuide.value, {
1038
+ drag.value?.guides.map((guide, index) => createVNode("line", mergeJsxProps({ "key": index }, mergeAttrs({ sx: diagramStyles.guide }, propsGuide.value, {
1039
1039
  x1: guide.from.x,
1040
1040
  y1: guide.from.y,
1041
1041
  x2: guide.to.x,
@@ -1043,7 +1043,7 @@ var Diagram = /*#__PURE__*/ _component((_props4, _ctx4) => {
1043
1043
  })), null)),
1044
1044
  ends.flatMap(({ edge, points }) => ["from", "to"].map((end) => {
1045
1045
  const at = end === "from" ? points[0] : points[points.length - 1];
1046
- return createVNode("circle", mergeProps({
1046
+ return createVNode("circle", mergeJsxProps({
1047
1047
  "key": `${edge.id}:${end}`,
1048
1048
  "cx": at.x,
1049
1049
  "cy": at.y,
@@ -1053,7 +1053,7 @@ var Diagram = /*#__PURE__*/ _component((_props4, _ctx4) => {
1053
1053
  "onPointerdown": (event) => actions.endDown(edge.id, end, event)
1054
1054
  }), null);
1055
1055
  })),
1056
- link.value && createVNode("g", css.attrs(diagramStyles.preview), [createVNode("path", mergeProps({ "d": polylinePath(trimEnd([link.value.from, link.value.to], ARROW * .7)) }, css.attrs(diagramStyles.edgeLine)), null), createVNode("polygon", mergeProps({ "points": arrowHead([link.value.from, link.value.to], ARROW) }, css.attrs(diagramStyles.edgeArrow)), null)])
1056
+ link.value && createVNode("g", css.attrs(diagramStyles.preview), [createVNode("path", mergeJsxProps({ "d": polylinePath(trimEnd([link.value.from, link.value.to], ARROW * .7)) }, css.attrs(diagramStyles.edgeLine)), null), createVNode("polygon", mergeJsxProps({ "points": arrowHead([link.value.from, link.value.to], ARROW) }, css.attrs(diagramStyles.edgeArrow)), null)])
1057
1057
  ])
1058
1058
  ]),
1059
1059
  marquee.value && createVNode("div", mergeAttrs({ sx: [diagramStyles.marquee, css.bind(diagramDynamicStyles.box, () => [
@@ -1062,7 +1062,7 @@ var Diagram = /*#__PURE__*/ _component((_props4, _ctx4) => {
1062
1062
  marquee.value.width,
1063
1063
  marquee.value.height
1064
1064
  ], true)] }, propsMarquee.value), null),
1065
- overlay.value != null && createVNode("div", mergeProps(css.attrs(diagramStyles.overlay), { "data-diagram-overlay": "" }), [overlay.value])
1065
+ overlay.value != null && createVNode("div", mergeJsxProps(css.attrs(diagramStyles.overlay), { "data-diagram-overlay": "" }), [overlay.value])
1066
1066
  ]);
1067
1067
  };
1068
1068
  }, {