@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
@@ -1 +1 @@
1
- {"version":3,"file":"ModelViewer.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/model/ModelViewer.tsx"],"sourcesContent":["/**\n * 模型查看器(div):加载 glTF / GLB(或直接给一个 three 的对象),自动居中、缩放到合适的大小,\n * 拖动环绕查看(松手带惯性),方向键也能转;没在拖时缓缓自转。参考 Google 的 <model-viewer>。\n *\n * <ModelViewer src=\"/models/chair.glb\" alt=\"扶手椅,胡桃木与灰色布面\" />\n * <ModelViewer object={mesh} rotationSpeed={0} zoom sx={styles.viewer} />\n *\n * 光照是一间柔和的摄影棚(RoomEnvironment 的环境光),金属、粗糙度材质都能正确地反光;exposure 调整体亮度。\n * 加载时中间显示转圈,失败时显示语言包里的提示(onError 拿到原因)。写了 alt 时整块是带名称的图像(role=\"img\")。\n * 默认正方形,尺寸由使用方决定。减少动态效果时不自转,拖动仍可用。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(加载中与出错的提示)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n ACESFilmicToneMapping,\n Box3,\n Group,\n PerspectiveCamera,\n PMREMGenerator,\n Sphere,\n Vector3,\n type Object3D,\n} from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';\nimport { Small } from '../../base/Text';\nimport { Spinner } from '../../base/Spinner';\nimport { useLang } from '../../config/context';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { mergePartProps, type PartProps } from '../../utils/props';\n\n/** 加载状态 */\nexport interface ModelViewerStatuses {\n /** 加载中 */\n loading: unknown;\n /** 已显示 */\n loaded: unknown;\n /** 加载失败 */\n error: unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ModelViewerProps extends Omit<EffectProps, 'children' | 'onLoad' | 'onError'> {\n /** 模型的地址(glTF / GLB);和 object 二选一 */\n src?: string;\n /** 直接给一个 three 的对象(程序生成的模型);和 src 二选一 */\n object?: Object3D;\n /** 模型的文字描述:写了时整块是 role=\"img\"、以它为名称 */\n alt?: string;\n /**\n * 自转速度(度 / 秒);0 时不自转\n * @default 20\n */\n rotationSpeed?: number;\n /**\n * 可以拖动、用方向键环绕查看\n * @default true\n */\n controls?: boolean;\n /**\n * 滚轮、+ / - 键缩放\n * @default false\n */\n zoom?: boolean;\n /**\n * 一开始的角度(度):yaw 绕竖轴,pitch 从上往下看为正\n * @default { yaw: 30, pitch: 15 }\n */\n orbit?: { yaw: number; pitch: number };\n /**\n * 曝光:整体亮度\n * @default 1\n */\n exposure?: number;\n /** 加载完成 */\n onLoad?: (model: Object3D) => void;\n /** 加载失败 */\n onError?: (error: unknown) => void;\n}\n\n/** ModelViewer 的样式:root、interactive、dragging、content、overlay */\nexport const modelViewerStyles = css.create({\n root: { aspectRatio: '1', width: '100%', outlineStyle: 'none' },\n interactive: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n // 内容层不定位:提示按外层(整块)铺满、居中\n content: { position: 'static' },\n // 加载中、出错的提示:盖在画布中间\n overlay: {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n },\n});\n\nconst DEG = Math.PI / 180;\nconst FOV = 35;\n/** 模型(外接球)占画面短边的比例 */\nconst FIT = 0.85;\n/** 缩放的范围:相对合适距离的倍数 */\nconst ZOOM_RANGE = [0.5, 2.5] as const;\n\n/** 模型查看器 */\nexport const ModelViewer = _component(\n ({\n src,\n object,\n alt,\n rotationSpeed = 20,\n controls = true,\n zoom = false,\n orbit: initial = { yaw: 30, pitch: 15 },\n exposure = 1,\n onLoad,\n onError,\n ...rest\n }: ModelViewerProps) => {\n const lang = useLang();\n let status = _state<keyof ModelViewerStatuses>('loading');\n const start = _untrack(initial);\n const orbit = createOrbit({ yaw: start.yaw * DEG, pitch: start.pitch * DEG, pitchLimit: 1.4 });\n let distance = 1;\n // 场景建好后换成真正的 invalidate:静止模式下交互也要重画\n let redraw = () => {};\n\n function onKeydown(event: KeyboardEvent) {\n if (!controls) return;\n const step = 15 * DEG;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (move) orbit.nudge(...move);\n else if (zoom && (event.key === '+' || event.key === '='))\n distance = Math.max(ZOOM_RANGE[0], distance / 1.15);\n else if (zoom && event.key === '-') distance = Math.min(ZOOM_RANGE[1], distance * 1.15);\n else return;\n event.preventDefault();\n redraw();\n }\n\n function onWheel(event: WheelEvent) {\n if (!zoom) return;\n event.preventDefault();\n distance = Math.min(\n ZOOM_RANGE[1],\n Math.max(ZOOM_RANGE[0], distance * Math.exp(event.deltaY * 0.001)),\n );\n redraw();\n }\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n modelViewerStyles.root,\n controls && modelViewerStyles.interactive,\n orbit.dragging && modelViewerStyles.dragging,\n rest.sx,\n ]}\n role={alt ? 'img' : undefined}\n aria-label={alt}\n aria-busy={status === 'loading' || undefined}\n tabindex={controls ? 0 : undefined}\n data-status={status}\n {...(controls ? orbit.handlers : {})}\n onKeydown={onKeydown}\n onWheel={onWheel}\n propsContent={mergePartProps<PartProps<'div'>>(\n { sx: modelViewerStyles.content },\n rest.propsContent,\n )}\n sceneKey={src ?? object?.uuid}\n setup={({ renderer, scene, still, invalidate }) => {\n redraw = invalidate;\n renderer.toneMapping = ACESFilmicToneMapping;\n renderer.toneMappingExposure = exposure;\n const environment = new PMREMGenerator(renderer);\n scene.environment = environment.fromScene(new RoomEnvironment(), 0.04).texture;\n\n const camera = new PerspectiveCamera(FOV, 1, 0.01, 100);\n // 合适的距离:外接球(半径 1)正好占短边的 FIT\n let fit = 1 / Math.sin((FOV * DEG) / 2) / FIT;\n const holder = new Group();\n scene.add(holder);\n let disposed = false;\n\n status = 'loading';\n const source = object\n ? Promise.resolve(object)\n : new GLTFLoader().loadAsync(src ?? '').then((gltf) => gltf.scene);\n source.then(\n (model) => {\n if (disposed) return;\n // 居中,缩放到外接球半径为 1\n const sphere = new Box3().setFromObject(model).getBoundingSphere(new Sphere());\n const scale = sphere.radius > 0 ? 1 / sphere.radius : 1;\n holder.scale.setScalar(scale);\n holder.position.copy(sphere.center).multiplyScalar(-scale);\n holder.add(model);\n status = 'loaded';\n onLoad?.(model);\n invalidate();\n },\n (error: unknown) => {\n if (disposed) return;\n status = 'error';\n onError?.(error);\n },\n );\n\n const eye = new Vector3();\n const place = () => {\n const d = fit * distance;\n eye.set(\n Math.sin(orbit.yaw) * Math.cos(orbit.pitch),\n Math.sin(orbit.pitch),\n Math.cos(orbit.yaw) * Math.cos(orbit.pitch),\n );\n camera.position.copy(eye.multiplyScalar(d));\n camera.lookAt(0, 0, 0);\n };\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n fit = 1 / Math.sin((FOV * DEG) / 2) / FIT / Math.min(1, camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n place();\n },\n frame: ({ delta }) => {\n // 自转是相机绕模型反向转:看起来模型朝 rotationSpeed 的方向转\n orbit.step(delta, still ? 0 : -rotationSpeed * DEG);\n place();\n },\n dispose: () => {\n disposed = true;\n scene.environment?.dispose();\n environment.dispose();\n redraw = () => {};\n },\n };\n }}\n >\n {status !== 'loaded' && (\n <div {...css.attrs(modelViewerStyles.overlay)}>\n {status === 'loading' ? (\n <Spinner label={lang.modelViewerLoading} />\n ) : (\n <Small tone=\"muted\">{lang.modelViewerError}</Small>\n )}\n </div>\n )}\n </EffectSurface>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"ModelViewer.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_ref","_vtp_untrack","_createVNode","_mergeProps"],"sources":["../../../src/three/model/ModelViewer.tsx"],"sourcesContent":["/**\n * 模型查看器(div):加载 glTF / GLB(或直接给一个 three 的对象),自动居中、缩放到合适的大小,\n * 拖动环绕查看(松手带惯性),方向键也能转;没在拖时缓缓自转。参考 Google 的 <model-viewer>。\n *\n * <ModelViewer src=\"/models/chair.glb\" alt=\"扶手椅,胡桃木与灰色布面\" />\n * <ModelViewer object={mesh} rotationSpeed={0} zoom sx={styles.viewer} />\n *\n * 光照是一间柔和的摄影棚(RoomEnvironment 的环境光),金属、粗糙度材质都能正确地反光;exposure 调整体亮度。\n * 加载时中间显示转圈,失败时显示语言包里的提示(onError 拿到原因)。写了 alt 时整块是带名称的图像(role=\"img\")。\n * 默认正方形,尺寸由使用方决定。减少动态效果时不自转,拖动仍可用。\n *\n * 部件:Root(div)、Canvas(ThreeCanvas)、Content(加载中与出错的提示)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n ACESFilmicToneMapping,\n Box3,\n Group,\n PerspectiveCamera,\n PMREMGenerator,\n Sphere,\n Vector3,\n type Object3D,\n} from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';\nimport { Small } from '../../base/Text';\nimport { Spinner } from '../../base/Spinner';\nimport { useLang } from '../../config/context';\nimport { EffectSurface, type EffectProps } from '../core/EffectSurface';\nimport { createOrbit } from '../core/orbit';\nimport { mergePartProps, type PartProps } from '../../utils/props';\n\n/** 加载状态 */\nexport interface ModelViewerStatuses {\n /** 加载中 */\n loading: unknown;\n /** 已显示 */\n loaded: unknown;\n /** 加载失败 */\n error: unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface ModelViewerProps extends Omit<EffectProps, 'children' | 'onLoad' | 'onError'> {\n /** 模型的地址(glTF / GLB);和 object 二选一 */\n src?: string;\n /** 直接给一个 three 的对象(程序生成的模型);和 src 二选一 */\n object?: Object3D;\n /** 模型的文字描述:写了时整块是 role=\"img\"、以它为名称 */\n alt?: string;\n /**\n * 自转速度(度 / 秒);0 时不自转\n * @default 20\n */\n rotationSpeed?: number;\n /**\n * 可以拖动、用方向键环绕查看\n * @default true\n */\n controls?: boolean;\n /**\n * 滚轮、+ / - 键缩放\n * @default false\n */\n zoom?: boolean;\n /**\n * 一开始的角度(度):yaw 绕竖轴,pitch 从上往下看为正\n * @default { yaw: 30, pitch: 15 }\n */\n orbit?: { yaw: number; pitch: number };\n /**\n * 曝光:整体亮度\n * @default 1\n */\n exposure?: number;\n /** 加载完成 */\n onLoad?: (model: Object3D) => void;\n /** 加载失败 */\n onError?: (error: unknown) => void;\n}\n\n/** ModelViewer 的样式:root、interactive、dragging、content、overlay */\nexport const modelViewerStyles = css.create({\n root: { aspectRatio: '1', width: '100%', outlineStyle: 'none' },\n interactive: { cursor: 'grab', touchAction: 'pan-y' },\n dragging: { cursor: 'grabbing' },\n // 内容层不定位:提示按外层(整块)铺满、居中\n content: { position: 'static' },\n // 加载中、出错的提示:盖在画布中间\n overlay: {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n },\n});\n\nconst DEG = Math.PI / 180;\nconst FOV = 35;\n/** 模型(外接球)占画面短边的比例 */\nconst FIT = 0.85;\n/** 缩放的范围:相对合适距离的倍数 */\nconst ZOOM_RANGE = [0.5, 2.5] as const;\n\n/** 模型查看器 */\nexport const ModelViewer = _component(\n ({\n src,\n object,\n alt,\n rotationSpeed = 20,\n controls = true,\n zoom = false,\n orbit: initial = { yaw: 30, pitch: 15 },\n exposure = 1,\n onLoad,\n onError,\n ...rest\n }: ModelViewerProps) => {\n const lang = useLang();\n let status = _state<keyof ModelViewerStatuses>('loading');\n const start = _untrack(initial);\n const orbit = createOrbit({ yaw: start.yaw * DEG, pitch: start.pitch * DEG, pitchLimit: 1.4 });\n let distance = 1;\n // 场景建好后换成真正的 invalidate:静止模式下交互也要重画\n let redraw = () => {};\n\n function onKeydown(event: KeyboardEvent) {\n if (!controls) return;\n const step = 15 * DEG;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, -step],\n ArrowDown: [0, step],\n };\n const move = moves[event.key];\n if (move) orbit.nudge(...move);\n else if (zoom && (event.key === '+' || event.key === '='))\n distance = Math.max(ZOOM_RANGE[0], distance / 1.15);\n else if (zoom && event.key === '-') distance = Math.min(ZOOM_RANGE[1], distance * 1.15);\n else return;\n event.preventDefault();\n redraw();\n }\n\n function onWheel(event: WheelEvent) {\n if (!zoom) return;\n event.preventDefault();\n distance = Math.min(\n ZOOM_RANGE[1],\n Math.max(ZOOM_RANGE[0], distance * Math.exp(event.deltaY * 0.001)),\n );\n redraw();\n }\n\n return () => (\n <EffectSurface\n {...rest}\n sx={[\n modelViewerStyles.root,\n controls && modelViewerStyles.interactive,\n orbit.dragging && modelViewerStyles.dragging,\n rest.sx,\n ]}\n role={alt ? 'img' : undefined}\n aria-label={alt}\n aria-busy={status === 'loading' || undefined}\n tabindex={controls ? 0 : undefined}\n data-status={status}\n {...(controls ? orbit.handlers : {})}\n onKeydown={onKeydown}\n onWheel={onWheel}\n propsContent={mergePartProps<PartProps<'div'>>(\n { sx: modelViewerStyles.content },\n rest.propsContent,\n )}\n sceneKey={src ?? object?.uuid}\n setup={({ renderer, scene, still, invalidate }) => {\n redraw = invalidate;\n renderer.toneMapping = ACESFilmicToneMapping;\n renderer.toneMappingExposure = exposure;\n const environment = new PMREMGenerator(renderer);\n scene.environment = environment.fromScene(new RoomEnvironment(), 0.04).texture;\n\n const camera = new PerspectiveCamera(FOV, 1, 0.01, 100);\n // 合适的距离:外接球(半径 1)正好占短边的 FIT\n let fit = 1 / Math.sin((FOV * DEG) / 2) / FIT;\n const holder = new Group();\n scene.add(holder);\n let disposed = false;\n\n status = 'loading';\n const source = object\n ? Promise.resolve(object)\n : new GLTFLoader().loadAsync(src ?? '').then((gltf) => gltf.scene);\n source.then(\n (model) => {\n if (disposed) return;\n // 居中,缩放到外接球半径为 1\n const sphere = new Box3().setFromObject(model).getBoundingSphere(new Sphere());\n const scale = sphere.radius > 0 ? 1 / sphere.radius : 1;\n holder.scale.setScalar(scale);\n holder.position.copy(sphere.center).multiplyScalar(-scale);\n holder.add(model);\n status = 'loaded';\n onLoad?.(model);\n invalidate();\n },\n (error: unknown) => {\n if (disposed) return;\n status = 'error';\n onError?.(error);\n },\n );\n\n const eye = new Vector3();\n const place = () => {\n const d = fit * distance;\n eye.set(\n Math.sin(orbit.yaw) * Math.cos(orbit.pitch),\n Math.sin(orbit.pitch),\n Math.cos(orbit.yaw) * Math.cos(orbit.pitch),\n );\n camera.position.copy(eye.multiplyScalar(d));\n camera.lookAt(0, 0, 0);\n };\n\n return {\n resize: (size, context) => {\n camera.aspect = size.width / Math.max(size.height, 1);\n fit = 1 / Math.sin((FOV * DEG) / 2) / FIT / Math.min(1, camera.aspect);\n camera.updateProjectionMatrix();\n context.camera = camera;\n place();\n },\n frame: ({ delta }) => {\n // 自转是相机绕模型反向转:看起来模型朝 rotationSpeed 的方向转\n orbit.step(delta, still ? 0 : -rotationSpeed * DEG);\n place();\n },\n dispose: () => {\n disposed = true;\n scene.environment?.dispose();\n environment.dispose();\n redraw = () => {};\n },\n };\n }}\n >\n {status !== 'loaded' && (\n <div {...css.attrs(modelViewerStyles.overlay)}>\n {status === 'loading' ? (\n <Spinner label={lang.modelViewerLoading} />\n ) : (\n <Small tone=\"muted\">{lang.modelViewerError}</Small>\n )}\n </div>\n )}\n </EffectSurface>\n );\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。
3
+ * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),
4
+ * 它们本身不可变,共用同一个实例没有问题
5
+ *
6
+ * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate
7
+ */
8
+ export declare function cloneValue<T>(value: T): T;
@@ -0,0 +1,21 @@
1
+ import { toRaw } from "vue";
2
+ //#region src/utils/data/clone.ts
3
+ /**
4
+ * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。
5
+ * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),
6
+ * 它们本身不可变,共用同一个实例没有问题
7
+ *
8
+ * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate
9
+ */
10
+ function cloneValue(value) {
11
+ const raw = toRaw(value);
12
+ if (Array.isArray(raw)) return raw.map(cloneValue);
13
+ if (raw === null || typeof raw !== "object") return raw;
14
+ const prototype = Object.getPrototypeOf(raw);
15
+ if (prototype !== Object.prototype && prototype !== null) return raw;
16
+ return Object.fromEntries(Object.entries(raw).map(([key, item]) => [key, cloneValue(item)]));
17
+ }
18
+ //#endregion
19
+ export { cloneValue };
20
+
21
+ //# sourceMappingURL=clone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone.js","names":[],"sources":["../../../src/utils/data/clone.ts"],"sourcesContent":["import { toRaw } from 'vue';\n\n/**\n * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。\n * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),\n * 它们本身不可变,共用同一个实例没有问题\n *\n * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate\n */\nexport function cloneValue<T>(value: T): T {\n const raw = toRaw(value);\n if (Array.isArray(raw)) return raw.map(cloneValue) as T;\n if (raw === null || typeof raw !== 'object') return raw;\n const prototype = Object.getPrototypeOf(raw);\n if (prototype !== Object.prototype && prototype !== null) return raw;\n return Object.fromEntries(Object.entries(raw).map(([key, item]) => [key, cloneValue(item)])) as T;\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,WAAc,OAAa;CACzC,MAAM,MAAM,MAAM,KAAK;CACvB,IAAI,MAAM,QAAQ,GAAG,GAAG,OAAO,IAAI,IAAI,UAAU;CACjD,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;CACpD,MAAM,YAAY,OAAO,eAAe,GAAG;CAC3C,IAAI,cAAc,OAAO,aAAa,cAAc,MAAM,OAAO;CACjE,OAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC;AAC7F"}
@@ -137,6 +137,16 @@ export interface DateRange<T = CalendarDate> {
137
137
  /** 结束(含) */
138
138
  end: T;
139
139
  }
140
+ /**
141
+ * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。
142
+ * 一天按 timeZone 算(默认浏览器的时区),所以"10 月 27 日"在东八区是 26 日 16:00Z 到 27 日 16:00Z。
143
+ *
144
+ * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()
145
+ */
146
+ export declare function dayRangeBounds(range: DateRange, timeZone?: string): {
147
+ from: Date;
148
+ to: Date;
149
+ };
140
150
  /** 两个日期排成区间:先的在前 */
141
151
  export declare function orderedRange(a: CalendarDate, b: CalendarDate): DateRange;
142
152
  /** 日期是否在区间里(含两端;按粒度) */
@@ -240,6 +240,18 @@ function clampDate(date, { min, max }) {
240
240
  if (max != null && date.compare(toCalendar(max, date.calendar)) > 0) return toCalendar(max, date.calendar);
241
241
  return date;
242
242
  }
243
+ /**
244
+ * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。
245
+ * 一天按 timeZone 算(默认浏览器的时区),所以"10 月 27 日"在东八区是 26 日 16:00Z 到 27 日 16:00Z。
246
+ *
247
+ * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()
248
+ */
249
+ function dayRangeBounds(range, timeZone = getLocalTimeZone()) {
250
+ return {
251
+ from: range.start.toDate(timeZone),
252
+ to: range.end.add({ days: 1 }).toDate(timeZone)
253
+ };
254
+ }
243
255
  /** 两个日期排成区间:先的在前 */
244
256
  function orderedRange(a, b) {
245
257
  return a.compare(b) <= 0 ? {
@@ -404,6 +416,6 @@ function cachedFormatter(locale, options) {
404
416
  return formatter;
405
417
  }
406
418
  //#endregion
407
- export { calendarOf, clampDate, compareDates, daysBetween, fullIsoDay, isDateDisabled, isInRange, isOutOfRange, isOutsideDecade, isSameDate, isoDayOfWeek, isoWeekOf, isoWeeksInYear, lastIsoDay, monthGrid, monthsOfYear, orderedRange, parseIsoDate, parseIsoDateTime, parseIsoRange, parseIsoTime, presetIsoRange, presetRange, rangeDays, rangeHasUnavailable, relativeUnit, shiftIsoDate, toDayOfWeek, toInstant, toIsoDate, toIsoDateTime, toIsoQuarter, toIsoRange, toIsoTime, toIsoWeek, todayIso, truncateDate, weekOfYear, weekdayNames, yearsOfDecade };
419
+ export { calendarOf, clampDate, compareDates, dayRangeBounds, daysBetween, fullIsoDay, isDateDisabled, isInRange, isOutOfRange, isOutsideDecade, isSameDate, isoDayOfWeek, isoWeekOf, isoWeeksInYear, lastIsoDay, monthGrid, monthsOfYear, orderedRange, parseIsoDate, parseIsoDateTime, parseIsoRange, parseIsoTime, presetIsoRange, presetRange, rangeDays, rangeHasUnavailable, relativeUnit, shiftIsoDate, toDayOfWeek, toInstant, toIsoDate, toIsoDateTime, toIsoQuarter, toIsoRange, toIsoTime, toIsoWeek, todayIso, truncateDate, weekOfYear, weekdayNames, yearsOfDecade };
408
420
 
409
421
  //# sourceMappingURL=date.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"date.js","names":[],"sources":["../../../src/utils/data/date.ts"],"sourcesContent":["/**\n * 日期运算(不含界面):ISO 字符串互转、月份网格、星期名与月份名、可选范围、区间、周数、快捷区间。\n * Calendar、DateField、各种日期选择器共用;运算交给 @internationalized/date(时区、地区的周起始日、非公历)。\n *\n * 组件对外的值是 ISO 8601 字符串('2026-10-20'、'14:30'、'2026-10-20T14:30'),与原生 input、URL 参数、\n * zod 的 z.iso.date() 一致;组件内部换成 CalendarDate 等对象运算。月份名、星期名一律取自 Intl。\n * 出错的约定:parseXxx 解析不了时返回 null(输入框里的半截内容是常态);shiftIsoDate、daysBetween 这类运算\n * 要求合法的 ISO 字符串,不合法时抛 RangeError 并带上原值(多半是调用方的数据错了,不该悄悄算出别的日子)。\n *\n * monthGrid(new CalendarDate(2026, 10, 1), { locale: 'zh-CN' }) → 6 行 × 7 天,补齐上下月\n * weekdayNames('en-US', { format: 'short' }) → ['Sun', 'Mon', …]\n */\nimport {\n CalendarDate,\n CalendarDateTime,\n createCalendar,\n DateFormatter,\n endOfMonth,\n getDayOfWeek,\n getLocalTimeZone,\n GregorianCalendar,\n parseDate,\n parseDateTime,\n parseTime,\n startOfMonth,\n startOfWeek,\n Time,\n toCalendar,\n today,\n type Calendar,\n type CalendarIdentifier,\n type DateDuration,\n type DateValue,\n type DayOfWeek,\n} from '@internationalized/date';\n\n// ───────── ISO 字符串 ─────────\n\n/** 'YYYY-MM-DD' → CalendarDate(公历);空值或格式不对时为 null */\nexport function parseIsoDate(value: string | null | undefined): CalendarDate | null {\n return tryParse(value, parseDate);\n}\n\n/** 'HH:mm' 或 'HH:mm:ss' → Time;空值或格式不对时为 null */\nexport function parseIsoTime(value: string | null | undefined): Time | null {\n return tryParse(value, parseTime);\n}\n\n/**\n * 补成完整的 ISO 日期(这一段的第一天):'2026' 与 '2026-10' 补成 1 日,'2026-Q4' 是 10 月 1 日,\n * '2026-W43' 是那一周的周一,日期时间取日期部分(DateField、各种日期选择器的粒度)\n */\nexport function fullIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.start.toString();\n return iso.length === 4 ? `${iso}-01-01` : iso.length === 7 ? `${iso}-01` : iso.slice(0, 10);\n}\n\n/** 这一段的最后一天:'2026' 是 12 月 31 日,'2026-10' 是 31 日,'2026-Q4' 是 12 月 31 日,'2026-W43' 是那周的周日 */\nexport function lastIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.end.toString();\n if (iso.length === 4) return `${iso}-12-31`;\n if (iso.length === 7) return endOfMonth(parseDate(`${iso}-01`)).toString();\n return iso.slice(0, 10);\n}\n\n// ───────── 季度与 ISO 周 ─────────\n\nconst QUARTER_PATTERN = /^(\\d{4})-Q([1-4])$/;\nconst WEEK_PATTERN = /^(\\d{4})-W(\\d{2})$/;\n\n/** 日期所在的季度:'2026-Q4' */\nexport function toIsoQuarter(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return `${String(gregorian.year).padStart(4, '0')}-Q${Math.ceil(gregorian.month / 3)}`;\n}\n\n/** ISO 8601 的周(周一开始,含 1 月 4 日的那周是第 1 周,跨年的周归周四所在的年):所属的年与第几周 */\nexport function isoWeekOf(date: DateValue): { year: number; week: number } {\n const gregorian = toCalendar(date, GREGORIAN);\n const day = new CalendarDate(gregorian.year, gregorian.month, gregorian.day);\n const thursday = day.add({ days: 4 - isoWeekday(day) });\n return {\n year: thursday.year,\n week: Math.floor(thursday.compare(new CalendarDate(thursday.year, 1, 1)) / 7) + 1,\n };\n}\n\n/** 日期所在的 ISO 周:'2026-W43'(同原生 input type=\"week\") */\nexport function toIsoWeek(date: DateValue): string {\n const { year, week } = isoWeekOf(date);\n return `${String(year).padStart(4, '0')}-W${String(week).padStart(2, '0')}`;\n}\n\n/** 一年有几个 ISO 周(52 或 53):12 月 28 日总在最后一周里 */\nexport const isoWeeksInYear = (year: number): number =>\n isoWeekOf(new CalendarDate(year, 12, 28)).week;\n\n/** 周一是 1、周日是 7(与地区无关) */\nfunction isoWeekday(date: CalendarDate): number {\n return date.toDate('UTC').getUTCDay() || 7;\n}\n\n/** '2026-Q4'、'2026-W43' → 这一段的第一天与最后一天;不是季度、周的形式时 null */\nfunction parsePeriod(iso: string): { start: CalendarDate; end: CalendarDate } | null {\n const quarter = QUARTER_PATTERN.exec(iso);\n if (quarter) {\n const start = new CalendarDate(Number(quarter[1]), Number(quarter[2]) * 3 - 2, 1);\n return { start, end: endOfMonth(start.add({ months: 2 })) };\n }\n const week = WEEK_PATTERN.exec(iso);\n if (week) {\n const january4 = new CalendarDate(Number(week[1]), 1, 4);\n const start = january4.add({ days: 1 - isoWeekday(january4) + (Number(week[2]) - 1) * 7 });\n return { start, end: start.add({ days: 6 }) };\n }\n return null;\n}\n\n/** 'YYYY-MM-DDTHH:mm[:ss]' → CalendarDateTime(公历);空值或格式不对时为 null */\nexport function parseIsoDateTime(value: string | null | undefined): CalendarDateTime | null {\n return tryParse(value, parseDateTime);\n}\n\n/** 日期 → 'YYYY-MM-DD';不是公历的日期先换回公历 */\nexport function toIsoDate(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return new CalendarDate(gregorian.year, gregorian.month, gregorian.day).toString();\n}\n\n/** 时间 → 'HH:mm';withSeconds 时 'HH:mm:ss'(同原生 input type=\"time\") */\nexport function toIsoTime(time: Time, withSeconds = false): string {\n const text = new Time(time.hour, time.minute, withSeconds ? time.second : 0).toString();\n return withSeconds ? text : text.slice(0, 5);\n}\n\n/** 日期时间 → 'YYYY-MM-DDTHH:mm';withSeconds 时带秒(同原生 input type=\"datetime-local\") */\nexport function toIsoDateTime(value: CalendarDateTime, withSeconds = false): string {\n const gregorian = toCalendar(value, GREGORIAN);\n return `${toIsoDate(gregorian)}T${toIsoTime(new Time(gregorian.hour, gregorian.minute, gregorian.second), withSeconds)}`;\n}\n\n/** 今天的 ISO 日期,按时区(不写时取浏览器的):`todayIso()` → '2026-10-20' */\nexport function todayIso(timeZone = getLocalTimeZone()): string {\n return today(timeZone).toString();\n}\n\n/** ISO 日期加减(月末自动夹到下个月的最后一天):`shiftIsoDate('2026-01-31', { months: 1 })` → '2026-02-28' */\nexport function shiftIsoDate(value: string, duration: DateDuration): string {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return date.add(duration).toString();\n}\n\n/** 从 a 到 b 相隔几天(b 在后为正):`daysBetween('2026-10-20', '2026-10-23')` → 3 */\nexport function daysBetween(a: string, b: string): number {\n const start = parseIsoDate(a);\n const end = parseIsoDate(b);\n if (!start || !end) throw new RangeError(`不是 ISO 日期:${start ? b : a}`);\n return end.compare(start);\n}\n\n/**\n * ISO 日期是星期几:0 周日 … 6 周六(同 Date#getDay)。直接按日期算,不受时区影响;\n * `new Date('2026-10-20').getDay()` 在 UTC 以西的时区会算成前一天\n */\nexport function isoDayOfWeek(value: string): number {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return getDayOfWeek(date, 'en-US');\n}\n\n// ───────── 日历系统与周 ─────────\n\nconst GREGORIAN = new GregorianCalendar();\n\n/**\n * 语言里的日历标识 → 运算用的日历;@internationalized/date 不支持的(如农历 'chinese')退回公历,\n * 月份网格仍按公历排,显示的文字照常由 Intl 按该日历格式化\n */\nexport function calendarOf(identifier: string): Calendar {\n if (identifier === 'gregory') return GREGORIAN;\n try {\n return createCalendar(identifier as CalendarIdentifier);\n } catch {\n return GREGORIAN;\n }\n}\n\nconst DAYS_OF_WEEK: readonly DayOfWeek[] = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n\n/** 语言配置的一周第一天(0 表示周日)→ @internationalized/date 的写法;不写时按地区惯例 */\nexport function toDayOfWeek(firstDayOfWeek: number | undefined): DayOfWeek | undefined {\n return firstDayOfWeek == null ? undefined : DAYS_OF_WEEK[((firstDayOfWeek % 7) + 7) % 7];\n}\n\n/** 一周的排法:语言与一周第一天(0 表示周日,不写时按地区惯例) */\nexport interface WeekOptions {\n /** BCP 47 语言标签 */\n locale: string;\n /** 一周的第一天,0 表示周日;不写时按地区惯例(zh-CN 周一,en-US 周日) */\n firstDayOfWeek?: number;\n}\n\n/** monthGrid 的选项 */\nexport interface MonthGridOptions extends WeekOptions {\n /** 总是 6 行:几个月并排、或翻页时高度不跳,默认 true */\n fixedWeeks?: boolean;\n}\n\n/** 一个月的日期网格:按周分行,首尾用上个月、下个月的日期补齐(同 React Aria 的 getDatesInWeek) */\nexport function monthGrid(\n month: CalendarDate,\n { locale, firstDayOfWeek, fixedWeeks = true }: MonthGridOptions,\n): CalendarDate[][] {\n const first = startOfWeek(startOfMonth(month), locale, toDayOfWeek(firstDayOfWeek));\n const last = endOfMonth(month);\n const weeks: CalendarDate[][] = [];\n for (let start = first; weeks.length < 6; start = start.add({ weeks: 1 })) {\n if (!fixedWeeks && start.compare(last) > 0) break;\n weeks.push(Array.from({ length: 7 }, (_, index) => start.add({ days: index })));\n }\n return weeks;\n}\n\n/** 星期名的长短 */\nexport interface WeekdayFormats {\n /** 最短:一、二 / S、M */\n narrow: unknown;\n /** 简写:周一 / Mon */\n short: unknown;\n /** 全称:星期一 / Monday */\n long: unknown;\n}\n\n/** 按一周的排法列出七天的星期名(取自 Intl),从一周第一天开始 */\nexport function weekdayNames(\n locale: string,\n {\n firstDayOfWeek,\n format = 'short',\n }: { firstDayOfWeek?: number; format?: keyof WeekdayFormats } = {},\n): string[] {\n const formatter = cachedFormatter(locale, { weekday: format, timeZone: 'UTC' });\n // 任取一周:从这周的第一天起连续七天\n const start = startOfWeek(new CalendarDate(2024, 1, 10), locale, toDayOfWeek(firstDayOfWeek));\n return Array.from({ length: 7 }, (_, index) =>\n formatter.format(start.add({ days: index }).toDate('UTC')),\n );\n}\n\n/** 一年的各月(每月 1 日),按日期所在的日历系统(个别日历一年有 13 个月) */\nexport function monthsOfYear(date: CalendarDate): CalendarDate[] {\n const first = date.set({ month: 1, day: 1 });\n return Array.from({ length: date.calendar.getMonthsInYear(first) }, (_, index) =>\n first.add({ months: index }),\n );\n}\n\n/** 年份视图的一页:所在的十年,前后各补一年(共 12 年,排成 4 × 3;同 Ant Design 的年份面板) */\nexport function yearsOfDecade(date: CalendarDate): CalendarDate[] {\n const start = date.set({ year: Math.floor(date.year / 10) * 10, month: 1, day: 1 });\n return Array.from({ length: 12 }, (_, index) => start.add({ years: index - 1 }));\n}\n\n/** 是不是十年之外、补上的那两年 */\nexport const isOutsideDecade = (year: CalendarDate, page: CalendarDate) =>\n Math.floor(year.year / 10) !== Math.floor(page.year / 10);\n\n/**\n * 一年里的第几周:一周从周一开始时按 ISO 8601(含 1 月 4 日的那周是第 1 周),\n * 其他(周日、周六开始)按含 1 月 1 日的那周是第 1 周(美国、日本的惯例)\n */\nexport function weekOfYear(date: CalendarDate, options: WeekOptions): number {\n const gregorian = toCalendar(date, GREGORIAN);\n const monday =\n getDayOfWeek(\n new CalendarDate(2024, 1, 1),\n options.locale,\n toDayOfWeek(options.firstDayOfWeek),\n ) === 0;\n const weekStart = startOfWeek(gregorian, options.locale, toDayOfWeek(options.firstDayOfWeek));\n // 一周归属的年份:ISO 按这周的周四,其他按这周的最后一天(含 1 月 1 日的周就算新年的第 1 周)\n const anchor = weekStart.add({ days: monday ? 3 : 6 });\n const firstAnchor = new CalendarDate(anchor.year, 1, monday ? 4 : 1);\n const firstWeek = startOfWeek(firstAnchor, options.locale, toDayOfWeek(options.firstDayOfWeek));\n return Math.round(weekStart.compare(firstWeek) / 7) + 1;\n}\n\n// ───────── 比较、范围与不可选 ─────────\n\n/** 比较的粒度:日历的三种视图 */\nexport interface DateUnits {\n /** 天 */\n day: unknown;\n /** 月 */\n month: unknown;\n /** 年 */\n year: unknown;\n}\n\n/** 日期的粒度 */\nexport type DateUnit = keyof DateUnits;\n\n/** 截到粒度:月取 1 日,年取 1 月 1 日 */\nexport function truncateDate(date: CalendarDate, unit: DateUnit): CalendarDate {\n if (unit === 'day') return date;\n return unit === 'month' ? date.set({ day: 1 }) : date.set({ month: 1, day: 1 });\n}\n\n/** 按粒度比较:小于 0 表示 a 在前;跨日历系统时按同一天比较 */\nexport function compareDates(a: CalendarDate, b: CalendarDate, unit: DateUnit = 'day'): number {\n const other = toCalendar(b, a.calendar);\n return truncateDate(a, unit).compare(truncateDate(other, unit));\n}\n\n/** 是不是同一天 / 同一月 / 同一年;任一方为空时为 false */\nexport function isSameDate(\n a: CalendarDate | null | undefined,\n b: CalendarDate | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return a != null && b != null && compareDates(a, b, unit) === 0;\n}\n\n/** 可选范围与不可选的日期:Calendar、DatePicker、DateField 共用 */\nexport interface DateLimits {\n /** 最早可选的日期 */\n min?: CalendarDate | null;\n /** 最晚可选的日期 */\n max?: CalendarDate | null;\n /** 不可选的日期(已订满、节假日):仍能用方向键经过,读屏能听到,不能选 */\n isUnavailable?: (date: CalendarDate) => boolean;\n}\n\n/** 在 min–max 之外(按粒度:月份视图里只要这个月有一天可选就不算在外面) */\nexport function isOutOfRange(\n date: CalendarDate,\n { min, max }: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n (min != null && compareDates(date, min, unit) < 0) ||\n (max != null && compareDates(date, max, unit) > 0)\n );\n}\n\n/** 不能选:在范围外,或是不可选的日期(只在天的粒度上判断 isUnavailable) */\nexport function isDateDisabled(\n date: CalendarDate,\n limits: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n isOutOfRange(date, limits, unit) || (unit === 'day' && (limits.isUnavailable?.(date) ?? false))\n );\n}\n\n/** 把日期夹到 min–max 之间 */\nexport function clampDate(date: CalendarDate, { min, max }: DateLimits): CalendarDate {\n if (min != null && date.compare(toCalendar(min, date.calendar)) < 0)\n return toCalendar(min, date.calendar);\n if (max != null && date.compare(toCalendar(max, date.calendar)) > 0)\n return toCalendar(max, date.calendar);\n return date;\n}\n\n/** 日期区间:两端都包含 */\nexport interface DateRange<T = CalendarDate> {\n /** 开始(含) */\n start: T;\n /** 结束(含) */\n end: T;\n}\n\n/** 两个日期排成区间:先的在前 */\nexport function orderedRange(a: CalendarDate, b: CalendarDate): DateRange {\n return a.compare(b) <= 0 ? { start: a, end: b } : { start: b, end: a };\n}\n\n/** 日期是否在区间里(含两端;按粒度) */\nexport function isInRange(\n date: CalendarDate,\n range: DateRange | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return (\n range != null &&\n compareDates(date, range.start, unit) >= 0 &&\n compareDates(date, range.end, unit) <= 0\n );\n}\n\n/** 区间一共几天(含两端) */\nexport function rangeDays({ start, end }: DateRange): number {\n return end.compare(start) + 1;\n}\n\n/** 区间里有没有不可选的日期:酒店连住时中间不能有订满的一天(React Aria 的 allowsNonContiguousRanges 为 false 时) */\nexport function rangeHasUnavailable(\n { start, end }: DateRange,\n isUnavailable: ((date: CalendarDate) => boolean) | undefined,\n): boolean {\n if (!isUnavailable) return false;\n for (let date = start; date.compare(end) <= 0; date = date.add({ days: 1 })) {\n if (isUnavailable(date)) return true;\n }\n return false;\n}\n\n/** ISO 字符串的区间 → CalendarDate 的区间;任一端解析不了时为 null */\nexport function parseIsoRange(range: DateRange<string> | null | undefined): DateRange | null {\n const start = parseIsoDate(range?.start);\n const end = parseIsoDate(range?.end);\n return start && end ? orderedRange(start, end) : null;\n}\n\n/** CalendarDate 的区间 → ISO 字符串的区间 */\nexport function toIsoRange(range: DateRange): DateRange<string> {\n return { start: toIsoDate(range.start), end: toIsoDate(range.end) };\n}\n\n// ───────── 快捷区间 ─────────\n\n/** 常用的快捷区间:报表、筛选里的“最近 7 天”“本月” */\nexport interface DateRangePresets {\n /** 今天 */\n today: unknown;\n /** 昨天 */\n yesterday: unknown;\n /** 最近 7 天(含今天) */\n last7Days: unknown;\n /** 最近 30 天(含今天) */\n last30Days: unknown;\n /** 本周(按语言的一周第一天) */\n thisWeek: unknown;\n /** 本月 */\n thisMonth: unknown;\n /** 上月 */\n lastMonth: unknown;\n /** 今年 */\n thisYear: unknown;\n}\n\n/** 快捷区间的名字 */\nexport type DateRangePreset = keyof DateRangePresets;\n\n/** 按今天算出快捷区间 */\nexport function presetRange(\n preset: DateRangePreset,\n today: CalendarDate,\n week: WeekOptions,\n): DateRange {\n switch (preset) {\n case 'today':\n return { start: today, end: today };\n case 'yesterday': {\n const day = today.subtract({ days: 1 });\n return { start: day, end: day };\n }\n case 'last7Days':\n return { start: today.subtract({ days: 6 }), end: today };\n case 'last30Days':\n return { start: today.subtract({ days: 29 }), end: today };\n case 'thisWeek': {\n const start = startOfWeek(today, week.locale, toDayOfWeek(week.firstDayOfWeek));\n return { start, end: start.add({ days: 6 }) };\n }\n case 'thisMonth':\n return { start: startOfMonth(today), end: endOfMonth(today) };\n case 'lastMonth': {\n const month = startOfMonth(today).subtract({ months: 1 });\n return { start: month, end: endOfMonth(month) };\n }\n case 'thisYear':\n return { start: today.set({ month: 1, day: 1 }), end: today.set({ month: 12, day: 31 }) };\n }\n}\n\n/** 快捷区间的 ISO 值,按今天(时区,不写时取浏览器的)与一周的排法:`presetIsoRange('last7Days', { locale: 'zh-CN' })` */\nexport function presetIsoRange(\n preset: DateRangePreset,\n week: WeekOptions,\n timeZone = getLocalTimeZone(),\n): DateRange<string> {\n return toIsoRange(presetRange(preset, today(timeZone), week));\n}\n\n// ───────── 时刻与相对时间 ─────────\n\n/** 带时区或 UTC 标记的 ISO 字符串('2026-10-20T14:30:00Z'、'…+08:00'):本身就是一个时刻 */\nconst ABSOLUTE_ISO = /(?:[zZ]|[+-]\\d\\d:?\\d\\d)$/;\n\n/**\n * 日期值 → 时刻(毫秒时间戳):Date 与带时区的值照原样;不带时区的('2026-10-20T14:30'、CalendarDateTime)\n * 按 timeZone 的墙上时间算。格式不对时 NaN\n */\nexport function toInstant(value: Date | DateValue | string, timeZone = getLocalTimeZone()): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value !== 'string') {\n return ('timeZone' in value ? value.toDate() : value.toDate(timeZone)).getTime();\n }\n if (ABSOLUTE_ISO.test(value)) return Date.parse(value);\n const parsed = parseIsoDateTime(value) ?? parseIsoDate(value);\n return parsed ? parsed.toDate(timeZone).getTime() : Number.NaN;\n}\n\n/** 相对时间用的单位:多久以内用这个单位(秒),参考 moment.js 的取整阈值 */\nconst RELATIVE_UNITS: readonly [Intl.RelativeTimeFormatUnit, number, number][] = [\n // [单位, 一个单位多少秒, 小于多少秒时用它]\n ['second', 1, 45],\n ['minute', 60, 45 * 60],\n ['hour', 3600, 22 * 3600],\n ['day', 86_400, 26 * 86_400],\n ['month', 30 * 86_400, 320 * 86_400],\n ['year', 365 * 86_400, Infinity],\n];\n\n/** 相差的毫秒数 → 相对时间的数值与单位:`relativeUnit(-180_000)` → `{ value: -3, unit: 'minute' }` */\nexport function relativeUnit(diff: number): { value: number; unit: Intl.RelativeTimeFormatUnit } {\n const seconds = diff / 1000;\n const [unit, size] = RELATIVE_UNITS.find(([, , below]) => Math.abs(seconds) < below)!;\n // -0 换成 0:Intl 的 numeric: auto 才念“现在”\n return { value: Math.round(seconds / size) || 0, unit };\n}\n\n// ───────── 内部实现 ─────────\n\nfunction tryParse<T>(value: string | null | undefined, parse: (text: string) => T): T | null {\n if (!value) return null;\n try {\n return parse(value);\n } catch {\n return null;\n }\n}\n\nconst formatters = new Map<string, DateFormatter>();\n\nfunction cachedFormatter(locale: string, options: Intl.DateTimeFormatOptions): DateFormatter {\n const key = `${locale}|${JSON.stringify(options)}`;\n let formatter = formatters.get(key);\n if (!formatter) formatters.set(key, (formatter = new DateFormatter(locale, options)));\n return formatter;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"date.js","names":[],"sources":["../../../src/utils/data/date.ts"],"sourcesContent":["/**\n * 日期运算(不含界面):ISO 字符串互转、月份网格、星期名与月份名、可选范围、区间、周数、快捷区间。\n * Calendar、DateField、各种日期选择器共用;运算交给 @internationalized/date(时区、地区的周起始日、非公历)。\n *\n * 组件对外的值是 ISO 8601 字符串('2026-10-20'、'14:30'、'2026-10-20T14:30'),与原生 input、URL 参数、\n * zod 的 z.iso.date() 一致;组件内部换成 CalendarDate 等对象运算。月份名、星期名一律取自 Intl。\n * 出错的约定:parseXxx 解析不了时返回 null(输入框里的半截内容是常态);shiftIsoDate、daysBetween 这类运算\n * 要求合法的 ISO 字符串,不合法时抛 RangeError 并带上原值(多半是调用方的数据错了,不该悄悄算出别的日子)。\n *\n * monthGrid(new CalendarDate(2026, 10, 1), { locale: 'zh-CN' }) → 6 行 × 7 天,补齐上下月\n * weekdayNames('en-US', { format: 'short' }) → ['Sun', 'Mon', …]\n */\nimport {\n CalendarDate,\n CalendarDateTime,\n createCalendar,\n DateFormatter,\n endOfMonth,\n getDayOfWeek,\n getLocalTimeZone,\n GregorianCalendar,\n parseDate,\n parseDateTime,\n parseTime,\n startOfMonth,\n startOfWeek,\n Time,\n toCalendar,\n today,\n type Calendar,\n type CalendarIdentifier,\n type DateDuration,\n type DateValue,\n type DayOfWeek,\n} from '@internationalized/date';\n\n// ───────── ISO 字符串 ─────────\n\n/** 'YYYY-MM-DD' → CalendarDate(公历);空值或格式不对时为 null */\nexport function parseIsoDate(value: string | null | undefined): CalendarDate | null {\n return tryParse(value, parseDate);\n}\n\n/** 'HH:mm' 或 'HH:mm:ss' → Time;空值或格式不对时为 null */\nexport function parseIsoTime(value: string | null | undefined): Time | null {\n return tryParse(value, parseTime);\n}\n\n/**\n * 补成完整的 ISO 日期(这一段的第一天):'2026' 与 '2026-10' 补成 1 日,'2026-Q4' 是 10 月 1 日,\n * '2026-W43' 是那一周的周一,日期时间取日期部分(DateField、各种日期选择器的粒度)\n */\nexport function fullIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.start.toString();\n return iso.length === 4 ? `${iso}-01-01` : iso.length === 7 ? `${iso}-01` : iso.slice(0, 10);\n}\n\n/** 这一段的最后一天:'2026' 是 12 月 31 日,'2026-10' 是 31 日,'2026-Q4' 是 12 月 31 日,'2026-W43' 是那周的周日 */\nexport function lastIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.end.toString();\n if (iso.length === 4) return `${iso}-12-31`;\n if (iso.length === 7) return endOfMonth(parseDate(`${iso}-01`)).toString();\n return iso.slice(0, 10);\n}\n\n// ───────── 季度与 ISO 周 ─────────\n\nconst QUARTER_PATTERN = /^(\\d{4})-Q([1-4])$/;\nconst WEEK_PATTERN = /^(\\d{4})-W(\\d{2})$/;\n\n/** 日期所在的季度:'2026-Q4' */\nexport function toIsoQuarter(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return `${String(gregorian.year).padStart(4, '0')}-Q${Math.ceil(gregorian.month / 3)}`;\n}\n\n/** ISO 8601 的周(周一开始,含 1 月 4 日的那周是第 1 周,跨年的周归周四所在的年):所属的年与第几周 */\nexport function isoWeekOf(date: DateValue): { year: number; week: number } {\n const gregorian = toCalendar(date, GREGORIAN);\n const day = new CalendarDate(gregorian.year, gregorian.month, gregorian.day);\n const thursday = day.add({ days: 4 - isoWeekday(day) });\n return {\n year: thursday.year,\n week: Math.floor(thursday.compare(new CalendarDate(thursday.year, 1, 1)) / 7) + 1,\n };\n}\n\n/** 日期所在的 ISO 周:'2026-W43'(同原生 input type=\"week\") */\nexport function toIsoWeek(date: DateValue): string {\n const { year, week } = isoWeekOf(date);\n return `${String(year).padStart(4, '0')}-W${String(week).padStart(2, '0')}`;\n}\n\n/** 一年有几个 ISO 周(52 或 53):12 月 28 日总在最后一周里 */\nexport const isoWeeksInYear = (year: number): number =>\n isoWeekOf(new CalendarDate(year, 12, 28)).week;\n\n/** 周一是 1、周日是 7(与地区无关) */\nfunction isoWeekday(date: CalendarDate): number {\n return date.toDate('UTC').getUTCDay() || 7;\n}\n\n/** '2026-Q4'、'2026-W43' → 这一段的第一天与最后一天;不是季度、周的形式时 null */\nfunction parsePeriod(iso: string): { start: CalendarDate; end: CalendarDate } | null {\n const quarter = QUARTER_PATTERN.exec(iso);\n if (quarter) {\n const start = new CalendarDate(Number(quarter[1]), Number(quarter[2]) * 3 - 2, 1);\n return { start, end: endOfMonth(start.add({ months: 2 })) };\n }\n const week = WEEK_PATTERN.exec(iso);\n if (week) {\n const january4 = new CalendarDate(Number(week[1]), 1, 4);\n const start = january4.add({ days: 1 - isoWeekday(january4) + (Number(week[2]) - 1) * 7 });\n return { start, end: start.add({ days: 6 }) };\n }\n return null;\n}\n\n/** 'YYYY-MM-DDTHH:mm[:ss]' → CalendarDateTime(公历);空值或格式不对时为 null */\nexport function parseIsoDateTime(value: string | null | undefined): CalendarDateTime | null {\n return tryParse(value, parseDateTime);\n}\n\n/** 日期 → 'YYYY-MM-DD';不是公历的日期先换回公历 */\nexport function toIsoDate(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return new CalendarDate(gregorian.year, gregorian.month, gregorian.day).toString();\n}\n\n/** 时间 → 'HH:mm';withSeconds 时 'HH:mm:ss'(同原生 input type=\"time\") */\nexport function toIsoTime(time: Time, withSeconds = false): string {\n const text = new Time(time.hour, time.minute, withSeconds ? time.second : 0).toString();\n return withSeconds ? text : text.slice(0, 5);\n}\n\n/** 日期时间 → 'YYYY-MM-DDTHH:mm';withSeconds 时带秒(同原生 input type=\"datetime-local\") */\nexport function toIsoDateTime(value: CalendarDateTime, withSeconds = false): string {\n const gregorian = toCalendar(value, GREGORIAN);\n return `${toIsoDate(gregorian)}T${toIsoTime(new Time(gregorian.hour, gregorian.minute, gregorian.second), withSeconds)}`;\n}\n\n/** 今天的 ISO 日期,按时区(不写时取浏览器的):`todayIso()` → '2026-10-20' */\nexport function todayIso(timeZone = getLocalTimeZone()): string {\n return today(timeZone).toString();\n}\n\n/** ISO 日期加减(月末自动夹到下个月的最后一天):`shiftIsoDate('2026-01-31', { months: 1 })` → '2026-02-28' */\nexport function shiftIsoDate(value: string, duration: DateDuration): string {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return date.add(duration).toString();\n}\n\n/** 从 a 到 b 相隔几天(b 在后为正):`daysBetween('2026-10-20', '2026-10-23')` → 3 */\nexport function daysBetween(a: string, b: string): number {\n const start = parseIsoDate(a);\n const end = parseIsoDate(b);\n if (!start || !end) throw new RangeError(`不是 ISO 日期:${start ? b : a}`);\n return end.compare(start);\n}\n\n/**\n * ISO 日期是星期几:0 周日 … 6 周六(同 Date#getDay)。直接按日期算,不受时区影响;\n * `new Date('2026-10-20').getDay()` 在 UTC 以西的时区会算成前一天\n */\nexport function isoDayOfWeek(value: string): number {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return getDayOfWeek(date, 'en-US');\n}\n\n// ───────── 日历系统与周 ─────────\n\nconst GREGORIAN = new GregorianCalendar();\n\n/**\n * 语言里的日历标识 → 运算用的日历;@internationalized/date 不支持的(如农历 'chinese')退回公历,\n * 月份网格仍按公历排,显示的文字照常由 Intl 按该日历格式化\n */\nexport function calendarOf(identifier: string): Calendar {\n if (identifier === 'gregory') return GREGORIAN;\n try {\n return createCalendar(identifier as CalendarIdentifier);\n } catch {\n return GREGORIAN;\n }\n}\n\nconst DAYS_OF_WEEK: readonly DayOfWeek[] = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n\n/** 语言配置的一周第一天(0 表示周日)→ @internationalized/date 的写法;不写时按地区惯例 */\nexport function toDayOfWeek(firstDayOfWeek: number | undefined): DayOfWeek | undefined {\n return firstDayOfWeek == null ? undefined : DAYS_OF_WEEK[((firstDayOfWeek % 7) + 7) % 7];\n}\n\n/** 一周的排法:语言与一周第一天(0 表示周日,不写时按地区惯例) */\nexport interface WeekOptions {\n /** BCP 47 语言标签 */\n locale: string;\n /** 一周的第一天,0 表示周日;不写时按地区惯例(zh-CN 周一,en-US 周日) */\n firstDayOfWeek?: number;\n}\n\n/** monthGrid 的选项 */\nexport interface MonthGridOptions extends WeekOptions {\n /** 总是 6 行:几个月并排、或翻页时高度不跳,默认 true */\n fixedWeeks?: boolean;\n}\n\n/** 一个月的日期网格:按周分行,首尾用上个月、下个月的日期补齐(同 React Aria 的 getDatesInWeek) */\nexport function monthGrid(\n month: CalendarDate,\n { locale, firstDayOfWeek, fixedWeeks = true }: MonthGridOptions,\n): CalendarDate[][] {\n const first = startOfWeek(startOfMonth(month), locale, toDayOfWeek(firstDayOfWeek));\n const last = endOfMonth(month);\n const weeks: CalendarDate[][] = [];\n for (let start = first; weeks.length < 6; start = start.add({ weeks: 1 })) {\n if (!fixedWeeks && start.compare(last) > 0) break;\n weeks.push(Array.from({ length: 7 }, (_, index) => start.add({ days: index })));\n }\n return weeks;\n}\n\n/** 星期名的长短 */\nexport interface WeekdayFormats {\n /** 最短:一、二 / S、M */\n narrow: unknown;\n /** 简写:周一 / Mon */\n short: unknown;\n /** 全称:星期一 / Monday */\n long: unknown;\n}\n\n/** 按一周的排法列出七天的星期名(取自 Intl),从一周第一天开始 */\nexport function weekdayNames(\n locale: string,\n {\n firstDayOfWeek,\n format = 'short',\n }: { firstDayOfWeek?: number; format?: keyof WeekdayFormats } = {},\n): string[] {\n const formatter = cachedFormatter(locale, { weekday: format, timeZone: 'UTC' });\n // 任取一周:从这周的第一天起连续七天\n const start = startOfWeek(new CalendarDate(2024, 1, 10), locale, toDayOfWeek(firstDayOfWeek));\n return Array.from({ length: 7 }, (_, index) =>\n formatter.format(start.add({ days: index }).toDate('UTC')),\n );\n}\n\n/** 一年的各月(每月 1 日),按日期所在的日历系统(个别日历一年有 13 个月) */\nexport function monthsOfYear(date: CalendarDate): CalendarDate[] {\n const first = date.set({ month: 1, day: 1 });\n return Array.from({ length: date.calendar.getMonthsInYear(first) }, (_, index) =>\n first.add({ months: index }),\n );\n}\n\n/** 年份视图的一页:所在的十年,前后各补一年(共 12 年,排成 4 × 3;同 Ant Design 的年份面板) */\nexport function yearsOfDecade(date: CalendarDate): CalendarDate[] {\n const start = date.set({ year: Math.floor(date.year / 10) * 10, month: 1, day: 1 });\n return Array.from({ length: 12 }, (_, index) => start.add({ years: index - 1 }));\n}\n\n/** 是不是十年之外、补上的那两年 */\nexport const isOutsideDecade = (year: CalendarDate, page: CalendarDate) =>\n Math.floor(year.year / 10) !== Math.floor(page.year / 10);\n\n/**\n * 一年里的第几周:一周从周一开始时按 ISO 8601(含 1 月 4 日的那周是第 1 周),\n * 其他(周日、周六开始)按含 1 月 1 日的那周是第 1 周(美国、日本的惯例)\n */\nexport function weekOfYear(date: CalendarDate, options: WeekOptions): number {\n const gregorian = toCalendar(date, GREGORIAN);\n const monday =\n getDayOfWeek(\n new CalendarDate(2024, 1, 1),\n options.locale,\n toDayOfWeek(options.firstDayOfWeek),\n ) === 0;\n const weekStart = startOfWeek(gregorian, options.locale, toDayOfWeek(options.firstDayOfWeek));\n // 一周归属的年份:ISO 按这周的周四,其他按这周的最后一天(含 1 月 1 日的周就算新年的第 1 周)\n const anchor = weekStart.add({ days: monday ? 3 : 6 });\n const firstAnchor = new CalendarDate(anchor.year, 1, monday ? 4 : 1);\n const firstWeek = startOfWeek(firstAnchor, options.locale, toDayOfWeek(options.firstDayOfWeek));\n return Math.round(weekStart.compare(firstWeek) / 7) + 1;\n}\n\n// ───────── 比较、范围与不可选 ─────────\n\n/** 比较的粒度:日历的三种视图 */\nexport interface DateUnits {\n /** 天 */\n day: unknown;\n /** 月 */\n month: unknown;\n /** 年 */\n year: unknown;\n}\n\n/** 日期的粒度 */\nexport type DateUnit = keyof DateUnits;\n\n/** 截到粒度:月取 1 日,年取 1 月 1 日 */\nexport function truncateDate(date: CalendarDate, unit: DateUnit): CalendarDate {\n if (unit === 'day') return date;\n return unit === 'month' ? date.set({ day: 1 }) : date.set({ month: 1, day: 1 });\n}\n\n/** 按粒度比较:小于 0 表示 a 在前;跨日历系统时按同一天比较 */\nexport function compareDates(a: CalendarDate, b: CalendarDate, unit: DateUnit = 'day'): number {\n const other = toCalendar(b, a.calendar);\n return truncateDate(a, unit).compare(truncateDate(other, unit));\n}\n\n/** 是不是同一天 / 同一月 / 同一年;任一方为空时为 false */\nexport function isSameDate(\n a: CalendarDate | null | undefined,\n b: CalendarDate | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return a != null && b != null && compareDates(a, b, unit) === 0;\n}\n\n/** 可选范围与不可选的日期:Calendar、DatePicker、DateField 共用 */\nexport interface DateLimits {\n /** 最早可选的日期 */\n min?: CalendarDate | null;\n /** 最晚可选的日期 */\n max?: CalendarDate | null;\n /** 不可选的日期(已订满、节假日):仍能用方向键经过,读屏能听到,不能选 */\n isUnavailable?: (date: CalendarDate) => boolean;\n}\n\n/** 在 min–max 之外(按粒度:月份视图里只要这个月有一天可选就不算在外面) */\nexport function isOutOfRange(\n date: CalendarDate,\n { min, max }: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n (min != null && compareDates(date, min, unit) < 0) ||\n (max != null && compareDates(date, max, unit) > 0)\n );\n}\n\n/** 不能选:在范围外,或是不可选的日期(只在天的粒度上判断 isUnavailable) */\nexport function isDateDisabled(\n date: CalendarDate,\n limits: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n isOutOfRange(date, limits, unit) || (unit === 'day' && (limits.isUnavailable?.(date) ?? false))\n );\n}\n\n/** 把日期夹到 min–max 之间 */\nexport function clampDate(date: CalendarDate, { min, max }: DateLimits): CalendarDate {\n if (min != null && date.compare(toCalendar(min, date.calendar)) < 0)\n return toCalendar(min, date.calendar);\n if (max != null && date.compare(toCalendar(max, date.calendar)) > 0)\n return toCalendar(max, date.calendar);\n return date;\n}\n\n/** 日期区间:两端都包含 */\nexport interface DateRange<T = CalendarDate> {\n /** 开始(含) */\n start: T;\n /** 结束(含) */\n end: T;\n}\n\n/**\n * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。\n * 一天按 timeZone 算(默认浏览器的时区),所以\"10 月 27 日\"在东八区是 26 日 16:00Z 到 27 日 16:00Z。\n *\n * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()\n */\nexport function dayRangeBounds(\n range: DateRange,\n timeZone: string = getLocalTimeZone(),\n): { from: Date; to: Date } {\n return { from: range.start.toDate(timeZone), to: range.end.add({ days: 1 }).toDate(timeZone) };\n}\n\n/** 两个日期排成区间:先的在前 */\nexport function orderedRange(a: CalendarDate, b: CalendarDate): DateRange {\n return a.compare(b) <= 0 ? { start: a, end: b } : { start: b, end: a };\n}\n\n/** 日期是否在区间里(含两端;按粒度) */\nexport function isInRange(\n date: CalendarDate,\n range: DateRange | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return (\n range != null &&\n compareDates(date, range.start, unit) >= 0 &&\n compareDates(date, range.end, unit) <= 0\n );\n}\n\n/** 区间一共几天(含两端) */\nexport function rangeDays({ start, end }: DateRange): number {\n return end.compare(start) + 1;\n}\n\n/** 区间里有没有不可选的日期:酒店连住时中间不能有订满的一天(React Aria 的 allowsNonContiguousRanges 为 false 时) */\nexport function rangeHasUnavailable(\n { start, end }: DateRange,\n isUnavailable: ((date: CalendarDate) => boolean) | undefined,\n): boolean {\n if (!isUnavailable) return false;\n for (let date = start; date.compare(end) <= 0; date = date.add({ days: 1 })) {\n if (isUnavailable(date)) return true;\n }\n return false;\n}\n\n/** ISO 字符串的区间 → CalendarDate 的区间;任一端解析不了时为 null */\nexport function parseIsoRange(range: DateRange<string> | null | undefined): DateRange | null {\n const start = parseIsoDate(range?.start);\n const end = parseIsoDate(range?.end);\n return start && end ? orderedRange(start, end) : null;\n}\n\n/** CalendarDate 的区间 → ISO 字符串的区间 */\nexport function toIsoRange(range: DateRange): DateRange<string> {\n return { start: toIsoDate(range.start), end: toIsoDate(range.end) };\n}\n\n// ───────── 快捷区间 ─────────\n\n/** 常用的快捷区间:报表、筛选里的“最近 7 天”“本月” */\nexport interface DateRangePresets {\n /** 今天 */\n today: unknown;\n /** 昨天 */\n yesterday: unknown;\n /** 最近 7 天(含今天) */\n last7Days: unknown;\n /** 最近 30 天(含今天) */\n last30Days: unknown;\n /** 本周(按语言的一周第一天) */\n thisWeek: unknown;\n /** 本月 */\n thisMonth: unknown;\n /** 上月 */\n lastMonth: unknown;\n /** 今年 */\n thisYear: unknown;\n}\n\n/** 快捷区间的名字 */\nexport type DateRangePreset = keyof DateRangePresets;\n\n/** 按今天算出快捷区间 */\nexport function presetRange(\n preset: DateRangePreset,\n today: CalendarDate,\n week: WeekOptions,\n): DateRange {\n switch (preset) {\n case 'today':\n return { start: today, end: today };\n case 'yesterday': {\n const day = today.subtract({ days: 1 });\n return { start: day, end: day };\n }\n case 'last7Days':\n return { start: today.subtract({ days: 6 }), end: today };\n case 'last30Days':\n return { start: today.subtract({ days: 29 }), end: today };\n case 'thisWeek': {\n const start = startOfWeek(today, week.locale, toDayOfWeek(week.firstDayOfWeek));\n return { start, end: start.add({ days: 6 }) };\n }\n case 'thisMonth':\n return { start: startOfMonth(today), end: endOfMonth(today) };\n case 'lastMonth': {\n const month = startOfMonth(today).subtract({ months: 1 });\n return { start: month, end: endOfMonth(month) };\n }\n case 'thisYear':\n return { start: today.set({ month: 1, day: 1 }), end: today.set({ month: 12, day: 31 }) };\n }\n}\n\n/** 快捷区间的 ISO 值,按今天(时区,不写时取浏览器的)与一周的排法:`presetIsoRange('last7Days', { locale: 'zh-CN' })` */\nexport function presetIsoRange(\n preset: DateRangePreset,\n week: WeekOptions,\n timeZone = getLocalTimeZone(),\n): DateRange<string> {\n return toIsoRange(presetRange(preset, today(timeZone), week));\n}\n\n// ───────── 时刻与相对时间 ─────────\n\n/** 带时区或 UTC 标记的 ISO 字符串('2026-10-20T14:30:00Z'、'…+08:00'):本身就是一个时刻 */\nconst ABSOLUTE_ISO = /(?:[zZ]|[+-]\\d\\d:?\\d\\d)$/;\n\n/**\n * 日期值 → 时刻(毫秒时间戳):Date 与带时区的值照原样;不带时区的('2026-10-20T14:30'、CalendarDateTime)\n * 按 timeZone 的墙上时间算。格式不对时 NaN\n */\nexport function toInstant(value: Date | DateValue | string, timeZone = getLocalTimeZone()): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value !== 'string') {\n return ('timeZone' in value ? value.toDate() : value.toDate(timeZone)).getTime();\n }\n if (ABSOLUTE_ISO.test(value)) return Date.parse(value);\n const parsed = parseIsoDateTime(value) ?? parseIsoDate(value);\n return parsed ? parsed.toDate(timeZone).getTime() : Number.NaN;\n}\n\n/** 相对时间用的单位:多久以内用这个单位(秒),参考 moment.js 的取整阈值 */\nconst RELATIVE_UNITS: readonly [Intl.RelativeTimeFormatUnit, number, number][] = [\n // [单位, 一个单位多少秒, 小于多少秒时用它]\n ['second', 1, 45],\n ['minute', 60, 45 * 60],\n ['hour', 3600, 22 * 3600],\n ['day', 86_400, 26 * 86_400],\n ['month', 30 * 86_400, 320 * 86_400],\n ['year', 365 * 86_400, Infinity],\n];\n\n/** 相差的毫秒数 → 相对时间的数值与单位:`relativeUnit(-180_000)` → `{ value: -3, unit: 'minute' }` */\nexport function relativeUnit(diff: number): { value: number; unit: Intl.RelativeTimeFormatUnit } {\n const seconds = diff / 1000;\n const [unit, size] = RELATIVE_UNITS.find(([, , below]) => Math.abs(seconds) < below)!;\n // -0 换成 0:Intl 的 numeric: auto 才念“现在”\n return { value: Math.round(seconds / size) || 0, unit };\n}\n\n// ───────── 内部实现 ─────────\n\nfunction tryParse<T>(value: string | null | undefined, parse: (text: string) => T): T | null {\n if (!value) return null;\n try {\n return parse(value);\n } catch {\n return null;\n }\n}\n\nconst formatters = new Map<string, DateFormatter>();\n\nfunction cachedFormatter(locale: string, options: Intl.DateTimeFormatOptions): DateFormatter {\n const key = `${locale}|${JSON.stringify(options)}`;\n let formatter = formatters.get(key);\n if (!formatter) formatters.set(key, (formatter = new DateFormatter(locale, options)));\n return formatter;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuCA,SAAgB,aAAa,OAAuD;CAClF,OAAO,SAAS,OAAO,SAAS;AAClC;;AAGA,SAAgB,aAAa,OAA+C;CAC1E,OAAO,SAAS,OAAO,SAAS;AAClC;;;;;AAMA,SAAgB,WAAW,KAAqB;CAC9C,MAAM,SAAS,YAAY,GAAG;CAC9B,IAAI,QAAQ,OAAO,OAAO,MAAM,SAAS;CACzC,OAAO,IAAI,WAAW,IAAI,GAAG,IAAI,UAAU,IAAI,WAAW,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM,GAAG,EAAE;AAC7F;;AAGA,SAAgB,WAAW,KAAqB;CAC9C,MAAM,SAAS,YAAY,GAAG;CAC9B,IAAI,QAAQ,OAAO,OAAO,IAAI,SAAS;CACvC,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,IAAI;CACpC,IAAI,IAAI,WAAW,GAAG,OAAO,WAAW,UAAU,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS;CACzE,OAAO,IAAI,MAAM,GAAG,EAAE;AACxB;AAIA,IAAM,kBAAkB;AACxB,IAAM,eAAe;;AAGrB,SAAgB,aAAa,MAAyB;CACpD,MAAM,YAAY,WAAW,MAAM,SAAS;CAC5C,OAAO,GAAG,OAAO,UAAU,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,IAAI,KAAK,KAAK,UAAU,QAAQ,CAAC;AACrF;;AAGA,SAAgB,UAAU,MAAiD;CACzE,MAAM,YAAY,WAAW,MAAM,SAAS;CAC5C,MAAM,MAAM,IAAI,aAAa,UAAU,MAAM,UAAU,OAAO,UAAU,GAAG;CAC3E,MAAM,WAAW,IAAI,IAAI,EAAE,MAAM,IAAI,WAAW,GAAG,EAAE,CAAC;CACtD,OAAO;EACL,MAAM,SAAS;EACf,MAAM,KAAK,MAAM,SAAS,QAAQ,IAAI,aAAa,SAAS,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI;CAClF;AACF;;AAGA,SAAgB,UAAU,MAAyB;CACjD,MAAM,EAAE,MAAM,SAAS,UAAU,IAAI;CACrC,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,IAAI,OAAO,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;AAC1E;;AAGA,IAAa,kBAAkB,SAC7B,UAAU,IAAI,aAAa,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;;AAG5C,SAAS,WAAW,MAA4B;CAC9C,OAAO,KAAK,OAAO,KAAK,CAAC,CAAC,UAAU,KAAK;AAC3C;;AAGA,SAAS,YAAY,KAAgE;CACnF,MAAM,UAAU,gBAAgB,KAAK,GAAG;CACxC,IAAI,SAAS;EACX,MAAM,QAAQ,IAAI,aAAa,OAAO,QAAQ,EAAE,GAAG,OAAO,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC;EAChF,OAAO;GAAE;GAAO,KAAK,WAAW,MAAM,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;EAAE;CAC5D;CACA,MAAM,OAAO,aAAa,KAAK,GAAG;CAClC,IAAI,MAAM;EACR,MAAM,WAAW,IAAI,aAAa,OAAO,KAAK,EAAE,GAAG,GAAG,CAAC;EACvD,MAAM,QAAQ,SAAS,IAAI,EAAE,MAAM,IAAI,WAAW,QAAQ,KAAK,OAAO,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC;EACzF,OAAO;GAAE;GAAO,KAAK,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;EAAE;CAC9C;CACA,OAAO;AACT;;AAGA,SAAgB,iBAAiB,OAA2D;CAC1F,OAAO,SAAS,OAAO,aAAa;AACtC;;AAGA,SAAgB,UAAU,MAAyB;CACjD,MAAM,YAAY,WAAW,MAAM,SAAS;CAC5C,OAAO,IAAI,aAAa,UAAU,MAAM,UAAU,OAAO,UAAU,GAAG,CAAC,CAAC,SAAS;AACnF;;AAGA,SAAgB,UAAU,MAAY,cAAc,OAAe;CACjE,MAAM,OAAO,IAAI,KAAK,KAAK,MAAM,KAAK,QAAQ,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS;CACtF,OAAO,cAAc,OAAO,KAAK,MAAM,GAAG,CAAC;AAC7C;;AAGA,SAAgB,cAAc,OAAyB,cAAc,OAAe;CAClF,MAAM,YAAY,WAAW,OAAO,SAAS;CAC7C,OAAO,GAAG,UAAU,SAAS,EAAE,GAAG,UAAU,IAAI,KAAK,UAAU,MAAM,UAAU,QAAQ,UAAU,MAAM,GAAG,WAAW;AACvH;;AAGA,SAAgB,SAAS,WAAW,iBAAiB,GAAW;CAC9D,OAAO,MAAM,QAAQ,CAAC,CAAC,SAAS;AAClC;;AAGA,SAAgB,aAAa,OAAe,UAAgC;CAC1E,MAAM,OAAO,aAAa,KAAK;CAC/B,IAAI,CAAC,MAAM,MAAM,IAAI,WAAW,aAAa,OAAO;CACpD,OAAO,KAAK,IAAI,QAAQ,CAAC,CAAC,SAAS;AACrC;;AAGA,SAAgB,YAAY,GAAW,GAAmB;CACxD,MAAM,QAAQ,aAAa,CAAC;CAC5B,MAAM,MAAM,aAAa,CAAC;CAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,WAAW,aAAa,QAAQ,IAAI,GAAG;CACrE,OAAO,IAAI,QAAQ,KAAK;AAC1B;;;;;AAMA,SAAgB,aAAa,OAAuB;CAClD,MAAM,OAAO,aAAa,KAAK;CAC/B,IAAI,CAAC,MAAM,MAAM,IAAI,WAAW,aAAa,OAAO;CACpD,OAAO,aAAa,MAAM,OAAO;AACnC;AAIA,IAAM,YAAY,IAAI,kBAAkB;;;;;AAMxC,SAAgB,WAAW,YAA8B;CACvD,IAAI,eAAe,WAAW,OAAO;CACrC,IAAI;EACF,OAAO,eAAe,UAAgC;CACxD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,IAAM,eAAqC;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;CAAO;AAAK;;AAG3F,SAAgB,YAAY,gBAA2D;CACrF,OAAO,kBAAkB,OAAO,KAAA,IAAY,cAAe,iBAAiB,IAAK,KAAK;AACxF;;AAiBA,SAAgB,UACd,OACA,EAAE,QAAQ,gBAAgB,aAAa,QACrB;CAClB,MAAM,QAAQ,YAAY,aAAa,KAAK,GAAG,QAAQ,YAAY,cAAc,CAAC;CAClF,MAAM,OAAO,WAAW,KAAK;CAC7B,MAAM,QAA0B,CAAC;CACjC,KAAK,IAAI,QAAQ,OAAO,MAAM,SAAS,GAAG,QAAQ,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG;EACzE,IAAI,CAAC,cAAc,MAAM,QAAQ,IAAI,IAAI,GAAG;EAC5C,MAAM,KAAK,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,UAAU,MAAM,IAAI,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC;CAChF;CACA,OAAO;AACT;;AAaA,SAAgB,aACd,QACA,EACE,gBACA,SAAS,YACqD,CAAC,GACvD;CACV,MAAM,YAAY,gBAAgB,QAAQ;EAAE,SAAS;EAAQ,UAAU;CAAM,CAAC;CAE9E,MAAM,QAAQ,YAAY,IAAI,aAAa,MAAM,GAAG,EAAE,GAAG,QAAQ,YAAY,cAAc,CAAC;CAC5F,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,UACnC,UAAU,OAAO,MAAM,IAAI,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAC3D;AACF;;AAGA,SAAgB,aAAa,MAAoC;CAC/D,MAAM,QAAQ,KAAK,IAAI;EAAE,OAAO;EAAG,KAAK;CAAE,CAAC;CAC3C,OAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,SAAS,gBAAgB,KAAK,EAAE,IAAI,GAAG,UACtE,MAAM,IAAI,EAAE,QAAQ,MAAM,CAAC,CAC7B;AACF;;AAGA,SAAgB,cAAc,MAAoC;CAChE,MAAM,QAAQ,KAAK,IAAI;EAAE,MAAM,KAAK,MAAM,KAAK,OAAO,EAAE,IAAI;EAAI,OAAO;EAAG,KAAK;CAAE,CAAC;CAClF,OAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,MAAM,IAAI,EAAE,OAAO,QAAQ,EAAE,CAAC,CAAC;AACjF;;AAGA,IAAa,mBAAmB,MAAoB,SAClD,KAAK,MAAM,KAAK,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,OAAO,EAAE;;;;;AAM1D,SAAgB,WAAW,MAAoB,SAA8B;CAC3E,MAAM,YAAY,WAAW,MAAM,SAAS;CAC5C,MAAM,SACJ,aACE,IAAI,aAAa,MAAM,GAAG,CAAC,GAC3B,QAAQ,QACR,YAAY,QAAQ,cAAc,CACpC,MAAM;CACR,MAAM,YAAY,YAAY,WAAW,QAAQ,QAAQ,YAAY,QAAQ,cAAc,CAAC;CAE5F,MAAM,SAAS,UAAU,IAAI,EAAE,MAAM,SAAS,IAAI,EAAE,CAAC;CACrD,MAAM,cAAc,IAAI,aAAa,OAAO,MAAM,GAAG,SAAS,IAAI,CAAC;CACnE,MAAM,YAAY,YAAY,aAAa,QAAQ,QAAQ,YAAY,QAAQ,cAAc,CAAC;CAC9F,OAAO,KAAK,MAAM,UAAU,QAAQ,SAAS,IAAI,CAAC,IAAI;AACxD;;AAkBA,SAAgB,aAAa,MAAoB,MAA8B;CAC7E,IAAI,SAAS,OAAO,OAAO;CAC3B,OAAO,SAAS,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI,KAAK,IAAI;EAAE,OAAO;EAAG,KAAK;CAAE,CAAC;AAChF;;AAGA,SAAgB,aAAa,GAAiB,GAAiB,OAAiB,OAAe;CAC7F,MAAM,QAAQ,WAAW,GAAG,EAAE,QAAQ;CACtC,OAAO,aAAa,GAAG,IAAI,CAAC,CAAC,QAAQ,aAAa,OAAO,IAAI,CAAC;AAChE;;AAGA,SAAgB,WACd,GACA,GACA,OAAiB,OACR;CACT,OAAO,KAAK,QAAQ,KAAK,QAAQ,aAAa,GAAG,GAAG,IAAI,MAAM;AAChE;;AAaA,SAAgB,aACd,MACA,EAAE,KAAK,OACP,OAAiB,OACR;CACT,OACG,OAAO,QAAQ,aAAa,MAAM,KAAK,IAAI,IAAI,KAC/C,OAAO,QAAQ,aAAa,MAAM,KAAK,IAAI,IAAI;AAEpD;;AAGA,SAAgB,eACd,MACA,QACA,OAAiB,OACR;CACT,OACE,aAAa,MAAM,QAAQ,IAAI,KAAM,SAAS,UAAU,OAAO,gBAAgB,IAAI,KAAK;AAE5F;;AAGA,SAAgB,UAAU,MAAoB,EAAE,KAAK,OAAiC;CACpF,IAAI,OAAO,QAAQ,KAAK,QAAQ,WAAW,KAAK,KAAK,QAAQ,CAAC,IAAI,GAChE,OAAO,WAAW,KAAK,KAAK,QAAQ;CACtC,IAAI,OAAO,QAAQ,KAAK,QAAQ,WAAW,KAAK,KAAK,QAAQ,CAAC,IAAI,GAChE,OAAO,WAAW,KAAK,KAAK,QAAQ;CACtC,OAAO;AACT;;;;;;;AAgBA,SAAgB,eACd,OACA,WAAmB,iBAAiB,GACV;CAC1B,OAAO;EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ;EAAG,IAAI,MAAM,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,QAAQ;CAAE;AAC/F;;AAGA,SAAgB,aAAa,GAAiB,GAA4B;CACxE,OAAO,EAAE,QAAQ,CAAC,KAAK,IAAI;EAAE,OAAO;EAAG,KAAK;CAAE,IAAI;EAAE,OAAO;EAAG,KAAK;CAAE;AACvE;;AAGA,SAAgB,UACd,MACA,OACA,OAAiB,OACR;CACT,OACE,SAAS,QACT,aAAa,MAAM,MAAM,OAAO,IAAI,KAAK,KACzC,aAAa,MAAM,MAAM,KAAK,IAAI,KAAK;AAE3C;;AAGA,SAAgB,UAAU,EAAE,OAAO,OAA0B;CAC3D,OAAO,IAAI,QAAQ,KAAK,IAAI;AAC9B;;AAGA,SAAgB,oBACd,EAAE,OAAO,OACT,eACS;CACT,IAAI,CAAC,eAAe,OAAO;CAC3B,KAAK,IAAI,OAAO,OAAO,KAAK,QAAQ,GAAG,KAAK,GAAG,OAAO,KAAK,IAAI,EAAE,MAAM,EAAE,CAAC,GACxE,IAAI,cAAc,IAAI,GAAG,OAAO;CAElC,OAAO;AACT;;AAGA,SAAgB,cAAc,OAA+D;CAC3F,MAAM,QAAQ,aAAa,OAAO,KAAK;CACvC,MAAM,MAAM,aAAa,OAAO,GAAG;CACnC,OAAO,SAAS,MAAM,aAAa,OAAO,GAAG,IAAI;AACnD;;AAGA,SAAgB,WAAW,OAAqC;CAC9D,OAAO;EAAE,OAAO,UAAU,MAAM,KAAK;EAAG,KAAK,UAAU,MAAM,GAAG;CAAE;AACpE;;AA4BA,SAAgB,YACd,QACA,OACA,MACW;CACX,QAAQ,QAAR;EACE,KAAK,SACH,OAAO;GAAE,OAAO;GAAO,KAAK;EAAM;EACpC,KAAK,aAAa;GAChB,MAAM,MAAM,MAAM,SAAS,EAAE,MAAM,EAAE,CAAC;GACtC,OAAO;IAAE,OAAO;IAAK,KAAK;GAAI;EAChC;EACA,KAAK,aACH,OAAO;GAAE,OAAO,MAAM,SAAS,EAAE,MAAM,EAAE,CAAC;GAAG,KAAK;EAAM;EAC1D,KAAK,cACH,OAAO;GAAE,OAAO,MAAM,SAAS,EAAE,MAAM,GAAG,CAAC;GAAG,KAAK;EAAM;EAC3D,KAAK,YAAY;GACf,MAAM,QAAQ,YAAY,OAAO,KAAK,QAAQ,YAAY,KAAK,cAAc,CAAC;GAC9E,OAAO;IAAE;IAAO,KAAK,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;GAAE;EAC9C;EACA,KAAK,aACH,OAAO;GAAE,OAAO,aAAa,KAAK;GAAG,KAAK,WAAW,KAAK;EAAE;EAC9D,KAAK,aAAa;GAChB,MAAM,QAAQ,aAAa,KAAK,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC;GACxD,OAAO;IAAE,OAAO;IAAO,KAAK,WAAW,KAAK;GAAE;EAChD;EACA,KAAK,YACH,OAAO;GAAE,OAAO,MAAM,IAAI;IAAE,OAAO;IAAG,KAAK;GAAE,CAAC;GAAG,KAAK,MAAM,IAAI;IAAE,OAAO;IAAI,KAAK;GAAG,CAAC;EAAE;CAC5F;AACF;;AAGA,SAAgB,eACd,QACA,MACA,WAAW,iBAAiB,GACT;CACnB,OAAO,WAAW,YAAY,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC;AAC9D;;AAKA,IAAM,eAAe;;;;;AAMrB,SAAgB,UAAU,OAAkC,WAAW,iBAAiB,GAAW;CACjG,IAAI,iBAAiB,MAAM,OAAO,MAAM,QAAQ;CAChD,IAAI,OAAO,UAAU,UACnB,QAAQ,cAAc,QAAQ,MAAM,OAAO,IAAI,MAAM,OAAO,QAAQ,EAAA,CAAG,QAAQ;CAEjF,IAAI,aAAa,KAAK,KAAK,GAAG,OAAO,KAAK,MAAM,KAAK;CACrD,MAAM,SAAS,iBAAiB,KAAK,KAAK,aAAa,KAAK;CAC5D,OAAO,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC,QAAQ,IAAI;AACtD;;AAGA,IAAM,iBAA2E;CAE/E;EAAC;EAAU;EAAG;CAAE;CAChB;EAAC;EAAU;EAAI;CAAO;CACtB;EAAC;EAAQ;EAAM;CAAS;CACxB;EAAC;EAAO;EAAQ;CAAW;CAC3B;EAAC;EAAS;EAAa;CAAY;CACnC;EAAC;EAAQ;EAAc;CAAQ;AACjC;;AAGA,SAAgB,aAAa,MAAoE;CAC/F,MAAM,UAAU,OAAO;CACvB,MAAM,CAAC,MAAM,QAAQ,eAAe,MAAM,KAAK,WAAW,KAAK,IAAI,OAAO,IAAI,KAAK;CAEnF,OAAO;EAAE,OAAO,KAAK,MAAM,UAAU,IAAI,KAAK;EAAG;CAAK;AACxD;AAIA,SAAS,SAAY,OAAkC,OAAsC;CAC3F,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI;EACF,OAAO,MAAM,KAAK;CACpB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,IAAM,6BAAa,IAAI,IAA2B;AAElD,SAAS,gBAAgB,QAAgB,SAAoD;CAC3F,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,UAAU,OAAO;CAC/C,IAAI,YAAY,WAAW,IAAI,GAAG;CAClC,IAAI,CAAC,WAAW,WAAW,IAAI,KAAM,YAAY,IAAI,cAAc,QAAQ,OAAO,CAAE;CACpF,OAAO;AACT"}
@@ -8,3 +8,8 @@ export declare function clamp(value: number, min: number, max: number): number;
8
8
  * 结果按 step 与 min 的小数位取整,不带进 0.1 + 0.2 这类浮点误差。Slider、NumberField 共用
9
9
  */
10
10
  export declare function snapToStep(value: number, step: number, min?: number, max?: number): number;
11
+ /**
12
+ * SVG 里的坐标保留三位小数:三角函数在不同的 JS 引擎、平台上末几位可能不同,服务端渲染与浏览器算出的路径就对不上(水合不一致);
13
+ * 千分之一个单位看不出差别,HTML 也短一些
14
+ */
15
+ export declare function svgNumber(value: number): number;
@@ -22,7 +22,14 @@ function snapToStep(value, step, min = -Infinity, max = Infinity) {
22
22
  const places = Math.max(decimals(step), Number.isFinite(min) ? decimals(min) : 0);
23
23
  return Number(clamp(stepped, min, max).toFixed(places));
24
24
  }
25
+ /**
26
+ * SVG 里的坐标保留三位小数:三角函数在不同的 JS 引擎、平台上末几位可能不同,服务端渲染与浏览器算出的路径就对不上(水合不一致);
27
+ * 千分之一个单位看不出差别,HTML 也短一些
28
+ */
29
+ function svgNumber(value) {
30
+ return Math.round(value * 1e3) / 1e3;
31
+ }
25
32
  //#endregion
26
- export { clamp, snapToStep };
33
+ export { clamp, snapToStep, svgNumber };
27
34
 
28
35
  //# sourceMappingURL=number.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../../../src/utils/data/number.ts"],"sourcesContent":["/**\n * 数值的小工具:取值夹在范围内、对齐到步长(滑块、数字输入、分页、虚拟滚动共用)。\n */\n\n/** 把 value 夹在 [min, max] 之间 */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** 小数位数:0.1 → 1,1e-7 → 7(String(1e-7) 是科学计数法,不能按小数点拆) */\nfunction decimals(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const [mantissa = '', exponent = '0'] = value.toExponential().split('e');\n return Math.max(0, (mantissa.split('.')[1] ?? '').length - Number(exponent));\n}\n\n/**\n * 夹在 [min, max] 之间并对齐到 min + n × step(没有 min 时对齐到 0 + n × step);\n * 结果按 step 与 min 的小数位取整,不带进 0.1 + 0.2 这类浮点误差。Slider、NumberField 共用\n */\nexport function snapToStep(value: number, step: number, min = -Infinity, max = Infinity): number {\n const base = Number.isFinite(min) ? min : 0;\n const stepped = base + Math.round((value - base) / step) * step;\n const places = Math.max(decimals(step), Number.isFinite(min) ? decimals(min) : 0);\n return Number(clamp(stepped, min, max).toFixed(places));\n}\n"],"mappings":";;;;;AAKA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;;AAGA,SAAS,SAAS,OAAuB;CACvC,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CACpC,MAAM,CAAC,WAAW,IAAI,WAAW,OAAO,MAAM,cAAc,CAAC,CAAC,MAAM,GAAG;CACvE,OAAO,KAAK,IAAI,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC,MAAM,GAAA,CAAI,SAAS,OAAO,QAAQ,CAAC;AAC7E;;;;;AAMA,SAAgB,WAAW,OAAe,MAAc,MAAM,WAAW,MAAM,UAAkB;CAC/F,MAAM,OAAO,OAAO,SAAS,GAAG,IAAI,MAAM;CAC1C,MAAM,UAAU,OAAO,KAAK,OAAO,QAAQ,QAAQ,IAAI,IAAI;CAC3D,MAAM,SAAS,KAAK,IAAI,SAAS,IAAI,GAAG,OAAO,SAAS,GAAG,IAAI,SAAS,GAAG,IAAI,CAAC;CAChF,OAAO,OAAO,MAAM,SAAS,KAAK,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC;AACxD"}
1
+ {"version":3,"file":"number.js","names":[],"sources":["../../../src/utils/data/number.ts"],"sourcesContent":["/**\n * 数值的小工具:取值夹在范围内、对齐到步长(滑块、数字输入、分页、虚拟滚动共用)。\n */\n\n/** 把 value 夹在 [min, max] 之间 */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** 小数位数:0.1 → 1,1e-7 → 7(String(1e-7) 是科学计数法,不能按小数点拆) */\nfunction decimals(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const [mantissa = '', exponent = '0'] = value.toExponential().split('e');\n return Math.max(0, (mantissa.split('.')[1] ?? '').length - Number(exponent));\n}\n\n/**\n * 夹在 [min, max] 之间并对齐到 min + n × step(没有 min 时对齐到 0 + n × step);\n * 结果按 step 与 min 的小数位取整,不带进 0.1 + 0.2 这类浮点误差。Slider、NumberField 共用\n */\nexport function snapToStep(value: number, step: number, min = -Infinity, max = Infinity): number {\n const base = Number.isFinite(min) ? min : 0;\n const stepped = base + Math.round((value - base) / step) * step;\n const places = Math.max(decimals(step), Number.isFinite(min) ? decimals(min) : 0);\n return Number(clamp(stepped, min, max).toFixed(places));\n}\n\n/**\n * SVG 里的坐标保留三位小数:三角函数在不同的 JS 引擎、平台上末几位可能不同,服务端渲染与浏览器算出的路径就对不上(水合不一致);\n * 千分之一个单位看不出差别,HTML 也短一些\n */\nexport function svgNumber(value: number): number {\n return Math.round(value * 1000) / 1000;\n}\n"],"mappings":";;;;;AAKA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;;AAGA,SAAS,SAAS,OAAuB;CACvC,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CACpC,MAAM,CAAC,WAAW,IAAI,WAAW,OAAO,MAAM,cAAc,CAAC,CAAC,MAAM,GAAG;CACvE,OAAO,KAAK,IAAI,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC,MAAM,GAAA,CAAI,SAAS,OAAO,QAAQ,CAAC;AAC7E;;;;;AAMA,SAAgB,WAAW,OAAe,MAAc,MAAM,WAAW,MAAM,UAAkB;CAC/F,MAAM,OAAO,OAAO,SAAS,GAAG,IAAI,MAAM;CAC1C,MAAM,UAAU,OAAO,KAAK,OAAO,QAAQ,QAAQ,IAAI,IAAI;CAC3D,MAAM,SAAS,KAAK,IAAI,SAAS,IAAI,GAAG,OAAO,SAAS,GAAG,IAAI,SAAS,GAAG,IAAI,CAAC;CAChF,OAAO,OAAO,MAAM,SAAS,KAAK,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC;AACxD;;;;;AAMA,SAAgB,UAAU,OAAuB;CAC/C,OAAO,KAAK,MAAM,QAAQ,GAAI,IAAI;AACpC"}
@@ -32,6 +32,13 @@ export declare function shiftDecimal(text: string, places: number): string;
32
32
  * 有 Decimal 时按十进制精确比较;number 与 bigint 之间不经过浮点数(大整数不丢精度);NaN 排在最后
33
33
  */
34
34
  export declare function compareNumeric(a: NumericValue, b: NumericValue): number;
35
+ /**
36
+ * 能精确比较的值 → 十进制文本:number(NaN、Infinity 不算)、bigint、Decimal、十进制写法的文字;其余是 undefined。
37
+ * 条件比较(input/condition.ts)用它:与流程引擎模型包的规则一致,长小数、大整数不丢精度
38
+ */
39
+ export declare function decimalTextOf(value: unknown): string | undefined;
40
+ /** 两段十进制文本(decimalTextOf 给出的)按数值比:负数、0、正数;不经过浮点数 */
41
+ export declare function compareDecimalText(a: string, b: string): number;
35
42
  /** 两个数值是否相等(1 与 1n、Decimal('1.0') 与 1 都算相等) */
36
43
  export declare const sameNumeric: (a: NumericValue, b: NumericValue) => boolean;
37
44
  /** 数值写回成什么类型:number、bigint,或某个 Decimal 构造函数(使用方 Decimal.clone 配过精度的也行) */
@@ -63,6 +63,51 @@ function compareNumeric(a, b) {
63
63
  if (isDecimal(b)) return compareWithDecimal(a, b, b.constructor);
64
64
  return a < b ? -1 : a > b ? 1 : 0;
65
65
  }
66
+ /** 十进制写法(可带指数):'19.90'、'-.5'、'1e3' */
67
+ var DECIMAL_TEXT = /^([+-]?)(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$|^([+-]?)\.(\d+)(?:[eE]([+-]?\d+))?$/;
68
+ function decimalParts(text) {
69
+ const match = DECIMAL_TEXT.exec(text);
70
+ if (!match) return void 0;
71
+ const [, sign1, int1, frac1, exp1, sign2, frac2, exp2] = match;
72
+ const intDigits = int1 ?? "";
73
+ const digits = intDigits + (frac1 ?? frac2 ?? "");
74
+ const point = intDigits.length + Number(exp1 ?? exp2 ?? 0);
75
+ const padded = point < 0 ? "0".repeat(-point) + digits : point > digits.length ? digits + "0".repeat(point - digits.length) : digits;
76
+ const at = Math.max(point, 0);
77
+ const int = padded.slice(0, at).replace(/^0+/, "");
78
+ const frac = padded.slice(at).replace(/0+$/, "");
79
+ return {
80
+ negative: (sign1 ?? sign2) === "-" && (int !== "" || frac !== ""),
81
+ int,
82
+ frac
83
+ };
84
+ }
85
+ /**
86
+ * 能精确比较的值 → 十进制文本:number(NaN、Infinity 不算)、bigint、Decimal、十进制写法的文字;其余是 undefined。
87
+ * 条件比较(input/condition.ts)用它:与流程引擎模型包的规则一致,长小数、大整数不丢精度
88
+ */
89
+ function decimalTextOf(value) {
90
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : void 0;
91
+ if (typeof value === "bigint" || isDecimal(value)) return numericText(value);
92
+ if (typeof value === "string" && DECIMAL_TEXT.test(value.trim())) return value.trim();
93
+ }
94
+ /** 两段十进制文本(decimalTextOf 给出的)按数值比:负数、0、正数;不经过浮点数 */
95
+ function compareDecimalText(a, b) {
96
+ const x = decimalParts(a);
97
+ const y = decimalParts(b);
98
+ if (!x || !y) return a === b ? 0 : a < b ? -1 : 1;
99
+ if (x.negative !== y.negative) return x.negative ? -1 : 1;
100
+ let magnitude = 0;
101
+ if (x.int.length !== y.int.length) magnitude = x.int.length < y.int.length ? -1 : 1;
102
+ else if (x.int !== y.int) magnitude = x.int < y.int ? -1 : 1;
103
+ else {
104
+ const width = Math.max(x.frac.length, y.frac.length);
105
+ const left = x.frac.padEnd(width, "0");
106
+ const right = y.frac.padEnd(width, "0");
107
+ magnitude = left === right ? 0 : left < right ? -1 : 1;
108
+ }
109
+ return x.negative ? -magnitude : magnitude;
110
+ }
66
111
  /** 两个数值是否相等(1 与 1n、Decimal('1.0') 与 1 都算相等) */
67
112
  var sameNumeric = (a, b) => compareNumeric(a, b) === 0;
68
113
  /** 值的类型:Decimal 取它自己的构造函数 */
@@ -128,6 +173,6 @@ function snapNumeric(value, step, min, max, kind) {
128
173
  return snapped;
129
174
  }
130
175
  //#endregion
131
- export { addNumeric, compareNumeric, isDecimal, isNumeric, isNumericText, multiplyNumeric, numericKind, numericText, sameNumeric, shiftDecimal, snapNumeric, toNumber, toNumericKind };
176
+ export { addNumeric, compareDecimalText, compareNumeric, decimalTextOf, isDecimal, isNumeric, isNumericText, multiplyNumeric, numericKind, numericText, sameNumeric, shiftDecimal, snapNumeric, toNumber, toNumericKind };
132
177
 
133
178
  //# sourceMappingURL=numeric.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"numeric.js","names":[],"sources":["../../../src/utils/data/numeric.ts"],"sourcesContent":["/**\n * 内置支持的数值类型:number、bigint 与 decimal.js 的 Decimal(金额、精确运算)。\n * 组件的数值属性都接受它们(NumericValue),排序、格式化、表单提交不丢精度。\n *\n * compareNumeric(new Decimal('1.5'), 1.25) // 1:不同类型也按大小比\n * numericText(new Decimal('1e21')) // '1000000000000000000000':提交给服务端的十进制文本\n *\n * 这里不在运行时导入 decimal.js:按实例自己的构造函数识别与运算(使用方可能用 Decimal.clone 配了精度),\n * 没用到 Decimal 的应用不会因此打包它。\n */\nimport type Decimal from 'decimal.js';\nimport { snapToStep } from './number';\n\n/** 组件接受的数值 */\nexport type NumericValue = number | bigint | Decimal;\n\ntype DecimalConstructor = typeof Decimal;\n\n/** 是不是 decimal.js 的 Decimal(含 Decimal.clone 出来的构造函数的实例) */\nexport function isDecimal(value: unknown): value is Decimal {\n if (typeof value !== 'object' || value === null) return false;\n const constructor = (value as { constructor?: Partial<DecimalConstructor> }).constructor;\n return typeof constructor?.isDecimal === 'function' && constructor.isDecimal(value);\n}\n\n/** 能读成数字的文字:接口常把金额给成十进制字符串('19.90');空白、Infinity、不是数字的都不算 */\nexport function isNumericText(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value));\n}\n\n/** 是不是组件接受的数值(NaN 也算 number,由使用方决定怎么处理) */\nexport function isNumeric(value: unknown): value is NumericValue {\n return typeof value === 'number' || typeof value === 'bigint' || isDecimal(value);\n}\n\n/** 转成 number:只给需要浮点数的地方用(动画的中间帧、图表坐标、aria-valuenow),会丢精度 */\nexport function toNumber(value: NumericValue): number {\n if (typeof value === 'number') return value;\n if (typeof value === 'bigint') return Number(value);\n return value.toNumber();\n}\n\n/** 十进制文本,不用科学计数法:表单提交、复制给服务端;NaN、Infinity 原样 */\nexport function numericText(value: NumericValue): string {\n if (typeof value === 'bigint') return value.toString();\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return String(value);\n // 1e21 以上、1e-6 以下 String() 会写成科学计数法;toLocaleString 不带分组时给出完整的十进制\n const plain = value === 0 || (Math.abs(value) < 1e21 && Math.abs(value) >= 1e-6);\n return plain\n ? String(value)\n : value.toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 });\n }\n return value.isFinite() ? value.toFixed() : value.toString();\n}\n\n/**\n * 十进制文本的小数点左移 places 位(除以 10 的 places 次方;负数右移),按文字移位、不经过浮点数:\n * `shiftDecimal('155353.2', 4)` → `'15.53532'`。不是普通十进制写法的文本(NaN、科学计数法)原样返回\n */\nexport function shiftDecimal(text: string, places: number): string {\n const match = /^([+-]?)(\\d*)(?:\\.(\\d*))?$/.exec(text);\n if (!match || places === 0 || !/\\d/.test(text)) return text;\n const [, sign, whole = '', fraction = ''] = match;\n const digits = whole + fraction;\n const point = whole.length - places;\n const padded = point <= 0 ? '0'.repeat(1 - point) + digits : digits.padEnd(point, '0');\n const at = Math.max(point, 1);\n const integer = padded.slice(0, at).replace(/^0+(?=\\d)/, '');\n const decimal = padded.slice(at).replace(/0+$/, '');\n return `${sign}${integer}${decimal ? `.${decimal}` : ''}`;\n}\n\n/** 用 Decimal 的构造函数(从 a 或 b 里找)把两个值都转成 Decimal 比较 */\nfunction compareWithDecimal(a: NumericValue, b: NumericValue, Ctor: DecimalConstructor): number {\n const left = isDecimal(a) ? a : new Ctor(numericText(a));\n return left.cmp(isDecimal(b) ? b : new Ctor(numericText(b)));\n}\n\n/**\n * 按大小比较两个数值,不同类型混着也行:返回负数、0 或正数(同 Array.prototype.sort 的约定)。\n * 有 Decimal 时按十进制精确比较;number 与 bigint 之间不经过浮点数(大整数不丢精度);NaN 排在最后\n */\nexport function compareNumeric(a: NumericValue, b: NumericValue): number {\n if (typeof a === 'number' && Number.isNaN(a))\n return typeof b === 'number' && Number.isNaN(b) ? 0 : 1;\n if (typeof b === 'number' && Number.isNaN(b)) return -1;\n if (isDecimal(a)) return compareWithDecimal(a, b, a.constructor as DecimalConstructor);\n if (isDecimal(b)) return compareWithDecimal(a, b, b.constructor as DecimalConstructor);\n // number、bigint 之间:JavaScript 的关系运算符对混合类型按数学值比较,不丢精度\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** 两个数值是否相等(1 与 1n、Decimal('1.0') 与 1 都算相等) */\nexport const sameNumeric = (a: NumericValue, b: NumericValue) => compareNumeric(a, b) === 0;\n\n/** 数值写回成什么类型:number、bigint,或某个 Decimal 构造函数(使用方 Decimal.clone 配过精度的也行) */\nexport type NumericKind = 'number' | 'bigint' | DecimalConstructor;\n\n/** 值的类型:Decimal 取它自己的构造函数 */\nexport function numericKind(value: NumericValue): NumericKind {\n if (typeof value === 'number') return 'number';\n if (typeof value === 'bigint') return 'bigint';\n return value.constructor as DecimalConstructor;\n}\n\n/** 十进制文本('-12.5')→ 整数,四舍五入(远离 0) */\nfunction roundedBigInt(text: string): bigint {\n const [whole = '0', fraction = ''] = text.replace(/^[+-]/, '').split('.');\n const negative = text.startsWith('-');\n let result = BigInt(whole || '0');\n if (Number(fraction[0] ?? 0) >= 5) result += 1n;\n return negative ? -result : result;\n}\n\n/**\n * 转成指定类型;value 也可以是十进制文本('-12.5',输入框解析出来的)。\n * bigint 四舍五入到整数,Decimal 按十进制文本转(不经过浮点数)\n */\nexport function toNumericKind(value: NumericValue | string, kind: NumericKind): NumericValue {\n const text = () => (typeof value === 'string' ? value : numericText(value));\n if (kind === 'number') return typeof value === 'string' ? Number(value) : toNumber(value);\n if (kind === 'bigint') return typeof value === 'bigint' ? value : roundedBigInt(text());\n return isDecimal(value) && value.constructor === kind ? value : new kind(text());\n}\n\n/** 按 kind 精确相加:Decimal 用它的构造函数算,bigint 整数相加,number 浮点相加(再由 snapNumeric 去掉误差) */\nexport function addNumeric(value: NumericValue, delta: NumericValue, kind: NumericKind) {\n const left = toNumericKind(value, kind);\n const right = toNumericKind(delta, kind);\n if (typeof left === 'number') return left + (right as number);\n if (typeof left === 'bigint') return left + (right as bigint);\n return (left as Decimal).plus(right as Decimal);\n}\n\n/** value 的 times 倍(times 是整数,如 -1、10),按 kind 精确运算 */\nexport function multiplyNumeric(value: NumericValue, times: number, kind: NumericKind) {\n const typed = toNumericKind(value, kind);\n if (typeof typed === 'number') return typed * times;\n if (typeof typed === 'bigint') return typed * BigInt(times);\n return (typed as Decimal).times(times);\n}\n\n/**\n * 夹在 [min, max] 之间并对齐到 min + n × step(没有 min 时对齐到 0 + n × step),按 kind 精确运算:\n * number 走 snapToStep(按小数位取整去掉浮点误差),bigint 的步长至少为 1,Decimal 用值自己的构造函数\n */\nexport function snapNumeric(\n value: NumericValue,\n step: NumericValue,\n min: NumericValue | undefined,\n max: NumericValue | undefined,\n kind: NumericKind,\n): NumericValue {\n if (kind === 'number') {\n return snapToStep(\n toNumber(value),\n toNumber(step),\n min == null ? -Infinity : toNumber(min),\n max == null ? Infinity : toNumber(max),\n );\n }\n const at = (item: NumericValue) => toNumericKind(item, kind);\n let snapped: NumericValue;\n if (kind === 'bigint') {\n const size = (at(step) as bigint) > 0n ? (at(step) as bigint) : 1n;\n const base = min == null ? 0n : (at(min) as bigint);\n const offset = (at(value) as bigint) - base;\n // 整数除法四舍五入(远离 0)\n const half = offset < 0n ? -size : size;\n snapped = base + ((2n * offset + half) / (2n * size)) * size;\n } else {\n const base = (min == null ? new kind(0) : at(min)) as Decimal;\n const size = at(step) as Decimal;\n snapped = base.plus((at(value) as Decimal).minus(base).div(size).round().times(size));\n }\n if (min != null && compareNumeric(snapped, min) < 0) snapped = at(min);\n if (max != null && compareNumeric(snapped, max) > 0) snapped = at(max);\n return snapped;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"numeric.js","names":[],"sources":["../../../src/utils/data/numeric.ts"],"sourcesContent":["/**\n * 内置支持的数值类型:number、bigint 与 decimal.js 的 Decimal(金额、精确运算)。\n * 组件的数值属性都接受它们(NumericValue),排序、格式化、表单提交不丢精度。\n *\n * compareNumeric(new Decimal('1.5'), 1.25) // 1:不同类型也按大小比\n * numericText(new Decimal('1e21')) // '1000000000000000000000':提交给服务端的十进制文本\n *\n * 这里不在运行时导入 decimal.js:按实例自己的构造函数识别与运算(使用方可能用 Decimal.clone 配了精度),\n * 没用到 Decimal 的应用不会因此打包它。\n */\nimport type Decimal from 'decimal.js';\nimport { snapToStep } from './number';\n\n/** 组件接受的数值 */\nexport type NumericValue = number | bigint | Decimal;\n\ntype DecimalConstructor = typeof Decimal;\n\n/** 是不是 decimal.js 的 Decimal(含 Decimal.clone 出来的构造函数的实例) */\nexport function isDecimal(value: unknown): value is Decimal {\n if (typeof value !== 'object' || value === null) return false;\n const constructor = (value as { constructor?: Partial<DecimalConstructor> }).constructor;\n return typeof constructor?.isDecimal === 'function' && constructor.isDecimal(value);\n}\n\n/** 能读成数字的文字:接口常把金额给成十进制字符串('19.90');空白、Infinity、不是数字的都不算 */\nexport function isNumericText(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value));\n}\n\n/** 是不是组件接受的数值(NaN 也算 number,由使用方决定怎么处理) */\nexport function isNumeric(value: unknown): value is NumericValue {\n return typeof value === 'number' || typeof value === 'bigint' || isDecimal(value);\n}\n\n/** 转成 number:只给需要浮点数的地方用(动画的中间帧、图表坐标、aria-valuenow),会丢精度 */\nexport function toNumber(value: NumericValue): number {\n if (typeof value === 'number') return value;\n if (typeof value === 'bigint') return Number(value);\n return value.toNumber();\n}\n\n/** 十进制文本,不用科学计数法:表单提交、复制给服务端;NaN、Infinity 原样 */\nexport function numericText(value: NumericValue): string {\n if (typeof value === 'bigint') return value.toString();\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return String(value);\n // 1e21 以上、1e-6 以下 String() 会写成科学计数法;toLocaleString 不带分组时给出完整的十进制\n const plain = value === 0 || (Math.abs(value) < 1e21 && Math.abs(value) >= 1e-6);\n return plain\n ? String(value)\n : value.toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 });\n }\n return value.isFinite() ? value.toFixed() : value.toString();\n}\n\n/**\n * 十进制文本的小数点左移 places 位(除以 10 的 places 次方;负数右移),按文字移位、不经过浮点数:\n * `shiftDecimal('155353.2', 4)` → `'15.53532'`。不是普通十进制写法的文本(NaN、科学计数法)原样返回\n */\nexport function shiftDecimal(text: string, places: number): string {\n const match = /^([+-]?)(\\d*)(?:\\.(\\d*))?$/.exec(text);\n if (!match || places === 0 || !/\\d/.test(text)) return text;\n const [, sign, whole = '', fraction = ''] = match;\n const digits = whole + fraction;\n const point = whole.length - places;\n const padded = point <= 0 ? '0'.repeat(1 - point) + digits : digits.padEnd(point, '0');\n const at = Math.max(point, 1);\n const integer = padded.slice(0, at).replace(/^0+(?=\\d)/, '');\n const decimal = padded.slice(at).replace(/0+$/, '');\n return `${sign}${integer}${decimal ? `.${decimal}` : ''}`;\n}\n\n/** 用 Decimal 的构造函数(从 a 或 b 里找)把两个值都转成 Decimal 比较 */\nfunction compareWithDecimal(a: NumericValue, b: NumericValue, Ctor: DecimalConstructor): number {\n const left = isDecimal(a) ? a : new Ctor(numericText(a));\n return left.cmp(isDecimal(b) ? b : new Ctor(numericText(b)));\n}\n\n/**\n * 按大小比较两个数值,不同类型混着也行:返回负数、0 或正数(同 Array.prototype.sort 的约定)。\n * 有 Decimal 时按十进制精确比较;number 与 bigint 之间不经过浮点数(大整数不丢精度);NaN 排在最后\n */\nexport function compareNumeric(a: NumericValue, b: NumericValue): number {\n if (typeof a === 'number' && Number.isNaN(a))\n return typeof b === 'number' && Number.isNaN(b) ? 0 : 1;\n if (typeof b === 'number' && Number.isNaN(b)) return -1;\n if (isDecimal(a)) return compareWithDecimal(a, b, a.constructor as DecimalConstructor);\n if (isDecimal(b)) return compareWithDecimal(a, b, b.constructor as DecimalConstructor);\n // number、bigint 之间:JavaScript 的关系运算符对混合类型按数学值比较,不丢精度\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** 十进制写法(可带指数):'19.90'、'-.5'、'1e3' */\nconst DECIMAL_TEXT =\n /^([+-]?)(\\d+)(?:\\.(\\d*))?(?:[eE]([+-]?\\d+))?$|^([+-]?)\\.(\\d+)(?:[eE]([+-]?\\d+))?$/;\n\n/** 拆开的十进制数:符号、去掉前导零的整数位、去掉末尾零的小数位 */\ninterface DecimalParts {\n negative: boolean;\n int: string;\n frac: string;\n}\n\nfunction decimalParts(text: string): DecimalParts | undefined {\n const match = DECIMAL_TEXT.exec(text);\n if (!match) return undefined;\n const [, sign1, int1, frac1, exp1, sign2, frac2, exp2] = match;\n const intDigits = int1 ?? '';\n const digits = intDigits + (frac1 ?? frac2 ?? '');\n // 小数点按指数移动后,再拆成整数位与小数位\n const point = intDigits.length + Number(exp1 ?? exp2 ?? 0);\n const padded =\n point < 0\n ? '0'.repeat(-point) + digits\n : point > digits.length\n ? digits + '0'.repeat(point - digits.length)\n : digits;\n const at = Math.max(point, 0);\n const int = padded.slice(0, at).replace(/^0+/, '');\n const frac = padded.slice(at).replace(/0+$/, '');\n return { negative: (sign1 ?? sign2) === '-' && (int !== '' || frac !== ''), int, frac };\n}\n\n/**\n * 能精确比较的值 → 十进制文本:number(NaN、Infinity 不算)、bigint、Decimal、十进制写法的文字;其余是 undefined。\n * 条件比较(input/condition.ts)用它:与流程引擎模型包的规则一致,长小数、大整数不丢精度\n */\nexport function decimalTextOf(value: unknown): string | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? String(value) : undefined;\n if (typeof value === 'bigint' || isDecimal(value)) return numericText(value);\n if (typeof value === 'string' && DECIMAL_TEXT.test(value.trim())) return value.trim();\n return undefined;\n}\n\n/** 两段十进制文本(decimalTextOf 给出的)按数值比:负数、0、正数;不经过浮点数 */\nexport function compareDecimalText(a: string, b: string): number {\n const x = decimalParts(a);\n const y = decimalParts(b);\n if (!x || !y) return a === b ? 0 : a < b ? -1 : 1;\n if (x.negative !== y.negative) return x.negative ? -1 : 1;\n let magnitude = 0;\n if (x.int.length !== y.int.length) magnitude = x.int.length < y.int.length ? -1 : 1;\n else if (x.int !== y.int) magnitude = x.int < y.int ? -1 : 1;\n else {\n const width = Math.max(x.frac.length, y.frac.length);\n const left = x.frac.padEnd(width, '0');\n const right = y.frac.padEnd(width, '0');\n magnitude = left === right ? 0 : left < right ? -1 : 1;\n }\n return x.negative ? -magnitude : magnitude;\n}\n\n/** 两个数值是否相等(1 与 1n、Decimal('1.0') 与 1 都算相等) */\nexport const sameNumeric = (a: NumericValue, b: NumericValue) => compareNumeric(a, b) === 0;\n\n/** 数值写回成什么类型:number、bigint,或某个 Decimal 构造函数(使用方 Decimal.clone 配过精度的也行) */\nexport type NumericKind = 'number' | 'bigint' | DecimalConstructor;\n\n/** 值的类型:Decimal 取它自己的构造函数 */\nexport function numericKind(value: NumericValue): NumericKind {\n if (typeof value === 'number') return 'number';\n if (typeof value === 'bigint') return 'bigint';\n return value.constructor as DecimalConstructor;\n}\n\n/** 十进制文本('-12.5')→ 整数,四舍五入(远离 0) */\nfunction roundedBigInt(text: string): bigint {\n const [whole = '0', fraction = ''] = text.replace(/^[+-]/, '').split('.');\n const negative = text.startsWith('-');\n let result = BigInt(whole || '0');\n if (Number(fraction[0] ?? 0) >= 5) result += 1n;\n return negative ? -result : result;\n}\n\n/**\n * 转成指定类型;value 也可以是十进制文本('-12.5',输入框解析出来的)。\n * bigint 四舍五入到整数,Decimal 按十进制文本转(不经过浮点数)\n */\nexport function toNumericKind(value: NumericValue | string, kind: NumericKind): NumericValue {\n const text = () => (typeof value === 'string' ? value : numericText(value));\n if (kind === 'number') return typeof value === 'string' ? Number(value) : toNumber(value);\n if (kind === 'bigint') return typeof value === 'bigint' ? value : roundedBigInt(text());\n return isDecimal(value) && value.constructor === kind ? value : new kind(text());\n}\n\n/** 按 kind 精确相加:Decimal 用它的构造函数算,bigint 整数相加,number 浮点相加(再由 snapNumeric 去掉误差) */\nexport function addNumeric(value: NumericValue, delta: NumericValue, kind: NumericKind) {\n const left = toNumericKind(value, kind);\n const right = toNumericKind(delta, kind);\n if (typeof left === 'number') return left + (right as number);\n if (typeof left === 'bigint') return left + (right as bigint);\n return (left as Decimal).plus(right as Decimal);\n}\n\n/** value 的 times 倍(times 是整数,如 -1、10),按 kind 精确运算 */\nexport function multiplyNumeric(value: NumericValue, times: number, kind: NumericKind) {\n const typed = toNumericKind(value, kind);\n if (typeof typed === 'number') return typed * times;\n if (typeof typed === 'bigint') return typed * BigInt(times);\n return (typed as Decimal).times(times);\n}\n\n/**\n * 夹在 [min, max] 之间并对齐到 min + n × step(没有 min 时对齐到 0 + n × step),按 kind 精确运算:\n * number 走 snapToStep(按小数位取整去掉浮点误差),bigint 的步长至少为 1,Decimal 用值自己的构造函数\n */\nexport function snapNumeric(\n value: NumericValue,\n step: NumericValue,\n min: NumericValue | undefined,\n max: NumericValue | undefined,\n kind: NumericKind,\n): NumericValue {\n if (kind === 'number') {\n return snapToStep(\n toNumber(value),\n toNumber(step),\n min == null ? -Infinity : toNumber(min),\n max == null ? Infinity : toNumber(max),\n );\n }\n const at = (item: NumericValue) => toNumericKind(item, kind);\n let snapped: NumericValue;\n if (kind === 'bigint') {\n const size = (at(step) as bigint) > 0n ? (at(step) as bigint) : 1n;\n const base = min == null ? 0n : (at(min) as bigint);\n const offset = (at(value) as bigint) - base;\n // 整数除法四舍五入(远离 0)\n const half = offset < 0n ? -size : size;\n snapped = base + ((2n * offset + half) / (2n * size)) * size;\n } else {\n const base = (min == null ? new kind(0) : at(min)) as Decimal;\n const size = at(step) as Decimal;\n snapped = base.plus((at(value) as Decimal).minus(base).div(size).round().times(size));\n }\n if (min != null && compareNumeric(snapped, min) < 0) snapped = at(min);\n if (max != null && compareNumeric(snapped, max) > 0) snapped = at(max);\n return snapped;\n}\n"],"mappings":"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"}
@@ -1,7 +1,14 @@
1
1
  /**
2
- * 把一段文字存成文件(浏览器下载):导出代码、CSV、SVG。
2
+ * 浏览器里存文件、挑文件:导出代码、CSV、SVG;导入一份 JSON、一张表。
3
3
  * 内容原样写入:给 Excel 打开的 CSV 要由调用方在开头加 BOM(`'\uFEFF' + csv`),中文才不乱码。
4
4
  *
5
5
  * downloadFile('theme.ts', code, 'text/typescript');
6
+ * const file = await pickFile('.json');
7
+ * if (file) importFrom(await file.text());
6
8
  */
7
9
  export declare function downloadFile(name: string, content: BlobPart, type: string): void;
10
+ /**
11
+ * 弹出系统的选文件对话框,挑一个文件;取消时为 null。要在用户的点击里调(浏览器只在用户操作时允许弹)。
12
+ * accept 同 input 的 accept(`.json`、`image/*`)。
13
+ */
14
+ export declare function pickFile(accept?: string): Promise<File | null>;
@@ -1,9 +1,11 @@
1
1
  //#region src/utils/dom/download.ts
2
2
  /**
3
- * 把一段文字存成文件(浏览器下载):导出代码、CSV、SVG。
3
+ * 浏览器里存文件、挑文件:导出代码、CSV、SVG;导入一份 JSON、一张表。
4
4
  * 内容原样写入:给 Excel 打开的 CSV 要由调用方在开头加 BOM(`'\uFEFF' + csv`),中文才不乱码。
5
5
  *
6
6
  * downloadFile('theme.ts', code, 'text/typescript');
7
+ * const file = await pickFile('.json');
8
+ * if (file) importFrom(await file.text());
7
9
  */
8
10
  function downloadFile(name, content, type) {
9
11
  const url = URL.createObjectURL(new Blob([content], { type }));
@@ -13,7 +15,22 @@ function downloadFile(name, content, type) {
13
15
  }).click();
14
16
  setTimeout(() => URL.revokeObjectURL(url), 4e4);
15
17
  }
18
+ /**
19
+ * 弹出系统的选文件对话框,挑一个文件;取消时为 null。要在用户的点击里调(浏览器只在用户操作时允许弹)。
20
+ * accept 同 input 的 accept(`.json`、`image/*`)。
21
+ */
22
+ function pickFile(accept) {
23
+ return new Promise((resolve) => {
24
+ const input = Object.assign(document.createElement("input"), {
25
+ type: "file",
26
+ ...accept ? { accept } : {}
27
+ });
28
+ input.addEventListener("change", () => resolve(input.files?.[0] ?? null), { once: true });
29
+ input.addEventListener("cancel", () => resolve(null), { once: true });
30
+ input.click();
31
+ });
32
+ }
16
33
  //#endregion
17
- export { downloadFile };
34
+ export { downloadFile, pickFile };
18
35
 
19
36
  //# sourceMappingURL=download.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","names":[],"sources":["../../../src/utils/dom/download.ts"],"sourcesContent":["/**\n * 把一段文字存成文件(浏览器下载):导出代码、CSV、SVG。\n * 内容原样写入:给 Excel 打开的 CSV 要由调用方在开头加 BOM(`'\\uFEFF' + csv`),中文才不乱码。\n *\n * downloadFile('theme.ts', code, 'text/typescript');\n */\nexport function downloadFile(name: string, content: BlobPart, type: string): void {\n const url = URL.createObjectURL(new Blob([content], { type }));\n const link = Object.assign(document.createElement('a'), { href: url, download: name });\n link.click();\n // 点击后浏览器才开始读这个地址:Safari、Firefox 里立即回收会让下载失败,过一会儿再回收(同 FileSaver.js)\n setTimeout(() => URL.revokeObjectURL(url), 40_000);\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,aAAa,MAAc,SAAmB,MAAoB;CAChF,MAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;CAE7D,OADoB,OAAO,SAAS,cAAc,GAAG,GAAG;EAAE,MAAM;EAAK,UAAU;CAAK,CACpF,CAAA,CAAK,MAAM;CAEX,iBAAiB,IAAI,gBAAgB,GAAG,GAAG,GAAM;AACnD"}
1
+ {"version":3,"file":"download.js","names":[],"sources":["../../../src/utils/dom/download.ts"],"sourcesContent":["/**\n * 浏览器里存文件、挑文件:导出代码、CSV、SVG;导入一份 JSON、一张表。\n * 内容原样写入:给 Excel 打开的 CSV 要由调用方在开头加 BOM(`'\\uFEFF' + csv`),中文才不乱码。\n *\n * downloadFile('theme.ts', code, 'text/typescript');\n * const file = await pickFile('.json');\n * if (file) importFrom(await file.text());\n */\nexport function downloadFile(name: string, content: BlobPart, type: string): void {\n const url = URL.createObjectURL(new Blob([content], { type }));\n const link = Object.assign(document.createElement('a'), { href: url, download: name });\n link.click();\n // 点击后浏览器才开始读这个地址:Safari、Firefox 里立即回收会让下载失败,过一会儿再回收(同 FileSaver.js)\n setTimeout(() => URL.revokeObjectURL(url), 40_000);\n}\n\n/**\n * 弹出系统的选文件对话框,挑一个文件;取消时为 null。要在用户的点击里调(浏览器只在用户操作时允许弹)。\n * accept 同 input 的 accept(`.json`、`image/*`)。\n */\nexport function pickFile(accept?: string): Promise<File | null> {\n return new Promise((resolve) => {\n const input = Object.assign(document.createElement('input'), {\n type: 'file',\n ...(accept ? { accept } : {}),\n });\n input.addEventListener('change', () => resolve(input.files?.[0] ?? null), { once: true });\n input.addEventListener('cancel', () => resolve(null), { once: true });\n input.click();\n });\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,aAAa,MAAc,SAAmB,MAAoB;CAChF,MAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;CAE7D,OADoB,OAAO,SAAS,cAAc,GAAG,GAAG;EAAE,MAAM;EAAK,UAAU;CAAK,CACpF,CAAA,CAAK,MAAM;CAEX,iBAAiB,IAAI,gBAAgB,GAAG,GAAG,GAAM;AACnD;;;;;AAMA,SAAgB,SAAS,QAAuC;CAC9D,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,OAAO,OAAO,SAAS,cAAc,OAAO,GAAG;GAC3D,MAAM;GACN,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC7B,CAAC;EACD,MAAM,iBAAiB,gBAAgB,QAAQ,MAAM,QAAQ,MAAM,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;EACxF,MAAM,iBAAiB,gBAAgB,QAAQ,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;EACpE,MAAM,MAAM;CACd,CAAC;AACH"}
@@ -1,3 +1,5 @@
1
- /** 模板 ref 的取值换成 DOM 元素 */
1
+ /** 模板 ref 的取值换成 DOM 元素;判断是不是元素(服务端渲染时没有 HTMLElement 这个全局,也能安全调用) */
2
+ /** 是不是 HTML 元素;服务端渲染时总是 false(直接写 `instanceof HTMLElement` 在服务端会抛 ReferenceError) */
3
+ export declare function isHTMLElement(value: unknown): value is HTMLElement;
2
4
  /** ref 落在组件上拿到的是组件实例,取它的根元素;本来就是元素时原样返回 */
3
5
  export declare function toElement(value: unknown): HTMLElement | null;
@@ -1,12 +1,16 @@
1
1
  //#region src/utils/dom/element.ts
2
- /** 模板 ref 的取值换成 DOM 元素 */
2
+ /** 模板 ref 的取值换成 DOM 元素;判断是不是元素(服务端渲染时没有 HTMLElement 这个全局,也能安全调用) */
3
+ /** 是不是 HTML 元素;服务端渲染时总是 false(直接写 `instanceof HTMLElement` 在服务端会抛 ReferenceError) */
4
+ function isHTMLElement(value) {
5
+ return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
6
+ }
3
7
  /** ref 落在组件上拿到的是组件实例,取它的根元素;本来就是元素时原样返回 */
4
8
  function toElement(value) {
5
- if (value instanceof HTMLElement) return value;
9
+ if (isHTMLElement(value)) return value;
6
10
  const root = value?.$el;
7
- return root instanceof HTMLElement ? root : null;
11
+ return isHTMLElement(root) ? root : null;
8
12
  }
9
13
  //#endregion
10
- export { toElement };
14
+ export { isHTMLElement, toElement };
11
15
 
12
16
  //# sourceMappingURL=element.js.map