@zerodep-dev/vue-tsx-pro-ui 0.2.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 (416) 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/config/Provider.d.ts +3 -1
  62. package/dist/config/Provider.js +9 -4
  63. package/dist/config/Provider.js.map +1 -1
  64. package/dist/config/context.d.ts +18 -0
  65. package/dist/config/context.js +16 -1
  66. package/dist/config/context.js.map +1 -1
  67. package/dist/config/createUi.d.ts +20 -3
  68. package/dist/config/createUi.js +80 -49
  69. package/dist/config/createUi.js.map +1 -1
  70. package/dist/config/layout/preference.d.ts +43 -0
  71. package/dist/config/layout/preference.js +108 -0
  72. package/dist/config/layout/preference.js.map +1 -0
  73. package/dist/date/Calendar.js +3 -3
  74. package/dist/date/Calendar.js.map +1 -1
  75. package/dist/date/CalendarBoard.js +9 -9
  76. package/dist/date/CalendarBoard.js.map +1 -1
  77. package/dist/date/CalendarView.js +7 -7
  78. package/dist/date/CalendarView.js.map +1 -1
  79. package/dist/date/DateField.js +3 -3
  80. package/dist/date/DateField.js.map +1 -1
  81. package/dist/date/DatePicker.js +5 -5
  82. package/dist/date/DatePicker.js.map +1 -1
  83. package/dist/date/DateRangePicker.js +5 -5
  84. package/dist/date/DateRangePicker.js.map +1 -1
  85. package/dist/date/DateSegmentGroup.js +5 -5
  86. package/dist/date/DateSegmentGroup.js.map +1 -1
  87. package/dist/date/QuarterCalendar.js +6 -6
  88. package/dist/date/QuarterCalendar.js.map +1 -1
  89. package/dist/date/RangeCalendar.js +3 -3
  90. package/dist/date/RangeCalendar.js.map +1 -1
  91. package/dist/date/SegmentedField.js +3 -3
  92. package/dist/date/SegmentedField.js.map +1 -1
  93. package/dist/date/TimeField.js +3 -3
  94. package/dist/date/TimeField.js.map +1 -1
  95. package/dist/date/TimePicker.js +4 -4
  96. package/dist/date/TimePicker.js.map +1 -1
  97. package/dist/date/date-segments.js +1 -1
  98. package/dist/date/date-segments.js.map +1 -1
  99. package/dist/date/picker-popover.js +3 -2
  100. package/dist/date/picker-popover.js.map +1 -1
  101. package/dist/diagram/Diagram.js +12 -12
  102. package/dist/diagram/Diagram.js.map +1 -1
  103. package/dist/diagram/DiagramLanes.js +3 -3
  104. package/dist/diagram/DiagramLanes.js.map +1 -1
  105. package/dist/diagram/DiagramMinimap.js +4 -4
  106. package/dist/diagram/DiagramMinimap.js.map +1 -1
  107. package/dist/display/Accordion.js +6 -6
  108. package/dist/display/Accordion.js.map +1 -1
  109. package/dist/display/AnimatedNumber.js +4 -4
  110. package/dist/display/AnimatedNumber.js.map +1 -1
  111. package/dist/display/Avatar.js +4 -4
  112. package/dist/display/Avatar.js.map +1 -1
  113. package/dist/display/Checklist.js +7 -7
  114. package/dist/display/Checklist.js.map +1 -1
  115. package/dist/display/Collapse.js +8 -5
  116. package/dist/display/Collapse.js.map +1 -1
  117. package/dist/display/Collapsible.js +3 -3
  118. package/dist/display/Collapsible.js.map +1 -1
  119. package/dist/display/Descriptions.js +5 -5
  120. package/dist/display/Descriptions.js.map +1 -1
  121. package/dist/display/Ellipsis.js +3 -3
  122. package/dist/display/Ellipsis.js.map +1 -1
  123. package/dist/display/FieldCompare.js +4 -4
  124. package/dist/display/FieldCompare.js.map +1 -1
  125. package/dist/display/Gauge.js +11 -11
  126. package/dist/display/Gauge.js.map +1 -1
  127. package/dist/display/Image.js +4 -4
  128. package/dist/display/Image.js.map +1 -1
  129. package/dist/display/Marquee.js +3 -3
  130. package/dist/display/Marquee.js.map +1 -1
  131. package/dist/display/ProportionBar.js +4 -4
  132. package/dist/display/ProportionBar.js.map +1 -1
  133. package/dist/display/Sortable.js +4 -4
  134. package/dist/display/Sortable.js.map +1 -1
  135. package/dist/display/Sparkline.js +6 -6
  136. package/dist/display/Sparkline.js.map +1 -1
  137. package/dist/display/Stat.js +3 -3
  138. package/dist/display/Stat.js.map +1 -1
  139. package/dist/display/Timeline.js +7 -7
  140. package/dist/display/Timeline.js.map +1 -1
  141. package/dist/display/Tree.js +10 -10
  142. package/dist/display/Tree.js.map +1 -1
  143. package/dist/display/VirtualList.js +7 -7
  144. package/dist/display/VirtualList.js.map +1 -1
  145. package/dist/display/Watermark.js +3 -3
  146. package/dist/display/Watermark.js.map +1 -1
  147. package/dist/docs-kit/CodeGroup.js +5 -5
  148. package/dist/docs-kit/CodeGroup.js.map +1 -1
  149. package/dist/docs-kit/CodePreview.js +6 -6
  150. package/dist/docs-kit/CodePreview.js.map +1 -1
  151. package/dist/docs-kit/PropsTable.js +4 -4
  152. package/dist/docs-kit/PropsTable.js.map +1 -1
  153. package/dist/feedback/Alert.js +5 -5
  154. package/dist/feedback/Alert.js.map +1 -1
  155. package/dist/feedback/Banner.js +5 -5
  156. package/dist/feedback/Banner.js.map +1 -1
  157. package/dist/feedback/Empty.js +4 -4
  158. package/dist/feedback/Empty.js.map +1 -1
  159. package/dist/feedback/LoadingBar.js +20 -13
  160. package/dist/feedback/LoadingBar.js.map +1 -1
  161. package/dist/feedback/LoadingOverlay.js +3 -3
  162. package/dist/feedback/LoadingOverlay.js.map +1 -1
  163. package/dist/feedback/Progress.js +14 -14
  164. package/dist/feedback/Progress.js.map +1 -1
  165. package/dist/feedback/Result.js +4 -4
  166. package/dist/feedback/Result.js.map +1 -1
  167. package/dist/feedback/SkeletonText.js +3 -3
  168. package/dist/feedback/SkeletonText.js.map +1 -1
  169. package/dist/feedback/Toast.js +6 -6
  170. package/dist/feedback/Toast.js.map +1 -1
  171. package/dist/form/Field.js +7 -7
  172. package/dist/form/Field.js.map +1 -1
  173. package/dist/form/Form.js +3 -3
  174. package/dist/form/Form.js.map +1 -1
  175. package/dist/form/FormErrorSummary.js +3 -3
  176. package/dist/form/FormErrorSummary.js.map +1 -1
  177. package/dist/form/FormSection.js +6 -6
  178. package/dist/form/FormSection.js.map +1 -1
  179. package/dist/index.d.ts +11 -6
  180. package/dist/index.js +10 -5
  181. package/dist/input/Autocomplete.js +3 -3
  182. package/dist/input/Autocomplete.js.map +1 -1
  183. package/dist/input/Cascader.js +7 -7
  184. package/dist/input/Cascader.js.map +1 -1
  185. package/dist/input/CharacterCount.js +3 -3
  186. package/dist/input/CharacterCount.js.map +1 -1
  187. package/dist/input/Checkbox.js +5 -5
  188. package/dist/input/Checkbox.js.map +1 -1
  189. package/dist/input/ColorField.js +4 -4
  190. package/dist/input/ColorField.js.map +1 -1
  191. package/dist/input/Combobox.js +4 -4
  192. package/dist/input/Combobox.js.map +1 -1
  193. package/dist/input/ConditionBuilder.js +15 -14
  194. package/dist/input/ConditionBuilder.js.map +1 -1
  195. package/dist/input/FileDrop.js +3 -3
  196. package/dist/input/FileDrop.js.map +1 -1
  197. package/dist/input/Listbox.js +9 -9
  198. package/dist/input/Listbox.js.map +1 -1
  199. package/dist/input/Mentions.js +3 -3
  200. package/dist/input/Mentions.js.map +1 -1
  201. package/dist/input/NumberField.js +3 -3
  202. package/dist/input/NumberField.js.map +1 -1
  203. package/dist/input/NumberRangeField.js +5 -5
  204. package/dist/input/NumberRangeField.js.map +1 -1
  205. package/dist/input/OtpField.js +5 -5
  206. package/dist/input/OtpField.js.map +1 -1
  207. package/dist/input/PeoplePicker.js +6 -6
  208. package/dist/input/PeoplePicker.js.map +1 -1
  209. package/dist/input/PeoplePickerPanel.js +4 -4
  210. package/dist/input/PeoplePickerPanel.js.map +1 -1
  211. package/dist/input/Radio.js +4 -4
  212. package/dist/input/Radio.js.map +1 -1
  213. package/dist/input/Rating.js +5 -5
  214. package/dist/input/Rating.js.map +1 -1
  215. package/dist/input/Select.js +4 -4
  216. package/dist/input/Select.js.map +1 -1
  217. package/dist/input/SelectedTags.js +4 -4
  218. package/dist/input/SelectedTags.js.map +1 -1
  219. package/dist/input/Slider.js +6 -6
  220. package/dist/input/Slider.js.map +1 -1
  221. package/dist/input/Switch.js +3 -3
  222. package/dist/input/Switch.js.map +1 -1
  223. package/dist/input/TagsInput.js +5 -5
  224. package/dist/input/TagsInput.js.map +1 -1
  225. package/dist/input/TextField.js +5 -5
  226. package/dist/input/TextField.js.map +1 -1
  227. package/dist/input/Textarea.js +4 -4
  228. package/dist/input/Textarea.js.map +1 -1
  229. package/dist/input/ToggleGroup.js +4 -4
  230. package/dist/input/ToggleGroup.js.map +1 -1
  231. package/dist/input/Transfer.js +8 -8
  232. package/dist/input/Transfer.js.map +1 -1
  233. package/dist/input/TreeSelect.js +6 -6
  234. package/dist/input/TreeSelect.js.map +1 -1
  235. package/dist/input/Upload.js +8 -8
  236. package/dist/input/Upload.js.map +1 -1
  237. package/dist/layout/Affix.js +4 -4
  238. package/dist/layout/Affix.js.map +1 -1
  239. package/dist/layout/ResizeHandle.d.ts +6 -2
  240. package/dist/layout/ResizeHandle.js +32 -9
  241. package/dist/layout/ResizeHandle.js.map +1 -1
  242. package/dist/layout/ScrollArea.js +3 -3
  243. package/dist/layout/ScrollArea.js.map +1 -1
  244. package/dist/layout/Separator.js +3 -3
  245. package/dist/layout/Separator.js.map +1 -1
  246. package/dist/layout/Splitter.js +3 -3
  247. package/dist/layout/Splitter.js.map +1 -1
  248. package/dist/layout/ViewportFill.d.ts +2 -2
  249. package/dist/layout/ViewportFill.js +4 -4
  250. package/dist/layout/ViewportFill.js.map +1 -1
  251. package/dist/navigation/Breadcrumbs.js +4 -4
  252. package/dist/navigation/Breadcrumbs.js.map +1 -1
  253. package/dist/navigation/NavBar.js +6 -6
  254. package/dist/navigation/NavBar.js.map +1 -1
  255. package/dist/navigation/NavList.d.ts +1 -0
  256. package/dist/navigation/NavList.js +20 -12
  257. package/dist/navigation/NavList.js.map +1 -1
  258. package/dist/navigation/NavMenu.d.ts +27 -0
  259. package/dist/navigation/NavMenu.js +54 -0
  260. package/dist/navigation/NavMenu.js.map +1 -0
  261. package/dist/navigation/PageJump.js +3 -3
  262. package/dist/navigation/PageJump.js.map +1 -1
  263. package/dist/navigation/PageSizeSelect.js +4 -4
  264. package/dist/navigation/PageSizeSelect.js.map +1 -1
  265. package/dist/navigation/Pagination.js +6 -6
  266. package/dist/navigation/Pagination.js.map +1 -1
  267. package/dist/navigation/PaginationBar.js +5 -5
  268. package/dist/navigation/PaginationBar.js.map +1 -1
  269. package/dist/navigation/Steps.js +4 -4
  270. package/dist/navigation/Steps.js.map +1 -1
  271. package/dist/navigation/TableOfContents.js +5 -5
  272. package/dist/navigation/TableOfContents.js.map +1 -1
  273. package/dist/navigation/Tabs.js +7 -7
  274. package/dist/navigation/Tabs.js.map +1 -1
  275. package/dist/navigation/Toolbar.js +3 -3
  276. package/dist/navigation/Toolbar.js.map +1 -1
  277. package/dist/overlay/AlertDialog.js +4 -4
  278. package/dist/overlay/AlertDialog.js.map +1 -1
  279. package/dist/overlay/CommandPalette.js +4 -4
  280. package/dist/overlay/CommandPalette.js.map +1 -1
  281. package/dist/overlay/ContextMenu.js +3 -3
  282. package/dist/overlay/ContextMenu.js.map +1 -1
  283. package/dist/overlay/Dialog.js +4 -4
  284. package/dist/overlay/Dialog.js.map +1 -1
  285. package/dist/overlay/Drawer.js +5 -5
  286. package/dist/overlay/Drawer.js.map +1 -1
  287. package/dist/overlay/HoverCard.js +5 -3
  288. package/dist/overlay/HoverCard.js.map +1 -1
  289. package/dist/overlay/Lightbox.js +5 -5
  290. package/dist/overlay/Lightbox.js.map +1 -1
  291. package/dist/overlay/Menu.js +7 -7
  292. package/dist/overlay/Menu.js.map +1 -1
  293. package/dist/overlay/ModalCore.js +9 -9
  294. package/dist/overlay/ModalCore.js.map +1 -1
  295. package/dist/overlay/Popconfirm.js +6 -6
  296. package/dist/overlay/Popconfirm.js.map +1 -1
  297. package/dist/overlay/Popover.js +5 -3
  298. package/dist/overlay/Popover.js.map +1 -1
  299. package/dist/overlay/Tooltip.js +5 -3
  300. package/dist/overlay/Tooltip.js.map +1 -1
  301. package/dist/overlay/Tour.js +8 -8
  302. package/dist/overlay/Tour.js.map +1 -1
  303. package/dist/overlay/detached.d.ts +2 -0
  304. package/dist/overlay/detached.js +73 -42
  305. package/dist/overlay/detached.js.map +1 -1
  306. package/dist/patterns/ActionBar.js +3 -3
  307. package/dist/patterns/ActionBar.js.map +1 -1
  308. package/dist/patterns/AppShell.d.ts +28 -1
  309. package/dist/patterns/AppShell.js +158 -52
  310. package/dist/patterns/AppShell.js.map +1 -1
  311. package/dist/patterns/AuthLayout.d.ts +28 -0
  312. package/dist/patterns/AuthLayout.js +77 -0
  313. package/dist/patterns/AuthLayout.js.map +1 -0
  314. package/dist/patterns/CommentThread.js +9 -9
  315. package/dist/patterns/CommentThread.js.map +1 -1
  316. package/dist/patterns/DataImport.js +4 -4
  317. package/dist/patterns/DataImport.js.map +1 -1
  318. package/dist/patterns/DeadlineBadge.js +3 -3
  319. package/dist/patterns/DeadlineBadge.js.map +1 -1
  320. package/dist/patterns/FilterBar.d.ts +11 -1
  321. package/dist/patterns/FilterBar.js +39 -10
  322. package/dist/patterns/FilterBar.js.map +1 -1
  323. package/dist/patterns/FormDialog.d.ts +18 -0
  324. package/dist/patterns/FormDialog.js +46 -0
  325. package/dist/patterns/FormDialog.js.map +1 -0
  326. package/dist/patterns/KanbanBoard.js +8 -8
  327. package/dist/patterns/KanbanBoard.js.map +1 -1
  328. package/dist/patterns/LayoutSwitcher.d.ts +12 -0
  329. package/dist/patterns/LayoutSwitcher.js +79 -0
  330. package/dist/patterns/LayoutSwitcher.js.map +1 -0
  331. package/dist/patterns/NotificationCenter.js +8 -8
  332. package/dist/patterns/NotificationCenter.js.map +1 -1
  333. package/dist/patterns/PageTabs.d.ts +12 -7
  334. package/dist/patterns/PageTabs.js +41 -29
  335. package/dist/patterns/PageTabs.js.map +1 -1
  336. package/dist/patterns/QueryTable.d.ts +7 -1
  337. package/dist/patterns/QueryTable.js +116 -81
  338. package/dist/patterns/QueryTable.js.map +1 -1
  339. package/dist/patterns/SlideCaptcha.d.ts +80 -0
  340. package/dist/patterns/SlideCaptcha.js +354 -0
  341. package/dist/patterns/SlideCaptcha.js.map +1 -0
  342. package/dist/patterns/StepsForm.js +7 -7
  343. package/dist/patterns/StepsForm.js.map +1 -1
  344. package/dist/patterns/ThemeSwitcher.js +3 -3
  345. package/dist/patterns/ThemeSwitcher.js.map +1 -1
  346. package/dist/patterns/index.d.ts +7 -3
  347. package/dist/patterns/index.js +5 -1
  348. package/dist/patterns/messages.d.ts +37 -1
  349. package/dist/patterns/messages.js +38 -2
  350. package/dist/patterns/messages.js.map +1 -1
  351. package/dist/table/ColumnHeaderActions.js +3 -3
  352. package/dist/table/ColumnHeaderActions.js.map +1 -1
  353. package/dist/table/ColumnResizer.js +3 -3
  354. package/dist/table/ColumnResizer.js.map +1 -1
  355. package/dist/table/ColumnSettings.js +5 -5
  356. package/dist/table/ColumnSettings.js.map +1 -1
  357. package/dist/table/ColumnTable.js +8 -8
  358. package/dist/table/ColumnTable.js.map +1 -1
  359. package/dist/table/DataTable.js +8 -8
  360. package/dist/table/DataTable.js.map +1 -1
  361. package/dist/table/DataTableView.js +21 -21
  362. package/dist/table/DataTableView.js.map +1 -1
  363. package/dist/table/PivotTable.js +3 -3
  364. package/dist/table/PivotTable.js.map +1 -1
  365. package/dist/table/SelectionBar.js +4 -4
  366. package/dist/table/SelectionBar.js.map +1 -1
  367. package/dist/table/TreeDataTable.js +5 -5
  368. package/dist/table/TreeDataTable.js.map +1 -1
  369. package/dist/theme-customize/ThemeCustomizer.js +7 -6
  370. package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
  371. package/dist/theme-customize/ThemeThumbnail.js +3 -3
  372. package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
  373. package/dist/three/background/AuroraBackground.js +3 -3
  374. package/dist/three/background/AuroraBackground.js.map +1 -1
  375. package/dist/three/background/MeshGradient.js +3 -3
  376. package/dist/three/background/MeshGradient.js.map +1 -1
  377. package/dist/three/background/ShaderBackground.js +3 -3
  378. package/dist/three/background/ShaderBackground.js.map +1 -1
  379. package/dist/three/core/EffectSurface.js +3 -3
  380. package/dist/three/core/EffectSurface.js.map +1 -1
  381. package/dist/three/core/ThreeCanvas.js +4 -4
  382. package/dist/three/core/ThreeCanvas.js.map +1 -1
  383. package/dist/three/effects/Confetti.js +3 -3
  384. package/dist/three/effects/Confetti.js.map +1 -1
  385. package/dist/three/effects/ParticleField.js +3 -3
  386. package/dist/three/effects/ParticleField.js.map +1 -1
  387. package/dist/three/effects/WaveGrid.js +3 -3
  388. package/dist/three/effects/WaveGrid.js.map +1 -1
  389. package/dist/three/globe/Globe.js +3 -3
  390. package/dist/three/globe/Globe.js.map +1 -1
  391. package/dist/three/model/ModelViewer.js +3 -3
  392. package/dist/three/model/ModelViewer.js.map +1 -1
  393. package/dist/utils/data/number.d.ts +5 -0
  394. package/dist/utils/data/number.js +8 -1
  395. package/dist/utils/data/number.js.map +1 -1
  396. package/dist/utils/dom/element.d.ts +3 -1
  397. package/dist/utils/dom/element.js +8 -4
  398. package/dist/utils/dom/element.js.map +1 -1
  399. package/dist/utils/dom/fullscreen.d.ts +1 -1
  400. package/dist/utils/dom/fullscreen.js +12 -8
  401. package/dist/utils/dom/fullscreen.js.map +1 -1
  402. package/dist/utils/dom/mounted.d.ts +7 -0
  403. package/dist/utils/dom/mounted.js +16 -0
  404. package/dist/utils/dom/mounted.js.map +1 -0
  405. package/dist/utils/dom/overflow.js +2 -1
  406. package/dist/utils/dom/overflow.js.map +1 -1
  407. package/dist/utils/dom/pan-zoom.js +2 -1
  408. package/dist/utils/dom/pan-zoom.js.map +1 -1
  409. package/dist/utils/props.js +3 -13
  410. package/dist/utils/props.js.map +1 -1
  411. package/dist/utils/request/http.d.ts +12 -0
  412. package/dist/utils/request/http.js +6 -2
  413. package/dist/utils/request/http.js.map +1 -1
  414. package/dist/utils/request/use-request.js +4 -2
  415. package/dist/utils/request/use-request.js.map +1 -1
  416. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"Steps.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/navigation/Steps.tsx"],"sourcesContent":["/**\n * 步骤条(ol):多步流程里的位置(下单、注册、配置向导、任务的流转)。当前步骤带 aria-current=\"step\",\n * 已完成的步骤显示对勾(Lucide 的 Check),出错的步骤显示警示图标;已完成、未开始、出错另有读屏文字,不只靠颜色。\n *\n * <Steps current={1} items={[{ title: '填写信息' }, { title: '确认订单' }, { title: '完成' }]} />\n * <Steps _current={step} items={items} navigable /> 已完成的步骤可以点回去\n * <Steps current={2} items={[{ title: '概览', href: '/task/1' }, …]} /> 已完成的步骤是链接\n *\n * 每一步的状态默认按 current 推出(之前已完成、当前、之后未开始),item 的 status 可以改:出错的一步、非线性的流程。\n */\nimport { Check } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { Icon, type IconData } from '../base/Icon';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useRouterLink } from '../utils/dom/link';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { statusIcons } from '../utils/style/tone-styles';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { FlexOrderedList, type FlexProps } from '../layout/Flex';\nimport { t } from '../config/theme/tokens';\n\n/** 步骤条方向 */\nexport interface StepsOrientations {\n /** 横排(默认) */\n horizontal: unknown;\n /** 竖排:步骤多、说明长时;步骤之间有竖的连接线 */\n vertical: unknown;\n}\n\n/** 步骤的状态 */\nexport interface StepStates {\n /** 已完成:对勾、品牌色 */\n complete: unknown;\n /** 当前:aria-current=\"step\" */\n current: unknown;\n /** 未开始 */\n upcoming: unknown;\n /** 出错:警示图标、危险色 */\n error: unknown;\n}\n\n/** 步骤的状态:已完成、当前、未开始、出错 */\nexport type StepState = keyof StepStates;\n\n/** 一个步骤 */\nexport interface StepItem {\n /** 唯一的 key;不写时用位置 */\n key?: string;\n /** 标题 */\n title: VNodeChild;\n /** 说明(标题下面的小字) */\n description?: VNodeChild;\n /** 代替序号的图标;已完成时仍显示对勾,出错时仍显示警示图标 */\n icon?: IconData;\n /** 状态;不写时按 current 推出 */\n status?: StepState;\n /** 地址:已完成的这一步渲染成链接(走路由适配),点了跳过去 */\n href?: string;\n /** 不可点回(即使已完成、有 href 或 navigable) */\n disabled?: boolean;\n}\n\n/** 未声明的属性落到 ol 上;aria-label 是步骤条的名称 */\nexport interface StepsProps extends PartProps<'ol'> {\n /** 步骤 */\n items: readonly StepItem[];\n /** 当前步骤的序号,从 0 开始:父级可以写 _current={x},配合 navigable 点回已完成的步骤 */\n _current?: number;\n /** 方向,默认 horizontal */\n orientation?: keyof StepsOrientations;\n /** 字号档位:圆圈、文字随之缩放;不写时继承上下文字号 */\n size?: TextSize;\n /** 已完成的步骤可以点击回去:点了写回 current */\n navigable?: boolean;\n /** 每个步骤(li)的部件属性,可以按项计算 */\n propsItem?: PartProps<'li'> | ((item: StepItem, index: number) => PartProps<'li'>);\n /** 序号圆圈的部件属性 */\n propsIndicator?: PartProps<'span'>;\n /** 可点回的步骤外层(按钮,或有 href 时的链接)的部件属性 */\n propsTrigger?: Partial<ButtonBaseProps> & PartProps<'a'>;\n /** 文字区(标题与说明的容器)的部件属性 */\n propsText?: PartProps<'span'>;\n /** 标题的部件属性 */\n propsTitle?: PartProps<'span'>;\n /** 说明的部件属性 */\n propsDescription?: PartProps<'span'>;\n /** 步骤之间连接线的部件属性 */\n propsConnector?: PartProps<'span'>;\n}\n\n/** Steps 的样式:item、itemVertical、trigger、link、indicator、text、title、description、connector 等 */\nexport const stepsStyles = css.create({\n item: {\n display: 'flex',\n flexGrow: 1,\n flexBasis: 0,\n alignItems: 'flex-start',\n gap: '_sm',\n minWidth: 0,\n },\n // 竖排:高度随内容,连接线相对这一项定位\n itemVertical: { flexGrow: 0, flexBasis: 'auto', position: 'relative' },\n // 可点回的步骤:整块是按钮或链接\n // 去掉按钮默认外观、焦点环、波纹由 ButtonBase 给出\n trigger: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: '_sm',\n borderRadius: '_sm',\n textAlign: 'start',\n },\n link: { color: 'inherit', textDecorationLine: 'none' },\n indicator: {\n boxSizing: 'border-box',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n width: '2em',\n height: '2em',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderRadius: '_full',\n // 用 em 而不是 _sm(默认字号下 13 / 14 ≈ 0.93):随 size 缩放\n fontSize: '0.93em',\n fontWeight: '_semibold',\n // 走到下一步时圆圈换色、连接线变色都过渡,不是一下跳过去\n transition: `background-color ${t.durations.md} ${t.easings.standard}, border-color ${t.durations.md} ${t.easings.standard}, color ${t.durations.md} ${t.easings.standard}`,\n },\n text: { display: 'grid', gap: '_xs', paddingTop: '0.3em', minWidth: 0 },\n title: { fontWeight: '_medium' },\n description: { color: '_textMuted', fontSize: '0.93em' },\n // 步骤之间的连接线:横排在标题右侧延伸\n connector: {\n flexGrow: 1,\n alignSelf: 'center',\n minWidth: '_space.lg',\n height: '_borderWidths.xs',\n backgroundColor: '_border',\n transition: `background-color ${t.durations.md} ${t.easings.standard}`,\n },\n // 竖排:从圆圈下面一直连到下一步的圆圈(圆圈宽 2 × 0.93em,中线在 0.93em)\n connectorVertical: {\n position: 'absolute',\n insetInlineStart: '0.93em',\n insetBlockStart: `calc(1.86em + ${t.space.xs})`,\n insetBlockEnd: `calc(-1 * ${t.space.lg} + ${t.space.xs})`,\n width: '_borderWidths.xs',\n height: 'auto',\n minWidth: 0,\n // 两端都定了位置时按 align-self 对齐:横排的 center 会让空的 span 缩成 0 高,这里要拉伸\n alignSelf: 'stretch',\n marginInlineStart: `calc(${t.borderWidths.xs} / -2)`,\n },\n connectorDone: { backgroundColor: '_accent' },\n});\n\n/** Steps 的样式:complete、current、upcoming、error */\nexport const stepsStateStyles = css.create({\n complete: { borderColor: '_accent', backgroundColor: '_accent', color: '_accentContrast' },\n current: { borderColor: '_accent', color: '_accentText' },\n upcoming: { borderColor: '_border', color: '_textMuted' },\n error: { borderColor: '_danger', backgroundColor: '_dangerSoft', color: '_dangerText' },\n});\n\n/** 步骤条:已完成、当前、未开始、出错;已完成的步骤可以点回去或是链接 */\nexport const Steps = _component(\n ({\n items,\n _current: current = _bindable(0),\n orientation = 'horizontal',\n size,\n navigable = false,\n propsItem,\n propsIndicator,\n propsTrigger,\n propsText,\n propsTitle,\n propsDescription,\n propsConnector,\n ...rest\n }: StepsProps) => {\n const lang = useLang();\n const router = useRouterLink();\n return () => {\n const vertical = orientation === 'vertical';\n return (\n <FlexOrderedList\n {...mergePartProps<FlexProps<'ol'>>(\n {\n direction: vertical ? 'column' : 'row',\n gap: vertical ? 'lg' : 'sm',\n sx: size && fontSizeStyles[size],\n },\n rest,\n )}\n data-orientation={orientation}\n >\n {items.map((item, index) => {\n const state: StepState =\n item.status ??\n (index < current ? 'complete' : index === current ? 'current' : 'upcoming');\n const own = typeof propsItem === 'function' ? propsItem(item, index) : propsItem;\n const content = [\n <span\n {...mergeAttrs<'span'>({ sx: stepsStyles.indicator }, propsIndicator, {\n sx: stepsStateStyles[state],\n 'aria-hidden': true,\n })}\n >\n {state === 'complete' ? (\n <Icon icon={Check} />\n ) : state === 'error' ? (\n <Icon icon={statusIcons.danger} />\n ) : item.icon ? (\n <Icon icon={item.icon} />\n ) : (\n index + 1\n )}\n </span>,\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.text }, propsText)}>\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.title }, propsTitle)}>\n {item.title}\n {/* 当前步骤由 aria-current 念出,其余的状态补一句文字:不只靠颜色与图标 */}\n {state !== 'current' && <VisuallyHidden>{lang.stepState(state)}</VisuallyHidden>}\n </span>\n {item.description != null && (\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.description }, propsDescription)}>\n {item.description}\n </span>\n )}\n </span>,\n ];\n const reachable = state === 'complete' && !item.disabled;\n const link = reachable && item.href != null;\n const button = reachable && !link && navigable;\n return (\n <li\n key={item.key ?? index}\n {...mergeAttrs<'li'>(\n { sx: [stepsStyles.item, vertical && stepsStyles.itemVertical] },\n own,\n { 'aria-current': state === 'current' ? 'step' : undefined },\n )}\n data-state={state}\n >\n {link ? (\n <a\n {...mergeAttrs<'a'>(\n { sx: [stepsStyles.trigger, stepsStyles.link, focusRingStyles.visible] },\n propsTrigger,\n {\n href: router.href(item.href!),\n onClick: (event: MouseEvent) => router.onClick(event, item.href!),\n },\n )}\n >\n {content}\n </a>\n ) : button ? (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>({ sx: stepsStyles.trigger }, propsTrigger, {\n onClick: () => (current = index),\n })}\n >\n {content}\n </ButtonBase>\n ) : (\n content\n )}\n {index < items.length - 1 && (\n <span\n {...mergeAttrs<'span'>(\n { sx: [stepsStyles.connector, vertical && stepsStyles.connectorVertical] },\n propsConnector,\n {\n sx: state === 'complete' && stepsStyles.connectorDone,\n 'aria-hidden': true,\n },\n )}\n />\n )}\n </li>\n );\n })}\n </FlexOrderedList>\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"Steps.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/navigation/Steps.tsx"],"sourcesContent":["/**\n * 步骤条(ol):多步流程里的位置(下单、注册、配置向导、任务的流转)。当前步骤带 aria-current=\"step\",\n * 已完成的步骤显示对勾(Lucide 的 Check),出错的步骤显示警示图标;已完成、未开始、出错另有读屏文字,不只靠颜色。\n *\n * <Steps current={1} items={[{ title: '填写信息' }, { title: '确认订单' }, { title: '完成' }]} />\n * <Steps _current={step} items={items} navigable /> 已完成的步骤可以点回去\n * <Steps current={2} items={[{ title: '概览', href: '/task/1' }, …]} /> 已完成的步骤是链接\n *\n * 每一步的状态默认按 current 推出(之前已完成、当前、之后未开始),item 的 status 可以改:出错的一步、非线性的流程。\n */\nimport { Check } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { Icon, type IconData } from '../base/Icon';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useRouterLink } from '../utils/dom/link';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { statusIcons } from '../utils/style/tone-styles';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { FlexOrderedList, type FlexProps } from '../layout/Flex';\nimport { t } from '../config/theme/tokens';\n\n/** 步骤条方向 */\nexport interface StepsOrientations {\n /** 横排(默认) */\n horizontal: unknown;\n /** 竖排:步骤多、说明长时;步骤之间有竖的连接线 */\n vertical: unknown;\n}\n\n/** 步骤的状态 */\nexport interface StepStates {\n /** 已完成:对勾、品牌色 */\n complete: unknown;\n /** 当前:aria-current=\"step\" */\n current: unknown;\n /** 未开始 */\n upcoming: unknown;\n /** 出错:警示图标、危险色 */\n error: unknown;\n}\n\n/** 步骤的状态:已完成、当前、未开始、出错 */\nexport type StepState = keyof StepStates;\n\n/** 一个步骤 */\nexport interface StepItem {\n /** 唯一的 key;不写时用位置 */\n key?: string;\n /** 标题 */\n title: VNodeChild;\n /** 说明(标题下面的小字) */\n description?: VNodeChild;\n /** 代替序号的图标;已完成时仍显示对勾,出错时仍显示警示图标 */\n icon?: IconData;\n /** 状态;不写时按 current 推出 */\n status?: StepState;\n /** 地址:已完成的这一步渲染成链接(走路由适配),点了跳过去 */\n href?: string;\n /** 不可点回(即使已完成、有 href 或 navigable) */\n disabled?: boolean;\n}\n\n/** 未声明的属性落到 ol 上;aria-label 是步骤条的名称 */\nexport interface StepsProps extends PartProps<'ol'> {\n /** 步骤 */\n items: readonly StepItem[];\n /** 当前步骤的序号,从 0 开始:父级可以写 _current={x},配合 navigable 点回已完成的步骤 */\n _current?: number;\n /** 方向,默认 horizontal */\n orientation?: keyof StepsOrientations;\n /** 字号档位:圆圈、文字随之缩放;不写时继承上下文字号 */\n size?: TextSize;\n /** 已完成的步骤可以点击回去:点了写回 current */\n navigable?: boolean;\n /** 每个步骤(li)的部件属性,可以按项计算 */\n propsItem?: PartProps<'li'> | ((item: StepItem, index: number) => PartProps<'li'>);\n /** 序号圆圈的部件属性 */\n propsIndicator?: PartProps<'span'>;\n /** 可点回的步骤外层(按钮,或有 href 时的链接)的部件属性 */\n propsTrigger?: Partial<ButtonBaseProps> & PartProps<'a'>;\n /** 文字区(标题与说明的容器)的部件属性 */\n propsText?: PartProps<'span'>;\n /** 标题的部件属性 */\n propsTitle?: PartProps<'span'>;\n /** 说明的部件属性 */\n propsDescription?: PartProps<'span'>;\n /** 步骤之间连接线的部件属性 */\n propsConnector?: PartProps<'span'>;\n}\n\n/** Steps 的样式:item、itemVertical、trigger、link、indicator、text、title、description、connector 等 */\nexport const stepsStyles = css.create({\n item: {\n display: 'flex',\n flexGrow: 1,\n flexBasis: 0,\n alignItems: 'flex-start',\n gap: '_sm',\n minWidth: 0,\n },\n // 竖排:高度随内容,连接线相对这一项定位\n itemVertical: { flexGrow: 0, flexBasis: 'auto', position: 'relative' },\n // 可点回的步骤:整块是按钮或链接\n // 去掉按钮默认外观、焦点环、波纹由 ButtonBase 给出\n trigger: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: '_sm',\n borderRadius: '_sm',\n textAlign: 'start',\n },\n link: { color: 'inherit', textDecorationLine: 'none' },\n indicator: {\n boxSizing: 'border-box',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n width: '2em',\n height: '2em',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderRadius: '_full',\n // 用 em 而不是 _sm(默认字号下 13 / 14 ≈ 0.93):随 size 缩放\n fontSize: '0.93em',\n fontWeight: '_semibold',\n // 走到下一步时圆圈换色、连接线变色都过渡,不是一下跳过去\n transition: `background-color ${t.durations.md} ${t.easings.standard}, border-color ${t.durations.md} ${t.easings.standard}, color ${t.durations.md} ${t.easings.standard}`,\n },\n text: { display: 'grid', gap: '_xs', paddingTop: '0.3em', minWidth: 0 },\n title: { fontWeight: '_medium' },\n description: { color: '_textMuted', fontSize: '0.93em' },\n // 步骤之间的连接线:横排在标题右侧延伸\n connector: {\n flexGrow: 1,\n alignSelf: 'center',\n minWidth: '_space.lg',\n height: '_borderWidths.xs',\n backgroundColor: '_border',\n transition: `background-color ${t.durations.md} ${t.easings.standard}`,\n },\n // 竖排:从圆圈下面一直连到下一步的圆圈(圆圈宽 2 × 0.93em,中线在 0.93em)\n connectorVertical: {\n position: 'absolute',\n insetInlineStart: '0.93em',\n insetBlockStart: `calc(1.86em + ${t.space.xs})`,\n insetBlockEnd: `calc(-1 * ${t.space.lg} + ${t.space.xs})`,\n width: '_borderWidths.xs',\n height: 'auto',\n minWidth: 0,\n // 两端都定了位置时按 align-self 对齐:横排的 center 会让空的 span 缩成 0 高,这里要拉伸\n alignSelf: 'stretch',\n marginInlineStart: `calc(${t.borderWidths.xs} / -2)`,\n },\n connectorDone: { backgroundColor: '_accent' },\n});\n\n/** Steps 的样式:complete、current、upcoming、error */\nexport const stepsStateStyles = css.create({\n complete: { borderColor: '_accent', backgroundColor: '_accent', color: '_accentContrast' },\n current: { borderColor: '_accent', color: '_accentText' },\n upcoming: { borderColor: '_border', color: '_textMuted' },\n error: { borderColor: '_danger', backgroundColor: '_dangerSoft', color: '_dangerText' },\n});\n\n/** 步骤条:已完成、当前、未开始、出错;已完成的步骤可以点回去或是链接 */\nexport const Steps = _component(\n ({\n items,\n _current: current = _bindable(0),\n orientation = 'horizontal',\n size,\n navigable = false,\n propsItem,\n propsIndicator,\n propsTrigger,\n propsText,\n propsTitle,\n propsDescription,\n propsConnector,\n ...rest\n }: StepsProps) => {\n const lang = useLang();\n const router = useRouterLink();\n return () => {\n const vertical = orientation === 'vertical';\n return (\n <FlexOrderedList\n {...mergePartProps<FlexProps<'ol'>>(\n {\n direction: vertical ? 'column' : 'row',\n gap: vertical ? 'lg' : 'sm',\n sx: size && fontSizeStyles[size],\n },\n rest,\n )}\n data-orientation={orientation}\n >\n {items.map((item, index) => {\n const state: StepState =\n item.status ??\n (index < current ? 'complete' : index === current ? 'current' : 'upcoming');\n const own = typeof propsItem === 'function' ? propsItem(item, index) : propsItem;\n const content = [\n <span\n {...mergeAttrs<'span'>({ sx: stepsStyles.indicator }, propsIndicator, {\n sx: stepsStateStyles[state],\n 'aria-hidden': true,\n })}\n >\n {state === 'complete' ? (\n <Icon icon={Check} />\n ) : state === 'error' ? (\n <Icon icon={statusIcons.danger} />\n ) : item.icon ? (\n <Icon icon={item.icon} />\n ) : (\n index + 1\n )}\n </span>,\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.text }, propsText)}>\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.title }, propsTitle)}>\n {item.title}\n {/* 当前步骤由 aria-current 念出,其余的状态补一句文字:不只靠颜色与图标 */}\n {state !== 'current' && <VisuallyHidden>{lang.stepState(state)}</VisuallyHidden>}\n </span>\n {item.description != null && (\n <span {...mergeAttrs<'span'>({ sx: stepsStyles.description }, propsDescription)}>\n {item.description}\n </span>\n )}\n </span>,\n ];\n const reachable = state === 'complete' && !item.disabled;\n const link = reachable && item.href != null;\n const button = reachable && !link && navigable;\n return (\n <li\n key={item.key ?? index}\n {...mergeAttrs<'li'>(\n { sx: [stepsStyles.item, vertical && stepsStyles.itemVertical] },\n own,\n { 'aria-current': state === 'current' ? 'step' : undefined },\n )}\n data-state={state}\n >\n {link ? (\n <a\n {...mergeAttrs<'a'>(\n { sx: [stepsStyles.trigger, stepsStyles.link, focusRingStyles.visible] },\n propsTrigger,\n {\n href: router.href(item.href!),\n onClick: (event: MouseEvent) => router.onClick(event, item.href!),\n },\n )}\n >\n {content}\n </a>\n ) : button ? (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>({ sx: stepsStyles.trigger }, propsTrigger, {\n onClick: () => (current = index),\n })}\n >\n {content}\n </ButtonBase>\n ) : (\n content\n )}\n {index < items.length - 1 && (\n <span\n {...mergeAttrs<'span'>(\n { sx: [stepsStyles.connector, vertical && stepsStyles.connectorVertical] },\n propsConnector,\n {\n sx: state === 'complete' && stepsStyles.connectorDone,\n 'aria-hidden': true,\n },\n )}\n />\n )}\n </li>\n );\n })}\n </FlexOrderedList>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -7,8 +7,8 @@ import { Text as Text$1 } from "../base/Text.js";
7
7
  import { FlexList } from "../layout/Flex.js";
8
8
  import { useScrollSpy } from "../utils/dom/scroll-spy.js";
9
9
  import { useActiveIndicator } from "../utils/motion/active-indicator.js";
10
- import { createVNode, mergeProps, shallowRef, useId } from "vue";
11
- import { _component, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
10
+ import { createVNode, shallowRef, useId } from "vue";
11
+ import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
12
12
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
13
13
  //#region src/navigation/TableOfContents.tsx
14
14
  /** 未声明的属性落到 nav 上;原生的 title 属性(悬停提示)让给目录的标题 */
@@ -77,18 +77,18 @@ var TableOfContents = /*#__PURE__*/ _component((_props, _ctx) => {
77
77
  axis: "vertical",
78
78
  value: current.value
79
79
  }));
80
- return () => createVNode("nav", mergeAttrs({}, rest, { "aria-labelledby": titleId }), [createVNode(Text$1, mergeProps(mergePartProps({
80
+ return () => createVNode("nav", mergeAttrs({}, rest, { "aria-labelledby": titleId }), [createVNode(Text$1, mergeJsxProps(mergePartProps({
81
81
  sx: tableOfContentsStyles.title,
82
82
  size: "sm",
83
83
  weight: "semibold"
84
84
  }, propsTitle.value, { id: titleId }), { "key": "__site0" }), {
85
85
  default: () => [title.value ?? lang.tableOfContents],
86
86
  $stable: true
87
- }), createVNode(FlexList, mergeProps(mergePartProps({
87
+ }), createVNode(FlexList, mergeJsxProps(mergePartProps({
88
88
  sx: tableOfContentsStyles.list,
89
89
  direction: "column"
90
90
  }, propsList.value, { ref: (value) => list.value = toElement(value) }), { "key": "__site1" }), {
91
- default: () => [current.value !== void 0 && createVNode("span", mergeProps(mergeAttrs({ sx: tableOfContentsStyles.indicator }), {
91
+ default: () => [current.value !== void 0 && createVNode("span", mergeJsxProps(mergeAttrs({ sx: tableOfContentsStyles.indicator }), {
92
92
  "ref": indicator,
93
93
  "aria-hidden": "true"
94
94
  }), null), items.value.map((item) => createVNode("li", { "key": item.id }, [createVNode("a", mergeAttrs({ sx: [
@@ -1 +1 @@
1
- {"version":3,"file":"TableOfContents.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","Text","_mergeProps"],"sources":["../../src/navigation/TableOfContents.tsx"],"sourcesContent":["/**\n * 本页目录:列出页面的各节标题,滚动时高亮正在读的一节(useScrollSpy),侧边的指示条滑过去(useActiveIndicator)。\n *\n * <TableOfContents items={[{ id: 'install', label: '安装', level: 2 }, …]} />\n *\n * 目录项可以手写,也可以在页面渲染后用 collectHeadings(article) 从带 id 的标题收集。\n * 链接是普通的页内锚点(#install):标题的 scroll-margin 让开粘性顶栏(layoutVars.stickyOffset)。\n * 当前节的链接带 aria-current=\"location\"。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useId, type VNodeChild } from 'vue';\nimport { Text, type TextProps } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { FlexList, type FlexProps } from '../layout/Flex';\nimport { toElement } from '../utils/dom/element';\nimport { useScrollSpy, type HeadingEntry } from '../utils/dom/scroll-spy';\nimport { useActiveIndicator } from '../utils/motion/active-indicator';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { t } from '../config/theme/tokens';\n\n/** 未声明的属性落到 nav 上;原生的 title 属性(悬停提示)让给目录的标题 */\nexport interface TableOfContentsProps extends PartProps<'nav', 'aria-labelledby' | 'title'> {\n /** 目录项:标题的 id、文字与级别(2 级起,每深一级多缩进一档) */\n items: readonly HeadingEntry[];\n /** 目录的标题,同时是导航的名称;默认取语言包(本页目录) */\n title?: VNodeChild;\n /** 页面在哪个容器里滚动;不写时是窗口 */\n scrollRoot?: HTMLElement | null;\n /** 标题的部件属性 */\n propsTitle?: Partial<TextProps>;\n /** 列表(ul)的部件属性 */\n propsList?: Partial<FlexProps<'ul'>>;\n /** 链接的部件属性 */\n propsLink?: PartProps<'a'>;\n}\n\n/** TableOfContents 的样式:title、list、indicator、link、current */\nexport const tableOfContentsStyles = css.create({\n title: { display: 'block', marginBlockEnd: '_sm' },\n // 指示条按链接的 offsetTop 定位:列表是它的定位容器\n list: {\n position: 'relative',\n borderInlineStartWidth: '_xs',\n borderInlineStartStyle: 'solid',\n borderInlineStartColor: '_border',\n },\n indicator: {\n position: 'absolute',\n insetBlockStart: 0,\n insetInlineStart: 0,\n // 盖住列表左边的细线\n marginInlineStart: `calc(-1 * ${t.borderWidths.xs})`,\n width: '_borderWidths.sm',\n borderRadius: '_full',\n backgroundColor: '_accent',\n },\n link: {\n display: 'block',\n paddingBlock: '_xs',\n paddingInlineEnd: '_xs',\n borderRadius: '_xs',\n color: { default: '_textMuted', ':hover': '_text' },\n fontSize: '_sm',\n lineHeight: '_snug',\n textDecoration: 'none',\n transition: `color ${t.durations.sm} ${t.easings.standard}`,\n },\n current: { color: { default: '_accentText', ':hover': '_accentText' } },\n // 按级别缩进:2 级贴着细线留一档,往下每级多一档\n indent: (level: number) => ({ paddingInlineStart: `calc(${Math.max(level - 1, 1)} * 0.75em)` }),\n});\n\n/** 本页目录(nav):滚动时高亮当前节 */\nexport const TableOfContents = _component(\n ({\n items,\n title,\n scrollRoot,\n propsTitle,\n propsList,\n propsLink,\n ...rest\n }: TableOfContentsProps) => {\n const lang = useLang();\n const titleId = useId();\n let list = _state.raw<HTMLElement | null>(null);\n let indicator = _state.raw<HTMLElement | null>(null);\n const current = useScrollSpy(() => ({\n ids: items.map((item) => item.id),\n root: scrollRoot,\n }));\n useActiveIndicator(() => ({\n container: list,\n indicator,\n active: '[aria-current=\"location\"]',\n axis: 'vertical',\n value: current.value,\n }));\n\n return () => (\n <nav {...mergeAttrs<'nav'>({}, rest, { 'aria-labelledby': titleId })}>\n <Text\n {...mergePartProps<TextProps>(\n { sx: tableOfContentsStyles.title, size: 'sm', weight: 'semibold' },\n propsTitle,\n { id: titleId },\n )}\n >\n {title ?? lang.tableOfContents}\n </Text>\n <FlexList\n {...mergePartProps<FlexProps<'ul'>>(\n { sx: tableOfContentsStyles.list, direction: 'column' },\n propsList,\n { ref: (value: unknown) => (list = toElement(value)) },\n )}\n >\n {current.value !== undefined && (\n <span\n {...mergeAttrs<'span'>({ sx: tableOfContentsStyles.indicator })}\n ref={_toRef(indicator)}\n aria-hidden=\"true\"\n />\n )}\n {items.map((item) => (\n <li key={item.id}>\n <a\n {...mergeAttrs<'a'>(\n {\n sx: [\n tableOfContentsStyles.link,\n tableOfContentsStyles.indent(item.level),\n current.value === item.id && tableOfContentsStyles.current,\n focusRingStyles.visible,\n ],\n },\n propsLink,\n {\n href: `#${item.id}`,\n 'aria-current': current.value === item.id ? 'location' : undefined,\n },\n )}\n >\n {item.label}\n </a>\n </li>\n ))}\n </FlexList>\n </nav>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"TableOfContents.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","Text","_mergeProps"],"sources":["../../src/navigation/TableOfContents.tsx"],"sourcesContent":["/**\n * 本页目录:列出页面的各节标题,滚动时高亮正在读的一节(useScrollSpy),侧边的指示条滑过去(useActiveIndicator)。\n *\n * <TableOfContents items={[{ id: 'install', label: '安装', level: 2 }, …]} />\n *\n * 目录项可以手写,也可以在页面渲染后用 collectHeadings(article) 从带 id 的标题收集。\n * 链接是普通的页内锚点(#install):标题的 scroll-margin 让开粘性顶栏(layoutVars.stickyOffset)。\n * 当前节的链接带 aria-current=\"location\"。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useId, type VNodeChild } from 'vue';\nimport { Text, type TextProps } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { FlexList, type FlexProps } from '../layout/Flex';\nimport { toElement } from '../utils/dom/element';\nimport { useScrollSpy, type HeadingEntry } from '../utils/dom/scroll-spy';\nimport { useActiveIndicator } from '../utils/motion/active-indicator';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { t } from '../config/theme/tokens';\n\n/** 未声明的属性落到 nav 上;原生的 title 属性(悬停提示)让给目录的标题 */\nexport interface TableOfContentsProps extends PartProps<'nav', 'aria-labelledby' | 'title'> {\n /** 目录项:标题的 id、文字与级别(2 级起,每深一级多缩进一档) */\n items: readonly HeadingEntry[];\n /** 目录的标题,同时是导航的名称;默认取语言包(本页目录) */\n title?: VNodeChild;\n /** 页面在哪个容器里滚动;不写时是窗口 */\n scrollRoot?: HTMLElement | null;\n /** 标题的部件属性 */\n propsTitle?: Partial<TextProps>;\n /** 列表(ul)的部件属性 */\n propsList?: Partial<FlexProps<'ul'>>;\n /** 链接的部件属性 */\n propsLink?: PartProps<'a'>;\n}\n\n/** TableOfContents 的样式:title、list、indicator、link、current */\nexport const tableOfContentsStyles = css.create({\n title: { display: 'block', marginBlockEnd: '_sm' },\n // 指示条按链接的 offsetTop 定位:列表是它的定位容器\n list: {\n position: 'relative',\n borderInlineStartWidth: '_xs',\n borderInlineStartStyle: 'solid',\n borderInlineStartColor: '_border',\n },\n indicator: {\n position: 'absolute',\n insetBlockStart: 0,\n insetInlineStart: 0,\n // 盖住列表左边的细线\n marginInlineStart: `calc(-1 * ${t.borderWidths.xs})`,\n width: '_borderWidths.sm',\n borderRadius: '_full',\n backgroundColor: '_accent',\n },\n link: {\n display: 'block',\n paddingBlock: '_xs',\n paddingInlineEnd: '_xs',\n borderRadius: '_xs',\n color: { default: '_textMuted', ':hover': '_text' },\n fontSize: '_sm',\n lineHeight: '_snug',\n textDecoration: 'none',\n transition: `color ${t.durations.sm} ${t.easings.standard}`,\n },\n current: { color: { default: '_accentText', ':hover': '_accentText' } },\n // 按级别缩进:2 级贴着细线留一档,往下每级多一档\n indent: (level: number) => ({ paddingInlineStart: `calc(${Math.max(level - 1, 1)} * 0.75em)` }),\n});\n\n/** 本页目录(nav):滚动时高亮当前节 */\nexport const TableOfContents = _component(\n ({\n items,\n title,\n scrollRoot,\n propsTitle,\n propsList,\n propsLink,\n ...rest\n }: TableOfContentsProps) => {\n const lang = useLang();\n const titleId = useId();\n let list = _state.raw<HTMLElement | null>(null);\n let indicator = _state.raw<HTMLElement | null>(null);\n const current = useScrollSpy(() => ({\n ids: items.map((item) => item.id),\n root: scrollRoot,\n }));\n useActiveIndicator(() => ({\n container: list,\n indicator,\n active: '[aria-current=\"location\"]',\n axis: 'vertical',\n value: current.value,\n }));\n\n return () => (\n <nav {...mergeAttrs<'nav'>({}, rest, { 'aria-labelledby': titleId })}>\n <Text\n {...mergePartProps<TextProps>(\n { sx: tableOfContentsStyles.title, size: 'sm', weight: 'semibold' },\n propsTitle,\n { id: titleId },\n )}\n >\n {title ?? lang.tableOfContents}\n </Text>\n <FlexList\n {...mergePartProps<FlexProps<'ul'>>(\n { sx: tableOfContentsStyles.list, direction: 'column' },\n propsList,\n { ref: (value: unknown) => (list = toElement(value)) },\n )}\n >\n {current.value !== undefined && (\n <span\n {...mergeAttrs<'span'>({ sx: tableOfContentsStyles.indicator })}\n ref={_toRef(indicator)}\n aria-hidden=\"true\"\n />\n )}\n {items.map((item) => (\n <li key={item.id}>\n <a\n {...mergeAttrs<'a'>(\n {\n sx: [\n tableOfContentsStyles.link,\n tableOfContentsStyles.indent(item.level),\n current.value === item.id && tableOfContentsStyles.current,\n focusRingStyles.visible,\n ],\n },\n propsLink,\n {\n href: `#${item.id}`,\n 'aria-current': current.value === item.id ? 'location' : undefined,\n },\n )}\n >\n {item.label}\n </a>\n </li>\n ))}\n </FlexList>\n </nav>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;AAuCA,IAAa,wBAAwB,IAAI,OAAO;CAC9C,OAAO;EAAE,SAAS;EAAS,gBAAgB;CAAM;CAEjD,MAAM;EACJ,UAAU;EACV,wBAAwB;EACxB,wBAAwB;EACxB,wBAAwB;CAC1B;CACA,WAAW;EACT,UAAU;EACV,iBAAiB;EACjB,kBAAkB;EAElB,mBAAmB,aAAa,EAAE,aAAa,GAAE;EACjD,OAAO;EACP,cAAc;EACd,iBAAiB;CACnB;CACA,MAAM;EACJ,SAAS;EACT,cAAc;EACd,kBAAkB;EAClB,cAAc;EACd,OAAO;GAAE,SAAS;GAAc,UAAU;EAAQ;EAClD,UAAU;EACV,YAAY;EACZ,gBAAgB;EAChB,YAAY,SAAS,EAAE,UAAU,GAAE,GAAI,EAAE,QAAQ;CACnD;CACA,SAAS,EAAE,OAAO;EAAE,SAAS;EAAe,UAAU;CAAc,EAAE;CAEtE,SAAS,WAAmB,EAAE,oBAAoB,QAAQ,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAC,YAAa;AAC/F,CAAC;;AAGD,IAAa,kBAAkB,0BAC7B,QAAA,SAQ4B;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MADvB,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,UAAU,MAAM;CACtB,IAAI,OAAIC,WAAkC,IAAI;CAC9C,IAAI,YAASA,WAAkC,IAAI;CACnD,MAAM,UAAU,oBAAoB;EAClC,KAAK,MAAA,MAAM,KAAK,SAAS,KAAK,EAAE;EAChC,MAAI,WAAA;CACN,EAAE;CACF,0BAA0B;EACxB,WAAS,KAAA;EACT,WAAS,UAAA;EACT,QAAQ;EACR,MAAM;EACN,OAAO,QAAQ;CACjB,EAAE;CAEF,aAAOC,YAAA,OACI,WAAkB,CAAC,GAAG,MAAM,EAAE,mBAAmB,QAAQ,CAAC,GAAC,CAAAA,YAAAC,QAAAC,cAE5D,eACF;EAAE,IAAI,sBAAsB;EAAO,MAAM;EAAM,QAAQ;CAAW,GAAC,WAAA,OAEnE,EAAE,IAAI,QAAQ,CAChB,GAAC,EAAA,OAAA,UAAA,CAAA,GAAA;EAAA,eAAA,CAEA,MAAA,SAAS,KAAK,eAAe;EAAA,SAAA;CAAA,CAAA,GAAAF,YAAA,UAAAE,cAG1B,eACF;EAAE,IAAI,sBAAsB;EAAM,WAAW;CAAS,GAAC,UAAA,OAEvD,EAAE,MAAM,UAAoB,KAAA,QAAO,UAAU,KAAK,EAAG,CACvD,GAAC,EAAA,OAAA,UAAA,CAAA,GAAA;EAAA,eAAA,CAEA,QAAQ,UAAU,KAAA,KAASF,YAAA,QAAAE,cAEpB,WAAmB,EAAE,IAAI,sBAAsB,UAAU,CAAC,GAAC;GAAA,OAAA;GAAA,eAAA;EAAA,CAAA,GAAA,IAAA,GAKlE,MAAA,MAAM,KAAK,SAAIF,YAAA,MAAA,EAAA,OACL,KAAK,GAAE,GAAA,CAAAA,YAAA,KAER,WACF,EACE,IAAI;GACF,sBAAsB;GAAI,IAAA,KAC1B,sBAAsB,cAAM,CAAC,KAAK,KAAK,CAAA;GACvC,QAAQ,UAAU,KAAK,MAAM,sBAAsB;GACnD,gBAAgB;EAAO,EAE3B,GAAC,UAAA,OAED;GACE,MAAM,IAAI,KAAK;GACf,gBAAgB,QAAQ,UAAU,KAAK,KAAK,aAAa,KAAA;EAC3D,CACF,GAAC,CAEA,KAAK,KAAK,CAAA,CAAA,CAAA,CAGhB,CAAC;EAAA,SAAA;CAAA,CAAA,CAAA,CAAA;AAIV,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -17,8 +17,8 @@ import { plainText } from "../utils/data/text.js";
17
17
  import { rovingFocus } from "../utils/dom/roving-focus.js";
18
18
  import { Menu as Menu$1, MenuRadioGroup, MenuRadioItem } from "../overlay/Menu.js";
19
19
  import { useActiveIndicator } from "../utils/motion/active-indicator.js";
20
- import { computed, createVNode, isVNode, mergeProps, nextTick, onBeforeUnmount, ref, shallowRef, useId, watch } from "vue";
21
- import { _component, bindable, childrenProp, createContext, effect, forwardChildren, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
20
+ import { computed, createVNode, isVNode, nextTick, onBeforeUnmount, ref, shallowRef, useId, watch } from "vue";
21
+ import { _component, bindable, childrenProp, createContext, effect, forwardChildren, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
22
22
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
23
23
  import { ChevronDown, ChevronLeft, ChevronRight, Plus, X } from "@lucide/icons";
24
24
  //#region src/navigation/Tabs.tsx
@@ -139,7 +139,7 @@ var Tabs = /*#__PURE__*/ _component((_props, _ctx) => {
139
139
  if (current.value !== void 0) document.getElementById(tabId(current.value))?.focus();
140
140
  })
141
141
  });
142
- return () => createVNode("div", mergeProps(mergeAttrs({ sx: [
142
+ return () => createVNode("div", mergeJsxProps(mergeAttrs({ sx: [
143
143
  tabsStyles.root,
144
144
  orientation.value === "vertical" && tabsStyles.vertical,
145
145
  appearance().size && fontSizeStyles[appearance().size]
@@ -345,7 +345,7 @@ var TabList = /*#__PURE__*/ _component((_props2, _ctx2) => {
345
345
  label: tabs.label(value)
346
346
  }));
347
347
  return createVNode(Menu$1, {
348
- "trigger": _cache[0] || (_cache[0] = (props) => createVNode(IconButton, mergeProps(props, {
348
+ "trigger": _cache[0] || (_cache[0] = (props) => createVNode(IconButton, mergeJsxProps(props, {
349
349
  "icon": ChevronDown,
350
350
  "size": "sm",
351
351
  "variant": "ghost",
@@ -537,7 +537,7 @@ var Tab = /*#__PURE__*/ _component((_props3, _ctx3) => {
537
537
  orientation: tabs.orientation,
538
538
  closable: !!onClose.value
539
539
  });
540
- const tab = createVNode(ButtonBase, mergeProps(mergePartProps({
540
+ const tab = createVNode(ButtonBase, mergeJsxProps(mergePartProps({
541
541
  ...styles.root,
542
542
  ripple: tabs.ripple
543
543
  }, rest, {
@@ -561,7 +561,7 @@ var Tab = /*#__PURE__*/ _component((_props3, _ctx3) => {
561
561
  "data-dragging": tabs.dragging === value.value || void 0
562
562
  }), _isSlot(_slot2 = forwardChildren(_props3)) ? _slot2 : { default: () => [_slot2] });
563
563
  if (!onClose.value) return tab;
564
- return createVNode("span", mergeProps({ "role": "presentation" }, mergeAttrs(styles.closeWrapper)), [tab, createVNode(IconButton, mergePartProps({
564
+ return createVNode("span", mergeJsxProps({ "role": "presentation" }, mergeAttrs(styles.closeWrapper)), [tab, createVNode(IconButton, mergePartProps({
565
565
  icon: X,
566
566
  size: "xs",
567
567
  variant: "ghost",
@@ -606,7 +606,7 @@ var TabPanel = /*#__PURE__*/ _component((_props4, _ctx4) => {
606
606
  const showContent = useLazyContent(() => tabs.value === value.value, () => tabs.lazy);
607
607
  return () => {
608
608
  const selected = tabs.value === value.value;
609
- return createVNode("div", mergeProps(mergeAttrs({
609
+ return createVNode("div", mergeJsxProps(mergeAttrs({
610
610
  sx: [tabPanelStyles.root, focusRingStyles.visible],
611
611
  tabindex: 0
612
612
  }, rest, {
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.js","names":["_isVNode","_vtp_bindable","_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_vue_computed","_createVNode","_mergeProps","Menu","_vtp_untrack","_vtp_forwardChildren"],"sources":["../../src/navigation/Tabs.tsx"],"sourcesContent":["/**\n * 标签页(WAI-ARIA 的 Tabs 模式),复合组件:Tabs(状态)> TabList(role=\"tablist\")> Tab(role=\"tab\"),\n * 加上与每个 Tab 对应的 TabPanel(role=\"tabpanel\")。各层都是独立的组件,可以自由排版、各自加属性。\n *\n * <Tabs _value={tab}>\n * <TabList aria-label=\"订单\">\n * <Tab value=\"all\">全部</Tab>\n * <Tab value=\"paid\">已付款</Tab>\n * </TabList>\n * <TabPanel value=\"all\">…</TabPanel>\n * <TabPanel value=\"paid\">…</TabPanel>\n * </Tabs>\n *\n * 键盘:标签之间用方向键移动(漫游焦点,整组一个 Tab 位置),Home / End 到两端;\n * activation=\"automatic\"(默认)时焦点移到哪个标签就切换到哪个,\"manual\" 时按 Enter / 空格才切换。\n *\n * line 样式的下划线是 TabList 里的一个指示条(Indicator):跟着当前标签走(useActiveIndicator:\n * 切换时用 Anime.js 滑过去,时长取主题,减少动态效果时直接到位;尺寸变化时直接对齐)。\n */\nimport { ChevronDown, ChevronLeft, ChevronRight, Plus, X } from '@lucide/icons';\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, onBeforeUnmount, useId, watch, type VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useLang } from '../config/context';\nimport { useDefaults } from '../config/defaults';\nimport { useRecipe } from '../config/styles';\nimport { useActiveIndicator } from '../utils/motion/active-indicator';\nimport { useLazyContent } from '../utils/motion/presence';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { Menu, MenuRadioGroup, MenuRadioItem } from '../overlay/Menu';\nimport { plainText } from '../utils/data/text';\nimport { announce } from '../utils/dom/announcer';\nimport { inlineArrows, isRtl } from '../utils/dom/direction';\nimport { batchLayout } from '../utils/dom/layout-batch';\nimport { startMove } from '../utils/dom/move';\nimport { useResizeObserver } from '../utils/dom/resize';\nimport { rovingFocus } from '../utils/dom/roving-focus';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { t } from '../config/theme/tokens';\n\n/** 标签的排列方向 */\nexport interface TabsOrientations {\n /** 横排(默认),左右键切换 */\n horizontal: unknown;\n /** 竖排(标签在左侧),上下键切换 */\n vertical: unknown;\n}\n\n/** 焦点移动时是否同时切换 */\nexport interface TabsActivations {\n /** 焦点移到哪个标签就显示哪个面板(默认):面板内容轻量时用 */\n automatic: unknown;\n /** 方向键只移动焦点,按 Enter / 空格才切换:切换面板代价大(要请求数据)时用 */\n manual: unknown;\n}\n\n/** 标签的样式 */\nexport interface TabsVariants {\n /** 下划线(默认):当前标签下方一条品牌色的线 */\n line: unknown;\n /** 浅色底:当前标签有浅色底,像分段控件 */\n soft: unknown;\n}\n\n/** Tabs 的外观选项;可以用 createUi / Provider 的 defaults.Tabs 统一改默认值 */\nexport interface TabsOptions {\n /** 样式,默认 line */\n variant?: keyof TabsVariants;\n /** 字号档位,不写时继承 */\n size?: TextSize;\n}\n\n/** Tabs 交给 TabList、Tab、TabPanel 的状态 */\nexport interface TabsState {\n /** 当前标签的值 */\n readonly value: string | undefined;\n /** 横排或竖排 */\n readonly orientation: keyof TabsOrientations;\n /** 方向键移动焦点时是否同时切换 */\n readonly activation: keyof TabsActivations;\n /** 样式 */\n readonly variant: keyof TabsVariants;\n /** 面板第一次显示时才渲染 */\n readonly lazy: boolean;\n /** 波纹;不写时沿用配置 */\n readonly ripple: boolean | undefined;\n /** 切换到某个标签 */\n select(value: string): void;\n /** 标签与面板的 id,互相引用 */\n id(part: 'tab' | 'panel', value: string): string;\n /**\n * 登记标签(按渲染顺序)与它的文字,没有选中值时选第一个;返回注销函数\n * (参数是注销时各标签显示的顺序,关掉当前标签时按它选旁边的)\n */\n register(value: string, label: () => string): (order?: readonly string[]) => void;\n /** 标签的文字(“全部标签页”菜单用) */\n label(value: string): string;\n /** 登记面板;返回注销函数 */\n registerPanel(value: string): () => void;\n /** 这个标签有没有对应的面板:只当导航用的标签(没有 TabPanel)不写 aria-controls */\n hasPanel(value: string): boolean;\n /** 登记了的标签,按渲染顺序 */\n readonly values: readonly string[];\n /** 正在拖动的标签 */\n readonly dragging: string | undefined;\n /** 开始、结束拖动 */\n setDragging(value: string | undefined): void;\n /** 关闭了有焦点的标签:等选中的标签换好之后,把焦点交给它 */\n refocus(): void;\n}\n\n/** Tabs 的上下文:自定义的标签或面板可以 inject 它 */\nexport const TabsContext = createContext<TabsState>('Tabs');\n\n/** 值里的空格等字符不能出现在 id 里 */\nconst idSafe = (value: string) => value.replace(/[^\\w-]/g, '_');\n\n// ─────────────── Tabs ───────────────\n\n/** 未声明的属性落到外层 div 上 */\nexport interface TabsProps extends PartProps<'div'>, TabsOptions {\n /** 当前标签的 value:父级写 _value={x};不写时默认第一个标签 */\n _value?: string;\n /** 方向,默认 horizontal */\n orientation?: keyof TabsOrientations;\n /** 焦点移动时是否同时切换,默认 automatic */\n activation?: keyof TabsActivations;\n /** 面板第一次显示时才渲染,之后切走也保留(面板内容重时用) */\n lazy?: boolean;\n /** 标签按下时的波纹;不写时沿用全局配置 */\n ripple?: boolean;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root、vertical */\nexport const tabsStyles = css.create({\n // 能收缩:放在顶栏这类一行里时,列表放不下就在列表里滚动\n root: { display: 'flex', flexDirection: 'column', gap: '_md', minWidth: 0 },\n vertical: { flexDirection: 'row', alignItems: 'flex-start' },\n});\n\n/** 标签页的状态容器:管理当前值,并把它交给 TabList、Tab、TabPanel */\nexport const Tabs = _component(\n ({\n _value: value = _bindable<string | undefined>(undefined),\n orientation = 'horizontal',\n activation = 'automatic',\n variant,\n size,\n lazy = false,\n ripple,\n children,\n ...rest\n }: TabsProps) => {\n const appearance = useDefaults('Tabs', () => ({ variant, size }), { variant: 'line' });\n const baseId = useId();\n let registered = _state.raw<string[]>([]);\n let panels = _state.raw<string[]>([]);\n let dragging = _state<string | undefined>(undefined);\n // 各标签的文字:读的是 Tab 的子内容,跟着它变\n const labels = new Map<string, () => string>();\n const current = _derived(value ?? registered[0]);\n const tabId = (tab: string) => `${baseId}-tab-${idSafe(tab)}`;\n\n TabsContext.provide({\n get value() {\n return current;\n },\n get orientation() {\n return orientation;\n },\n get activation() {\n return activation;\n },\n get variant() {\n return appearance().variant;\n },\n get lazy() {\n return lazy;\n },\n get ripple() {\n return ripple;\n },\n select: (next) => (value = next),\n id: (part, tab) => (part === 'tab' ? tabId(tab) : `${baseId}-${part}-${idSafe(tab)}`),\n register(tab, label) {\n registered = [...registered, tab];\n labels.set(tab, label);\n return (order = registered) => {\n registered = registered.filter((item) => item !== tab);\n labels.delete(tab);\n if (current !== tab) return;\n // 关掉的是当前标签(使用方没有另选):按显示的顺序选它后面的一个,没有时选前面的一个\n const index = order.indexOf(tab);\n const rest = order.filter((item) => item !== tab && registered.includes(item));\n value = rest[Math.min(Math.max(index, 0), rest.length - 1)];\n };\n },\n registerPanel(tab) {\n panels = [...panels, tab];\n return () => (panels = panels.filter((item) => item !== tab));\n },\n hasPanel: (tab) => panels.includes(tab),\n label: (tab) => labels.get(tab)?.() ?? tab,\n get values() {\n return registered;\n },\n get dragging() {\n return dragging;\n },\n setDragging: (next) => (dragging = next),\n refocus: () =>\n void nextTick(() => {\n if (current !== undefined) document.getElementById(tabId(current))?.focus();\n }),\n });\n\n return () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n tabsStyles.root,\n orientation === 'vertical' && tabsStyles.vertical,\n appearance().size && fontSizeStyles[appearance().size!],\n ],\n },\n rest,\n )}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n },\n);\n\n// ─────────────── TabList ───────────────\n\n/** 角色、方向由组件管理 */\nexport type TabListManaged = 'role' | 'aria-orientation';\n\n/** 未声明的属性落到 role=\"tablist\" 的 div 上;aria-label 是这组标签的名称 */\nexport interface TabListProps extends PartProps<'div', TabListManaged> {\n /** 到两端后是否从另一端继续,默认 true */\n loop?: boolean;\n /** 列表末尾的“新建标签页”按钮:点了调用 */\n onAdd?: () => void;\n /**\n * 拖动标签(或在标签上按 Alt + ←→)改变顺序:参数是新的顺序(各标签的 value),使用方按它重排;\n * 不写时不能拖\n */\n onReorder?: (values: string[]) => void;\n /** 标签栏右边“全部标签页”的菜单(标签多、放不下时一眼找到并切过去) */\n showAllMenu?: boolean;\n /** line 样式的下划线指示条的部件属性 */\n propsIndicator?: PartProps<'span'>;\n /** 横排时包着标签列表与右边按钮的那一层的部件属性 */\n propsBar?: PartProps<'div'>;\n /** “新建标签页”按钮的部件属性 */\n propsAdd?: Partial<IconButtonProps>;\n children?: VNodeChild;\n}\n\n/** TabList 的样式:bar、barLine、root、scrollable、line、lineVertical、soft、softVertical、indicator、indicatorVertical */\nexport const tabListStyles = css.create({\n // 横排时包着标签列表与右边的按钮(滚动、全部标签页、新建):列表按内容宽,放不下时收缩并滚动\n bar: { display: 'flex', alignItems: 'center', gap: '_xs', minWidth: 0 },\n // 横排 line 的分隔线画在整行上:标签少时也铺满(页签区、页面顶部的标签)\n barLine: {\n borderBottomWidth: '_xs',\n borderBottomStyle: 'solid',\n borderBottomColor: '_borderMuted',\n },\n root: { display: 'flex', flexShrink: 0 },\n // 横排放不下时(顶栏、窄屏)在列表里横向滚动,不盖到旁边的内容上;滚动条藏起来,触控板、拖动照样能滚\n scrollable: {\n flexShrink: 1,\n minWidth: 0,\n overflowX: 'auto',\n overflowY: 'hidden',\n scrollbarWidth: 'none',\n },\n // 指示条按标签的 offsetLeft / offsetTop 定位,列表要是它的定位容器\n line: { position: 'relative', gap: '_md' },\n lineVertical: {\n flexDirection: 'column',\n gap: '_xs',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: '_borderMuted',\n },\n soft: { gap: '_xs', padding: '_xs', borderRadius: '_md', backgroundColor: '_fill' },\n softVertical: { flexDirection: 'column' },\n // 一条 2px 的品牌色线,压在列表的分隔线上;位置与长度由脚本写(transform 与 width/height)\n indicator: {\n position: 'absolute',\n left: 0,\n // 压在列表底边的分隔线上(滚动的列表会裁掉伸出去的部分,所以放在边框内侧)\n bottom: 0,\n width: 0,\n height: '_borderWidths.sm',\n borderRadius: '_sm',\n backgroundColor: '_accent',\n pointerEvents: 'none',\n },\n indicatorVertical: {\n left: 'auto',\n bottom: 'auto',\n top: 0,\n insetInlineEnd: `calc(-1 * ${t.borderWidths.xs})`,\n width: '_borderWidths.sm',\n height: 0,\n },\n});\n\n/** 列表里各标签的 value,按显示的顺序(拖动排序后组件的登记顺序不再是显示顺序) */\nconst tabOrder = (list: Element | null | undefined) =>\n [...(list?.querySelectorAll<HTMLElement>('[role=\"tab\"]') ?? [])].map((tab) => tab.dataset.value!);\n\n/** 标签列表(role=\"tablist\"):方向键在标签之间移动;横排放不下时有滚动按钮,可以拖动排序、新建 */\nexport const TabList = _component(\n ({\n loop = true,\n onAdd,\n onReorder,\n showAllMenu = false,\n propsIndicator,\n propsBar,\n propsAdd,\n children,\n ...rest\n }: TabListProps) => {\n const lang = useLang();\n const tabs = TabsContext.inject();\n let list = _state.raw<HTMLElement | null>(null);\n let indicator = _state.raw<HTMLElement | null>(null);\n // 横排放不下时:能不能往前、往后滚(滚动按钮)\n let overflow = _state.raw({ overflowing: false, start: false, end: false });\n _effect(() =>\n list\n ? rovingFocus(list, { items: '[role=\"tab\"]', orientation: tabs.orientation, loop })\n : undefined,\n );\n\n useActiveIndicator(() => ({\n container: list,\n indicator,\n active: '[role=\"tab\"][aria-selected=\"true\"]',\n axis: tabs.orientation,\n value: tabs.value,\n }));\n\n function measure() {\n batchLayout(() => {\n if (!list || tabs.orientation === 'vertical') return;\n // 从右到左排版时 scrollLeft 是负的:取绝对值就是离起始端多远\n const scrolled = Math.abs(list.scrollLeft);\n const max = list.scrollWidth - list.clientWidth;\n const next = { overflowing: max > 1, start: scrolled > 1, end: scrolled < max - 1 };\n return () => {\n if (Object.entries(next).some(([key, value]) => overflow[key as 'start'] !== value))\n overflow = next;\n };\n });\n }\n useResizeObserver(\n () => (list ? [list, ...list.querySelectorAll<HTMLElement>('[role=\"tab\"]')] : []),\n measure,\n );\n watch(() => tabs.values.length, measure, { flush: 'post' });\n\n // 切到一个滚到外面的标签(方向键、菜单、程序):把它滚进来\n watch(\n () => tabs.value,\n (value) => {\n const tab = value === undefined ? null : document.getElementById(tabs.id('tab', value));\n if (!list || !tab || list.scrollWidth <= list.clientWidth) return;\n const outer = list.getBoundingClientRect();\n const inner = tab.getBoundingClientRect();\n if (inner.left < outer.left) list.scrollBy({ left: inner.left - outer.left - 16 });\n else if (inner.right > outer.right) list.scrollBy({ left: inner.right - outer.right + 16 });\n },\n { flush: 'post' },\n );\n\n /** 滚动按钮:往前(-1)或往后(1)滚大半屏 */\n function scrollBy(direction: 1 | -1) {\n if (!list) return;\n const sign = isRtl(list) ? -direction : direction;\n list.scrollBy({ left: sign * list.clientWidth * 0.8, behavior: 'smooth' });\n }\n\n /** 把 value 移到 to(按显示的顺序),交给使用方重排;键盘移动时告诉读屏 */\n function moveTab(value: string, to: number, announceMove: boolean) {\n const order = tabOrder(list);\n const from = order.indexOf(value);\n if (!onReorder || from < 0 || to < 0 || to >= order.length || to === from) return;\n const next = order.filter((item) => item !== value);\n next.splice(to, 0, value);\n onReorder(next);\n if (!announceMove) return;\n const label = document.getElementById(tabs.id('tab', value))?.textContent ?? value;\n announce(lang.tabMoved(label, to + 1, order.length));\n // 标签的元素被移动过:焦点放回它上面\n void nextTick(() => document.getElementById(tabs.id('tab', value))?.focus());\n }\n\n // 拖动排序:越过别的标签的中线就换位(同 Sortable);触摸时照常横向滚动\n function onPointerdown(event: PointerEvent) {\n const target = event.target as Element;\n const tab = target.closest<HTMLElement>('[role=\"tab\"]');\n if (!onReorder || !tab || !list || event.pointerType === 'touch') return;\n const value = tab.dataset.value!;\n startMove(event, {\n threshold: 4,\n // 标签的元素会被重排:捕获在不动的列表上\n captureTarget: list,\n onMove: ({ clientX }) => {\n tabs.setDragging(value);\n const order = tabOrder(list);\n const from = order.indexOf(value);\n const over = [...list!.querySelectorAll<HTMLElement>('[role=\"tab\"]')].find((item) => {\n const rect = item.getBoundingClientRect();\n return clientX >= rect.left && clientX <= rect.right;\n });\n const to = over ? order.indexOf(over.dataset.value!) : -1;\n if (!over || to === from) return;\n const rect = over.getBoundingClientRect();\n const center = rect.left + rect.width / 2;\n // 按书写方向“越过中线”:往后挪时要过了它的中线,往前挪时要回到中线之前\n const past = isRtl(list!) ? clientX < center : clientX > center;\n if (to > from === past) moveTab(value, to, false);\n },\n onEnd: () => tabs.setDragging(undefined),\n });\n }\n\n // 键盘替代拖动:在标签上按 Alt + ←→ 往前、往后挪一位(从右到左排版时反过来)\n function onKeydown(event: KeyboardEvent) {\n if (!onReorder || !event.altKey || event.ctrlKey || event.metaKey || !list) return;\n const tab = (event.target as Element).closest<HTMLElement>('[role=\"tab\"]');\n const { forward, backward } = inlineArrows(isRtl(list));\n if (!tab || (event.key !== forward && event.key !== backward)) return;\n event.preventDefault();\n const value = tab.dataset.value!;\n const from = tabOrder(list).indexOf(value);\n moveTab(value, from + (event.key === forward ? 1 : -1), true);\n }\n\n /** “全部标签页”菜单:按显示的顺序(刚加上、还没渲染出来的排在最后)列出标签的文字 */\n function renderAllMenu() {\n const shown = tabOrder(list).filter((value) => tabs.values.includes(value));\n const order = [...shown, ...tabs.values.filter((value) => !shown.includes(value))];\n const items = order.map((value) => ({ value, label: tabs.label(value) }));\n return (\n <Menu\n trigger={(props) => (\n <IconButton\n {...props}\n icon={ChevronDown}\n size=\"sm\"\n variant=\"ghost\"\n aria-label={lang.tabList}\n />\n )}\n placement=\"bottom-end\"\n >\n <MenuRadioGroup\n label={lang.tabList}\n _value={tabs.value ?? ''}\n onUpdate:_value={(next: string) => tabs.select(next)}\n >\n {items.map((item) => (\n <MenuRadioItem key={item.value} value={item.value}>\n {item.label}\n </MenuRadioItem>\n ))}\n </MenuRadioGroup>\n </Menu>\n );\n }\n\n return () => {\n const vertical = tabs.orientation === 'vertical';\n const tablist = (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n tabListStyles.root,\n !vertical && tabListStyles.scrollable,\n tabs.variant === 'line'\n ? [tabListStyles.line, vertical && tabListStyles.lineVertical]\n : [tabListStyles.soft, vertical && tabListStyles.softVertical],\n ],\n },\n rest,\n {\n ref: _toRef(list),\n role: 'tablist',\n 'aria-orientation': tabs.orientation,\n onScroll: measure,\n onPointerdown,\n onKeydown,\n },\n )}\n >\n {children}\n {tabs.variant === 'line' && (\n <span\n {...mergeAttrs<'span'>(\n { sx: [tabListStyles.indicator, vertical && tabListStyles.indicatorVertical] },\n propsIndicator,\n { ref: _toRef(indicator), 'aria-hidden': true },\n )}\n />\n )}\n </div>\n );\n if (vertical) return tablist;\n // 滚动按钮只给指针用:键盘在标签之间移动时,当前标签会自己滚进来\n const scrollButton = (direction: 1 | -1) =>\n overflow.overflowing && (\n <IconButton\n icon={direction === 1 ? ChevronRight : ChevronLeft}\n propsIcon={{ flipInRtl: true }}\n size=\"sm\"\n variant=\"ghost\"\n tabindex={-1}\n aria-label={direction === 1 ? lang.tabScrollNext : lang.tabScrollPrevious}\n disabled={direction === 1 ? !overflow.end : !overflow.start}\n onClick={() => scrollBy(direction)}\n />\n );\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [tabListStyles.bar, tabs.variant === 'line' && tabListStyles.barLine] },\n propsBar,\n )}\n >\n {scrollButton(-1)}\n {tablist}\n {scrollButton(1)}\n {showAllMenu && renderAllMenu()}\n {onAdd && (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n { icon: Plus, size: 'sm', variant: 'ghost', 'aria-label': lang.tabAdd },\n propsAdd,\n { onClick: onAdd },\n )}\n />\n )}\n </div>\n );\n };\n },\n);\n\n// ─────────────── Tab ───────────────\n\n/** 角色、选中、关联与可聚焦由组件管理 */\nexport type TabManaged =\n 'role' | 'aria-selected' | 'aria-controls' | 'id' | 'tabindex' | 'disabled';\n\n/** 未声明的属性落到 role=\"tab\" 的 button 上 */\nexport interface TabProps extends PartProps<'button', TabManaged> {\n /** 这个标签的值,与对应 TabPanel 的 value 相同 */\n value: string;\n /** 不可用:方向键跳过它 */\n disabled?: boolean;\n /**\n * 可以关闭:标签末尾有关闭按钮,标签上按 Delete、鼠标中键点也关闭。使用方移除这个标签;\n * 关掉的是当前标签时 Tabs 选它后面(没有时前面)的一个,焦点也跟过去\n */\n onClose?: () => void;\n /** 关闭按钮的部件属性 */\n propsClose?: Partial<IconButtonProps>;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root、hover、line、lineVertical、lineActive、soft 等 */\n/**\n * 标签的配方:状态(选中、禁用、拖动中)由 DOM 上的 aria-selected、disabled、data-dragging 决定,\n * 样式、方向、可关闭是档位\n */\nexport const tabRecipe = css.recipe({\n name: 'Tab',\n parts: ['root', 'closeWrapper', 'close'],\n base: {\n // 去掉按钮默认外观、焦点环、波纹、颜色过渡由 ButtonBase 给出\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '_sm',\n minHeight: `max(${t.sizes.control}, ${t.sizes.minTarget})`,\n paddingInline: '_md',\n color: { default: '_textMuted', _hover: '_text', _selected: '_text' },\n fontWeight: '_medium',\n whiteSpace: 'nowrap',\n borderRadius: '_sm',\n opacity: { default: null, _dragging: 0.6, _disabled: '_disabled' },\n },\n closeWrapper: { display: 'inline-grid', flexShrink: 0 },\n close: { gridArea: '1 / 1', justifySelf: 'end', alignSelf: 'center', marginInlineEnd: '_xs' },\n },\n variants: {\n variant: {\n // 下划线:当前标签的底边(竖排时是结束边)一条 2px 的品牌色线,压在列表的分隔线上;\n // 线由 TabList 的指示条画(切换时滑过去),标签自己只变文字颜色\n line: {\n root: {\n marginBottom: `calc(-1 * ${t.borderWidths.xs})`,\n borderBottomWidth: '_sm',\n borderBottomStyle: 'solid',\n borderBottomColor: 'transparent',\n },\n },\n soft: {\n root: {\n // 未选中时同 ButtonBase 的透明底:条件对象按属性整体覆盖前面的值,default 写 null 会露出原生按钮底色\n backgroundColor: { default: 'transparent', _selected: '_surface' },\n boxShadow: { default: null, _selected: '_xs' },\n },\n },\n },\n orientation: { horizontal: {}, vertical: {} },\n // 可关闭:标签与关闭按钮叠在同一个网格格子里,关闭按钮靠结束端,标签给它留出位置。\n // 不用定位:标签的 offsetParent 还得是列表,下划线指示条按它的 offsetLeft 对齐\n closable: {\n true: { root: { gridArea: '1 / 1', paddingInlineEnd: `calc(${t.space.md} + 1.25em)` } },\n },\n },\n compound: [\n {\n when: { variant: 'line', orientation: 'vertical' },\n root: {\n justifyContent: 'flex-start',\n marginBottom: 0,\n marginInlineEnd: `calc(-1 * ${t.borderWidths.xs})`,\n borderBottomWidth: 0,\n borderInlineEndWidth: '_sm',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: 'transparent',\n },\n },\n ],\n});\n\n/** 标签的部件(createUi / Provider 的 styles.Tab 按它定制) */\nexport type TabPart = (typeof tabRecipe.parts)[number];\n\n/** 标签(role=\"tab\" 的 button) */\nexport const Tab = _component(\n ({ value, disabled = false, onClose, propsClose, children, ...rest }: TabProps) => {\n const lang = useLang();\n const tabs = TabsContext.inject();\n const recipe = useRecipe(tabRecipe);\n const unregister = tabs.register(_untrack(value), () => plainText(children) || value);\n onBeforeUnmount(() => {\n const element = document.getElementById(tabs.id('tab', value));\n // 关掉的标签有焦点:等 Tabs 选好旁边的标签再把焦点交过去(元素一移除焦点就丢到 body 上了)\n if (element && element === document.activeElement) tabs.refocus();\n unregister(tabOrder(element?.closest('[role=\"tablist\"]')));\n });\n\n function onKeydown(event: KeyboardEvent) {\n if (event.key === 'Delete' && onClose && !disabled) {\n event.preventDefault();\n onClose();\n }\n }\n\n return () => {\n const selected = tabs.value === value;\n const styles = recipe({\n variant: tabs.variant,\n orientation: tabs.orientation,\n closable: !!onClose,\n });\n const tab = (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>(\n {\n ...styles.root,\n ripple: tabs.ripple,\n },\n rest as Partial<ButtonBaseProps>,\n {\n role: 'tab',\n id: tabs.id('tab', value),\n 'aria-selected': selected,\n 'aria-controls': tabs.hasPanel(value) ? tabs.id('panel', value) : undefined,\n disabled,\n // 使用方的 onClick / onFocus 先执行(mergeProps 的规则),onClick 里 preventDefault 可以拦下切换\n onClick: () => tabs.select(value),\n onFocus: () => {\n if (tabs.activation === 'automatic') tabs.select(value);\n },\n onKeydown,\n 'aria-keyshortcuts': onClose ? 'Delete' : undefined,\n // 鼠标中键关闭(同浏览器的标签页)\n onAuxclick: (event: MouseEvent) => {\n if (event.button === 1 && onClose && !disabled) onClose();\n },\n },\n )}\n data-state={selected ? 'active' : 'inactive'}\n data-value={value}\n data-dragging={tabs.dragging === value || undefined}\n >\n {children}\n </ButtonBase>\n );\n if (!onClose) return tab;\n // 关闭按钮不能放进标签按钮里(按钮里不能有按钮):一起包在 role=\"presentation\" 里,按钮本身只给指针用(对读屏隐藏)\n return (\n <span role=\"presentation\" {...mergeAttrs<'span'>(styles.closeWrapper)}>\n {tab}\n <IconButton\n {...mergePartProps<IconButtonProps>(\n {\n icon: X,\n size: 'xs',\n variant: 'ghost',\n radius: 'full',\n ...styles.close,\n 'aria-label': lang.tabClose(plainText(children) || value),\n },\n propsClose,\n {\n tabindex: -1,\n // 只给指针用:tablist 里只能有标签;键盘、读屏用标签上的 Delete(aria-keyshortcuts)\n 'aria-hidden': true,\n disabled,\n // 按下时不把焦点挪到关闭按钮上\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onClick: (event: MouseEvent) => {\n event.stopPropagation();\n onClose();\n },\n },\n )}\n />\n </span>\n );\n };\n },\n);\n\n// ─────────────── TabPanel ───────────────\n\n/** 角色、关联与显示由组件管理 */\nexport type TabPanelManaged = 'role' | 'id' | 'aria-labelledby' | 'hidden';\n\n/** 未声明的属性落到 role=\"tabpanel\" 的 div 上 */\nexport interface TabPanelProps extends PartProps<'div', TabPanelManaged> {\n /** 对应标签的 value */\n value: string;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root */\nexport const tabPanelStyles = css.create({\n root: { flexGrow: 1, minWidth: 0, borderRadius: '_sm' },\n});\n\n/** 标签面板(role=\"tabpanel\"):只显示当前标签的那一个 */\nexport const TabPanel = _component(({ value, children, ...rest }: TabPanelProps) => {\n const tabs = TabsContext.inject();\n onBeforeUnmount(tabs.registerPanel(_untrack(value)));\n // 显示过:lazy 时从这以后一直渲染内容\n const showContent = useLazyContent(\n () => tabs.value === value,\n () => tabs.lazy,\n );\n\n return () => {\n const selected = tabs.value === value;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [tabPanelStyles.root, focusRingStyles.visible], tabindex: 0 },\n rest,\n {\n role: 'tabpanel',\n id: tabs.id('panel', value),\n 'aria-labelledby': tabs.id('tab', value),\n hidden: !selected,\n },\n )}\n data-state={selected ? 'active' : 'inactive'}\n >\n {showContent() && children}\n </div>\n );\n };\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tabs.js","names":["_isVNode","_vtp_bindable","_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_vue_computed","_createVNode","_mergeProps","Menu","_vtp_untrack","_vtp_forwardChildren"],"sources":["../../src/navigation/Tabs.tsx"],"sourcesContent":["/**\n * 标签页(WAI-ARIA 的 Tabs 模式),复合组件:Tabs(状态)> TabList(role=\"tablist\")> Tab(role=\"tab\"),\n * 加上与每个 Tab 对应的 TabPanel(role=\"tabpanel\")。各层都是独立的组件,可以自由排版、各自加属性。\n *\n * <Tabs _value={tab}>\n * <TabList aria-label=\"订单\">\n * <Tab value=\"all\">全部</Tab>\n * <Tab value=\"paid\">已付款</Tab>\n * </TabList>\n * <TabPanel value=\"all\">…</TabPanel>\n * <TabPanel value=\"paid\">…</TabPanel>\n * </Tabs>\n *\n * 键盘:标签之间用方向键移动(漫游焦点,整组一个 Tab 位置),Home / End 到两端;\n * activation=\"automatic\"(默认)时焦点移到哪个标签就切换到哪个,\"manual\" 时按 Enter / 空格才切换。\n *\n * line 样式的下划线是 TabList 里的一个指示条(Indicator):跟着当前标签走(useActiveIndicator:\n * 切换时用 Anime.js 滑过去,时长取主题,减少动态效果时直接到位;尺寸变化时直接对齐)。\n */\nimport { ChevronDown, ChevronLeft, ChevronRight, Plus, X } from '@lucide/icons';\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, onBeforeUnmount, useId, watch, type VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useLang } from '../config/context';\nimport { useDefaults } from '../config/defaults';\nimport { useRecipe } from '../config/styles';\nimport { useActiveIndicator } from '../utils/motion/active-indicator';\nimport { useLazyContent } from '../utils/motion/presence';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { Menu, MenuRadioGroup, MenuRadioItem } from '../overlay/Menu';\nimport { plainText } from '../utils/data/text';\nimport { announce } from '../utils/dom/announcer';\nimport { inlineArrows, isRtl } from '../utils/dom/direction';\nimport { batchLayout } from '../utils/dom/layout-batch';\nimport { startMove } from '../utils/dom/move';\nimport { useResizeObserver } from '../utils/dom/resize';\nimport { rovingFocus } from '../utils/dom/roving-focus';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { t } from '../config/theme/tokens';\n\n/** 标签的排列方向 */\nexport interface TabsOrientations {\n /** 横排(默认),左右键切换 */\n horizontal: unknown;\n /** 竖排(标签在左侧),上下键切换 */\n vertical: unknown;\n}\n\n/** 焦点移动时是否同时切换 */\nexport interface TabsActivations {\n /** 焦点移到哪个标签就显示哪个面板(默认):面板内容轻量时用 */\n automatic: unknown;\n /** 方向键只移动焦点,按 Enter / 空格才切换:切换面板代价大(要请求数据)时用 */\n manual: unknown;\n}\n\n/** 标签的样式 */\nexport interface TabsVariants {\n /** 下划线(默认):当前标签下方一条品牌色的线 */\n line: unknown;\n /** 浅色底:当前标签有浅色底,像分段控件 */\n soft: unknown;\n}\n\n/** Tabs 的外观选项;可以用 createUi / Provider 的 defaults.Tabs 统一改默认值 */\nexport interface TabsOptions {\n /** 样式,默认 line */\n variant?: keyof TabsVariants;\n /** 字号档位,不写时继承 */\n size?: TextSize;\n}\n\n/** Tabs 交给 TabList、Tab、TabPanel 的状态 */\nexport interface TabsState {\n /** 当前标签的值 */\n readonly value: string | undefined;\n /** 横排或竖排 */\n readonly orientation: keyof TabsOrientations;\n /** 方向键移动焦点时是否同时切换 */\n readonly activation: keyof TabsActivations;\n /** 样式 */\n readonly variant: keyof TabsVariants;\n /** 面板第一次显示时才渲染 */\n readonly lazy: boolean;\n /** 波纹;不写时沿用配置 */\n readonly ripple: boolean | undefined;\n /** 切换到某个标签 */\n select(value: string): void;\n /** 标签与面板的 id,互相引用 */\n id(part: 'tab' | 'panel', value: string): string;\n /**\n * 登记标签(按渲染顺序)与它的文字,没有选中值时选第一个;返回注销函数\n * (参数是注销时各标签显示的顺序,关掉当前标签时按它选旁边的)\n */\n register(value: string, label: () => string): (order?: readonly string[]) => void;\n /** 标签的文字(“全部标签页”菜单用) */\n label(value: string): string;\n /** 登记面板;返回注销函数 */\n registerPanel(value: string): () => void;\n /** 这个标签有没有对应的面板:只当导航用的标签(没有 TabPanel)不写 aria-controls */\n hasPanel(value: string): boolean;\n /** 登记了的标签,按渲染顺序 */\n readonly values: readonly string[];\n /** 正在拖动的标签 */\n readonly dragging: string | undefined;\n /** 开始、结束拖动 */\n setDragging(value: string | undefined): void;\n /** 关闭了有焦点的标签:等选中的标签换好之后,把焦点交给它 */\n refocus(): void;\n}\n\n/** Tabs 的上下文:自定义的标签或面板可以 inject 它 */\nexport const TabsContext = createContext<TabsState>('Tabs');\n\n/** 值里的空格等字符不能出现在 id 里 */\nconst idSafe = (value: string) => value.replace(/[^\\w-]/g, '_');\n\n// ─────────────── Tabs ───────────────\n\n/** 未声明的属性落到外层 div 上 */\nexport interface TabsProps extends PartProps<'div'>, TabsOptions {\n /** 当前标签的 value:父级写 _value={x};不写时默认第一个标签 */\n _value?: string;\n /** 方向,默认 horizontal */\n orientation?: keyof TabsOrientations;\n /** 焦点移动时是否同时切换,默认 automatic */\n activation?: keyof TabsActivations;\n /** 面板第一次显示时才渲染,之后切走也保留(面板内容重时用) */\n lazy?: boolean;\n /** 标签按下时的波纹;不写时沿用全局配置 */\n ripple?: boolean;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root、vertical */\nexport const tabsStyles = css.create({\n // 能收缩:放在顶栏这类一行里时,列表放不下就在列表里滚动\n root: { display: 'flex', flexDirection: 'column', gap: '_md', minWidth: 0 },\n vertical: { flexDirection: 'row', alignItems: 'flex-start' },\n});\n\n/** 标签页的状态容器:管理当前值,并把它交给 TabList、Tab、TabPanel */\nexport const Tabs = _component(\n ({\n _value: value = _bindable<string | undefined>(undefined),\n orientation = 'horizontal',\n activation = 'automatic',\n variant,\n size,\n lazy = false,\n ripple,\n children,\n ...rest\n }: TabsProps) => {\n const appearance = useDefaults('Tabs', () => ({ variant, size }), { variant: 'line' });\n const baseId = useId();\n let registered = _state.raw<string[]>([]);\n let panels = _state.raw<string[]>([]);\n let dragging = _state<string | undefined>(undefined);\n // 各标签的文字:读的是 Tab 的子内容,跟着它变\n const labels = new Map<string, () => string>();\n const current = _derived(value ?? registered[0]);\n const tabId = (tab: string) => `${baseId}-tab-${idSafe(tab)}`;\n\n TabsContext.provide({\n get value() {\n return current;\n },\n get orientation() {\n return orientation;\n },\n get activation() {\n return activation;\n },\n get variant() {\n return appearance().variant;\n },\n get lazy() {\n return lazy;\n },\n get ripple() {\n return ripple;\n },\n select: (next) => (value = next),\n id: (part, tab) => (part === 'tab' ? tabId(tab) : `${baseId}-${part}-${idSafe(tab)}`),\n register(tab, label) {\n registered = [...registered, tab];\n labels.set(tab, label);\n return (order = registered) => {\n registered = registered.filter((item) => item !== tab);\n labels.delete(tab);\n if (current !== tab) return;\n // 关掉的是当前标签(使用方没有另选):按显示的顺序选它后面的一个,没有时选前面的一个\n const index = order.indexOf(tab);\n const rest = order.filter((item) => item !== tab && registered.includes(item));\n value = rest[Math.min(Math.max(index, 0), rest.length - 1)];\n };\n },\n registerPanel(tab) {\n panels = [...panels, tab];\n return () => (panels = panels.filter((item) => item !== tab));\n },\n hasPanel: (tab) => panels.includes(tab),\n label: (tab) => labels.get(tab)?.() ?? tab,\n get values() {\n return registered;\n },\n get dragging() {\n return dragging;\n },\n setDragging: (next) => (dragging = next),\n refocus: () =>\n void nextTick(() => {\n if (current !== undefined) document.getElementById(tabId(current))?.focus();\n }),\n });\n\n return () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n tabsStyles.root,\n orientation === 'vertical' && tabsStyles.vertical,\n appearance().size && fontSizeStyles[appearance().size!],\n ],\n },\n rest,\n )}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n },\n);\n\n// ─────────────── TabList ───────────────\n\n/** 角色、方向由组件管理 */\nexport type TabListManaged = 'role' | 'aria-orientation';\n\n/** 未声明的属性落到 role=\"tablist\" 的 div 上;aria-label 是这组标签的名称 */\nexport interface TabListProps extends PartProps<'div', TabListManaged> {\n /** 到两端后是否从另一端继续,默认 true */\n loop?: boolean;\n /** 列表末尾的“新建标签页”按钮:点了调用 */\n onAdd?: () => void;\n /**\n * 拖动标签(或在标签上按 Alt + ←→)改变顺序:参数是新的顺序(各标签的 value),使用方按它重排;\n * 不写时不能拖\n */\n onReorder?: (values: string[]) => void;\n /** 标签栏右边“全部标签页”的菜单(标签多、放不下时一眼找到并切过去) */\n showAllMenu?: boolean;\n /** line 样式的下划线指示条的部件属性 */\n propsIndicator?: PartProps<'span'>;\n /** 横排时包着标签列表与右边按钮的那一层的部件属性 */\n propsBar?: PartProps<'div'>;\n /** “新建标签页”按钮的部件属性 */\n propsAdd?: Partial<IconButtonProps>;\n children?: VNodeChild;\n}\n\n/** TabList 的样式:bar、barLine、root、scrollable、line、lineVertical、soft、softVertical、indicator、indicatorVertical */\nexport const tabListStyles = css.create({\n // 横排时包着标签列表与右边的按钮(滚动、全部标签页、新建):列表按内容宽,放不下时收缩并滚动\n bar: { display: 'flex', alignItems: 'center', gap: '_xs', minWidth: 0 },\n // 横排 line 的分隔线画在整行上:标签少时也铺满(页签区、页面顶部的标签)\n barLine: {\n borderBottomWidth: '_xs',\n borderBottomStyle: 'solid',\n borderBottomColor: '_borderMuted',\n },\n root: { display: 'flex', flexShrink: 0 },\n // 横排放不下时(顶栏、窄屏)在列表里横向滚动,不盖到旁边的内容上;滚动条藏起来,触控板、拖动照样能滚\n scrollable: {\n flexShrink: 1,\n minWidth: 0,\n overflowX: 'auto',\n overflowY: 'hidden',\n scrollbarWidth: 'none',\n },\n // 指示条按标签的 offsetLeft / offsetTop 定位,列表要是它的定位容器\n line: { position: 'relative', gap: '_md' },\n lineVertical: {\n flexDirection: 'column',\n gap: '_xs',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: '_borderMuted',\n },\n soft: { gap: '_xs', padding: '_xs', borderRadius: '_md', backgroundColor: '_fill' },\n softVertical: { flexDirection: 'column' },\n // 一条 2px 的品牌色线,压在列表的分隔线上;位置与长度由脚本写(transform 与 width/height)\n indicator: {\n position: 'absolute',\n left: 0,\n // 压在列表底边的分隔线上(滚动的列表会裁掉伸出去的部分,所以放在边框内侧)\n bottom: 0,\n width: 0,\n height: '_borderWidths.sm',\n borderRadius: '_sm',\n backgroundColor: '_accent',\n pointerEvents: 'none',\n },\n indicatorVertical: {\n left: 'auto',\n bottom: 'auto',\n top: 0,\n insetInlineEnd: `calc(-1 * ${t.borderWidths.xs})`,\n width: '_borderWidths.sm',\n height: 0,\n },\n});\n\n/** 列表里各标签的 value,按显示的顺序(拖动排序后组件的登记顺序不再是显示顺序) */\nconst tabOrder = (list: Element | null | undefined) =>\n [...(list?.querySelectorAll<HTMLElement>('[role=\"tab\"]') ?? [])].map((tab) => tab.dataset.value!);\n\n/** 标签列表(role=\"tablist\"):方向键在标签之间移动;横排放不下时有滚动按钮,可以拖动排序、新建 */\nexport const TabList = _component(\n ({\n loop = true,\n onAdd,\n onReorder,\n showAllMenu = false,\n propsIndicator,\n propsBar,\n propsAdd,\n children,\n ...rest\n }: TabListProps) => {\n const lang = useLang();\n const tabs = TabsContext.inject();\n let list = _state.raw<HTMLElement | null>(null);\n let indicator = _state.raw<HTMLElement | null>(null);\n // 横排放不下时:能不能往前、往后滚(滚动按钮)\n let overflow = _state.raw({ overflowing: false, start: false, end: false });\n _effect(() =>\n list\n ? rovingFocus(list, { items: '[role=\"tab\"]', orientation: tabs.orientation, loop })\n : undefined,\n );\n\n useActiveIndicator(() => ({\n container: list,\n indicator,\n active: '[role=\"tab\"][aria-selected=\"true\"]',\n axis: tabs.orientation,\n value: tabs.value,\n }));\n\n function measure() {\n batchLayout(() => {\n if (!list || tabs.orientation === 'vertical') return;\n // 从右到左排版时 scrollLeft 是负的:取绝对值就是离起始端多远\n const scrolled = Math.abs(list.scrollLeft);\n const max = list.scrollWidth - list.clientWidth;\n const next = { overflowing: max > 1, start: scrolled > 1, end: scrolled < max - 1 };\n return () => {\n if (Object.entries(next).some(([key, value]) => overflow[key as 'start'] !== value))\n overflow = next;\n };\n });\n }\n useResizeObserver(\n () => (list ? [list, ...list.querySelectorAll<HTMLElement>('[role=\"tab\"]')] : []),\n measure,\n );\n watch(() => tabs.values.length, measure, { flush: 'post' });\n\n // 切到一个滚到外面的标签(方向键、菜单、程序):把它滚进来\n watch(\n () => tabs.value,\n (value) => {\n const tab = value === undefined ? null : document.getElementById(tabs.id('tab', value));\n if (!list || !tab || list.scrollWidth <= list.clientWidth) return;\n const outer = list.getBoundingClientRect();\n const inner = tab.getBoundingClientRect();\n if (inner.left < outer.left) list.scrollBy({ left: inner.left - outer.left - 16 });\n else if (inner.right > outer.right) list.scrollBy({ left: inner.right - outer.right + 16 });\n },\n { flush: 'post' },\n );\n\n /** 滚动按钮:往前(-1)或往后(1)滚大半屏 */\n function scrollBy(direction: 1 | -1) {\n if (!list) return;\n const sign = isRtl(list) ? -direction : direction;\n list.scrollBy({ left: sign * list.clientWidth * 0.8, behavior: 'smooth' });\n }\n\n /** 把 value 移到 to(按显示的顺序),交给使用方重排;键盘移动时告诉读屏 */\n function moveTab(value: string, to: number, announceMove: boolean) {\n const order = tabOrder(list);\n const from = order.indexOf(value);\n if (!onReorder || from < 0 || to < 0 || to >= order.length || to === from) return;\n const next = order.filter((item) => item !== value);\n next.splice(to, 0, value);\n onReorder(next);\n if (!announceMove) return;\n const label = document.getElementById(tabs.id('tab', value))?.textContent ?? value;\n announce(lang.tabMoved(label, to + 1, order.length));\n // 标签的元素被移动过:焦点放回它上面\n void nextTick(() => document.getElementById(tabs.id('tab', value))?.focus());\n }\n\n // 拖动排序:越过别的标签的中线就换位(同 Sortable);触摸时照常横向滚动\n function onPointerdown(event: PointerEvent) {\n const target = event.target as Element;\n const tab = target.closest<HTMLElement>('[role=\"tab\"]');\n if (!onReorder || !tab || !list || event.pointerType === 'touch') return;\n const value = tab.dataset.value!;\n startMove(event, {\n threshold: 4,\n // 标签的元素会被重排:捕获在不动的列表上\n captureTarget: list,\n onMove: ({ clientX }) => {\n tabs.setDragging(value);\n const order = tabOrder(list);\n const from = order.indexOf(value);\n const over = [...list!.querySelectorAll<HTMLElement>('[role=\"tab\"]')].find((item) => {\n const rect = item.getBoundingClientRect();\n return clientX >= rect.left && clientX <= rect.right;\n });\n const to = over ? order.indexOf(over.dataset.value!) : -1;\n if (!over || to === from) return;\n const rect = over.getBoundingClientRect();\n const center = rect.left + rect.width / 2;\n // 按书写方向“越过中线”:往后挪时要过了它的中线,往前挪时要回到中线之前\n const past = isRtl(list!) ? clientX < center : clientX > center;\n if (to > from === past) moveTab(value, to, false);\n },\n onEnd: () => tabs.setDragging(undefined),\n });\n }\n\n // 键盘替代拖动:在标签上按 Alt + ←→ 往前、往后挪一位(从右到左排版时反过来)\n function onKeydown(event: KeyboardEvent) {\n if (!onReorder || !event.altKey || event.ctrlKey || event.metaKey || !list) return;\n const tab = (event.target as Element).closest<HTMLElement>('[role=\"tab\"]');\n const { forward, backward } = inlineArrows(isRtl(list));\n if (!tab || (event.key !== forward && event.key !== backward)) return;\n event.preventDefault();\n const value = tab.dataset.value!;\n const from = tabOrder(list).indexOf(value);\n moveTab(value, from + (event.key === forward ? 1 : -1), true);\n }\n\n /** “全部标签页”菜单:按显示的顺序(刚加上、还没渲染出来的排在最后)列出标签的文字 */\n function renderAllMenu() {\n const shown = tabOrder(list).filter((value) => tabs.values.includes(value));\n const order = [...shown, ...tabs.values.filter((value) => !shown.includes(value))];\n const items = order.map((value) => ({ value, label: tabs.label(value) }));\n return (\n <Menu\n trigger={(props) => (\n <IconButton\n {...props}\n icon={ChevronDown}\n size=\"sm\"\n variant=\"ghost\"\n aria-label={lang.tabList}\n />\n )}\n placement=\"bottom-end\"\n >\n <MenuRadioGroup\n label={lang.tabList}\n _value={tabs.value ?? ''}\n onUpdate:_value={(next: string) => tabs.select(next)}\n >\n {items.map((item) => (\n <MenuRadioItem key={item.value} value={item.value}>\n {item.label}\n </MenuRadioItem>\n ))}\n </MenuRadioGroup>\n </Menu>\n );\n }\n\n return () => {\n const vertical = tabs.orientation === 'vertical';\n const tablist = (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n tabListStyles.root,\n !vertical && tabListStyles.scrollable,\n tabs.variant === 'line'\n ? [tabListStyles.line, vertical && tabListStyles.lineVertical]\n : [tabListStyles.soft, vertical && tabListStyles.softVertical],\n ],\n },\n rest,\n {\n ref: _toRef(list),\n role: 'tablist',\n 'aria-orientation': tabs.orientation,\n onScroll: measure,\n onPointerdown,\n onKeydown,\n },\n )}\n >\n {children}\n {tabs.variant === 'line' && (\n <span\n {...mergeAttrs<'span'>(\n { sx: [tabListStyles.indicator, vertical && tabListStyles.indicatorVertical] },\n propsIndicator,\n { ref: _toRef(indicator), 'aria-hidden': true },\n )}\n />\n )}\n </div>\n );\n if (vertical) return tablist;\n // 滚动按钮只给指针用:键盘在标签之间移动时,当前标签会自己滚进来\n const scrollButton = (direction: 1 | -1) =>\n overflow.overflowing && (\n <IconButton\n icon={direction === 1 ? ChevronRight : ChevronLeft}\n propsIcon={{ flipInRtl: true }}\n size=\"sm\"\n variant=\"ghost\"\n tabindex={-1}\n aria-label={direction === 1 ? lang.tabScrollNext : lang.tabScrollPrevious}\n disabled={direction === 1 ? !overflow.end : !overflow.start}\n onClick={() => scrollBy(direction)}\n />\n );\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [tabListStyles.bar, tabs.variant === 'line' && tabListStyles.barLine] },\n propsBar,\n )}\n >\n {scrollButton(-1)}\n {tablist}\n {scrollButton(1)}\n {showAllMenu && renderAllMenu()}\n {onAdd && (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n { icon: Plus, size: 'sm', variant: 'ghost', 'aria-label': lang.tabAdd },\n propsAdd,\n { onClick: onAdd },\n )}\n />\n )}\n </div>\n );\n };\n },\n);\n\n// ─────────────── Tab ───────────────\n\n/** 角色、选中、关联与可聚焦由组件管理 */\nexport type TabManaged =\n 'role' | 'aria-selected' | 'aria-controls' | 'id' | 'tabindex' | 'disabled';\n\n/** 未声明的属性落到 role=\"tab\" 的 button 上 */\nexport interface TabProps extends PartProps<'button', TabManaged> {\n /** 这个标签的值,与对应 TabPanel 的 value 相同 */\n value: string;\n /** 不可用:方向键跳过它 */\n disabled?: boolean;\n /**\n * 可以关闭:标签末尾有关闭按钮,标签上按 Delete、鼠标中键点也关闭。使用方移除这个标签;\n * 关掉的是当前标签时 Tabs 选它后面(没有时前面)的一个,焦点也跟过去\n */\n onClose?: () => void;\n /** 关闭按钮的部件属性 */\n propsClose?: Partial<IconButtonProps>;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root、hover、line、lineVertical、lineActive、soft 等 */\n/**\n * 标签的配方:状态(选中、禁用、拖动中)由 DOM 上的 aria-selected、disabled、data-dragging 决定,\n * 样式、方向、可关闭是档位\n */\nexport const tabRecipe = css.recipe({\n name: 'Tab',\n parts: ['root', 'closeWrapper', 'close'],\n base: {\n // 去掉按钮默认外观、焦点环、波纹、颜色过渡由 ButtonBase 给出\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '_sm',\n minHeight: `max(${t.sizes.control}, ${t.sizes.minTarget})`,\n paddingInline: '_md',\n color: { default: '_textMuted', _hover: '_text', _selected: '_text' },\n fontWeight: '_medium',\n whiteSpace: 'nowrap',\n borderRadius: '_sm',\n opacity: { default: null, _dragging: 0.6, _disabled: '_disabled' },\n },\n closeWrapper: { display: 'inline-grid', flexShrink: 0 },\n close: { gridArea: '1 / 1', justifySelf: 'end', alignSelf: 'center', marginInlineEnd: '_xs' },\n },\n variants: {\n variant: {\n // 下划线:当前标签的底边(竖排时是结束边)一条 2px 的品牌色线,压在列表的分隔线上;\n // 线由 TabList 的指示条画(切换时滑过去),标签自己只变文字颜色\n line: {\n root: {\n marginBottom: `calc(-1 * ${t.borderWidths.xs})`,\n borderBottomWidth: '_sm',\n borderBottomStyle: 'solid',\n borderBottomColor: 'transparent',\n },\n },\n soft: {\n root: {\n // 未选中时同 ButtonBase 的透明底:条件对象按属性整体覆盖前面的值,default 写 null 会露出原生按钮底色\n backgroundColor: { default: 'transparent', _selected: '_surface' },\n boxShadow: { default: null, _selected: '_xs' },\n },\n },\n },\n orientation: { horizontal: {}, vertical: {} },\n // 可关闭:标签与关闭按钮叠在同一个网格格子里,关闭按钮靠结束端,标签给它留出位置。\n // 不用定位:标签的 offsetParent 还得是列表,下划线指示条按它的 offsetLeft 对齐\n closable: {\n true: { root: { gridArea: '1 / 1', paddingInlineEnd: `calc(${t.space.md} + 1.25em)` } },\n },\n },\n compound: [\n {\n when: { variant: 'line', orientation: 'vertical' },\n root: {\n justifyContent: 'flex-start',\n marginBottom: 0,\n marginInlineEnd: `calc(-1 * ${t.borderWidths.xs})`,\n borderBottomWidth: 0,\n borderInlineEndWidth: '_sm',\n borderInlineEndStyle: 'solid',\n borderInlineEndColor: 'transparent',\n },\n },\n ],\n});\n\n/** 标签的部件(createUi / Provider 的 styles.Tab 按它定制) */\nexport type TabPart = (typeof tabRecipe.parts)[number];\n\n/** 标签(role=\"tab\" 的 button) */\nexport const Tab = _component(\n ({ value, disabled = false, onClose, propsClose, children, ...rest }: TabProps) => {\n const lang = useLang();\n const tabs = TabsContext.inject();\n const recipe = useRecipe(tabRecipe);\n const unregister = tabs.register(_untrack(value), () => plainText(children) || value);\n onBeforeUnmount(() => {\n const element = document.getElementById(tabs.id('tab', value));\n // 关掉的标签有焦点:等 Tabs 选好旁边的标签再把焦点交过去(元素一移除焦点就丢到 body 上了)\n if (element && element === document.activeElement) tabs.refocus();\n unregister(tabOrder(element?.closest('[role=\"tablist\"]')));\n });\n\n function onKeydown(event: KeyboardEvent) {\n if (event.key === 'Delete' && onClose && !disabled) {\n event.preventDefault();\n onClose();\n }\n }\n\n return () => {\n const selected = tabs.value === value;\n const styles = recipe({\n variant: tabs.variant,\n orientation: tabs.orientation,\n closable: !!onClose,\n });\n const tab = (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>(\n {\n ...styles.root,\n ripple: tabs.ripple,\n },\n rest as Partial<ButtonBaseProps>,\n {\n role: 'tab',\n id: tabs.id('tab', value),\n 'aria-selected': selected,\n 'aria-controls': tabs.hasPanel(value) ? tabs.id('panel', value) : undefined,\n disabled,\n // 使用方的 onClick / onFocus 先执行(mergeProps 的规则),onClick 里 preventDefault 可以拦下切换\n onClick: () => tabs.select(value),\n onFocus: () => {\n if (tabs.activation === 'automatic') tabs.select(value);\n },\n onKeydown,\n 'aria-keyshortcuts': onClose ? 'Delete' : undefined,\n // 鼠标中键关闭(同浏览器的标签页)\n onAuxclick: (event: MouseEvent) => {\n if (event.button === 1 && onClose && !disabled) onClose();\n },\n },\n )}\n data-state={selected ? 'active' : 'inactive'}\n data-value={value}\n data-dragging={tabs.dragging === value || undefined}\n >\n {children}\n </ButtonBase>\n );\n if (!onClose) return tab;\n // 关闭按钮不能放进标签按钮里(按钮里不能有按钮):一起包在 role=\"presentation\" 里,按钮本身只给指针用(对读屏隐藏)\n return (\n <span role=\"presentation\" {...mergeAttrs<'span'>(styles.closeWrapper)}>\n {tab}\n <IconButton\n {...mergePartProps<IconButtonProps>(\n {\n icon: X,\n size: 'xs',\n variant: 'ghost',\n radius: 'full',\n ...styles.close,\n 'aria-label': lang.tabClose(plainText(children) || value),\n },\n propsClose,\n {\n tabindex: -1,\n // 只给指针用:tablist 里只能有标签;键盘、读屏用标签上的 Delete(aria-keyshortcuts)\n 'aria-hidden': true,\n disabled,\n // 按下时不把焦点挪到关闭按钮上\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onClick: (event: MouseEvent) => {\n event.stopPropagation();\n onClose();\n },\n },\n )}\n />\n </span>\n );\n };\n },\n);\n\n// ─────────────── TabPanel ───────────────\n\n/** 角色、关联与显示由组件管理 */\nexport type TabPanelManaged = 'role' | 'id' | 'aria-labelledby' | 'hidden';\n\n/** 未声明的属性落到 role=\"tabpanel\" 的 div 上 */\nexport interface TabPanelProps extends PartProps<'div', TabPanelManaged> {\n /** 对应标签的 value */\n value: string;\n children?: VNodeChild;\n}\n\n/** Tabs 的样式:root */\nexport const tabPanelStyles = css.create({\n root: { flexGrow: 1, minWidth: 0, borderRadius: '_sm' },\n});\n\n/** 标签面板(role=\"tabpanel\"):只显示当前标签的那一个 */\nexport const TabPanel = _component(({ value, children, ...rest }: TabPanelProps) => {\n const tabs = TabsContext.inject();\n onBeforeUnmount(tabs.registerPanel(_untrack(value)));\n // 显示过:lazy 时从这以后一直渲染内容\n const showContent = useLazyContent(\n () => tabs.value === value,\n () => tabs.lazy,\n );\n\n return () => {\n const selected = tabs.value === value;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [tabPanelStyles.root, focusRingStyles.visible], tabindex: 0 },\n rest,\n {\n role: 'tabpanel',\n id: tabs.id('panel', value),\n 'aria-labelledby': tabs.id('tab', value),\n hidden: !selected,\n },\n )}\n data-state={selected ? 'active' : 'inactive'}\n >\n {showContent() && children}\n </div>\n );\n };\n});\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { mergeAttrs } from "../utils/props.js";
2
2
  import { gapStyles } from "../utils/style/styles.js";
3
3
  import { rovingFocus } from "../utils/dom/roving-focus.js";
4
- import { createVNode, mergeProps, shallowRef } from "vue";
5
- import { _component, childrenProp, createContext, effect, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
4
+ import { createVNode, shallowRef } from "vue";
5
+ import { _component, childrenProp, createContext, effect, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
6
6
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
7
7
  //#region src/navigation/Toolbar.tsx
8
8
  /** 工具栏方向 */
@@ -43,7 +43,7 @@ var Toolbar = /*#__PURE__*/ _component((_props, _ctx) => {
43
43
  ToolbarContext.provide({ get orientation() {
44
44
  return orientation.value;
45
45
  } });
46
- return () => createVNode("div", mergeProps(mergeAttrs({ sx: [
46
+ return () => createVNode("div", mergeJsxProps(mergeAttrs({ sx: [
47
47
  toolbarStyles.root,
48
48
  orientation.value === "vertical" && toolbarStyles.vertical,
49
49
  gapStyles[gap.value]
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/navigation/Toolbar.tsx"],"sourcesContent":["/**\n * 工具栏(role=\"toolbar\"):一组相关的按钮、链接。整组只占一个 Tab 位置,组内用方向键移动(漫游焦点),\n * 键盘用户不必一个个 Tab 过去(WAI-ARIA 的 Toolbar 模式)。名称写 aria-label。\n *\n * <Toolbar aria-label=\"文字格式\">\n * <IconButton icon={Bold} aria-label=\"加粗\" />\n * <IconButton icon={Italic} aria-label=\"斜体\" />\n * </Toolbar>\n *\n * 里面的输入框不参与方向键移动(左右键要用来移动光标),用 Tab 进出。\n * 里面的 ToggleGroup 不再自己管焦点,它的按钮和其他按钮一起用方向键移动(同 WAI-ARIA 的文字格式工具栏示例)。\n */\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { rovingFocus } from '../utils/dom/roving-focus';\nimport { gapStyles, type Space } from '../utils/style/styles';\n\n/** 工具栏方向 */\nexport interface ToolbarOrientations {\n /** 横排(默认),左右键移动 */\n horizontal: unknown;\n /** 竖排,上下键移动 */\n vertical: unknown;\n}\n\n/** 角色与方向由组件管理 */\nexport type ToolbarManaged = 'role' | 'aria-orientation';\n\n/** 未声明的属性落到 div 上;aria-label 是工具栏的名称 */\nexport interface ToolbarProps extends PartProps<'div', ToolbarManaged> {\n /** 方向,默认 horizontal */\n orientation?: keyof ToolbarOrientations;\n /** 到两端后是否从另一端继续,默认 true */\n loop?: boolean;\n /** 项之间的间距档位,默认 xs */\n gap?: Space;\n /** 参与方向键移动的项的选择器,默认按钮与链接 */\n items?: string;\n children?: VNodeChild;\n}\n\n/** Toolbar 的样式:root、vertical */\nexport const toolbarStyles = css.create({\n root: { display: 'flex', alignItems: 'center', flexWrap: 'wrap' },\n vertical: { flexDirection: 'column', alignItems: 'stretch' },\n});\n\n/** 默认参与方向键移动的项:按钮、链接、自定义的 role=\"button\" */\nconst DEFAULT_ITEMS = 'button, a[href], [role=\"button\"]';\n\n/** 工具栏交给里面的组件的状态 */\nexport interface ToolbarState {\n /** 方向 */\n readonly orientation: keyof ToolbarOrientations;\n}\n\n/** 工具栏的上下文:里面自带漫游焦点的组件(ToggleGroup)据此把焦点交给工具栏统一管理 */\nexport const ToolbarContext = createContext<ToolbarState>('Toolbar');\n\n/** 工具栏:一个 Tab 位置,组内方向键移动 */\nexport const Toolbar = _component(\n ({\n orientation = 'horizontal',\n loop = true,\n gap = 'xs',\n items = DEFAULT_ITEMS,\n children,\n ...rest\n }: ToolbarProps) => {\n let root = _state.raw<HTMLElement | null>(null);\n // Tab 进入时落在上次聚焦的项,没有就是第一项:不跳到按下的切换按钮上(那是标签页的习惯)\n _effect(() =>\n root\n ? rovingFocus(root, { items, orientation, loop, initial: (enabled) => enabled[0] })\n : undefined,\n );\n ToolbarContext.provide({\n get orientation() {\n return orientation;\n },\n });\n\n return () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n toolbarStyles.root,\n orientation === 'vertical' && toolbarStyles.vertical,\n gapStyles[gap],\n ],\n },\n rest,\n { ref: _toRef(root), role: 'toolbar', 'aria-orientation': orientation },\n )}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;AA4CA,IAAa,gBAAgB,IAAI,OAAO;CACtC,MAAM;EAAE,SAAS;EAAQ,YAAY;EAAU,UAAU;CAAO;CAChE,UAAU;EAAE,eAAe;EAAU,YAAY;CAAU;AAC7D,CAAC;;AAGD,IAAM,gBAAgB;;;AAStB,IAAa,iBAAiB,cAA4B,SAAS;;AAGnE,IAAa,UAAU,0BACrB,QAAA,SAOoB;CAAA,MAAA,cAAAA,aAAA,QAAA,eANJ,YAAY;CAAA,MAAA,OAAAA,aAAA,QAAA,QACnB,IAAI;CAAA,MAAA,MAAAA,aAAA,QAAA,OACL,IAAI;CAAA,MAAA,QAAAA,aAAA,QAAA,eACF,aAAa;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MAElB,OAAIC,UAAA,QAAA,MAAA,KAAA;CAEP,IAAI,OAAIC,WAAkC,IAAI;CAE9C,aACE,KAAA,QACI,YAAW,KAAA,OAAO;EAAE,OAAK,MAAA;EAAE,aAAW,YAAA;EAAE,MAAI,KAAA;EAAE,UAAU,YAAY,QAAQ;CAAG,CAAC,IAChF,KAAA,CAAS;CAEf,eAAe,QAAQ,EACrB,IAAI,cAAc;EAChB,OAAA,YAAA;CACF,EACF,CAAC;CAED,aAAOC,YAAA,OAAAC,WAEC,WACF,EACE,IAAI;EACF,cAAc;EACd,YAAA,UAAgB,cAAc,cAAc;EAC5C,UAAS,IAAA;CAAK,EAElB,GACA,MACA;EAAE,KAAG;EAAgB,MAAM;EAAW,oBAAkB,YAAA;CAAc,CACxE,GAAC,EAAA,oBAAA,YAAA,MAAA,CAAA,GAAA,CAAA,SAAA,KAAA,CAAA;AAMP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
1
+ {"version":3,"file":"Toolbar.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/navigation/Toolbar.tsx"],"sourcesContent":["/**\n * 工具栏(role=\"toolbar\"):一组相关的按钮、链接。整组只占一个 Tab 位置,组内用方向键移动(漫游焦点),\n * 键盘用户不必一个个 Tab 过去(WAI-ARIA 的 Toolbar 模式)。名称写 aria-label。\n *\n * <Toolbar aria-label=\"文字格式\">\n * <IconButton icon={Bold} aria-label=\"加粗\" />\n * <IconButton icon={Italic} aria-label=\"斜体\" />\n * </Toolbar>\n *\n * 里面的输入框不参与方向键移动(左右键要用来移动光标),用 Tab 进出。\n * 里面的 ToggleGroup 不再自己管焦点,它的按钮和其他按钮一起用方向键移动(同 WAI-ARIA 的文字格式工具栏示例)。\n */\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { rovingFocus } from '../utils/dom/roving-focus';\nimport { gapStyles, type Space } from '../utils/style/styles';\n\n/** 工具栏方向 */\nexport interface ToolbarOrientations {\n /** 横排(默认),左右键移动 */\n horizontal: unknown;\n /** 竖排,上下键移动 */\n vertical: unknown;\n}\n\n/** 角色与方向由组件管理 */\nexport type ToolbarManaged = 'role' | 'aria-orientation';\n\n/** 未声明的属性落到 div 上;aria-label 是工具栏的名称 */\nexport interface ToolbarProps extends PartProps<'div', ToolbarManaged> {\n /** 方向,默认 horizontal */\n orientation?: keyof ToolbarOrientations;\n /** 到两端后是否从另一端继续,默认 true */\n loop?: boolean;\n /** 项之间的间距档位,默认 xs */\n gap?: Space;\n /** 参与方向键移动的项的选择器,默认按钮与链接 */\n items?: string;\n children?: VNodeChild;\n}\n\n/** Toolbar 的样式:root、vertical */\nexport const toolbarStyles = css.create({\n root: { display: 'flex', alignItems: 'center', flexWrap: 'wrap' },\n vertical: { flexDirection: 'column', alignItems: 'stretch' },\n});\n\n/** 默认参与方向键移动的项:按钮、链接、自定义的 role=\"button\" */\nconst DEFAULT_ITEMS = 'button, a[href], [role=\"button\"]';\n\n/** 工具栏交给里面的组件的状态 */\nexport interface ToolbarState {\n /** 方向 */\n readonly orientation: keyof ToolbarOrientations;\n}\n\n/** 工具栏的上下文:里面自带漫游焦点的组件(ToggleGroup)据此把焦点交给工具栏统一管理 */\nexport const ToolbarContext = createContext<ToolbarState>('Toolbar');\n\n/** 工具栏:一个 Tab 位置,组内方向键移动 */\nexport const Toolbar = _component(\n ({\n orientation = 'horizontal',\n loop = true,\n gap = 'xs',\n items = DEFAULT_ITEMS,\n children,\n ...rest\n }: ToolbarProps) => {\n let root = _state.raw<HTMLElement | null>(null);\n // Tab 进入时落在上次聚焦的项,没有就是第一项:不跳到按下的切换按钮上(那是标签页的习惯)\n _effect(() =>\n root\n ? rovingFocus(root, { items, orientation, loop, initial: (enabled) => enabled[0] })\n : undefined,\n );\n ToolbarContext.provide({\n get orientation() {\n return orientation;\n },\n });\n\n return () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n toolbarStyles.root,\n orientation === 'vertical' && toolbarStyles.vertical,\n gapStyles[gap],\n ],\n },\n rest,\n { ref: _toRef(root), role: 'toolbar', 'aria-orientation': orientation },\n )}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;AA4CA,IAAa,gBAAgB,IAAI,OAAO;CACtC,MAAM;EAAE,SAAS;EAAQ,YAAY;EAAU,UAAU;CAAO;CAChE,UAAU;EAAE,eAAe;EAAU,YAAY;CAAU;AAC7D,CAAC;;AAGD,IAAM,gBAAgB;;;AAStB,IAAa,iBAAiB,cAA4B,SAAS;;AAGnE,IAAa,UAAU,0BACrB,QAAA,SAOoB;CAAA,MAAA,cAAAA,aAAA,QAAA,eANJ,YAAY;CAAA,MAAA,OAAAA,aAAA,QAAA,QACnB,IAAI;CAAA,MAAA,MAAAA,aAAA,QAAA,OACL,IAAI;CAAA,MAAA,QAAAA,aAAA,QAAA,eACF,aAAa;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MAElB,OAAIC,UAAA,QAAA,MAAA,KAAA;CAEP,IAAI,OAAIC,WAAkC,IAAI;CAE9C,aACE,KAAA,QACI,YAAW,KAAA,OAAO;EAAE,OAAK,MAAA;EAAE,aAAW,YAAA;EAAE,MAAI,KAAA;EAAE,UAAU,YAAY,QAAQ;CAAG,CAAC,IAChF,KAAA,CAAS;CAEf,eAAe,QAAQ,EACrB,IAAI,cAAc;EAChB,OAAA,YAAA;CACF,EACF,CAAC;CAED,aAAOC,YAAA,OAAAC,cAEC,WACF,EACE,IAAI;EACF,cAAc;EACd,YAAA,UAAgB,cAAc,cAAc;EAC5C,UAAS,IAAA;CAAK,EAElB,GACA,MACA;EAAE,KAAG;EAAgB,MAAM;EAAW,oBAAkB,YAAA;CAAc,CACxE,GAAC,EAAA,oBAAA,YAAA,MAAA,CAAA,GAAA,CAAA,SAAA,KAAA,CAAA;AAMP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -8,8 +8,8 @@ import { Textarea } from "../input/Textarea.js";
8
8
  import { useDetachedDialog } from "./detached.js";
9
9
  import { ModalCore } from "./ModalCore.js";
10
10
  import { dialogRecipe } from "./Dialog.js";
11
- import { createVNode, mergeProps, shallowRef } from "vue";
12
- import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
11
+ import { createVNode, shallowRef } from "vue";
12
+ import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
13
13
  //#region src/overlay/AlertDialog.tsx
14
14
  /** 未声明的属性落到 dialog 上;确认、取消按钮的属性(onConfirm、confirmText、tone、propsConfirm…)同 Dialog */
15
15
  /** 确认对话框:确认 / 取消两个按钮,焦点先落在取消上 */
@@ -22,7 +22,7 @@ var AlertDialog = /*#__PURE__*/ _component((_props, _ctx) => {
22
22
  const rest = restProps(_props, _ctx, true);
23
23
  const appearance = useDefaults("Dialog", () => ({ size: size.value }), { size: "xs" });
24
24
  const recipe = useRecipe(dialogRecipe);
25
- return () => createVNode(ModalCore, mergeProps(mergePartProps({
25
+ return () => createVNode(ModalCore, mergeJsxProps(mergePartProps({
26
26
  title: rest.title,
27
27
  parts: recipe({ size: appearance().size }),
28
28
  panelSx: transitions.scale
@@ -66,7 +66,7 @@ function useConfirm() {
66
66
  const text = shallowRef("");
67
67
  const tried = shallowRef(false);
68
68
  const missing = () => !!reason?.required && !text.value.trim();
69
- mount((host) => createVNode(AlertDialog, mergeProps(options, {
69
+ mount((host) => createVNode(AlertDialog, mergeJsxProps(options, {
70
70
  "propsCancel": reason ? {
71
71
  autofocus: false,
72
72
  ...options.propsCancel
@@ -1 +1 @@
1
- {"version":3,"file":"AlertDialog.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/overlay/AlertDialog.tsx"],"sourcesContent":["/**\n * 确认对话框(role=\"alertdialog\"):打断当前操作、要用户明确选择“确认”或“取消”,如删除前的确认。\n * 建在 Dialog 的内核上;没有右上角的关闭按钮,点击遮罩不关闭(Esc 仍然等于取消)。\n * 打开时焦点落在“取消”上,误按 Enter 不会执行破坏性操作(同 Radix AlertDialog)。\n *\n * <AlertDialog\n * _open={confirming}\n * tone=\"danger\"\n * title=\"删除这个项目?\"\n * description=\"删除后无法恢复。\"\n * confirmText=\"删除\"\n * onConfirm={() => api.remove(id)}\n * />\n *\n * onConfirm 返回 Promise 时:确认按钮显示加载中、取消与 Esc 暂不可用,完成后关闭;失败时保持打开,由调用方提示错误。\n *\n * 只想在一个操作前问一句时,用命令式的 useConfirm,不必自己管 open:\n *\n * const confirm = useConfirm(); // setup 里\n * if (await confirm({ title: '删除这个项目?', tone: 'danger', confirmText: '删除' })) remove();\n *\n * 要填理由的(驳回、作废、退回)给 reason:对话框里多一个多行输入框,得到填的理由,取消时是 null:\n *\n * const reason = await confirm({ title: '驳回这个申请?', tone: 'danger', reason: { label: '驳回理由', required: true } });\n * if (reason !== null) await api.reject(id, reason);\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { shallowRef, type VNodeChild } from 'vue';\nimport { useLang } from '../config/context';\nimport { useDefaults } from '../config/defaults';\nimport { useRecipe } from '../config/styles';\nimport { transitions } from '../utils/style/transitions';\nimport { Field } from '../form/Field';\nimport { Textarea } from '../input/Textarea';\nimport { mergePartProps } from '../utils/props';\nimport { useDetachedDialog } from './detached';\nimport { dialogRecipe, type DialogProps } from './Dialog';\nimport { ModalCore, type ModalCoreProps } from './ModalCore';\n\n/** 未声明的属性落到 dialog 上;确认、取消按钮的属性(onConfirm、confirmText、tone、propsConfirm…)同 Dialog */\nexport interface AlertDialogProps extends Omit<\n DialogProps,\n 'footer' | 'closable' | 'dismissible'\n> {}\n\n/** 确认对话框:确认 / 取消两个按钮,焦点先落在取消上 */\nexport const AlertDialog = _component(\n ({ _open: open = _bindable(false), size, onConfirm, propsCancel, ...rest }: AlertDialogProps) => {\n const appearance = useDefaults('Dialog', () => ({ size }), { size: 'xs' });\n const recipe = useRecipe(dialogRecipe);\n return () => (\n <ModalCore\n {...mergePartProps<ModalCoreProps>(\n {\n title: rest.title,\n parts: recipe({ size: appearance().size }),\n panelSx: transitions.scale,\n },\n rest,\n {\n role: 'alertdialog',\n closable: false,\n dismissible: false,\n // 没写 onConfirm 也有确认按钮:点了就关\n onConfirm: onConfirm ?? (() => {}),\n propsCancel: { autofocus: true, ...propsCancel },\n },\n )}\n _open={open}\n />\n );\n },\n);\n\n/** 确认时要填的理由 */\nexport interface ConfirmReason {\n /** 输入框的标签(“驳回理由”) */\n label: VNodeChild;\n /** 必填:空着点确认时提示“必填”、不关闭 */\n required?: boolean;\n /** 输入框的占位文字 */\n placeholder?: string;\n /** 输入框下的说明(“申请人会收到这段理由”) */\n description?: VNodeChild;\n /** 最多几个字,显示字数 */\n maxlength?: number;\n}\n\n/** confirm() 的选项:AlertDialog 的属性(open 由 confirm 管理) */\nexport interface ConfirmOptions extends Omit<AlertDialogProps, '_open' | 'onConfirm'> {\n /** 确认:拿到填的理由(没给 reason 时是空字符串);返回 false 或失败时保持打开 */\n onConfirm?: (reason: string) => unknown;\n /** 要填理由:对话框里多一个多行输入框,confirm 得到填的理由 */\n reason?: ConfirmReason;\n}\n\n/** useConfirm 返回的函数:给了 reason 时得到理由(取消时 null),否则得到是否确认 */\nexport interface Confirm {\n /** 要填理由:确认时得到理由,取消、Esc 时得到 null */\n (options: ConfirmOptions & { reason: ConfirmReason }): Promise<string | null>;\n /** 确认得到 true,取消、Esc 得到 false */\n (options: ConfirmOptions): Promise<boolean>;\n}\n\n/**\n * 命令式确认:在组件 setup 里调用,返回 confirm(options)。对话框渲染到 body 末尾,\n * 沿用调用处的主题、语言等配置(ConfigScope);关闭后自动卸载。\n * 确认(onConfirm 完成)时得到 true(有 reason 时得到理由),取消、Esc 时得到 false(有 reason 时 null);\n * onConfirm 返回 false 或失败时对话框保持打开,可以再试或取消。\n */\nexport function useConfirm(): Confirm {\n const mount = useDetachedDialog();\n const lang = useLang();\n const confirm = ({ reason, onConfirm, ...options }: ConfirmOptions) =>\n new Promise<string | boolean | null>((resolve) => {\n let confirmed = false;\n const text = shallowRef('');\n // 必填没填:点确认后才提示,之后随输入更新\n const tried = shallowRef(false);\n const missing = () => !!reason?.required && !text.value.trim();\n mount((host) => (\n <AlertDialog\n {...options}\n // 要填理由时焦点先进输入框;没有理由时落在取消上(误按 Enter 不会执行)\n propsCancel={reason ? { autofocus: false, ...options.propsCancel } : options.propsCancel}\n _open={host.open}\n onConfirm={async () => {\n tried.value = true;\n if (missing()) return false;\n if ((await onConfirm?.(text.value.trim())) === false) return false;\n confirmed = true;\n }}\n onClose={(event: Event & { currentTarget: HTMLDialogElement }) => {\n options.onClose?.(event);\n resolve(reason ? (confirmed ? text.value.trim() : null) : confirmed);\n host.closed();\n }}\n >\n {options.children}\n {reason && (\n <Field\n label={reason.label}\n description={reason.description}\n required={reason.required}\n error={tried.value && missing() ? lang.formRequired : undefined}\n >\n <Textarea\n _value={text.value}\n onUpdate:_value={(next: string) => (text.value = next)}\n placeholder={reason.placeholder}\n maxlength={reason.maxlength}\n showCount={reason.maxlength !== undefined}\n autofocus\n />\n </Field>\n )}\n </AlertDialog>\n ));\n });\n return confirm as Confirm;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8CA,IAAa,cAAc,0BACzB,QAAA,SAAiG;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,OAAAA,SAAA,QAAA,eAAtE,OAAK,KAAA,IAAA;CAAA,MAAA,OAAAC,aAAA,QAAA,MAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAoC,OAAIC,UAAA,QAAA,MAAA,IAAA;CACtE,MAAM,aAAa,YAAY,iBAAiB,EAAE,MAAI,KAAA,MAAC,IAAI,EAAE,MAAM,KAAK,CAAC;CACzE,MAAM,SAAS,UAAU,YAAY;CACrC,aAAOC,YAAA,WAAAC,WAEC,eACF;EACE,OAAO,KAAK;EACZ,OAAO,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,KAAK,CAAC;EACzC,SAAS,YAAY;CACvB,GACA,MACA;EACE,MAAM;EACN,UAAU;EACV,aAAa;EAEb,WAAW,UAAA,gBAAoB,CAAC;EAChC,aAAa;GAAE,WAAW;GAAM,GAAA,YAAA;EAAe;CACjD,CACF,GAAC;EAAA,SAAA,KAAA;EAAA,kBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAA,QAAA;CAAA,CAAA,GAAA,IAAA;AAIP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH;;;;;;;;;;AAsCA,SAAgB,aAAsB;CACpC,MAAM,QAAQ,kBAAkB;CAChC,MAAM,OAAO,QAAQ;CACrB,MAAM,WAAW,EAAE,QAAQ,WAAW,GAAG,cACvC,IAAI,SAAkC,YAAY;EAChD,IAAI,YAAY;EAChB,MAAM,OAAO,WAAW,EAAE;EAE1B,MAAM,QAAQ,WAAW,KAAK;EAC9B,MAAM,gBAAgB,CAAC,CAAC,QAAQ,YAAY,CAAC,KAAK,MAAM,KAAK;EAC7D,OAAO,SAAID,YAAA,aAAAC,WAEH,SAAO;GAAA,eAEE,SAAS;IAAE,WAAW;IAAO,GAAG,QAAQ;GAAY,IAAI,QAAQ;GAAW,SACjF,KAAK;GAAI,mBAAA,WAAT,KAAK,OAAI;GAAA,aACL,YAAY;IACrB,MAAM,QAAQ;IACd,IAAI,QAAQ,GAAG,OAAO;IACtB,IAAK,MAAM,YAAY,KAAK,MAAM,KAAK,CAAC,MAAO,OAAO,OAAO;IAC7D,YAAY;GACd;GAAC,YACS,UAAwD;IAChE,QAAQ,UAAU,KAAK;IACvB,QAAQ,SAAU,YAAY,KAAK,MAAM,KAAK,IAAI,OAAQ,SAAS;IACnE,KAAK,OAAO;GACd;EAAC,CAAA,GAAA,EAAA,eAAA,CAEA,QAAQ,UACR,UAAMD,YAAA,OAAA;GAAA,SAEI,OAAO;GAAK,eACN,OAAO;GAAW,YACrB,OAAO;GAAQ,SAClB,MAAM,SAAS,QAAQ,IAAI,KAAK,eAAe,KAAA;EAAS,GAAA,EAAA,eAAA,CAAAA,YAAA,UAAA;GAAA,UAGrD,KAAK;GAAK,oBACA,SAAkB,KAAK,QAAQ;GAAK,eACzC,OAAO;GAAW,aACpB,OAAO;GAAS,aAChB,OAAO,cAAc,KAAA;GAAS,aAAA;EAAA,GAAA,IAAA,CAAA,EAAA,CAAA,CAI9C,EAAA,CAAA,CAEJ;CACH,CAAC;CACH,OAAO;AACT"}
1
+ {"version":3,"file":"AlertDialog.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/overlay/AlertDialog.tsx"],"sourcesContent":["/**\n * 确认对话框(role=\"alertdialog\"):打断当前操作、要用户明确选择“确认”或“取消”,如删除前的确认。\n * 建在 Dialog 的内核上;没有右上角的关闭按钮,点击遮罩不关闭(Esc 仍然等于取消)。\n * 打开时焦点落在“取消”上,误按 Enter 不会执行破坏性操作(同 Radix AlertDialog)。\n *\n * <AlertDialog\n * _open={confirming}\n * tone=\"danger\"\n * title=\"删除这个项目?\"\n * description=\"删除后无法恢复。\"\n * confirmText=\"删除\"\n * onConfirm={() => api.remove(id)}\n * />\n *\n * onConfirm 返回 Promise 时:确认按钮显示加载中、取消与 Esc 暂不可用,完成后关闭;失败时保持打开,由调用方提示错误。\n *\n * 只想在一个操作前问一句时,用命令式的 useConfirm,不必自己管 open:\n *\n * const confirm = useConfirm(); // setup 里\n * if (await confirm({ title: '删除这个项目?', tone: 'danger', confirmText: '删除' })) remove();\n *\n * 要填理由的(驳回、作废、退回)给 reason:对话框里多一个多行输入框,得到填的理由,取消时是 null:\n *\n * const reason = await confirm({ title: '驳回这个申请?', tone: 'danger', reason: { label: '驳回理由', required: true } });\n * if (reason !== null) await api.reject(id, reason);\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { shallowRef, type VNodeChild } from 'vue';\nimport { useLang } from '../config/context';\nimport { useDefaults } from '../config/defaults';\nimport { useRecipe } from '../config/styles';\nimport { transitions } from '../utils/style/transitions';\nimport { Field } from '../form/Field';\nimport { Textarea } from '../input/Textarea';\nimport { mergePartProps } from '../utils/props';\nimport { useDetachedDialog } from './detached';\nimport { dialogRecipe, type DialogProps } from './Dialog';\nimport { ModalCore, type ModalCoreProps } from './ModalCore';\n\n/** 未声明的属性落到 dialog 上;确认、取消按钮的属性(onConfirm、confirmText、tone、propsConfirm…)同 Dialog */\nexport interface AlertDialogProps extends Omit<\n DialogProps,\n 'footer' | 'closable' | 'dismissible'\n> {}\n\n/** 确认对话框:确认 / 取消两个按钮,焦点先落在取消上 */\nexport const AlertDialog = _component(\n ({ _open: open = _bindable(false), size, onConfirm, propsCancel, ...rest }: AlertDialogProps) => {\n const appearance = useDefaults('Dialog', () => ({ size }), { size: 'xs' });\n const recipe = useRecipe(dialogRecipe);\n return () => (\n <ModalCore\n {...mergePartProps<ModalCoreProps>(\n {\n title: rest.title,\n parts: recipe({ size: appearance().size }),\n panelSx: transitions.scale,\n },\n rest,\n {\n role: 'alertdialog',\n closable: false,\n dismissible: false,\n // 没写 onConfirm 也有确认按钮:点了就关\n onConfirm: onConfirm ?? (() => {}),\n propsCancel: { autofocus: true, ...propsCancel },\n },\n )}\n _open={open}\n />\n );\n },\n);\n\n/** 确认时要填的理由 */\nexport interface ConfirmReason {\n /** 输入框的标签(“驳回理由”) */\n label: VNodeChild;\n /** 必填:空着点确认时提示“必填”、不关闭 */\n required?: boolean;\n /** 输入框的占位文字 */\n placeholder?: string;\n /** 输入框下的说明(“申请人会收到这段理由”) */\n description?: VNodeChild;\n /** 最多几个字,显示字数 */\n maxlength?: number;\n}\n\n/** confirm() 的选项:AlertDialog 的属性(open 由 confirm 管理) */\nexport interface ConfirmOptions extends Omit<AlertDialogProps, '_open' | 'onConfirm'> {\n /** 确认:拿到填的理由(没给 reason 时是空字符串);返回 false 或失败时保持打开 */\n onConfirm?: (reason: string) => unknown;\n /** 要填理由:对话框里多一个多行输入框,confirm 得到填的理由 */\n reason?: ConfirmReason;\n}\n\n/** useConfirm 返回的函数:给了 reason 时得到理由(取消时 null),否则得到是否确认 */\nexport interface Confirm {\n /** 要填理由:确认时得到理由,取消、Esc 时得到 null */\n (options: ConfirmOptions & { reason: ConfirmReason }): Promise<string | null>;\n /** 确认得到 true,取消、Esc 得到 false */\n (options: ConfirmOptions): Promise<boolean>;\n}\n\n/**\n * 命令式确认:在组件 setup 里调用,返回 confirm(options)。对话框渲染到 body 末尾,\n * 沿用调用处的主题、语言等配置(ConfigScope);关闭后自动卸载。\n * 确认(onConfirm 完成)时得到 true(有 reason 时得到理由),取消、Esc 时得到 false(有 reason 时 null);\n * onConfirm 返回 false 或失败时对话框保持打开,可以再试或取消。\n */\nexport function useConfirm(): Confirm {\n const mount = useDetachedDialog();\n const lang = useLang();\n const confirm = ({ reason, onConfirm, ...options }: ConfirmOptions) =>\n new Promise<string | boolean | null>((resolve) => {\n let confirmed = false;\n const text = shallowRef('');\n // 必填没填:点确认后才提示,之后随输入更新\n const tried = shallowRef(false);\n const missing = () => !!reason?.required && !text.value.trim();\n mount((host) => (\n <AlertDialog\n {...options}\n // 要填理由时焦点先进输入框;没有理由时落在取消上(误按 Enter 不会执行)\n propsCancel={reason ? { autofocus: false, ...options.propsCancel } : options.propsCancel}\n _open={host.open}\n onConfirm={async () => {\n tried.value = true;\n if (missing()) return false;\n if ((await onConfirm?.(text.value.trim())) === false) return false;\n confirmed = true;\n }}\n onClose={(event: Event & { currentTarget: HTMLDialogElement }) => {\n options.onClose?.(event);\n resolve(reason ? (confirmed ? text.value.trim() : null) : confirmed);\n host.closed();\n }}\n >\n {options.children}\n {reason && (\n <Field\n label={reason.label}\n description={reason.description}\n required={reason.required}\n error={tried.value && missing() ? lang.formRequired : undefined}\n >\n <Textarea\n _value={text.value}\n onUpdate:_value={(next: string) => (text.value = next)}\n placeholder={reason.placeholder}\n maxlength={reason.maxlength}\n showCount={reason.maxlength !== undefined}\n autofocus\n />\n </Field>\n )}\n </AlertDialog>\n ));\n });\n return confirm as Confirm;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8CA,IAAa,cAAc,0BACzB,QAAA,SAAiG;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,OAAAA,SAAA,QAAA,eAAtE,OAAK,KAAA,IAAA;CAAA,MAAA,OAAAC,aAAA,QAAA,MAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAoC,OAAIC,UAAA,QAAA,MAAA,IAAA;CACtE,MAAM,aAAa,YAAY,iBAAiB,EAAE,MAAI,KAAA,MAAC,IAAI,EAAE,MAAM,KAAK,CAAC;CACzE,MAAM,SAAS,UAAU,YAAY;CACrC,aAAOC,YAAA,WAAAC,cAEC,eACF;EACE,OAAO,KAAK;EACZ,OAAO,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,KAAK,CAAC;EACzC,SAAS,YAAY;CACvB,GACA,MACA;EACE,MAAM;EACN,UAAU;EACV,aAAa;EAEb,WAAW,UAAA,gBAAoB,CAAC;EAChC,aAAa;GAAE,WAAW;GAAM,GAAA,YAAA;EAAe;CACjD,CACF,GAAC;EAAA,SAAA,KAAA;EAAA,kBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAA,QAAA;CAAA,CAAA,GAAA,IAAA;AAIP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH;;;;;;;;;;AAsCA,SAAgB,aAAsB;CACpC,MAAM,QAAQ,kBAAkB;CAChC,MAAM,OAAO,QAAQ;CACrB,MAAM,WAAW,EAAE,QAAQ,WAAW,GAAG,cACvC,IAAI,SAAkC,YAAY;EAChD,IAAI,YAAY;EAChB,MAAM,OAAO,WAAW,EAAE;EAE1B,MAAM,QAAQ,WAAW,KAAK;EAC9B,MAAM,gBAAgB,CAAC,CAAC,QAAQ,YAAY,CAAC,KAAK,MAAM,KAAK;EAC7D,OAAO,SAAID,YAAA,aAAAC,cAEH,SAAO;GAAA,eAEE,SAAS;IAAE,WAAW;IAAO,GAAG,QAAQ;GAAY,IAAI,QAAQ;GAAW,SACjF,KAAK;GAAI,mBAAA,WAAT,KAAK,OAAI;GAAA,aACL,YAAY;IACrB,MAAM,QAAQ;IACd,IAAI,QAAQ,GAAG,OAAO;IACtB,IAAK,MAAM,YAAY,KAAK,MAAM,KAAK,CAAC,MAAO,OAAO,OAAO;IAC7D,YAAY;GACd;GAAC,YACS,UAAwD;IAChE,QAAQ,UAAU,KAAK;IACvB,QAAQ,SAAU,YAAY,KAAK,MAAM,KAAK,IAAI,OAAQ,SAAS;IACnE,KAAK,OAAO;GACd;EAAC,CAAA,GAAA,EAAA,eAAA,CAEA,QAAQ,UACR,UAAMD,YAAA,OAAA;GAAA,SAEI,OAAO;GAAK,eACN,OAAO;GAAW,YACrB,OAAO;GAAQ,SAClB,MAAM,SAAS,QAAQ,IAAI,KAAK,eAAe,KAAA;EAAS,GAAA,EAAA,eAAA,CAAAA,YAAA,UAAA;GAAA,UAGrD,KAAK;GAAK,oBACA,SAAkB,KAAK,QAAQ;GAAK,eACzC,OAAO;GAAW,aACpB,OAAO;GAAS,aAChB,OAAO,cAAc,KAAA;GAAS,aAAA;EAAA,GAAA,IAAA,CAAA,EAAA,CAAA,CAI9C,EAAA,CAAA,CAEJ;CACH,CAAC;CACH,OAAO;AACT"}