@zerodep-dev/vue-tsx-pro-ui 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/dist/base/Badge.js +3 -3
  2. package/dist/base/Badge.js.map +1 -1
  3. package/dist/base/Can.d.ts +12 -0
  4. package/dist/base/Can.js +20 -0
  5. package/dist/base/Can.js.map +1 -0
  6. package/dist/base/ClientOnly.d.ts +10 -0
  7. package/dist/base/ClientOnly.js +18 -0
  8. package/dist/base/ClientOnly.js.map +1 -0
  9. package/dist/base/CloseButton.js +3 -3
  10. package/dist/base/CloseButton.js.map +1 -1
  11. package/dist/base/CodeBlock.js +5 -5
  12. package/dist/base/CodeBlock.js.map +1 -1
  13. package/dist/base/CopyButton.js +3 -3
  14. package/dist/base/CopyButton.js.map +1 -1
  15. package/dist/base/Icon.js +3 -3
  16. package/dist/base/Icon.js.map +1 -1
  17. package/dist/base/Indicator.js +3 -3
  18. package/dist/base/Indicator.js.map +1 -1
  19. package/dist/base/StatusDot.js +3 -3
  20. package/dist/base/StatusDot.js.map +1 -1
  21. package/dist/base/Tag.js +5 -5
  22. package/dist/base/Tag.js.map +1 -1
  23. package/dist/base/button-core.js +4 -4
  24. package/dist/base/button-core.js.map +1 -1
  25. package/dist/charts/AreaChart.js +3 -3
  26. package/dist/charts/AreaChart.js.map +1 -1
  27. package/dist/charts/BarChart.js +3 -3
  28. package/dist/charts/BarChart.js.map +1 -1
  29. package/dist/charts/ChordChart.js +3 -3
  30. package/dist/charts/ChordChart.js.map +1 -1
  31. package/dist/charts/ComboChart.js +3 -3
  32. package/dist/charts/ComboChart.js.map +1 -1
  33. package/dist/charts/DonutChart.js +3 -3
  34. package/dist/charts/DonutChart.js.map +1 -1
  35. package/dist/charts/FunnelChart.js +5 -5
  36. package/dist/charts/FunnelChart.js.map +1 -1
  37. package/dist/charts/GraphChart.js +3 -3
  38. package/dist/charts/GraphChart.js.map +1 -1
  39. package/dist/charts/LineChart.js +3 -3
  40. package/dist/charts/LineChart.js.map +1 -1
  41. package/dist/charts/MapChart.js +7 -7
  42. package/dist/charts/MapChart.js.map +1 -1
  43. package/dist/charts/RadarChart.js +16 -15
  44. package/dist/charts/RadarChart.js.map +1 -1
  45. package/dist/charts/SankeyChart.js +3 -3
  46. package/dist/charts/SankeyChart.js.map +1 -1
  47. package/dist/charts/ScatterChart.js +3 -3
  48. package/dist/charts/ScatterChart.js.map +1 -1
  49. package/dist/charts/TimelineChart.js +6 -5
  50. package/dist/charts/TimelineChart.js.map +1 -1
  51. package/dist/charts/TreemapChart.js +3 -3
  52. package/dist/charts/TreemapChart.js.map +1 -1
  53. package/dist/charts/WaterfallChart.js +3 -3
  54. package/dist/charts/WaterfallChart.js.map +1 -1
  55. package/dist/charts/XYChart.js +9 -7
  56. package/dist/charts/XYChart.js.map +1 -1
  57. package/dist/charts/frame.js +10 -8
  58. package/dist/charts/frame.js.map +1 -1
  59. package/dist/charts/single.js +4 -3
  60. package/dist/charts/single.js.map +1 -1
  61. package/dist/code-editor/CodeEditor.d.ts +18 -0
  62. package/dist/code-editor/CodeEditor.js +57 -0
  63. package/dist/code-editor/CodeEditor.js.map +1 -0
  64. package/dist/code-editor/editor.d.ts +52 -0
  65. package/dist/code-editor/editor.js +225 -0
  66. package/dist/code-editor/editor.js.map +1 -0
  67. package/dist/code-editor/index.d.ts +9 -0
  68. package/dist/code-editor/index.js +3 -0
  69. package/dist/config/Provider.d.ts +3 -1
  70. package/dist/config/Provider.js +9 -4
  71. package/dist/config/Provider.js.map +1 -1
  72. package/dist/config/context.d.ts +18 -0
  73. package/dist/config/context.js +16 -1
  74. package/dist/config/context.js.map +1 -1
  75. package/dist/config/createUi.d.ts +20 -3
  76. package/dist/config/createUi.js +80 -49
  77. package/dist/config/createUi.js.map +1 -1
  78. package/dist/config/lang/en-US.js +21 -3
  79. package/dist/config/lang/en-US.js.map +1 -1
  80. package/dist/config/lang/format.d.ts +2 -1
  81. package/dist/config/lang/format.js +9 -2
  82. package/dist/config/lang/format.js.map +1 -1
  83. package/dist/config/lang/lang.d.ts +19 -6
  84. package/dist/config/lang/lang.js +11 -2
  85. package/dist/config/lang/lang.js.map +1 -1
  86. package/dist/config/lang/zh-CN.js +21 -3
  87. package/dist/config/lang/zh-CN.js.map +1 -1
  88. package/dist/config/layout/preference.d.ts +43 -0
  89. package/dist/config/layout/preference.js +108 -0
  90. package/dist/config/layout/preference.js.map +1 -0
  91. package/dist/date/Calendar.js +3 -3
  92. package/dist/date/Calendar.js.map +1 -1
  93. package/dist/date/CalendarBoard.js +9 -9
  94. package/dist/date/CalendarBoard.js.map +1 -1
  95. package/dist/date/CalendarView.js +7 -7
  96. package/dist/date/CalendarView.js.map +1 -1
  97. package/dist/date/DateField.js +3 -3
  98. package/dist/date/DateField.js.map +1 -1
  99. package/dist/date/DatePicker.js +5 -5
  100. package/dist/date/DatePicker.js.map +1 -1
  101. package/dist/date/DateRangePicker.js +5 -5
  102. package/dist/date/DateRangePicker.js.map +1 -1
  103. package/dist/date/DateSegmentGroup.js +5 -5
  104. package/dist/date/DateSegmentGroup.js.map +1 -1
  105. package/dist/date/QuarterCalendar.js +6 -6
  106. package/dist/date/QuarterCalendar.js.map +1 -1
  107. package/dist/date/RangeCalendar.js +3 -3
  108. package/dist/date/RangeCalendar.js.map +1 -1
  109. package/dist/date/SegmentedField.js +3 -3
  110. package/dist/date/SegmentedField.js.map +1 -1
  111. package/dist/date/TimeField.js +3 -3
  112. package/dist/date/TimeField.js.map +1 -1
  113. package/dist/date/TimePicker.js +4 -4
  114. package/dist/date/TimePicker.js.map +1 -1
  115. package/dist/date/date-segments.js +1 -1
  116. package/dist/date/date-segments.js.map +1 -1
  117. package/dist/date/picker-popover.js +3 -2
  118. package/dist/date/picker-popover.js.map +1 -1
  119. package/dist/diagram/Diagram.js +12 -12
  120. package/dist/diagram/Diagram.js.map +1 -1
  121. package/dist/diagram/DiagramLanes.js +3 -3
  122. package/dist/diagram/DiagramLanes.js.map +1 -1
  123. package/dist/diagram/DiagramMinimap.js +4 -4
  124. package/dist/diagram/DiagramMinimap.js.map +1 -1
  125. package/dist/diagram/index.d.ts +2 -1
  126. package/dist/diagram/index.js +2 -1
  127. package/dist/diagram/layout.d.ts +57 -0
  128. package/dist/diagram/layout.js +50 -0
  129. package/dist/diagram/layout.js.map +1 -0
  130. package/dist/display/Accordion.js +6 -6
  131. package/dist/display/Accordion.js.map +1 -1
  132. package/dist/display/AnimatedNumber.js +4 -4
  133. package/dist/display/AnimatedNumber.js.map +1 -1
  134. package/dist/display/Avatar.js +4 -4
  135. package/dist/display/Avatar.js.map +1 -1
  136. package/dist/display/Checklist.js +7 -7
  137. package/dist/display/Checklist.js.map +1 -1
  138. package/dist/display/Collapse.js +8 -5
  139. package/dist/display/Collapse.js.map +1 -1
  140. package/dist/display/Collapsible.js +3 -3
  141. package/dist/display/Collapsible.js.map +1 -1
  142. package/dist/display/Descriptions.js +5 -5
  143. package/dist/display/Descriptions.js.map +1 -1
  144. package/dist/display/Ellipsis.js +3 -3
  145. package/dist/display/Ellipsis.js.map +1 -1
  146. package/dist/display/FieldCompare.js +4 -4
  147. package/dist/display/FieldCompare.js.map +1 -1
  148. package/dist/display/Gauge.js +11 -11
  149. package/dist/display/Gauge.js.map +1 -1
  150. package/dist/display/Image.js +4 -4
  151. package/dist/display/Image.js.map +1 -1
  152. package/dist/display/Marquee.js +3 -3
  153. package/dist/display/Marquee.js.map +1 -1
  154. package/dist/display/ProportionBar.js +4 -4
  155. package/dist/display/ProportionBar.js.map +1 -1
  156. package/dist/display/Sortable.js +4 -4
  157. package/dist/display/Sortable.js.map +1 -1
  158. package/dist/display/Sparkline.js +6 -6
  159. package/dist/display/Sparkline.js.map +1 -1
  160. package/dist/display/Stat.js +3 -3
  161. package/dist/display/Stat.js.map +1 -1
  162. package/dist/display/Timeline.js +7 -7
  163. package/dist/display/Timeline.js.map +1 -1
  164. package/dist/display/Tree.js +10 -10
  165. package/dist/display/Tree.js.map +1 -1
  166. package/dist/display/VirtualList.js +7 -7
  167. package/dist/display/VirtualList.js.map +1 -1
  168. package/dist/display/Watermark.js +3 -3
  169. package/dist/display/Watermark.js.map +1 -1
  170. package/dist/docs-kit/CodeGroup.js +5 -5
  171. package/dist/docs-kit/CodeGroup.js.map +1 -1
  172. package/dist/docs-kit/CodePreview.js +6 -6
  173. package/dist/docs-kit/CodePreview.js.map +1 -1
  174. package/dist/docs-kit/PropsTable.js +4 -4
  175. package/dist/docs-kit/PropsTable.js.map +1 -1
  176. package/dist/feedback/Alert.js +5 -5
  177. package/dist/feedback/Alert.js.map +1 -1
  178. package/dist/feedback/Banner.js +5 -5
  179. package/dist/feedback/Banner.js.map +1 -1
  180. package/dist/feedback/Empty.js +4 -4
  181. package/dist/feedback/Empty.js.map +1 -1
  182. package/dist/feedback/LoadingBar.js +20 -13
  183. package/dist/feedback/LoadingBar.js.map +1 -1
  184. package/dist/feedback/LoadingOverlay.js +3 -3
  185. package/dist/feedback/LoadingOverlay.js.map +1 -1
  186. package/dist/feedback/Progress.js +14 -14
  187. package/dist/feedback/Progress.js.map +1 -1
  188. package/dist/feedback/Result.js +4 -4
  189. package/dist/feedback/Result.js.map +1 -1
  190. package/dist/feedback/SkeletonText.js +3 -3
  191. package/dist/feedback/SkeletonText.js.map +1 -1
  192. package/dist/feedback/Toast.js +6 -6
  193. package/dist/feedback/Toast.js.map +1 -1
  194. package/dist/form/Field.d.ts +7 -0
  195. package/dist/form/Field.js +20 -9
  196. package/dist/form/Field.js.map +1 -1
  197. package/dist/form/Form.js +3 -3
  198. package/dist/form/Form.js.map +1 -1
  199. package/dist/form/FormErrorSummary.js +3 -3
  200. package/dist/form/FormErrorSummary.js.map +1 -1
  201. package/dist/form/FormSection.js +6 -6
  202. package/dist/form/FormSection.js.map +1 -1
  203. package/dist/form/useForm.d.ts +4 -1
  204. package/dist/form/useForm.js +35 -13
  205. package/dist/form/useForm.js.map +1 -1
  206. package/dist/index.d.ts +18 -10
  207. package/dist/index.js +17 -9
  208. package/dist/input/Autocomplete.js +3 -3
  209. package/dist/input/Autocomplete.js.map +1 -1
  210. package/dist/input/Cascader.js +7 -7
  211. package/dist/input/Cascader.js.map +1 -1
  212. package/dist/input/CharacterCount.js +3 -3
  213. package/dist/input/CharacterCount.js.map +1 -1
  214. package/dist/input/Checkbox.js +5 -5
  215. package/dist/input/Checkbox.js.map +1 -1
  216. package/dist/input/ColorField.js +4 -4
  217. package/dist/input/ColorField.js.map +1 -1
  218. package/dist/input/Combobox.js +5 -5
  219. package/dist/input/Combobox.js.map +1 -1
  220. package/dist/input/ConditionBuilder.js +15 -14
  221. package/dist/input/ConditionBuilder.js.map +1 -1
  222. package/dist/input/FileDrop.js +3 -3
  223. package/dist/input/FileDrop.js.map +1 -1
  224. package/dist/input/Listbox.js +9 -9
  225. package/dist/input/Listbox.js.map +1 -1
  226. package/dist/input/Mentions.js +4 -4
  227. package/dist/input/Mentions.js.map +1 -1
  228. package/dist/input/NumberField.js +3 -3
  229. package/dist/input/NumberField.js.map +1 -1
  230. package/dist/input/NumberRangeField.js +5 -5
  231. package/dist/input/NumberRangeField.js.map +1 -1
  232. package/dist/input/OtpField.js +5 -5
  233. package/dist/input/OtpField.js.map +1 -1
  234. package/dist/input/PeoplePicker.js +6 -6
  235. package/dist/input/PeoplePicker.js.map +1 -1
  236. package/dist/input/PeoplePickerPanel.js +15 -15
  237. package/dist/input/PeoplePickerPanel.js.map +1 -1
  238. package/dist/input/Radio.js +4 -4
  239. package/dist/input/Radio.js.map +1 -1
  240. package/dist/input/Rating.js +5 -5
  241. package/dist/input/Rating.js.map +1 -1
  242. package/dist/input/Select.js +5 -5
  243. package/dist/input/Select.js.map +1 -1
  244. package/dist/input/SelectedTags.js +4 -4
  245. package/dist/input/SelectedTags.js.map +1 -1
  246. package/dist/input/Slider.js +6 -6
  247. package/dist/input/Slider.js.map +1 -1
  248. package/dist/input/Switch.js +3 -3
  249. package/dist/input/Switch.js.map +1 -1
  250. package/dist/input/TagsInput.js +5 -5
  251. package/dist/input/TagsInput.js.map +1 -1
  252. package/dist/input/TextField.js +5 -5
  253. package/dist/input/TextField.js.map +1 -1
  254. package/dist/input/Textarea.js +4 -4
  255. package/dist/input/Textarea.js.map +1 -1
  256. package/dist/input/ToggleGroup.js +4 -4
  257. package/dist/input/ToggleGroup.js.map +1 -1
  258. package/dist/input/Transfer.js +8 -8
  259. package/dist/input/Transfer.js.map +1 -1
  260. package/dist/input/TreeSelect.js +7 -7
  261. package/dist/input/TreeSelect.js.map +1 -1
  262. package/dist/input/Upload.js +10 -9
  263. package/dist/input/Upload.js.map +1 -1
  264. package/dist/input/condition.d.ts +1 -1
  265. package/dist/input/condition.js +32 -14
  266. package/dist/input/condition.js.map +1 -1
  267. package/dist/input/people.d.ts +15 -14
  268. package/dist/input/people.js +5 -5
  269. package/dist/input/people.js.map +1 -1
  270. package/dist/input/remote-items.d.ts +4 -2
  271. package/dist/input/remote-items.js +7 -2
  272. package/dist/input/remote-items.js.map +1 -1
  273. package/dist/layout/Affix.js +4 -4
  274. package/dist/layout/Affix.js.map +1 -1
  275. package/dist/layout/ResizeHandle.d.ts +6 -2
  276. package/dist/layout/ResizeHandle.js +32 -9
  277. package/dist/layout/ResizeHandle.js.map +1 -1
  278. package/dist/layout/ScrollArea.js +3 -3
  279. package/dist/layout/ScrollArea.js.map +1 -1
  280. package/dist/layout/Separator.js +3 -3
  281. package/dist/layout/Separator.js.map +1 -1
  282. package/dist/layout/Splitter.js +3 -3
  283. package/dist/layout/Splitter.js.map +1 -1
  284. package/dist/layout/ViewportFill.d.ts +2 -2
  285. package/dist/layout/ViewportFill.js +4 -4
  286. package/dist/layout/ViewportFill.js.map +1 -1
  287. package/dist/navigation/Breadcrumbs.js +4 -4
  288. package/dist/navigation/Breadcrumbs.js.map +1 -1
  289. package/dist/navigation/NavBar.js +6 -6
  290. package/dist/navigation/NavBar.js.map +1 -1
  291. package/dist/navigation/NavList.d.ts +1 -0
  292. package/dist/navigation/NavList.js +20 -12
  293. package/dist/navigation/NavList.js.map +1 -1
  294. package/dist/navigation/NavMenu.d.ts +27 -0
  295. package/dist/navigation/NavMenu.js +54 -0
  296. package/dist/navigation/NavMenu.js.map +1 -0
  297. package/dist/navigation/PageJump.js +3 -3
  298. package/dist/navigation/PageJump.js.map +1 -1
  299. package/dist/navigation/PageSizeSelect.js +4 -4
  300. package/dist/navigation/PageSizeSelect.js.map +1 -1
  301. package/dist/navigation/Pagination.js +6 -6
  302. package/dist/navigation/Pagination.js.map +1 -1
  303. package/dist/navigation/PaginationBar.js +5 -5
  304. package/dist/navigation/PaginationBar.js.map +1 -1
  305. package/dist/navigation/Steps.js +4 -4
  306. package/dist/navigation/Steps.js.map +1 -1
  307. package/dist/navigation/TableOfContents.js +5 -5
  308. package/dist/navigation/TableOfContents.js.map +1 -1
  309. package/dist/navigation/Tabs.js +7 -7
  310. package/dist/navigation/Tabs.js.map +1 -1
  311. package/dist/navigation/Toolbar.js +3 -3
  312. package/dist/navigation/Toolbar.js.map +1 -1
  313. package/dist/overlay/AlertDialog.js +4 -4
  314. package/dist/overlay/AlertDialog.js.map +1 -1
  315. package/dist/overlay/CommandPalette.js +4 -4
  316. package/dist/overlay/CommandPalette.js.map +1 -1
  317. package/dist/overlay/ContextMenu.js +3 -3
  318. package/dist/overlay/ContextMenu.js.map +1 -1
  319. package/dist/overlay/Dialog.js +4 -4
  320. package/dist/overlay/Dialog.js.map +1 -1
  321. package/dist/overlay/Drawer.js +5 -5
  322. package/dist/overlay/Drawer.js.map +1 -1
  323. package/dist/overlay/HoverCard.js +5 -3
  324. package/dist/overlay/HoverCard.js.map +1 -1
  325. package/dist/overlay/Lightbox.js +5 -5
  326. package/dist/overlay/Lightbox.js.map +1 -1
  327. package/dist/overlay/Menu.js +7 -7
  328. package/dist/overlay/Menu.js.map +1 -1
  329. package/dist/overlay/ModalCore.js +9 -9
  330. package/dist/overlay/ModalCore.js.map +1 -1
  331. package/dist/overlay/Popconfirm.js +6 -6
  332. package/dist/overlay/Popconfirm.js.map +1 -1
  333. package/dist/overlay/Popover.js +5 -3
  334. package/dist/overlay/Popover.js.map +1 -1
  335. package/dist/overlay/Tooltip.js +5 -3
  336. package/dist/overlay/Tooltip.js.map +1 -1
  337. package/dist/overlay/Tour.js +8 -8
  338. package/dist/overlay/Tour.js.map +1 -1
  339. package/dist/overlay/detached.d.ts +2 -0
  340. package/dist/overlay/detached.js +73 -42
  341. package/dist/overlay/detached.js.map +1 -1
  342. package/dist/patterns/ActionBar.js +3 -3
  343. package/dist/patterns/ActionBar.js.map +1 -1
  344. package/dist/patterns/AppShell.d.ts +28 -1
  345. package/dist/patterns/AppShell.js +158 -52
  346. package/dist/patterns/AppShell.js.map +1 -1
  347. package/dist/patterns/AuthLayout.d.ts +28 -0
  348. package/dist/patterns/AuthLayout.js +77 -0
  349. package/dist/patterns/AuthLayout.js.map +1 -0
  350. package/dist/patterns/CommentThread.js +9 -9
  351. package/dist/patterns/CommentThread.js.map +1 -1
  352. package/dist/patterns/DataImport.js +4 -4
  353. package/dist/patterns/DataImport.js.map +1 -1
  354. package/dist/patterns/DeadlineBadge.js +3 -3
  355. package/dist/patterns/DeadlineBadge.js.map +1 -1
  356. package/dist/patterns/FilterBar.d.ts +11 -1
  357. package/dist/patterns/FilterBar.js +39 -10
  358. package/dist/patterns/FilterBar.js.map +1 -1
  359. package/dist/patterns/FormDialog.d.ts +18 -0
  360. package/dist/patterns/FormDialog.js +46 -0
  361. package/dist/patterns/FormDialog.js.map +1 -0
  362. package/dist/patterns/KanbanBoard.js +8 -8
  363. package/dist/patterns/KanbanBoard.js.map +1 -1
  364. package/dist/patterns/LayoutSwitcher.d.ts +12 -0
  365. package/dist/patterns/LayoutSwitcher.js +79 -0
  366. package/dist/patterns/LayoutSwitcher.js.map +1 -0
  367. package/dist/patterns/NotificationCenter.js +8 -8
  368. package/dist/patterns/NotificationCenter.js.map +1 -1
  369. package/dist/patterns/PageTabs.d.ts +12 -7
  370. package/dist/patterns/PageTabs.js +41 -29
  371. package/dist/patterns/PageTabs.js.map +1 -1
  372. package/dist/patterns/QueryTable.d.ts +10 -1
  373. package/dist/patterns/QueryTable.js +128 -68
  374. package/dist/patterns/QueryTable.js.map +1 -1
  375. package/dist/patterns/SlideCaptcha.d.ts +80 -0
  376. package/dist/patterns/SlideCaptcha.js +354 -0
  377. package/dist/patterns/SlideCaptcha.js.map +1 -0
  378. package/dist/patterns/StepsForm.js +7 -7
  379. package/dist/patterns/StepsForm.js.map +1 -1
  380. package/dist/patterns/ThemeSwitcher.js +3 -3
  381. package/dist/patterns/ThemeSwitcher.js.map +1 -1
  382. package/dist/patterns/index.d.ts +7 -3
  383. package/dist/patterns/index.js +5 -1
  384. package/dist/patterns/messages.d.ts +39 -1
  385. package/dist/patterns/messages.js +40 -2
  386. package/dist/patterns/messages.js.map +1 -1
  387. package/dist/table/ColumnHeaderActions.js +3 -3
  388. package/dist/table/ColumnHeaderActions.js.map +1 -1
  389. package/dist/table/ColumnResizer.js +3 -3
  390. package/dist/table/ColumnResizer.js.map +1 -1
  391. package/dist/table/ColumnSettings.js +5 -5
  392. package/dist/table/ColumnSettings.js.map +1 -1
  393. package/dist/table/ColumnTable.js +8 -8
  394. package/dist/table/ColumnTable.js.map +1 -1
  395. package/dist/table/DataTable.js +8 -8
  396. package/dist/table/DataTable.js.map +1 -1
  397. package/dist/table/DataTableView.js +21 -21
  398. package/dist/table/DataTableView.js.map +1 -1
  399. package/dist/table/PivotTable.js +3 -3
  400. package/dist/table/PivotTable.js.map +1 -1
  401. package/dist/table/SelectionBar.js +4 -4
  402. package/dist/table/SelectionBar.js.map +1 -1
  403. package/dist/table/TreeDataTable.js +5 -5
  404. package/dist/table/TreeDataTable.js.map +1 -1
  405. package/dist/theme-customize/ThemeCustomizer.js +7 -6
  406. package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
  407. package/dist/theme-customize/ThemeThumbnail.js +3 -3
  408. package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
  409. package/dist/three/background/AuroraBackground.js +3 -3
  410. package/dist/three/background/AuroraBackground.js.map +1 -1
  411. package/dist/three/background/MeshGradient.js +3 -3
  412. package/dist/three/background/MeshGradient.js.map +1 -1
  413. package/dist/three/background/ShaderBackground.js +3 -3
  414. package/dist/three/background/ShaderBackground.js.map +1 -1
  415. package/dist/three/core/EffectSurface.js +3 -3
  416. package/dist/three/core/EffectSurface.js.map +1 -1
  417. package/dist/three/core/ThreeCanvas.js +4 -4
  418. package/dist/three/core/ThreeCanvas.js.map +1 -1
  419. package/dist/three/effects/Confetti.js +3 -3
  420. package/dist/three/effects/Confetti.js.map +1 -1
  421. package/dist/three/effects/ParticleField.js +3 -3
  422. package/dist/three/effects/ParticleField.js.map +1 -1
  423. package/dist/three/effects/WaveGrid.js +3 -3
  424. package/dist/three/effects/WaveGrid.js.map +1 -1
  425. package/dist/three/globe/Globe.js +3 -3
  426. package/dist/three/globe/Globe.js.map +1 -1
  427. package/dist/three/model/ModelViewer.js +3 -3
  428. package/dist/three/model/ModelViewer.js.map +1 -1
  429. package/dist/utils/data/clone.d.ts +8 -0
  430. package/dist/utils/data/clone.js +21 -0
  431. package/dist/utils/data/clone.js.map +1 -0
  432. package/dist/utils/data/date.d.ts +10 -0
  433. package/dist/utils/data/date.js +13 -1
  434. package/dist/utils/data/date.js.map +1 -1
  435. package/dist/utils/data/number.d.ts +5 -0
  436. package/dist/utils/data/number.js +8 -1
  437. package/dist/utils/data/number.js.map +1 -1
  438. package/dist/utils/data/numeric.d.ts +7 -0
  439. package/dist/utils/data/numeric.js +46 -1
  440. package/dist/utils/data/numeric.js.map +1 -1
  441. package/dist/utils/dom/download.d.ts +8 -1
  442. package/dist/utils/dom/download.js +19 -2
  443. package/dist/utils/dom/download.js.map +1 -1
  444. package/dist/utils/dom/element.d.ts +3 -1
  445. package/dist/utils/dom/element.js +8 -4
  446. package/dist/utils/dom/element.js.map +1 -1
  447. package/dist/utils/dom/fullscreen.d.ts +1 -1
  448. package/dist/utils/dom/fullscreen.js +12 -8
  449. package/dist/utils/dom/fullscreen.js.map +1 -1
  450. package/dist/utils/dom/mounted.d.ts +7 -0
  451. package/dist/utils/dom/mounted.js +16 -0
  452. package/dist/utils/dom/mounted.js.map +1 -0
  453. package/dist/utils/dom/overflow.js +2 -1
  454. package/dist/utils/dom/overflow.js.map +1 -1
  455. package/dist/utils/dom/pan-zoom.js +2 -1
  456. package/dist/utils/dom/pan-zoom.js.map +1 -1
  457. package/dist/utils/props.js +3 -13
  458. package/dist/utils/props.js.map +1 -1
  459. package/dist/utils/request/error-message.d.ts +17 -0
  460. package/dist/utils/request/error-message.js +50 -0
  461. package/dist/utils/request/error-message.js.map +1 -0
  462. package/dist/utils/request/http.d.ts +80 -4
  463. package/dist/utils/request/http.js +121 -24
  464. package/dist/utils/request/http.js.map +1 -1
  465. package/dist/utils/request/use-autosave.d.ts +35 -0
  466. package/dist/utils/request/use-autosave.js +69 -0
  467. package/dist/utils/request/use-autosave.js.map +1 -0
  468. package/dist/utils/request/use-request.js +4 -2
  469. package/dist/utils/request/use-request.js.map +1 -1
  470. package/package.json +57 -4
@@ -1,3 +1,4 @@
1
+ import { t } from "../config/theme/tokens.js";
1
2
  import { useLang } from "../config/context.js";
2
3
  import { mergeAttrs, mergePartProps } from "../utils/props.js";
3
4
  import { Badge } from "../base/Badge.js";
@@ -9,8 +10,8 @@ import { describeCondition, isConditionGroup } from "../input/condition.js";
9
10
  import { ConditionBuilder } from "../input/ConditionBuilder.js";
10
11
  import { useMessages } from "../config/lang/messages.js";
11
12
  import { patternsMessages } from "./messages.js";
12
- import { createVNode, mergeProps, ref, useId } from "vue";
13
- import { _component, bindable, childrenProp, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
13
+ import { createVNode, ref, useId } from "vue";
14
+ import { _component, bindable, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
14
15
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
16
  import { ChevronDown, ListFilter } from "@lucide/icons";
16
17
  //#region src/patterns/FilterBar.tsx
@@ -33,12 +34,15 @@ import { ChevronDown, ListFilter } from "@lucide/icons";
33
34
  *
34
35
  * <FilterBar onSearch={search} onReset={reset} conditionFields={fields} _condition={condition}>…</FilterBar>
35
36
  *
36
- * 部件:Root(form)、Fields(条件的栅格)、Field 们、More(收起的条件,display: contents)、Actions(div)、
37
+ * start、end 是整行两头的内容(标题在条件前面,工具栏的按钮在查询、重置后面):QueryTable 用它们把标题与工具栏并进查询栏这一行,
38
+ * 压成一行;点“展开”后更多的条件排在这一行下面,start、end 仍在第一行。
39
+ *
40
+ * 部件:Root(form)、Start、Fields(条件的栅格)、Field 们、More(收起的条件,display: contents)、Actions(div)、End、
37
41
  * Search、Reset(Button)、Toggle(展开收起的 Button)、AdvancedToggle(高级筛选的 Button)、Advanced(条件构造器那一行)。
38
42
  */
39
43
  /** 角色与提交由组件管理 */
40
44
  /** 未声明的属性落到 form 上 */
41
- /** FilterBar 的样式:root、fields、more、actions、toggleIconOpen */
45
+ /** FilterBar 的样式:root、start、end、fields、more、actions、toggleIconOpen */
42
46
  var filterBarStyles = css.create({
43
47
  root: {
44
48
  display: "flex",
@@ -47,6 +51,21 @@ var filterBarStyles = css.create({
47
51
  columnGap: "_xl",
48
52
  rowGap: "_md"
49
53
  },
54
+ start: {
55
+ display: "flex",
56
+ alignItems: "center",
57
+ alignSelf: "flex-start",
58
+ minHeight: t.sizes.control,
59
+ flexShrink: 0
60
+ },
61
+ end: {
62
+ display: "flex",
63
+ alignItems: "center",
64
+ alignSelf: "flex-start",
65
+ minHeight: t.sizes.control,
66
+ flexShrink: 0,
67
+ gap: "_sm"
68
+ },
50
69
  fields: {
51
70
  display: "grid",
52
71
  columnGap: "_xl",
@@ -96,9 +115,13 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
96
115
  const expanded = bindable(_props, "_expanded", () => false, _ctx.emit);
97
116
  const moreActive = readonlyProp(_props, "moreActive", 0);
98
117
  const minFieldWidth = readonlyProp(_props, "minFieldWidth", "16em");
118
+ const start = readonlyProp(_props, "start");
119
+ const end = readonlyProp(_props, "end");
99
120
  const actions = readonlyProp(_props, "actions");
100
121
  const labelPlacement = readonlyProp(_props, "labelPlacement", "start");
101
122
  const labelWidth = readonlyProp(_props, "labelWidth", "auto");
123
+ const propsStart = readonlyProp(_props, "propsStart");
124
+ const propsEnd = readonlyProp(_props, "propsEnd");
102
125
  const propsFields = readonlyProp(_props, "propsFields");
103
126
  const propsActions = readonlyProp(_props, "propsActions");
104
127
  const propsSearch = readonlyProp(_props, "propsSearch");
@@ -126,13 +149,14 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
126
149
  event.preventDefault();
127
150
  onSearch.value?.();
128
151
  }
129
- return () => createVNode("form", mergeProps(mergeAttrs({ sx: filterBarStyles.root }, rest, {
152
+ return () => createVNode("form", mergeJsxProps(mergeAttrs({ sx: filterBarStyles.root }, rest, {
130
153
  role: "search",
131
154
  onSubmit
132
155
  }), { "data-expanded": more.value != null ? expanded.value : void 0 }), [
156
+ start.value != null && createVNode("div", mergeAttrs({ sx: filterBarStyles.start }, propsStart.value), [start.value]),
133
157
  createVNode("div", mergeAttrs({ sx: [filterBarStyles.fields, css.bind(filterBarColumnStyles.columns, () => [minFieldWidth.value], true)] }, propsFields.value), [children.value, more.value != null && expanded.value && createVNode("div", mergeAttrs({ sx: filterBarStyles.more }, propsMore.value, { id: moreId }), [more.value])]),
134
158
  createVNode("div", mergeAttrs({ sx: filterBarStyles.actions }, propsActions.value), [
135
- more.value != null && createVNode(Button, mergeProps(mergePartProps({
159
+ more.value != null && createVNode(Button, mergeJsxProps(mergePartProps({
136
160
  variant: "ghost",
137
161
  tone: "neutral",
138
162
  iconEnd: ChevronDown,
@@ -153,7 +177,7 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
153
177
  })],
154
178
  $stable: true
155
179
  }),
156
- conditionFields.value && createVNode(Button, mergeProps(mergePartProps({
180
+ conditionFields.value && createVNode(Button, mergeJsxProps(mergePartProps({
157
181
  variant: "ghost",
158
182
  tone: "neutral",
159
183
  icon: ListFilter
@@ -174,7 +198,7 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
174
198
  $stable: true
175
199
  }),
176
200
  actions.value,
177
- createVNode(Button, mergeProps(mergePartProps({
201
+ createVNode(Button, mergeJsxProps(mergePartProps({
178
202
  variant: "outline",
179
203
  tone: "neutral"
180
204
  }, propsReset.value, {
@@ -187,12 +211,13 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
187
211
  default: () => [messages.filterReset],
188
212
  $stable: true
189
213
  }),
190
- createVNode(Button, mergeProps(mergePartProps({ loading: loading.value }, propsSearch.value, { type: "submit" }), { "key": "__site5" }), {
214
+ createVNode(Button, mergeJsxProps(mergePartProps({ loading: loading.value }, propsSearch.value, { type: "submit" }), { "key": "__site5" }), {
191
215
  default: () => [messages.filterSearch],
192
216
  $stable: true
193
217
  })
194
218
  ]),
195
- conditionFields.value && advancedOpen.value && createVNode(ConditionBuilder, mergeProps(mergePartProps({
219
+ end.value != null && createVNode("div", mergeAttrs({ sx: filterBarStyles.end }, propsEnd.value), [end.value]),
220
+ conditionFields.value && advancedOpen.value && createVNode(ConditionBuilder, mergeJsxProps(mergePartProps({
196
221
  fields: conditionFields.value,
197
222
  sx: filterBarStyles.advanced,
198
223
  "aria-label": messages.filterAdvanced
@@ -232,9 +257,13 @@ var FilterBar = /*#__PURE__*/ _component((_props, _ctx) => {
232
257
  "onUpdate:_expanded",
233
258
  "moreActive",
234
259
  "minFieldWidth",
260
+ "start",
261
+ "end",
235
262
  "actions",
236
263
  "labelPlacement",
237
264
  "labelWidth",
265
+ "propsStart",
266
+ "propsEnd",
238
267
  "propsFields",
239
268
  "propsActions",
240
269
  "propsSearch",
@@ -1 +1 @@
1
- {"version":3,"file":"FilterBar.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/patterns/FilterBar.tsx"],"sourcesContent":["/**\n * 查询栏(form role=\"search\"):列表页上方的一排筛选条件,最后是“查询”“重置”;条件多时其余的收起来,点“展开”再显示。\n *\n * <FilterBar onSearch={search} onReset={reset} more={<>…不常用的条件…</>} moreActive={2}>\n * <Field label=\"项目名称\"><TextField _value={query.name} /></Field>\n * <Field label=\"任务类别\"><Select … /></Field>\n * </FilterBar>\n *\n * 条件排成栅格:每格不窄于 minFieldWidth,栅格多宽就放几格;按钮区在栅格的结束边,宽度随按钮、不折行,\n * 和条件的最后一行对齐(按钮再多也不会在一格里挤成两行);容器太窄放不下时,按钮区整体换到下一行、靠结束边。\n * 默认标签在起始边、宽度随文字(labelWidth 为 auto:控件紧跟着标签,不留空白;要几行对齐时写固定宽度)。在输入框里按回车就是查询(原生表单提交)。\n * more 收起时不渲染;moreActive 是收起的条件里已经填了几项,显示在“展开”旁边,免得忘了还有条件生效。\n *\n * 高级筛选:给了 conditionFields 时按钮区多一个“高级筛选”,展开后在查询栏下面用 ConditionBuilder 编辑条件树(_condition),\n * 能表达固定条件表达不了的组合(任一满足、介于、不包含);收起时有条件就在下面写成一句话,带“清空”。\n * “重置”同时把条件清成 null。条件是纯 JSON:交给后端(query 的条件树转 SQL)或前端 matchesCondition 筛。\n *\n * <FilterBar onSearch={search} onReset={reset} conditionFields={fields} _condition={condition}>…</FilterBar>\n *\n * 部件:Root(form)、Fields(条件的栅格)、Field 们、More(收起的条件,display: contents)、Actions(div)、\n * Search、Reset(Button)、Toggle(展开收起的 Button)、AdvancedToggle(高级筛选的 Button)、Advanced(条件构造器那一行)。\n */\nimport { ChevronDown, ListFilter } from '@lucide/icons';\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 { Badge } from '../base/Badge';\nimport { Small } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { useMessages } from '../config/lang/messages';\nimport {\n describeCondition,\n isConditionGroup,\n type Condition,\n type ConditionField,\n} from '../input/condition';\nimport { ConditionBuilder, type ConditionBuilderProps } from '../input/ConditionBuilder';\nimport { patternsMessages } from './messages';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { provideFieldLayout, type FieldLayout } from '../form/field-layout';\n\n/** 角色与提交由组件管理 */\nexport type FilterBarManaged = 'role' | 'onSubmit' | 'onReset';\n\n/** 未声明的属性落到 form 上 */\nexport interface FilterBarProps\n extends PartProps<'form', FilterBarManaged>, Pick<FieldLayout, 'labelPlacement' | 'labelWidth'> {\n /** 点“查询”或在输入框里按回车 */\n onSearch?: () => void;\n /** 点“重置”:清空条件由使用方做(通常 Object.assign 回初始值,再查询一次) */\n onReset?: () => void;\n /** 查询中:“查询”按钮显示加载中 */\n loading?: boolean;\n /** 不常用的条件:默认收起,点“展开”才显示 */\n more?: VNodeChild;\n /** 是否展开了 more:父级写 _expanded={x} */\n _expanded?: boolean;\n /** 收起的条件里已经填了几项:大于 0 时显示在“展开”旁边 */\n moreActive?: number;\n /** 每个条件的最小宽度(CSS 长度),默认 `'16em'` */\n minFieldWidth?: string;\n /** 结束边额外的按钮:放在“重置”前面(如“导出筛选结果”) */\n actions?: VNodeChild;\n /** 条件栅格的部件属性 */\n propsFields?: PartProps<'div'>;\n /** 按钮区的部件属性 */\n propsActions?: PartProps<'div'>;\n /** 查询按钮的部件属性 */\n propsSearch?: Partial<ButtonProps>;\n /** 重置按钮的部件属性 */\n propsReset?: Partial<ButtonProps>;\n /** 展开收起按钮的部件属性 */\n propsToggle?: Partial<ButtonProps>;\n /** 收起的条件的外层(display: contents)的部件属性 */\n propsMore?: PartProps<'div'>;\n /** 高级筛选的字段:给了时按钮区多一个“高级筛选” */\n conditionFields?: readonly ConditionField[];\n /** 高级筛选的条件:父级写 _condition={condition};没有时是 null,“重置”时清成 null */\n _condition?: Condition | null;\n /** 高级筛选按钮的部件属性 */\n propsAdvancedToggle?: Partial<ButtonProps>;\n /** 高级筛选那一行(条件构造器)的部件属性 */\n propsAdvanced?: Partial<ConditionBuilderProps>;\n /** 常用的条件:Field */\n children?: VNodeChild;\n}\n\n/** FilterBar 的样式:root、fields、more、actions、toggleIconOpen */\nexport const filterBarStyles = css.create({\n // 条件栅格与按钮区并排;放不下时按钮区换行\n root: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'flex-end',\n columnGap: '_xl',\n rowGap: '_md',\n },\n fields: {\n display: 'grid',\n columnGap: '_xl',\n rowGap: '_md',\n alignItems: 'start',\n flexGrow: 1,\n minWidth: 0,\n },\n // 收起的条件直接是栅格的格子\n more: { display: 'contents' },\n // 宽度随按钮、不折行;换到下一行时也靠结束边\n actions: {\n display: 'flex',\n alignItems: 'center',\n gap: '_sm',\n flexShrink: 0,\n marginInlineStart: 'auto',\n },\n // 展开后箭头朝上\n toggleIconOpen: { rotate: '180deg' },\n // 高级筛选与它的摘要各占一整行,排在条件与按钮下面\n advanced: {\n flexBasis: '100%',\n padding: '_md',\n backgroundColor: '_surfaceMuted',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_borderMuted',\n borderRadius: '_md',\n },\n summary: { flexBasis: '100%', display: 'flex', alignItems: 'baseline', gap: '_sm', minWidth: 0 },\n});\n\n/** FilterBar 的样式:columns(每格的最小宽度;栅格本身至少放得下一格) */\nexport const filterBarColumnStyles = css.create({\n columns: (minWidth: string) => ({\n flexBasis: minWidth,\n gridTemplateColumns: `repeat(auto-fill, minmax(min(${minWidth}, 100%), 1fr))`,\n }),\n});\n\n/** 查询栏:筛选条件的栅格,查询、重置,不常用的条件可以展开收起 */\nexport const FilterBar = _component(\n ({\n onSearch,\n onReset,\n loading = false,\n more,\n _expanded: expanded = _bindable(false),\n moreActive = 0,\n minFieldWidth = '16em',\n actions,\n labelPlacement = 'start',\n labelWidth = 'auto',\n propsFields,\n propsActions,\n propsSearch,\n propsReset,\n propsToggle,\n propsMore,\n conditionFields,\n _condition: condition = _bindable<Condition | null>(null),\n propsAdvancedToggle,\n propsAdvanced,\n children,\n ...rest\n }: FilterBarProps) => {\n const messages = useMessages('patterns', patternsMessages);\n const lang = useLang();\n const moreId = useId();\n const advancedId = useId();\n let advancedOpen = _state(false);\n\n /** 条件里有几条比较(按钮旁的计数) */\n const countRules = (item: Condition): number =>\n !isConditionGroup(item)\n ? 1\n : 'not' in item\n ? countRules(item.not)\n : ('all' in item ? item.all : item.any).reduce(\n (sum, child) => sum + countRules(child),\n 0,\n );\n provideFieldLayout(() => ({ labelPlacement, labelWidth }));\n\n function onSubmit(event: Event) {\n event.preventDefault();\n onSearch?.();\n }\n\n return () => (\n <form\n {...mergeAttrs<'form'>({ sx: filterBarStyles.root }, rest, { role: 'search', onSubmit })}\n data-expanded={more != null ? expanded : undefined}\n >\n <div\n {...mergeAttrs<'div'>(\n { sx: [filterBarStyles.fields, filterBarColumnStyles.columns(minFieldWidth)] },\n propsFields,\n )}\n >\n {children}\n {more != null && expanded && (\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.more }, propsMore, { id: moreId })}>\n {more}\n </div>\n )}\n </div>\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.actions }, propsActions)}>\n {more != null && (\n <Button\n {...mergePartProps<ButtonProps>(\n {\n variant: 'ghost',\n tone: 'neutral',\n iconEnd: ChevronDown,\n propsIconEnd: {\n sx: [disclosureStyles.icon, expanded && filterBarStyles.toggleIconOpen],\n },\n },\n propsToggle,\n {\n type: 'button',\n 'aria-expanded': expanded,\n 'aria-controls': expanded ? moreId : undefined,\n onClick: () => (expanded = !expanded),\n },\n )}\n >\n {expanded ? messages.filterCollapse : messages.filterExpand}\n {!expanded && moreActive > 0 && (\n <Badge tone=\"accent\" radius=\"full\">\n {messages.filterActive(moreActive)}\n </Badge>\n )}\n </Button>\n )}\n {conditionFields && (\n <Button\n {...mergePartProps<ButtonProps>(\n { variant: 'ghost', tone: 'neutral', icon: ListFilter },\n propsAdvancedToggle,\n {\n type: 'button',\n 'aria-expanded': advancedOpen,\n 'aria-controls': advancedOpen ? advancedId : undefined,\n onClick: () => (advancedOpen = !advancedOpen),\n },\n )}\n >\n {messages.filterAdvanced}\n {!advancedOpen && condition && (\n <Badge tone=\"accent\" radius=\"full\">\n {messages.filterActive(countRules(condition))}\n </Badge>\n )}\n </Button>\n )}\n {actions}\n <Button\n {...mergePartProps<ButtonProps>({ variant: 'outline', tone: 'neutral' }, propsReset, {\n type: 'button',\n onClick: () => {\n if (conditionFields) condition = null;\n onReset?.();\n },\n })}\n >\n {messages.filterReset}\n </Button>\n <Button {...mergePartProps<ButtonProps>({ loading }, propsSearch, { type: 'submit' })}>\n {messages.filterSearch}\n </Button>\n </div>\n {conditionFields && advancedOpen && (\n <ConditionBuilder\n {...mergePartProps<ConditionBuilderProps>(\n {\n fields: conditionFields,\n sx: filterBarStyles.advanced,\n 'aria-label': messages.filterAdvanced,\n },\n propsAdvanced,\n { id: advancedId },\n )}\n _value={condition}\n />\n )}\n {conditionFields && !advancedOpen && condition && (\n <div {...css.attrs(filterBarStyles.summary)}>\n <Small tone=\"muted\">\n {messages.filterAdvanced}:{describeCondition(condition, conditionFields, lang)}\n </Small>\n <Button variant=\"link\" size=\"sm\" type=\"button\" onClick={() => (condition = null)}>\n {lang.clear}\n </Button>\n </div>\n )}\n </form>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterBar.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/patterns/FilterBar.tsx"],"sourcesContent":["/**\n * 查询栏(form role=\"search\"):列表页上方的一排筛选条件,最后是“查询”“重置”;条件多时其余的收起来,点“展开”再显示。\n *\n * <FilterBar onSearch={search} onReset={reset} more={<>…不常用的条件…</>} moreActive={2}>\n * <Field label=\"项目名称\"><TextField _value={query.name} /></Field>\n * <Field label=\"任务类别\"><Select … /></Field>\n * </FilterBar>\n *\n * 条件排成栅格:每格不窄于 minFieldWidth,栅格多宽就放几格;按钮区在栅格的结束边,宽度随按钮、不折行,\n * 和条件的最后一行对齐(按钮再多也不会在一格里挤成两行);容器太窄放不下时,按钮区整体换到下一行、靠结束边。\n * 默认标签在起始边、宽度随文字(labelWidth 为 auto:控件紧跟着标签,不留空白;要几行对齐时写固定宽度)。在输入框里按回车就是查询(原生表单提交)。\n * more 收起时不渲染;moreActive 是收起的条件里已经填了几项,显示在“展开”旁边,免得忘了还有条件生效。\n *\n * 高级筛选:给了 conditionFields 时按钮区多一个“高级筛选”,展开后在查询栏下面用 ConditionBuilder 编辑条件树(_condition),\n * 能表达固定条件表达不了的组合(任一满足、介于、不包含);收起时有条件就在下面写成一句话,带“清空”。\n * “重置”同时把条件清成 null。条件是纯 JSON:交给后端(query 的条件树转 SQL)或前端 matchesCondition 筛。\n *\n * <FilterBar onSearch={search} onReset={reset} conditionFields={fields} _condition={condition}>…</FilterBar>\n *\n * start、end 是整行两头的内容(标题在条件前面,工具栏的按钮在查询、重置后面):QueryTable 用它们把标题与工具栏并进查询栏这一行,\n * 压成一行;点“展开”后更多的条件排在这一行下面,start、end 仍在第一行。\n *\n * 部件:Root(form)、Start、Fields(条件的栅格)、Field 们、More(收起的条件,display: contents)、Actions(div)、End、\n * Search、Reset(Button)、Toggle(展开收起的 Button)、AdvancedToggle(高级筛选的 Button)、Advanced(条件构造器那一行)。\n */\nimport { ChevronDown, ListFilter } from '@lucide/icons';\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 { Badge } from '../base/Badge';\nimport { Small } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { useMessages } from '../config/lang/messages';\nimport {\n describeCondition,\n isConditionGroup,\n type Condition,\n type ConditionField,\n} from '../input/condition';\nimport { ConditionBuilder, type ConditionBuilderProps } from '../input/ConditionBuilder';\nimport { patternsMessages } from './messages';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { t } from '../config/theme/tokens';\nimport { provideFieldLayout, type FieldLayout } from '../form/field-layout';\n\n/** 角色与提交由组件管理 */\nexport type FilterBarManaged = 'role' | 'onSubmit' | 'onReset';\n\n/** 未声明的属性落到 form 上 */\nexport interface FilterBarProps\n extends PartProps<'form', FilterBarManaged>, Pick<FieldLayout, 'labelPlacement' | 'labelWidth'> {\n /** 点“查询”或在输入框里按回车 */\n onSearch?: () => void;\n /** 点“重置”:清空条件由使用方做(通常 Object.assign 回初始值,再查询一次) */\n onReset?: () => void;\n /** 查询中:“查询”按钮显示加载中 */\n loading?: boolean;\n /** 不常用的条件:默认收起,点“展开”才显示 */\n more?: VNodeChild;\n /** 是否展开了 more:父级写 _expanded={x} */\n _expanded?: boolean;\n /** 收起的条件里已经填了几项:大于 0 时显示在“展开”旁边 */\n moreActive?: number;\n /** 每个条件的最小宽度(CSS 长度),默认 `'16em'` */\n minFieldWidth?: string;\n /** 整行起始边的内容:在条件前面(QueryTable 的标题);对齐第一行 */\n start?: VNodeChild;\n /** 整行结束边的内容:在查询、重置后面(QueryTable 的工具栏按钮);对齐第一行,展开更多条件时也不往下掉 */\n end?: VNodeChild;\n /** 结束边额外的按钮:放在“重置”前面(如“导出筛选结果”) */\n actions?: VNodeChild;\n /** start 外层的部件属性 */\n propsStart?: PartProps<'div'>;\n /** end 外层的部件属性 */\n propsEnd?: PartProps<'div'>;\n /** 条件栅格的部件属性 */\n propsFields?: PartProps<'div'>;\n /** 按钮区的部件属性 */\n propsActions?: PartProps<'div'>;\n /** 查询按钮的部件属性 */\n propsSearch?: Partial<ButtonProps>;\n /** 重置按钮的部件属性 */\n propsReset?: Partial<ButtonProps>;\n /** 展开收起按钮的部件属性 */\n propsToggle?: Partial<ButtonProps>;\n /** 收起的条件的外层(display: contents)的部件属性 */\n propsMore?: PartProps<'div'>;\n /** 高级筛选的字段:给了时按钮区多一个“高级筛选” */\n conditionFields?: readonly ConditionField[];\n /** 高级筛选的条件:父级写 _condition={condition};没有时是 null,“重置”时清成 null */\n _condition?: Condition | null;\n /** 高级筛选按钮的部件属性 */\n propsAdvancedToggle?: Partial<ButtonProps>;\n /** 高级筛选那一行(条件构造器)的部件属性 */\n propsAdvanced?: Partial<ConditionBuilderProps>;\n /** 常用的条件:Field */\n children?: VNodeChild;\n}\n\n/** FilterBar 的样式:root、start、end、fields、more、actions、toggleIconOpen */\nexport const filterBarStyles = css.create({\n // 条件栅格与按钮区并排;放不下时按钮区换行\n root: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'flex-end',\n columnGap: '_xl',\n rowGap: '_md',\n },\n // 两头的内容和第一行的控件一样高、对齐第一行:展开更多条件时(按钮区落到最后一行)它们仍在第一行\n start: {\n display: 'flex',\n alignItems: 'center',\n alignSelf: 'flex-start',\n minHeight: t.sizes.control,\n flexShrink: 0,\n },\n end: {\n display: 'flex',\n alignItems: 'center',\n alignSelf: 'flex-start',\n minHeight: t.sizes.control,\n flexShrink: 0,\n gap: '_sm',\n },\n fields: {\n display: 'grid',\n columnGap: '_xl',\n rowGap: '_md',\n alignItems: 'start',\n flexGrow: 1,\n minWidth: 0,\n },\n // 收起的条件直接是栅格的格子\n more: { display: 'contents' },\n // 宽度随按钮、不折行;换到下一行时也靠结束边\n actions: {\n display: 'flex',\n alignItems: 'center',\n gap: '_sm',\n flexShrink: 0,\n marginInlineStart: 'auto',\n },\n // 展开后箭头朝上\n toggleIconOpen: { rotate: '180deg' },\n // 高级筛选与它的摘要各占一整行,排在条件与按钮下面\n advanced: {\n flexBasis: '100%',\n padding: '_md',\n backgroundColor: '_surfaceMuted',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_borderMuted',\n borderRadius: '_md',\n },\n summary: { flexBasis: '100%', display: 'flex', alignItems: 'baseline', gap: '_sm', minWidth: 0 },\n});\n\n/** FilterBar 的样式:columns(每格的最小宽度;栅格本身至少放得下一格) */\nexport const filterBarColumnStyles = css.create({\n columns: (minWidth: string) => ({\n flexBasis: minWidth,\n gridTemplateColumns: `repeat(auto-fill, minmax(min(${minWidth}, 100%), 1fr))`,\n }),\n});\n\n/** 查询栏:筛选条件的栅格,查询、重置,不常用的条件可以展开收起 */\nexport const FilterBar = _component(\n ({\n onSearch,\n onReset,\n loading = false,\n more,\n _expanded: expanded = _bindable(false),\n moreActive = 0,\n minFieldWidth = '16em',\n start,\n end,\n actions,\n labelPlacement = 'start',\n labelWidth = 'auto',\n propsStart,\n propsEnd,\n propsFields,\n propsActions,\n propsSearch,\n propsReset,\n propsToggle,\n propsMore,\n conditionFields,\n _condition: condition = _bindable<Condition | null>(null),\n propsAdvancedToggle,\n propsAdvanced,\n children,\n ...rest\n }: FilterBarProps) => {\n const messages = useMessages('patterns', patternsMessages);\n const lang = useLang();\n const moreId = useId();\n const advancedId = useId();\n let advancedOpen = _state(false);\n\n /** 条件里有几条比较(按钮旁的计数) */\n const countRules = (item: Condition): number =>\n !isConditionGroup(item)\n ? 1\n : 'not' in item\n ? countRules(item.not)\n : ('all' in item ? item.all : item.any).reduce(\n (sum, child) => sum + countRules(child),\n 0,\n );\n provideFieldLayout(() => ({ labelPlacement, labelWidth }));\n\n function onSubmit(event: Event) {\n event.preventDefault();\n onSearch?.();\n }\n\n return () => (\n <form\n {...mergeAttrs<'form'>({ sx: filterBarStyles.root }, rest, { role: 'search', onSubmit })}\n data-expanded={more != null ? expanded : undefined}\n >\n {start != null && (\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.start }, propsStart)}>{start}</div>\n )}\n <div\n {...mergeAttrs<'div'>(\n { sx: [filterBarStyles.fields, filterBarColumnStyles.columns(minFieldWidth)] },\n propsFields,\n )}\n >\n {children}\n {more != null && expanded && (\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.more }, propsMore, { id: moreId })}>\n {more}\n </div>\n )}\n </div>\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.actions }, propsActions)}>\n {more != null && (\n <Button\n {...mergePartProps<ButtonProps>(\n {\n variant: 'ghost',\n tone: 'neutral',\n iconEnd: ChevronDown,\n propsIconEnd: {\n sx: [disclosureStyles.icon, expanded && filterBarStyles.toggleIconOpen],\n },\n },\n propsToggle,\n {\n type: 'button',\n 'aria-expanded': expanded,\n 'aria-controls': expanded ? moreId : undefined,\n onClick: () => (expanded = !expanded),\n },\n )}\n >\n {expanded ? messages.filterCollapse : messages.filterExpand}\n {!expanded && moreActive > 0 && (\n <Badge tone=\"accent\" radius=\"full\">\n {messages.filterActive(moreActive)}\n </Badge>\n )}\n </Button>\n )}\n {conditionFields && (\n <Button\n {...mergePartProps<ButtonProps>(\n { variant: 'ghost', tone: 'neutral', icon: ListFilter },\n propsAdvancedToggle,\n {\n type: 'button',\n 'aria-expanded': advancedOpen,\n 'aria-controls': advancedOpen ? advancedId : undefined,\n onClick: () => (advancedOpen = !advancedOpen),\n },\n )}\n >\n {messages.filterAdvanced}\n {!advancedOpen && condition && (\n <Badge tone=\"accent\" radius=\"full\">\n {messages.filterActive(countRules(condition))}\n </Badge>\n )}\n </Button>\n )}\n {actions}\n <Button\n {...mergePartProps<ButtonProps>({ variant: 'outline', tone: 'neutral' }, propsReset, {\n type: 'button',\n onClick: () => {\n if (conditionFields) condition = null;\n onReset?.();\n },\n })}\n >\n {messages.filterReset}\n </Button>\n <Button {...mergePartProps<ButtonProps>({ loading }, propsSearch, { type: 'submit' })}>\n {messages.filterSearch}\n </Button>\n </div>\n {end != null && (\n <div {...mergeAttrs<'div'>({ sx: filterBarStyles.end }, propsEnd)}>{end}</div>\n )}\n {conditionFields && advancedOpen && (\n <ConditionBuilder\n {...mergePartProps<ConditionBuilderProps>(\n {\n fields: conditionFields,\n sx: filterBarStyles.advanced,\n 'aria-label': messages.filterAdvanced,\n },\n propsAdvanced,\n { id: advancedId },\n )}\n _value={condition}\n />\n )}\n {conditionFields && !advancedOpen && condition && (\n <div {...css.attrs(filterBarStyles.summary)}>\n <Small tone=\"muted\">\n {messages.filterAdvanced}:{describeCondition(condition, conditionFields, lang)}\n </Small>\n <Button variant=\"link\" size=\"sm\" type=\"button\" onClick={() => (condition = null)}>\n {lang.clear}\n </Button>\n </div>\n )}\n </form>\n );\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { VNodeChild } from 'vue';
2
+ import { type FormProps } from '../form/Form';
3
+ import { type FormErrorSummaryProps } from '../form/FormErrorSummary';
4
+ import type { FormControllerBase } from '../form/useForm';
5
+ import { type DialogProps } from '../overlay/Dialog';
6
+ /** 未声明的属性落到 dialog 上(见 Dialog) */
7
+ export interface FormDialogProps extends Omit<DialogProps, 'onConfirm' | 'children'> {
8
+ /** useForm() 创建的控制器;确认按钮调它的 submit */
9
+ controller: FormControllerBase;
10
+ /** 表单(form)的部件属性:标签的布局(labelPlacement、labelWidth)等写在这里 */
11
+ propsForm?: Partial<FormProps>;
12
+ /** 错误汇总的部件属性 */
13
+ propsSummary?: Partial<FormErrorSummaryProps>;
14
+ /** 字段 */
15
+ children?: VNodeChild;
16
+ }
17
+ /** 表单对话框:确认就是提交,没通过校验或提交失败时留着 */
18
+ export declare const FormDialog: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<FormDialogProps>;
@@ -0,0 +1,46 @@
1
+ import { mergePartProps } from "../utils/props.js";
2
+ import { Form } from "../form/Form.js";
3
+ import { Alert } from "../feedback/Alert.js";
4
+ import { Dialog } from "../overlay/Dialog.js";
5
+ import { FormErrorSummary } from "../form/FormErrorSummary.js";
6
+ import { createVNode, unref } from "vue";
7
+ import { _component, childrenProp, childrenStable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
8
+ //#region src/patterns/FormDialog.tsx
9
+ /** 未声明的属性落到 dialog 上(见 Dialog) */
10
+ /** 表单对话框:确认就是提交,没通过校验或提交失败时留着 */
11
+ var FormDialog = /*#__PURE__*/ _component((_props, _ctx) => {
12
+ const _cache = [];
13
+ const controller = readonlyProp(_props, "controller");
14
+ const propsForm = readonlyProp(_props, "propsForm");
15
+ const propsSummary = readonlyProp(_props, "propsSummary");
16
+ const children = childrenProp(_props);
17
+ const rest = restProps(_props, _ctx, false);
18
+ return () => createVNode(Dialog, mergeJsxProps(rest, {
19
+ "onConfirm": _cache[0] || (_cache[0] = () => controller.value.submit()),
20
+ "key": "__site1"
21
+ }), {
22
+ default: () => [createVNode(Form, mergeJsxProps(mergePartProps({ controller: controller.value }, propsForm.value), { "key": "__site0" }), {
23
+ default: () => [
24
+ controller.value.formError && createVNode(Alert, {
25
+ "tone": "danger",
26
+ "description": controller.value.formError
27
+ }, null),
28
+ createVNode(FormErrorSummary, propsSummary.value, null),
29
+ unref(children)
30
+ ],
31
+ $stable: childrenStable()
32
+ })],
33
+ $stable: childrenStable()
34
+ });
35
+ }, {
36
+ name: "FormDialog",
37
+ props: [
38
+ "controller",
39
+ "propsForm",
40
+ "propsSummary"
41
+ ]
42
+ });
43
+ //#endregion
44
+ export { FormDialog };
45
+
46
+ //# sourceMappingURL=FormDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormDialog.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps","_vue_unref","_vtp_childrenStable"],"sources":["../../src/patterns/FormDialog.tsx"],"sourcesContent":["/**\n * 表单对话框:Dialog 加 Form 加错误汇总,确认按钮就是提交——校验没通过时留在对话框里(焦点到第一个出错的字段),\n * 提交(useForm 的 onSubmit)进行时确认按钮显示加载中,成功后关闭,失败(reject)时留着。\n * 字段多、有联动、要自己排版的表单用它;一两个文字字段的小表单用命令式的 useFormDialog。\n *\n * const form = useForm({ schema, initial, onSubmit: async (values) => { await api.save(values); open = false; } });\n * <FormDialog controller={form} _open={open} title=\"新建菜单\" size=\"md\">\n * <form.Field name=\"name\" label=\"名称\"><TextField /></form.Field>\n * </FormDialog>\n *\n * 提交被后端拒绝(带业务错误码的错误,如“名称已存在”)时,说明显示在表单顶上的提示条里,对话框留着。\n *\n * 打开前由调用方 form.reset(初始值):新建是空白的初始值,修改是当前记录。在字段里按 Enter 也是提交,\n * 所以 onSubmit 成功后要自己关(写 open = false);只点确认按钮时对话框会在提交成功后自己关。\n *\n * 部件:Dialog 的全部部件(propsConfirm、propsCancel、propsBody 等),加上 Form(propsForm)与 FormErrorSummary(propsSummary)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport type { VNodeChild } from 'vue';\nimport { Alert } from '../feedback/Alert';\nimport { Form, type FormProps } from '../form/Form';\nimport { FormErrorSummary, type FormErrorSummaryProps } from '../form/FormErrorSummary';\nimport type { FormControllerBase } from '../form/useForm';\nimport { Dialog, type DialogProps } from '../overlay/Dialog';\nimport { mergePartProps } from '../utils/props';\n\n/** 未声明的属性落到 dialog 上(见 Dialog) */\nexport interface FormDialogProps extends Omit<DialogProps, 'onConfirm' | 'children'> {\n /** useForm() 创建的控制器;确认按钮调它的 submit */\n controller: FormControllerBase;\n /** 表单(form)的部件属性:标签的布局(labelPlacement、labelWidth)等写在这里 */\n propsForm?: Partial<FormProps>;\n /** 错误汇总的部件属性 */\n propsSummary?: Partial<FormErrorSummaryProps>;\n /** 字段 */\n children?: VNodeChild;\n}\n\n/** 表单对话框:确认就是提交,没通过校验或提交失败时留着 */\nexport const FormDialog = _component(\n ({ controller, propsForm, propsSummary, children, ...rest }: FormDialogProps) =>\n () => (\n <Dialog {...rest} onConfirm={() => controller.submit()}>\n <Form {...mergePartProps<FormProps>({ controller }, propsForm)}>\n {controller.formError && <Alert tone=\"danger\" description={controller.formError} />}\n <FormErrorSummary {...propsSummary} />\n {children}\n </Form>\n </Dialog>\n ),\n);\n"],"mappings":";;;;;;;;;;AAuCA,IAAa,aAAa,0BACxB,QAAA,SAAA;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MAAqD,OAAIC,UAAA,QAAA,MAAA,KAAA;CAAA,aACvDC,YAAA,QAAAC,cACc,MAAI;EAAA,aAAA,OAAA,OAAA,OAAA,WAAmB,WAAA,MAAW,OAAO;EAAC,OAAA;CAAA,CAAA,GAAA;EAAA,eAAA,CAAAD,YAAA,MAAAC,cAC1C,eAA0B,EAAE,YAAU,WAAA,MAAC,GAAC,UAAA,KAAW,GAAC,EAAA,OAAA,UAAA,CAAA,GAAA;GAAA,eAAA;IAC3D,WAAA,MAAW,aAASD,YAAA,OAAA;KAAA,QAAA;KAAA,eAAsC,WAAA,MAAW;IAAS,GAAA,IAAA;IAAIA,YAAA,kBAAA,aAAA,OAAA,IAAA;IAAAE,MAAA,QAAA;GAAA;GAAA,SAAAC,eAAA;EAAA,CAAA,CAAA;EAAA,SAAAA,eAAA;CAAA,CAAA;AAKxF,GAAA;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACL"}
@@ -9,8 +9,8 @@ import { ScrollArea } from "../layout/ScrollArea.js";
9
9
  import { useSortable } from "../utils/dom/sortable.js";
10
10
  import { useMessages } from "../config/lang/messages.js";
11
11
  import { patternsMessages } from "./messages.js";
12
- import { createVNode, mergeProps, shallowRef } from "vue";
13
- import { _component, childrenProp, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
12
+ import { createVNode, shallowRef } from "vue";
13
+ import { _component, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
14
14
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
15
  import { GripVertical } from "@lucide/icons";
16
16
  //#region src/patterns/KanbanBoard.tsx
@@ -209,16 +209,16 @@ var KanbanBoard = /*#__PURE__*/ _component((_props, _ctx) => {
209
209
  const draggedItem = dragging === void 0 ? void 0 : itemOf(dragging);
210
210
  const draggedFrom = draggedItem === void 0 ? void 0 : getColumn.value(draggedItem);
211
211
  return createVNode("div", mergeAttrs({}, rest, { role: "group" }), [
212
- createVNode(ScrollArea, { "axis": "x" }, { default: () => [createVNode("div", mergeProps({ "ref": _cache[0] || (_cache[0] = (element) => board.value = element instanceof HTMLElement ? element : null) }, css.attrs(kanbanBoardStyles.board)), [columns.value.map((column) => {
212
+ createVNode(ScrollArea, { "axis": "x" }, { default: () => [createVNode("div", mergeJsxProps({ "ref": _cache[0] || (_cache[0] = (element) => board.value = element instanceof HTMLElement ? element : null) }, css.attrs(kanbanBoardStyles.board)), [columns.value.map((column) => {
213
213
  const cards = items.value.filter((item) => getColumn.value(item) === column.key);
214
214
  const over = drop && draggedFrom !== column.key && drop.group === column.key;
215
215
  const reason = over ? drop.reason : null;
216
216
  const headingId = `${sortable.instructionsId}-${column.key}`;
217
- const indicator = createVNode("li", mergeProps({
217
+ const indicator = createVNode("li", mergeJsxProps({
218
218
  "key": "drop-indicator",
219
219
  "aria-hidden": "true"
220
220
  }, css.attrs(kanbanBoardStyles.indicator, reason != null && kanbanBoardStyles.indicatorDenied)), null);
221
- return createVNode("section", mergeProps({
221
+ return createVNode("section", mergeJsxProps({
222
222
  "key": column.key,
223
223
  "aria-labelledby": headingId
224
224
  }, sortable.groupProps(column.key), css.attrs(kanbanBoardStyles.column, css.bind(kanbanBoardDynamicStyles.width, () => [columnWidth.value], true), over && (reason ? kanbanBoardStyles.denied : kanbanBoardStyles.allowed))), [
@@ -233,10 +233,10 @@ var KanbanBoard = /*#__PURE__*/ _component((_props, _ctx) => {
233
233
  const key = getKey.value(item);
234
234
  const active = dragging === key;
235
235
  const { onPointerdown: _, ...handle } = sortable.handleProps(key);
236
- const card = createVNode("li", mergeProps({ "key": key }, sortable.itemProps(key), css.attrs(kanbanBoardStyles.card, active && ghost && kanbanBoardStyles.placeholder, active && !ghost && kanbanBoardStyles.lifted), {
236
+ const card = createVNode("li", mergeJsxProps({ "key": key }, sortable.itemProps(key), css.attrs(kanbanBoardStyles.card, active && ghost && kanbanBoardStyles.placeholder, active && !ghost && kanbanBoardStyles.lifted), {
237
237
  "data-state": active ? "dragging" : void 0,
238
238
  "onPointerdown": (event) => onPointerdown(event, key)
239
- }), [createVNode("div", null, [children.value(item, { dragging: active })]), createVNode(ButtonBase, mergeProps(handle, {
239
+ }), [createVNode("div", null, [children.value(item, { dragging: active })]), createVNode(ButtonBase, mergeJsxProps(handle, {
240
240
  "data-handle": "",
241
241
  "sx": kanbanBoardStyles.handle,
242
242
  "aria-label": lang.sortableHandle(labelOf(item))
@@ -250,7 +250,7 @@ var KanbanBoard = /*#__PURE__*/ _component((_props, _ctx) => {
250
250
  ])
251
251
  ]);
252
252
  })])] }),
253
- ghost && ghostItem !== void 0 && createVNode("div", mergeProps({ "aria-hidden": "true" }, css.attrs(kanbanBoardStyles.card, kanbanBoardStyles.ghost, css.bind(kanbanBoardDynamicStyles.ghost, () => [
253
+ ghost && ghostItem !== void 0 && createVNode("div", mergeJsxProps({ "aria-hidden": "true" }, css.attrs(kanbanBoardStyles.card, kanbanBoardStyles.ghost, css.bind(kanbanBoardDynamicStyles.ghost, () => [
254
254
  ghost.left,
255
255
  ghost.top,
256
256
  ghost.width
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanBoard.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/patterns/KanbanBoard.tsx"],"sourcesContent":["/**\n * 看板:一列一个状态(或阶段、负责人),卡片在列之间移动。任务看板、招聘流程、工单。\n *\n * <KanbanBoard\n * aria-label=\"任务看板\"\n * columns={[{ key: 'designing', label: '设计中' }, { key: 'verifying', label: '测试中' }]}\n * items={tasks}\n * getKey={(task) => task.code}\n * getColumn={(task) => task.status}\n * getLabel={(task) => task.name}\n * canMove={(task, to) => (to === next(task.status) ? null : '只能拖到下一列')}\n * onMove={(task, to) => openProcessDialog(task, to)}\n * >\n * {(task) => <TaskCard task={task} />}\n * </KanbanBoard>\n *\n * 数据由使用方控制:看板不自己挪卡片,只在放下时报告 onMove(使用方处理完、刷新数据,卡片才换列)。\n * canMove 返回不能移动的原因(null 是可以):拖动时经过的列按它高亮(可以放的是强调色,不能放的标红并写出原因),\n * 落点处画一条插入线;放在不能放的列上时卡片弹回、读屏播报原因,并报告 onReject。\n * 给了 onReorder 时列内也能排序(数据立即重排,写回整个数组)。\n *\n * 拖动、键盘、读屏播报、自动滚动建在 useSortable 的分组上(utils/dom/sortable.ts):\n * - 指针:在卡片上按下拖动超过 3px 开始(点在卡片里的链接、按钮上不算),影子卡跟着指针走,原位留着变淡的占位;\n * - 键盘:每张卡片有把手按钮,空格 / Enter 拿起,← / → 换列(从右到左排版下镜像),↑ / ↓ 调整位置,\n * 空格 / Enter 放下,Esc 取消;每一步都有读屏播报(aria-live)。\n * 列多时整块横向滚动(ScrollArea),每列里的卡片多时列自己竖向滚动。\n */\nimport { GripVertical } 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 { Badge } from '../base/Badge';\nimport { useMessages } from '../config/lang/messages';\nimport { patternsMessages } from './messages';\nimport { ButtonBase } from '../base/ButtonBase';\nimport { Icon } from '../base/Icon';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { ScrollArea } from '../layout/ScrollArea';\nimport { useSortable } from '../utils/dom/sortable';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { t } from '../config/theme/tokens';\n\n/** 看板的一列 */\nexport interface KanbanColumn {\n /** 列的标识:getColumn 返回它 */\n key: string;\n /** 列名 */\n label: string;\n /** 列名旁计数的色调(超时、异常这类要注意的列) */\n tone?: StatusTone;\n}\n\n/** 卡片的渲染状态 */\nexport interface KanbanCardState {\n /** 正在被拖动或被键盘拿起 */\n dragging: boolean;\n}\n\n/** 未声明的属性落到外层 div 上;aria-label 是看板的名称 */\nexport interface KanbanBoardProps<T> extends PartProps<'div'> {\n /** 各列:从起始边排 */\n columns: readonly KanbanColumn[];\n /** 全部卡片的数据 */\n items: readonly T[];\n /** 卡片的标识 */\n getKey: (item: T) => string;\n /** 卡片在哪一列 */\n getColumn: (item: T) => string;\n /** 卡片的名称:把手的名称、读屏播报;默认是 key */\n getLabel?: (item: T) => string;\n /** 能不能移到 to 列:返回不能的原因,null、undefined 是可以 */\n canMove?: (item: T, to: string) => string | null | undefined;\n /** 放到了可以放的列:使用方处理(打开处理的对话框、调接口),完成后刷新数据;index 是在目标列里的位置 */\n onMove: (item: T, to: string, index: number) => void;\n /** 列内排序:写回新的数组(所有列的卡片);不给时列内不能排序 */\n onReorder?: (items: T[]) => void;\n /** 放到了不能放的列:卡片已经弹回,可以在这里提示原因 */\n onReject?: (item: T, to: string, reason: string) => void;\n /**\n * 每列至少多宽(CSS 长度):放得下时各列平分整行,放不下时横向滚动\n * @default '16rem'\n */\n columnWidth?: string;\n /**\n * 每列的最大高度(CSS 长度):卡片多时列里竖向滚动\n * @default '70vh'\n */\n columnHeight?: string;\n /** 一列没有卡片时显示的内容,默认“没有” */\n empty?: VNodeChild;\n /** 卡片的内容 */\n children: (item: T, state: KanbanCardState) => VNodeChild;\n}\n\n/** KanbanBoard 的样式:board、column、header、list、card、handle… */\nexport const kanbanBoardStyles = css.create({\n board: { display: 'flex', gap: '_md', alignItems: 'flex-start', paddingBlockEnd: '_sm' },\n column: {\n display: 'flex',\n flexDirection: 'column',\n flexShrink: 0,\n borderRadius: '_lg',\n backgroundColor: '_surfaceMuted',\n outlineWidth: '_borderWidths.sm',\n outlineStyle: 'solid',\n outlineColor: 'transparent',\n outlineOffset: '-2px',\n transition: `outline-color ${t.durations.sm} ${t.easings.standard}`,\n },\n allowed: { outlineColor: '_accent' },\n denied: { outlineColor: '_danger' },\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '_sm',\n paddingBlock: '_sm',\n paddingInline: '_md',\n fontWeight: '_semibold',\n fontSize: '_sm',\n },\n reason: { paddingInline: '_md', paddingBlockEnd: '_xs', color: '_dangerText', fontSize: '_xs' },\n list: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_sm',\n margin: 0,\n paddingInline: '_sm',\n paddingBlockEnd: '_sm',\n listStyle: 'none',\n overflowY: 'auto',\n minHeight: '3rem',\n },\n card: {\n position: 'relative',\n display: 'grid',\n gridTemplateColumns: 'minmax(0, 1fr) auto',\n alignItems: 'start',\n gap: '_xs',\n padding: '_sm',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n backgroundColor: '_surfaceRaised',\n cursor: 'grab',\n touchAction: 'none',\n transition: `translate ${t.durations.md} ${t.easings.standard}`,\n },\n // 指针拖动中:原位的卡片变淡,跟着指针走的是影子卡(画在滚动区域外面,不被列裁掉)\n placeholder: { opacity: 0.4 },\n ghost: {\n position: 'fixed',\n zIndex: 50,\n pointerEvents: 'none',\n cursor: 'grabbing',\n boxShadow: '_lg',\n transition: 'none',\n rotate: '1.5deg',\n },\n // 键盘拿起:高亮边框\n lifted: { borderColor: '_accent', boxShadow: '_md' },\n handle: { color: '_textMuted', borderRadius: '_sm', padding: '2px', cursor: 'grab' },\n empty: { color: '_textMuted', fontSize: '_xs', paddingBlock: '_sm', textAlign: 'center' },\n // 拖到别的列时的落点:卡片之间的一条线\n indicator: {\n height: '_borderWidths.md',\n marginBlock: `calc(-1 * ${t.space.xs})`,\n borderRadius: '_full',\n backgroundColor: '_accent',\n },\n indicatorDenied: { backgroundColor: '_danger' },\n});\n\n/** KanbanBoard 的动态样式:列宽、列高、拖动的位移 */\nexport const kanbanBoardDynamicStyles = css.create({\n // 至少这么宽,富余的空间各列平分(同 Jira 的看板),放不下时外层横向滚动\n width: (width: string) => ({ flexBasis: width, flexGrow: 1, minWidth: width }),\n height: (height: string) => ({ maxHeight: height }),\n ghost: (left: number, top: number, width: number) => ({ left, top, width }),\n});\n\n/** 看板 */\nexport const KanbanBoard = _component(\n <T,>({\n columns,\n items,\n getKey,\n getColumn,\n getLabel,\n canMove,\n onMove,\n onReorder,\n onReject,\n columnWidth = '16rem',\n columnHeight = '70vh',\n empty,\n children,\n ...rest\n }: KanbanBoardProps<T>) => {\n const lang = useLang();\n const messages = useMessages('patterns', patternsMessages);\n let board = _state.raw<HTMLElement | null>(null);\n const labelOf = (item: T) => getLabel?.(item) ?? getKey(item);\n const itemOf = (key: string) => items.find((item) => getKey(item) === key);\n const sortable = useSortable({\n items: () => items,\n getKey: (item) => getKey(item),\n getLabel: labelOf,\n // 用时再读属性:写没写 onReorder 决定了列内能不能排序,父级后来才给也要跟上\n get onChange() {\n return onReorder && ((next: T[]) => onReorder(next));\n },\n container: () => board,\n groups: {\n keys: () => columns.map((column) => column.key),\n of: (item) => getColumn(item),\n label: (key) => columns.find((column) => column.key === key)?.label ?? key,\n canMove: (item, to) => canMove?.(item, to),\n onMove: (item, to, index) => onMove(item, to, index),\n onReject: (item, to, reason) => onReject?.(item, to, reason),\n },\n });\n\n /** 整张卡片都能拖:卡片里的链接、按钮(把手除外)、输入框照常点 */\n function onPointerdown(event: PointerEvent, key: string) {\n const target = event.target as Element;\n if (target.closest('a, input, select, textarea, button:not([data-handle])')) return;\n (sortable.handleProps(key).onPointerdown as (event: PointerEvent) => void)(event);\n }\n\n return () => {\n const dragging = sortable.active;\n const drop = sortable.target;\n const ghost = sortable.ghost;\n const ghostItem = ghost && itemOf(ghost.key);\n const draggedItem = dragging === undefined ? undefined : itemOf(dragging);\n const draggedFrom = draggedItem === undefined ? undefined : getColumn(draggedItem);\n return (\n <div {...mergeAttrs<'div'>({}, rest, { role: 'group' })}>\n <ScrollArea axis=\"x\">\n <div\n ref={(element: unknown) => (board = element instanceof HTMLElement ? element : null)}\n {...css.attrs(kanbanBoardStyles.board)}\n >\n {columns.map((column) => {\n const cards = items.filter((item) => getColumn(item) === column.key);\n // 拖到了别的列:高亮这一列,在落点画线\n const over = drop && draggedFrom !== column.key && drop.group === column.key;\n const reason = over ? drop.reason : null;\n const headingId = `${sortable.instructionsId}-${column.key}`;\n const indicator = (\n <li\n key=\"drop-indicator\"\n aria-hidden=\"true\"\n {...css.attrs(\n kanbanBoardStyles.indicator,\n reason != null && kanbanBoardStyles.indicatorDenied,\n )}\n />\n );\n return (\n <section\n key={column.key}\n aria-labelledby={headingId}\n {...sortable.groupProps(column.key)}\n {...css.attrs(\n kanbanBoardStyles.column,\n kanbanBoardDynamicStyles.width(columnWidth),\n over && (reason ? kanbanBoardStyles.denied : kanbanBoardStyles.allowed),\n )}\n >\n <div {...css.attrs(kanbanBoardStyles.header)}>\n <span id={headingId}>{column.label}</span>\n <Badge\n radius=\"full\"\n tone={cards.length > 0 ? (column.tone ?? 'neutral') : 'neutral'}\n >\n {cards.length}\n </Badge>\n </div>\n {reason && <div {...css.attrs(kanbanBoardStyles.reason)}>{reason}</div>}\n <ul\n {...css.attrs(\n kanbanBoardStyles.list,\n kanbanBoardDynamicStyles.height(columnHeight),\n )}\n >\n {cards.length === 0 && !over && (\n <li {...css.attrs(kanbanBoardStyles.empty)}>\n {empty ?? messages.kanbanEmpty}\n </li>\n )}\n {cards.flatMap((item, index) => {\n const key = getKey(item);\n const active = dragging === key;\n const { onPointerdown: _, ...handle } = sortable.handleProps(key);\n const card = (\n <li\n key={key}\n {...sortable.itemProps(key)}\n {...css.attrs(\n kanbanBoardStyles.card,\n active && ghost && kanbanBoardStyles.placeholder,\n active && !ghost && kanbanBoardStyles.lifted,\n )}\n data-state={active ? 'dragging' : undefined}\n onPointerdown={(event: PointerEvent) => onPointerdown(event, key)}\n >\n <div>{children(item, { dragging: active })}</div>\n <ButtonBase\n {...handle}\n data-handle=\"\"\n sx={kanbanBoardStyles.handle}\n aria-label={lang.sortableHandle(labelOf(item))}\n >\n <Icon icon={GripVertical} />\n </ButtonBase>\n </li>\n );\n return over && drop.index === index ? [indicator, card] : [card];\n })}\n {over && drop.index >= cards.length && indicator}\n </ul>\n </section>\n );\n })}\n </div>\n </ScrollArea>\n {ghost && ghostItem !== undefined && (\n <div\n aria-hidden=\"true\"\n {...css.attrs(\n kanbanBoardStyles.card,\n kanbanBoardStyles.ghost,\n kanbanBoardDynamicStyles.ghost(ghost.left, ghost.top, ghost.width),\n )}\n >\n <div>{children(ghostItem, { dragging: true })}</div>\n </div>\n )}\n <VisuallyHidden id={sortable.instructionsId}>\n {messages.kanbanInstructions}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{sortable.announcement}</VisuallyHidden>\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"KanbanBoard.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/patterns/KanbanBoard.tsx"],"sourcesContent":["/**\n * 看板:一列一个状态(或阶段、负责人),卡片在列之间移动。任务看板、招聘流程、工单。\n *\n * <KanbanBoard\n * aria-label=\"任务看板\"\n * columns={[{ key: 'designing', label: '设计中' }, { key: 'verifying', label: '测试中' }]}\n * items={tasks}\n * getKey={(task) => task.code}\n * getColumn={(task) => task.status}\n * getLabel={(task) => task.name}\n * canMove={(task, to) => (to === next(task.status) ? null : '只能拖到下一列')}\n * onMove={(task, to) => openProcessDialog(task, to)}\n * >\n * {(task) => <TaskCard task={task} />}\n * </KanbanBoard>\n *\n * 数据由使用方控制:看板不自己挪卡片,只在放下时报告 onMove(使用方处理完、刷新数据,卡片才换列)。\n * canMove 返回不能移动的原因(null 是可以):拖动时经过的列按它高亮(可以放的是强调色,不能放的标红并写出原因),\n * 落点处画一条插入线;放在不能放的列上时卡片弹回、读屏播报原因,并报告 onReject。\n * 给了 onReorder 时列内也能排序(数据立即重排,写回整个数组)。\n *\n * 拖动、键盘、读屏播报、自动滚动建在 useSortable 的分组上(utils/dom/sortable.ts):\n * - 指针:在卡片上按下拖动超过 3px 开始(点在卡片里的链接、按钮上不算),影子卡跟着指针走,原位留着变淡的占位;\n * - 键盘:每张卡片有把手按钮,空格 / Enter 拿起,← / → 换列(从右到左排版下镜像),↑ / ↓ 调整位置,\n * 空格 / Enter 放下,Esc 取消;每一步都有读屏播报(aria-live)。\n * 列多时整块横向滚动(ScrollArea),每列里的卡片多时列自己竖向滚动。\n */\nimport { GripVertical } 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 { Badge } from '../base/Badge';\nimport { useMessages } from '../config/lang/messages';\nimport { patternsMessages } from './messages';\nimport { ButtonBase } from '../base/ButtonBase';\nimport { Icon } from '../base/Icon';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { ScrollArea } from '../layout/ScrollArea';\nimport { useSortable } from '../utils/dom/sortable';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { t } from '../config/theme/tokens';\n\n/** 看板的一列 */\nexport interface KanbanColumn {\n /** 列的标识:getColumn 返回它 */\n key: string;\n /** 列名 */\n label: string;\n /** 列名旁计数的色调(超时、异常这类要注意的列) */\n tone?: StatusTone;\n}\n\n/** 卡片的渲染状态 */\nexport interface KanbanCardState {\n /** 正在被拖动或被键盘拿起 */\n dragging: boolean;\n}\n\n/** 未声明的属性落到外层 div 上;aria-label 是看板的名称 */\nexport interface KanbanBoardProps<T> extends PartProps<'div'> {\n /** 各列:从起始边排 */\n columns: readonly KanbanColumn[];\n /** 全部卡片的数据 */\n items: readonly T[];\n /** 卡片的标识 */\n getKey: (item: T) => string;\n /** 卡片在哪一列 */\n getColumn: (item: T) => string;\n /** 卡片的名称:把手的名称、读屏播报;默认是 key */\n getLabel?: (item: T) => string;\n /** 能不能移到 to 列:返回不能的原因,null、undefined 是可以 */\n canMove?: (item: T, to: string) => string | null | undefined;\n /** 放到了可以放的列:使用方处理(打开处理的对话框、调接口),完成后刷新数据;index 是在目标列里的位置 */\n onMove: (item: T, to: string, index: number) => void;\n /** 列内排序:写回新的数组(所有列的卡片);不给时列内不能排序 */\n onReorder?: (items: T[]) => void;\n /** 放到了不能放的列:卡片已经弹回,可以在这里提示原因 */\n onReject?: (item: T, to: string, reason: string) => void;\n /**\n * 每列至少多宽(CSS 长度):放得下时各列平分整行,放不下时横向滚动\n * @default '16rem'\n */\n columnWidth?: string;\n /**\n * 每列的最大高度(CSS 长度):卡片多时列里竖向滚动\n * @default '70vh'\n */\n columnHeight?: string;\n /** 一列没有卡片时显示的内容,默认“没有” */\n empty?: VNodeChild;\n /** 卡片的内容 */\n children: (item: T, state: KanbanCardState) => VNodeChild;\n}\n\n/** KanbanBoard 的样式:board、column、header、list、card、handle… */\nexport const kanbanBoardStyles = css.create({\n board: { display: 'flex', gap: '_md', alignItems: 'flex-start', paddingBlockEnd: '_sm' },\n column: {\n display: 'flex',\n flexDirection: 'column',\n flexShrink: 0,\n borderRadius: '_lg',\n backgroundColor: '_surfaceMuted',\n outlineWidth: '_borderWidths.sm',\n outlineStyle: 'solid',\n outlineColor: 'transparent',\n outlineOffset: '-2px',\n transition: `outline-color ${t.durations.sm} ${t.easings.standard}`,\n },\n allowed: { outlineColor: '_accent' },\n denied: { outlineColor: '_danger' },\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '_sm',\n paddingBlock: '_sm',\n paddingInline: '_md',\n fontWeight: '_semibold',\n fontSize: '_sm',\n },\n reason: { paddingInline: '_md', paddingBlockEnd: '_xs', color: '_dangerText', fontSize: '_xs' },\n list: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_sm',\n margin: 0,\n paddingInline: '_sm',\n paddingBlockEnd: '_sm',\n listStyle: 'none',\n overflowY: 'auto',\n minHeight: '3rem',\n },\n card: {\n position: 'relative',\n display: 'grid',\n gridTemplateColumns: 'minmax(0, 1fr) auto',\n alignItems: 'start',\n gap: '_xs',\n padding: '_sm',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n backgroundColor: '_surfaceRaised',\n cursor: 'grab',\n touchAction: 'none',\n transition: `translate ${t.durations.md} ${t.easings.standard}`,\n },\n // 指针拖动中:原位的卡片变淡,跟着指针走的是影子卡(画在滚动区域外面,不被列裁掉)\n placeholder: { opacity: 0.4 },\n ghost: {\n position: 'fixed',\n zIndex: 50,\n pointerEvents: 'none',\n cursor: 'grabbing',\n boxShadow: '_lg',\n transition: 'none',\n rotate: '1.5deg',\n },\n // 键盘拿起:高亮边框\n lifted: { borderColor: '_accent', boxShadow: '_md' },\n handle: { color: '_textMuted', borderRadius: '_sm', padding: '2px', cursor: 'grab' },\n empty: { color: '_textMuted', fontSize: '_xs', paddingBlock: '_sm', textAlign: 'center' },\n // 拖到别的列时的落点:卡片之间的一条线\n indicator: {\n height: '_borderWidths.md',\n marginBlock: `calc(-1 * ${t.space.xs})`,\n borderRadius: '_full',\n backgroundColor: '_accent',\n },\n indicatorDenied: { backgroundColor: '_danger' },\n});\n\n/** KanbanBoard 的动态样式:列宽、列高、拖动的位移 */\nexport const kanbanBoardDynamicStyles = css.create({\n // 至少这么宽,富余的空间各列平分(同 Jira 的看板),放不下时外层横向滚动\n width: (width: string) => ({ flexBasis: width, flexGrow: 1, minWidth: width }),\n height: (height: string) => ({ maxHeight: height }),\n ghost: (left: number, top: number, width: number) => ({ left, top, width }),\n});\n\n/** 看板 */\nexport const KanbanBoard = _component(\n <T,>({\n columns,\n items,\n getKey,\n getColumn,\n getLabel,\n canMove,\n onMove,\n onReorder,\n onReject,\n columnWidth = '16rem',\n columnHeight = '70vh',\n empty,\n children,\n ...rest\n }: KanbanBoardProps<T>) => {\n const lang = useLang();\n const messages = useMessages('patterns', patternsMessages);\n let board = _state.raw<HTMLElement | null>(null);\n const labelOf = (item: T) => getLabel?.(item) ?? getKey(item);\n const itemOf = (key: string) => items.find((item) => getKey(item) === key);\n const sortable = useSortable({\n items: () => items,\n getKey: (item) => getKey(item),\n getLabel: labelOf,\n // 用时再读属性:写没写 onReorder 决定了列内能不能排序,父级后来才给也要跟上\n get onChange() {\n return onReorder && ((next: T[]) => onReorder(next));\n },\n container: () => board,\n groups: {\n keys: () => columns.map((column) => column.key),\n of: (item) => getColumn(item),\n label: (key) => columns.find((column) => column.key === key)?.label ?? key,\n canMove: (item, to) => canMove?.(item, to),\n onMove: (item, to, index) => onMove(item, to, index),\n onReject: (item, to, reason) => onReject?.(item, to, reason),\n },\n });\n\n /** 整张卡片都能拖:卡片里的链接、按钮(把手除外)、输入框照常点 */\n function onPointerdown(event: PointerEvent, key: string) {\n const target = event.target as Element;\n if (target.closest('a, input, select, textarea, button:not([data-handle])')) return;\n (sortable.handleProps(key).onPointerdown as (event: PointerEvent) => void)(event);\n }\n\n return () => {\n const dragging = sortable.active;\n const drop = sortable.target;\n const ghost = sortable.ghost;\n const ghostItem = ghost && itemOf(ghost.key);\n const draggedItem = dragging === undefined ? undefined : itemOf(dragging);\n const draggedFrom = draggedItem === undefined ? undefined : getColumn(draggedItem);\n return (\n <div {...mergeAttrs<'div'>({}, rest, { role: 'group' })}>\n <ScrollArea axis=\"x\">\n <div\n ref={(element: unknown) => (board = element instanceof HTMLElement ? element : null)}\n {...css.attrs(kanbanBoardStyles.board)}\n >\n {columns.map((column) => {\n const cards = items.filter((item) => getColumn(item) === column.key);\n // 拖到了别的列:高亮这一列,在落点画线\n const over = drop && draggedFrom !== column.key && drop.group === column.key;\n const reason = over ? drop.reason : null;\n const headingId = `${sortable.instructionsId}-${column.key}`;\n const indicator = (\n <li\n key=\"drop-indicator\"\n aria-hidden=\"true\"\n {...css.attrs(\n kanbanBoardStyles.indicator,\n reason != null && kanbanBoardStyles.indicatorDenied,\n )}\n />\n );\n return (\n <section\n key={column.key}\n aria-labelledby={headingId}\n {...sortable.groupProps(column.key)}\n {...css.attrs(\n kanbanBoardStyles.column,\n kanbanBoardDynamicStyles.width(columnWidth),\n over && (reason ? kanbanBoardStyles.denied : kanbanBoardStyles.allowed),\n )}\n >\n <div {...css.attrs(kanbanBoardStyles.header)}>\n <span id={headingId}>{column.label}</span>\n <Badge\n radius=\"full\"\n tone={cards.length > 0 ? (column.tone ?? 'neutral') : 'neutral'}\n >\n {cards.length}\n </Badge>\n </div>\n {reason && <div {...css.attrs(kanbanBoardStyles.reason)}>{reason}</div>}\n <ul\n {...css.attrs(\n kanbanBoardStyles.list,\n kanbanBoardDynamicStyles.height(columnHeight),\n )}\n >\n {cards.length === 0 && !over && (\n <li {...css.attrs(kanbanBoardStyles.empty)}>\n {empty ?? messages.kanbanEmpty}\n </li>\n )}\n {cards.flatMap((item, index) => {\n const key = getKey(item);\n const active = dragging === key;\n const { onPointerdown: _, ...handle } = sortable.handleProps(key);\n const card = (\n <li\n key={key}\n {...sortable.itemProps(key)}\n {...css.attrs(\n kanbanBoardStyles.card,\n active && ghost && kanbanBoardStyles.placeholder,\n active && !ghost && kanbanBoardStyles.lifted,\n )}\n data-state={active ? 'dragging' : undefined}\n onPointerdown={(event: PointerEvent) => onPointerdown(event, key)}\n >\n <div>{children(item, { dragging: active })}</div>\n <ButtonBase\n {...handle}\n data-handle=\"\"\n sx={kanbanBoardStyles.handle}\n aria-label={lang.sortableHandle(labelOf(item))}\n >\n <Icon icon={GripVertical} />\n </ButtonBase>\n </li>\n );\n return over && drop.index === index ? [indicator, card] : [card];\n })}\n {over && drop.index >= cards.length && indicator}\n </ul>\n </section>\n );\n })}\n </div>\n </ScrollArea>\n {ghost && ghostItem !== undefined && (\n <div\n aria-hidden=\"true\"\n {...css.attrs(\n kanbanBoardStyles.card,\n kanbanBoardStyles.ghost,\n kanbanBoardDynamicStyles.ghost(ghost.left, ghost.top, ghost.width),\n )}\n >\n <div>{children(ghostItem, { dragging: true })}</div>\n </div>\n )}\n <VisuallyHidden id={sortable.instructionsId}>\n {messages.kanbanInstructions}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{sortable.announcement}</VisuallyHidden>\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type IconButtonProps } from '../base/IconButton';
2
+ import { type MenuProps } from '../overlay/Menu';
3
+ import { type LayoutPreference } from '../config/layout/preference';
4
+ /** 未声明的属性落到菜单(role="menu" 的 div)上 */
5
+ export interface LayoutSwitcherProps extends Omit<MenuProps, 'trigger' | 'children'> {
6
+ /** createLayoutPreference 的结果 */
7
+ layout: LayoutPreference;
8
+ /** 触发按钮的部件属性 */
9
+ propsTrigger?: Partial<IconButtonProps>;
10
+ }
11
+ /** 布局切换(图标按钮 + 两组单选菜单) */
12
+ export declare const LayoutSwitcher: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<LayoutSwitcherProps>;
@@ -0,0 +1,79 @@
1
+ import { mergePartProps } from "../utils/props.js";
2
+ import { IconButton } from "../base/IconButton.js";
3
+ import { Menu as Menu$1, MenuGroup, MenuRadioGroup, MenuRadioItem } from "../overlay/Menu.js";
4
+ import { LAYOUT_MODES, LAYOUT_SIDES } from "../config/layout/preference.js";
5
+ import { useMessages } from "../config/lang/messages.js";
6
+ import { patternsMessages } from "./messages.js";
7
+ import { createVNode, isVNode } from "vue";
8
+ import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
9
+ import { Columns2, PanelBottom, PanelLeft, PanelRight, PanelTop } from "@lucide/icons";
10
+ //#region src/patterns/LayoutSwitcher.tsx
11
+ /**
12
+ * 布局切换:图标按钮弹出菜单,两组单选——侧栏的形式(固定 / 抽屉)和抽屉从哪一边滑出(左 / 右 / 上 / 下),
13
+ * 配合 createLayoutPreference 与 AppShell 的 layout 使用,和 ThemeSwitcher 并排放在顶栏里。
14
+ *
15
+ * const layout = createLayoutPreference({ defaults: { mode: 'overlay' } });
16
+ * <AppShell layout={layout} header={<><LayoutSwitcher layout={layout} /><ThemeSwitcher preference={theme} /></>} …>
17
+ *
18
+ * 选了“固定”时抽屉位置不可选(固定侧栏总是在起始边)。触发按钮的图标表示当前的位置。
19
+ */
20
+ /** 未声明的属性落到菜单(role="menu" 的 div)上 */
21
+ function _isSlot(s) {
22
+ return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
23
+ }
24
+ var SIDE_ICONS = {
25
+ start: PanelLeft,
26
+ end: PanelRight,
27
+ top: PanelTop,
28
+ bottom: PanelBottom
29
+ };
30
+ /** 布局切换(图标按钮 + 两组单选菜单) */
31
+ var LayoutSwitcher = /*#__PURE__*/ _component((_props, _ctx) => {
32
+ const _cache = [];
33
+ const layout = readonlyProp(_props, "layout");
34
+ const propsTrigger = readonlyProp(_props, "propsTrigger");
35
+ const rest = restProps(_props, _ctx, true);
36
+ const messages = useMessages("patterns", patternsMessages);
37
+ const modeLabels = {
38
+ docked: messages.layoutModeDocked,
39
+ overlay: messages.layoutModeOverlay
40
+ };
41
+ const sideLabels = {
42
+ start: messages.layoutSideStart,
43
+ end: messages.layoutSideEnd,
44
+ top: messages.layoutSideTop,
45
+ bottom: messages.layoutSideBottom
46
+ };
47
+ const triggerIcon = () => layout.value.mode === "overlay" ? SIDE_ICONS[layout.value.side] : Columns2;
48
+ return () => {
49
+ let _slot, _slot2;
50
+ return createVNode(Menu$1, mergeJsxProps(rest, { "trigger": _cache[0] || (_cache[0] = (props) => createVNode(IconButton, mergePartProps({
51
+ icon: triggerIcon(),
52
+ "aria-label": messages.layoutLabel
53
+ }, propsTrigger.value, props), null)) }), { default: () => [createVNode(MenuGroup, { "label": messages.layoutMode }, { default: () => [createVNode(MenuRadioGroup, {
54
+ "_value": layout.value.mode,
55
+ "onUpdate:_value": _cache[1] || (_cache[1] = (value) => layout.value.mode = value),
56
+ "aria-label": messages.layoutMode
57
+ }, _isSlot(_slot = LAYOUT_MODES.map((mode) => createVNode(MenuRadioItem, {
58
+ "key": mode,
59
+ "value": mode,
60
+ "icon": mode === "overlay" ? PanelLeft : Columns2
61
+ }, { default: () => [modeLabels[mode]] }))) ? _slot : { default: () => [_slot] })] }), createVNode(MenuGroup, { "label": messages.layoutSide }, { default: () => [createVNode(MenuRadioGroup, {
62
+ "_value": layout.value.side,
63
+ "onUpdate:_value": _cache[2] || (_cache[2] = (value) => layout.value.side = value),
64
+ "aria-label": messages.layoutSide
65
+ }, _isSlot(_slot2 = LAYOUT_SIDES.map((side) => createVNode(MenuRadioItem, {
66
+ "key": side,
67
+ "value": side,
68
+ "icon": SIDE_ICONS[side],
69
+ "disabled": layout.value.mode !== "overlay"
70
+ }, { default: () => [sideLabels[side]] }))) ? _slot2 : { default: () => [_slot2] })] })] });
71
+ };
72
+ }, {
73
+ name: "LayoutSwitcher",
74
+ props: ["layout", "propsTrigger"]
75
+ });
76
+ //#endregion
77
+ export { LayoutSwitcher };
78
+
79
+ //# sourceMappingURL=LayoutSwitcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayoutSwitcher.js","names":["_isVNode","_vtp_readonlyProp","_vtp_restProps","_createVNode","Menu","_mergeProps"],"sources":["../../src/patterns/LayoutSwitcher.tsx"],"sourcesContent":["/**\n * 布局切换:图标按钮弹出菜单,两组单选——侧栏的形式(固定 / 抽屉)和抽屉从哪一边滑出(左 / 右 / 上 / 下),\n * 配合 createLayoutPreference 与 AppShell 的 layout 使用,和 ThemeSwitcher 并排放在顶栏里。\n *\n * const layout = createLayoutPreference({ defaults: { mode: 'overlay' } });\n * <AppShell layout={layout} header={<><LayoutSwitcher layout={layout} /><ThemeSwitcher preference={theme} /></>} …>\n *\n * 选了“固定”时抽屉位置不可选(固定侧栏总是在起始边)。触发按钮的图标表示当前的位置。\n */\nimport { Columns2, PanelBottom, PanelLeft, PanelRight, PanelTop } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useMessages } from '../config/lang/messages';\nimport { patternsMessages } from './messages';\nimport type { IconData } from '../base/Icon';\nimport { Menu, MenuGroup, MenuRadioGroup, MenuRadioItem, type MenuProps } from '../overlay/Menu';\nimport {\n LAYOUT_MODES,\n LAYOUT_SIDES,\n type LayoutMode,\n type LayoutPreference,\n type LayoutSide,\n} from '../config/layout/preference';\nimport { mergePartProps } from '../utils/props';\n\n/** 未声明的属性落到菜单(role=\"menu\" 的 div)上 */\nexport interface LayoutSwitcherProps extends Omit<MenuProps, 'trigger' | 'children'> {\n /** createLayoutPreference 的结果 */\n layout: LayoutPreference;\n /** 触发按钮的部件属性 */\n propsTrigger?: Partial<IconButtonProps>;\n}\n\nconst SIDE_ICONS: Record<LayoutSide, IconData> = {\n start: PanelLeft,\n end: PanelRight,\n top: PanelTop,\n bottom: PanelBottom,\n};\n\n/** 布局切换(图标按钮 + 两组单选菜单) */\nexport const LayoutSwitcher = _component(\n ({ layout, propsTrigger, ...rest }: LayoutSwitcherProps) => {\n const messages = useMessages('patterns', patternsMessages);\n const modeLabels: Record<LayoutMode, string> = {\n docked: messages.layoutModeDocked,\n overlay: messages.layoutModeOverlay,\n };\n const sideLabels: Record<LayoutSide, string> = {\n start: messages.layoutSideStart,\n end: messages.layoutSideEnd,\n top: messages.layoutSideTop,\n bottom: messages.layoutSideBottom,\n };\n // 触发按钮:抽屉时显示它的方向,固定时显示“两栏”\n const triggerIcon = () => (layout.mode === 'overlay' ? SIDE_ICONS[layout.side] : Columns2);\n\n return () => (\n <Menu\n {...rest}\n trigger={(props) => (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n { icon: triggerIcon(), 'aria-label': messages.layoutLabel },\n propsTrigger,\n props,\n )}\n />\n )}\n >\n <MenuGroup label={messages.layoutMode}>\n <MenuRadioGroup\n _value={layout.mode}\n onUpdate:_value={(value: string) => (layout.mode = value as LayoutMode)}\n aria-label={messages.layoutMode}\n >\n {LAYOUT_MODES.map((mode) => (\n <MenuRadioItem\n key={mode}\n value={mode}\n icon={mode === 'overlay' ? PanelLeft : Columns2}\n >\n {modeLabels[mode]}\n </MenuRadioItem>\n ))}\n </MenuRadioGroup>\n </MenuGroup>\n <MenuGroup label={messages.layoutSide}>\n <MenuRadioGroup\n _value={layout.side}\n onUpdate:_value={(value: string) => (layout.side = value as LayoutSide)}\n aria-label={messages.layoutSide}\n >\n {LAYOUT_SIDES.map((side) => (\n <MenuRadioItem\n key={side}\n value={side}\n icon={SIDE_ICONS[side]}\n disabled={layout.mode !== 'overlay'}\n >\n {sideLabels[side]}\n </MenuRadioItem>\n ))}\n </MenuRadioGroup>\n </MenuGroup>\n </Menu>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyBA,SAAA,QAAA,GAAA;CAAA,OAAA,OAAA,MAAA,cAAA,OAAA,UAAA,SAAA,KAAA,CAAA,MAAA,qBAAA,CAAAA,QAAA,CAAA;AAAA;AAQA,IAAM,aAA2C;CAC/C,OAAO;CACP,KAAK;CACL,KAAK;CACL,QAAQ;AACV;;AAGA,IAAa,iBAAiB,0BAC5B,QAAA,SAA4D;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,SAAAC,aAAA,QAAA,QAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAhC,OAAIC,UAAA,QAAA,MAAA,IAAA;CAC9B,MAAM,WAAW,YAAY,YAAY,gBAAgB;CACzD,MAAM,aAAyC;EAC7C,QAAQ,SAAS;EACjB,SAAS,SAAS;CACpB;CACA,MAAM,aAAyC;EAC7C,OAAO,SAAS;EAChB,KAAK,SAAS;EACd,KAAK,SAAS;EACd,QAAQ,SAAS;CACnB;CAEA,MAAM,oBAAqB,OAAA,MAAO,SAAS,YAAY,WAAW,OAAA,MAAO,QAAQ;CAEjF,aAAO;EAAA,IAAA,OAAA;EAAA,OAAAC,YAAAC,QAAAC,cAEC,MAAI,EAAA,WAAA,OAAA,OAAA,OAAA,MACE,UAAKF,YAAA,YAEP,eACF;GAAE,MAAM,YAAY;GAAG,cAAc,SAAS;EAAY,GAAC,aAAA,OAE3D,KACF,GAAC,IAAA,GAEJ,CAAA,GAAA,EAAA,eAAA,CAAAA,YAAA,WAAA,EAAA,SAEiB,SAAS,WAAU,GAAA,EAAA,eAAA,CAAAA,YAAA,gBAAA;GAAA,UAEzB,OAAA,MAAO;GAAI,mBAAA,OAAA,OAAA,OAAA,MACD,UAAmB,OAAA,MAAO,OAAO;GAAoB,cAC3D,SAAS;EAAU,GAAA,QAAA,QAE9B,aAAa,KAAK,SAAIA,YAAA,eAAA;GAAA,OAEd;GAAI,SACF;GAAI,QACL,SAAS,YAAY,YAAY;EAAQ,GAAA,EAAA,eAAA,CAE9C,WAAW,KAAK,EAAA,CAAA,CAEpB,CAAC,IAAA,QAAA,EAAA,eAAA,CAAA,KAAA,EAAA,CAAA,CAAA,EAAA,CAAA,GAAAA,YAAA,WAAA,EAAA,SAGY,SAAS,WAAU,GAAA,EAAA,eAAA,CAAAA,YAAA,gBAAA;GAAA,UAEzB,OAAA,MAAO;GAAI,mBAAA,OAAA,OAAA,OAAA,MACD,UAAmB,OAAA,MAAO,OAAO;GAAoB,cAC3D,SAAS;EAAU,GAAA,QAAA,SAE9B,aAAa,KAAK,SAAIA,YAAA,eAAA;GAAA,OAEd;GAAI,SACF;GAAI,QACL,WAAW;GAAK,YACZ,OAAA,MAAO,SAAS;EAAS,GAAA,EAAA,eAAA,CAElC,WAAW,KAAK,EAAA,CAAA,CAEpB,CAAC,IAAA,SAAA,EAAA,eAAA,CAAA,MAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA;CAAA;AAKZ,GAAC;CAAA,MAAA;CAAA,OAAA,CAAA,UAAA,cAAA;AAAA,CACH"}