@zerodep-dev/vue-tsx-pro-ui 0.3.1 → 0.3.3

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 (620) hide show
  1. package/dist/base/Blockquote.d.ts +1 -1
  2. package/dist/base/Blockquote.js +1 -1
  3. package/dist/base/Blockquote.js.map +1 -1
  4. package/dist/base/ButtonGroup.d.ts +1 -1
  5. package/dist/base/ButtonGroup.js +1 -1
  6. package/dist/base/ButtonGroup.js.map +1 -1
  7. package/dist/base/Code.d.ts +1 -1
  8. package/dist/base/Code.js +1 -1
  9. package/dist/base/Code.js.map +1 -1
  10. package/dist/base/CodeBlock.d.ts +1 -1
  11. package/dist/base/CodeBlock.js +1 -1
  12. package/dist/base/CodeBlock.js.map +1 -1
  13. package/dist/base/CopyButton.d.ts +1 -1
  14. package/dist/base/CopyButton.js +1 -1
  15. package/dist/base/CopyButton.js.map +1 -1
  16. package/dist/base/Heading.d.ts +1 -1
  17. package/dist/base/Heading.js +1 -1
  18. package/dist/base/Heading.js.map +1 -1
  19. package/dist/base/Icon.d.ts +1 -1
  20. package/dist/base/Icon.js +1 -1
  21. package/dist/base/Icon.js.map +1 -1
  22. package/dist/base/Indicator.d.ts +1 -1
  23. package/dist/base/Indicator.js +1 -1
  24. package/dist/base/Indicator.js.map +1 -1
  25. package/dist/base/Kbd.d.ts +1 -1
  26. package/dist/base/Kbd.js +1 -1
  27. package/dist/base/Kbd.js.map +1 -1
  28. package/dist/base/Link.d.ts +1 -1
  29. package/dist/base/Link.js +1 -1
  30. package/dist/base/Link.js.map +1 -1
  31. package/dist/base/List.d.ts +1 -1
  32. package/dist/base/List.js +1 -1
  33. package/dist/base/List.js.map +1 -1
  34. package/dist/base/Mark.d.ts +1 -1
  35. package/dist/base/Mark.js +1 -1
  36. package/dist/base/Mark.js.map +1 -1
  37. package/dist/base/Spinner.d.ts +1 -1
  38. package/dist/base/Spinner.js +1 -1
  39. package/dist/base/Spinner.js.map +1 -1
  40. package/dist/base/StatusDot.d.ts +1 -1
  41. package/dist/base/StatusDot.js +1 -1
  42. package/dist/base/StatusDot.js.map +1 -1
  43. package/dist/base/Tag.d.ts +1 -1
  44. package/dist/base/Tag.js +1 -1
  45. package/dist/base/Tag.js.map +1 -1
  46. package/dist/base/Text.d.ts +1 -1
  47. package/dist/base/Text.js +1 -1
  48. package/dist/base/Text.js.map +1 -1
  49. package/dist/base/VisuallyHidden.d.ts +1 -1
  50. package/dist/base/VisuallyHidden.js +1 -1
  51. package/dist/base/VisuallyHidden.js.map +1 -1
  52. package/dist/base/badge-styles.d.ts +1 -1
  53. package/dist/base/badge-styles.js +1 -1
  54. package/dist/base/badge-styles.js.map +1 -1
  55. package/dist/base/button-core.d.ts +1 -1
  56. package/dist/base/button-core.js +1 -1
  57. package/dist/base/button-core.js.map +1 -1
  58. package/dist/charts/ChordChart.d.ts +1 -1
  59. package/dist/charts/ChordChart.js +1 -1
  60. package/dist/charts/ChordChart.js.map +1 -1
  61. package/dist/charts/DonutChart.d.ts +1 -1
  62. package/dist/charts/DonutChart.js +1 -1
  63. package/dist/charts/DonutChart.js.map +1 -1
  64. package/dist/charts/FunnelChart.d.ts +1 -1
  65. package/dist/charts/FunnelChart.js +1 -1
  66. package/dist/charts/FunnelChart.js.map +1 -1
  67. package/dist/charts/GraphChart.d.ts +1 -1
  68. package/dist/charts/GraphChart.js +1 -1
  69. package/dist/charts/GraphChart.js.map +1 -1
  70. package/dist/charts/MapChart.d.ts +1 -1
  71. package/dist/charts/MapChart.js +1 -1
  72. package/dist/charts/MapChart.js.map +1 -1
  73. package/dist/charts/RadarChart.d.ts +1 -1
  74. package/dist/charts/RadarChart.js +1 -1
  75. package/dist/charts/RadarChart.js.map +1 -1
  76. package/dist/charts/SankeyChart.d.ts +1 -1
  77. package/dist/charts/SankeyChart.js +1 -1
  78. package/dist/charts/SankeyChart.js.map +1 -1
  79. package/dist/charts/TreemapChart.d.ts +1 -1
  80. package/dist/charts/TreemapChart.js +1 -1
  81. package/dist/charts/TreemapChart.js.map +1 -1
  82. package/dist/charts/XYChart.d.ts +1 -1
  83. package/dist/charts/XYChart.js +1 -1
  84. package/dist/charts/XYChart.js.map +1 -1
  85. package/dist/charts/frame.d.ts +1 -1
  86. package/dist/charts/frame.js +1 -1
  87. package/dist/charts/frame.js.map +1 -1
  88. package/dist/code-editor/CodeEditor.js +1 -1
  89. package/dist/code-editor/CodeEditor.js.map +1 -1
  90. package/dist/config/Provider.d.ts +1 -1
  91. package/dist/config/Provider.js +1 -1
  92. package/dist/config/Provider.js.map +1 -1
  93. package/dist/config/createUi.d.ts +1 -1
  94. package/dist/config/createUi.js +1 -1
  95. package/dist/config/createUi.js.map +1 -1
  96. package/dist/config/theme/coffee.d.ts +1 -1
  97. package/dist/config/theme/coffee.js +1 -1
  98. package/dist/config/theme/coffee.js.map +1 -1
  99. package/dist/config/theme/cyberpunk.d.ts +1 -1
  100. package/dist/config/theme/cyberpunk.js +1 -1
  101. package/dist/config/theme/cyberpunk.js.map +1 -1
  102. package/dist/config/theme/dark.d.ts +1 -1
  103. package/dist/config/theme/dark.js +1 -1
  104. package/dist/config/theme/dark.js.map +1 -1
  105. package/dist/config/theme/festive.d.ts +1 -1
  106. package/dist/config/theme/festive.js +1 -1
  107. package/dist/config/theme/festive.js.map +1 -1
  108. package/dist/config/theme/forest.d.ts +1 -1
  109. package/dist/config/theme/forest.js +1 -1
  110. package/dist/config/theme/forest.js.map +1 -1
  111. package/dist/config/theme/high-contrast.d.ts +1 -1
  112. package/dist/config/theme/high-contrast.js +1 -1
  113. package/dist/config/theme/high-contrast.js.map +1 -1
  114. package/dist/config/theme/lemon.d.ts +1 -1
  115. package/dist/config/theme/lemon.js +1 -1
  116. package/dist/config/theme/lemon.js.map +1 -1
  117. package/dist/config/theme/light.d.ts +1 -1
  118. package/dist/config/theme/light.js +1 -1
  119. package/dist/config/theme/light.js.map +1 -1
  120. package/dist/config/theme/midnight.d.ts +1 -1
  121. package/dist/config/theme/midnight.js +1 -1
  122. package/dist/config/theme/midnight.js.map +1 -1
  123. package/dist/config/theme/ocean.d.ts +1 -1
  124. package/dist/config/theme/ocean.js +1 -1
  125. package/dist/config/theme/ocean.js.map +1 -1
  126. package/dist/config/theme/paper.d.ts +1 -1
  127. package/dist/config/theme/paper.js +1 -1
  128. package/dist/config/theme/paper.js.map +1 -1
  129. package/dist/config/theme/sakura.d.ts +1 -1
  130. package/dist/config/theme/sakura.js +1 -1
  131. package/dist/config/theme/sakura.js.map +1 -1
  132. package/dist/config/theme/theme.js +1 -1
  133. package/dist/config/theme/theme.js.map +1 -1
  134. package/dist/config/theme/tokens.d.ts +1 -1
  135. package/dist/config/theme/tokens.js +1 -1
  136. package/dist/config/theme/tokens.js.map +1 -1
  137. package/dist/date/CalendarBoard.d.ts +1 -1
  138. package/dist/date/CalendarBoard.js +1 -1
  139. package/dist/date/CalendarBoard.js.map +1 -1
  140. package/dist/date/CalendarView.d.ts +1 -1
  141. package/dist/date/CalendarView.js +1 -1
  142. package/dist/date/CalendarView.js.map +1 -1
  143. package/dist/date/Countdown.d.ts +1 -1
  144. package/dist/date/Countdown.js +1 -1
  145. package/dist/date/Countdown.js.map +1 -1
  146. package/dist/date/DatePicker.d.ts +1 -1
  147. package/dist/date/DatePicker.js +1 -1
  148. package/dist/date/DatePicker.js.map +1 -1
  149. package/dist/date/DateRangePicker.d.ts +1 -1
  150. package/dist/date/DateRangePicker.js +1 -1
  151. package/dist/date/DateRangePicker.js.map +1 -1
  152. package/dist/date/DateSegmentGroup.d.ts +1 -1
  153. package/dist/date/DateSegmentGroup.js +1 -1
  154. package/dist/date/DateSegmentGroup.js.map +1 -1
  155. package/dist/date/QuarterCalendar.js +1 -1
  156. package/dist/date/QuarterCalendar.js.map +1 -1
  157. package/dist/date/SegmentedField.d.ts +1 -1
  158. package/dist/date/SegmentedField.js +1 -1
  159. package/dist/date/SegmentedField.js.map +1 -1
  160. package/dist/date/TimePicker.d.ts +1 -1
  161. package/dist/date/TimePicker.js +1 -1
  162. package/dist/date/TimePicker.js.map +1 -1
  163. package/dist/date/picker-popover.d.ts +1 -1
  164. package/dist/date/picker-popover.js +1 -1
  165. package/dist/date/picker-popover.js.map +1 -1
  166. package/dist/diagram/Diagram.d.ts +1 -1
  167. package/dist/diagram/Diagram.js +1 -1
  168. package/dist/diagram/Diagram.js.map +1 -1
  169. package/dist/diagram/DiagramControls.d.ts +1 -1
  170. package/dist/diagram/DiagramControls.js +1 -1
  171. package/dist/diagram/DiagramControls.js.map +1 -1
  172. package/dist/diagram/DiagramLanes.d.ts +1 -1
  173. package/dist/diagram/DiagramLanes.js +1 -1
  174. package/dist/diagram/DiagramLanes.js.map +1 -1
  175. package/dist/diagram/DiagramMinimap.d.ts +1 -1
  176. package/dist/diagram/DiagramMinimap.js +1 -1
  177. package/dist/diagram/DiagramMinimap.js.map +1 -1
  178. package/dist/diagram/DiagramNode.d.ts +1 -1
  179. package/dist/diagram/DiagramNode.js +1 -1
  180. package/dist/diagram/DiagramNode.js.map +1 -1
  181. package/dist/display/Accordion.d.ts +1 -1
  182. package/dist/display/Accordion.js +1 -1
  183. package/dist/display/Accordion.js.map +1 -1
  184. package/dist/display/AnimatedNumber.d.ts +1 -1
  185. package/dist/display/AnimatedNumber.js +1 -1
  186. package/dist/display/AnimatedNumber.js.map +1 -1
  187. package/dist/display/Avatar.d.ts +1 -1
  188. package/dist/display/Avatar.js +1 -1
  189. package/dist/display/Avatar.js.map +1 -1
  190. package/dist/display/AvatarGroup.d.ts +1 -1
  191. package/dist/display/AvatarGroup.js +1 -1
  192. package/dist/display/AvatarGroup.js.map +1 -1
  193. package/dist/display/Card.d.ts +1 -1
  194. package/dist/display/Card.js +1 -1
  195. package/dist/display/Card.js.map +1 -1
  196. package/dist/display/Checklist.d.ts +1 -1
  197. package/dist/display/Checklist.js +1 -1
  198. package/dist/display/Checklist.js.map +1 -1
  199. package/dist/display/Collapse.d.ts +1 -1
  200. package/dist/display/Collapse.js +1 -1
  201. package/dist/display/Collapse.js.map +1 -1
  202. package/dist/display/Descriptions.d.ts +1 -1
  203. package/dist/display/Descriptions.js +1 -1
  204. package/dist/display/Descriptions.js.map +1 -1
  205. package/dist/display/Ellipsis.d.ts +1 -1
  206. package/dist/display/Ellipsis.js +1 -1
  207. package/dist/display/Ellipsis.js.map +1 -1
  208. package/dist/display/FieldCompare.d.ts +1 -1
  209. package/dist/display/FieldCompare.js +1 -1
  210. package/dist/display/FieldCompare.js.map +1 -1
  211. package/dist/display/Gauge.d.ts +1 -1
  212. package/dist/display/Gauge.js +1 -1
  213. package/dist/display/Gauge.js.map +1 -1
  214. package/dist/display/Image.d.ts +1 -1
  215. package/dist/display/Image.js +1 -1
  216. package/dist/display/Image.js.map +1 -1
  217. package/dist/display/ItemList.d.ts +1 -1
  218. package/dist/display/ItemList.js +1 -1
  219. package/dist/display/ItemList.js.map +1 -1
  220. package/dist/display/Marquee.d.ts +1 -1
  221. package/dist/display/Marquee.js +1 -1
  222. package/dist/display/Marquee.js.map +1 -1
  223. package/dist/display/ProportionBar.d.ts +1 -1
  224. package/dist/display/ProportionBar.js +1 -1
  225. package/dist/display/ProportionBar.js.map +1 -1
  226. package/dist/display/Sortable.d.ts +1 -1
  227. package/dist/display/Sortable.js +1 -1
  228. package/dist/display/Sortable.js.map +1 -1
  229. package/dist/display/Sparkline.d.ts +1 -1
  230. package/dist/display/Sparkline.js +1 -1
  231. package/dist/display/Sparkline.js.map +1 -1
  232. package/dist/display/Stat.d.ts +1 -1
  233. package/dist/display/Stat.js +1 -1
  234. package/dist/display/Stat.js.map +1 -1
  235. package/dist/display/Timeline.d.ts +1 -1
  236. package/dist/display/Timeline.js +1 -1
  237. package/dist/display/Timeline.js.map +1 -1
  238. package/dist/display/Tree.d.ts +1 -1
  239. package/dist/display/Tree.js +1 -1
  240. package/dist/display/Tree.js.map +1 -1
  241. package/dist/display/VirtualList.d.ts +2 -3
  242. package/dist/display/VirtualList.js +12 -22
  243. package/dist/display/VirtualList.js.map +1 -1
  244. package/dist/display/Watermark.d.ts +1 -1
  245. package/dist/display/Watermark.js +1 -1
  246. package/dist/display/Watermark.js.map +1 -1
  247. package/dist/docs-kit/CodeGroup.d.ts +1 -1
  248. package/dist/docs-kit/CodeGroup.js +1 -1
  249. package/dist/docs-kit/CodeGroup.js.map +1 -1
  250. package/dist/docs-kit/CodePreview.d.ts +1 -1
  251. package/dist/docs-kit/CodePreview.js +1 -1
  252. package/dist/docs-kit/CodePreview.js.map +1 -1
  253. package/dist/docs-kit/ColorSwatch.d.ts +1 -1
  254. package/dist/docs-kit/ColorSwatch.js +1 -1
  255. package/dist/docs-kit/ColorSwatch.js.map +1 -1
  256. package/dist/docs-kit/PropsTable.d.ts +1 -1
  257. package/dist/docs-kit/PropsTable.js +1 -1
  258. package/dist/docs-kit/PropsTable.js.map +1 -1
  259. package/dist/feedback/Alert.d.ts +1 -1
  260. package/dist/feedback/Alert.js +1 -1
  261. package/dist/feedback/Alert.js.map +1 -1
  262. package/dist/feedback/Banner.d.ts +1 -1
  263. package/dist/feedback/Banner.js +1 -1
  264. package/dist/feedback/Banner.js.map +1 -1
  265. package/dist/feedback/Empty.d.ts +1 -1
  266. package/dist/feedback/Empty.js +1 -1
  267. package/dist/feedback/Empty.js.map +1 -1
  268. package/dist/feedback/LoadingBar.d.ts +1 -1
  269. package/dist/feedback/LoadingBar.js +1 -1
  270. package/dist/feedback/LoadingBar.js.map +1 -1
  271. package/dist/feedback/LoadingOverlay.d.ts +1 -1
  272. package/dist/feedback/LoadingOverlay.js +1 -1
  273. package/dist/feedback/LoadingOverlay.js.map +1 -1
  274. package/dist/feedback/Progress.d.ts +1 -1
  275. package/dist/feedback/Progress.js +1 -1
  276. package/dist/feedback/Progress.js.map +1 -1
  277. package/dist/feedback/Result.d.ts +1 -1
  278. package/dist/feedback/Result.js +1 -1
  279. package/dist/feedback/Result.js.map +1 -1
  280. package/dist/feedback/Skeleton.d.ts +1 -1
  281. package/dist/feedback/Skeleton.js +1 -1
  282. package/dist/feedback/Skeleton.js.map +1 -1
  283. package/dist/feedback/SkeletonText.d.ts +1 -1
  284. package/dist/feedback/SkeletonText.js +1 -1
  285. package/dist/feedback/SkeletonText.js.map +1 -1
  286. package/dist/feedback/Toast.d.ts +1 -1
  287. package/dist/feedback/Toast.js +1 -1
  288. package/dist/feedback/Toast.js.map +1 -1
  289. package/dist/form/Field.d.ts +1 -1
  290. package/dist/form/Field.js +1 -1
  291. package/dist/form/Field.js.map +1 -1
  292. package/dist/form/FormErrorSummary.d.ts +1 -1
  293. package/dist/form/FormErrorSummary.js +1 -1
  294. package/dist/form/FormErrorSummary.js.map +1 -1
  295. package/dist/form/FormSection.d.ts +1 -1
  296. package/dist/form/FormSection.js +1 -1
  297. package/dist/form/FormSection.js.map +1 -1
  298. package/dist/form/schemas.d.ts +1 -1
  299. package/dist/form/schemas.js +1 -1
  300. package/dist/form/schemas.js.map +1 -1
  301. package/dist/input/Cascader.d.ts +1 -1
  302. package/dist/input/Cascader.js +1 -1
  303. package/dist/input/Cascader.js.map +1 -1
  304. package/dist/input/CharacterCount.d.ts +1 -1
  305. package/dist/input/CharacterCount.js +1 -1
  306. package/dist/input/CharacterCount.js.map +1 -1
  307. package/dist/input/Checkbox.d.ts +1 -1
  308. package/dist/input/Checkbox.js +1 -1
  309. package/dist/input/Checkbox.js.map +1 -1
  310. package/dist/input/ColorField.d.ts +1 -1
  311. package/dist/input/ColorField.js +1 -1
  312. package/dist/input/ColorField.js.map +1 -1
  313. package/dist/input/Combobox.d.ts +2 -2
  314. package/dist/input/Combobox.js +1 -1
  315. package/dist/input/Combobox.js.map +1 -1
  316. package/dist/input/ConditionBuilder.d.ts +1 -1
  317. package/dist/input/ConditionBuilder.js +1 -1
  318. package/dist/input/ConditionBuilder.js.map +1 -1
  319. package/dist/input/ControlGroup.d.ts +1 -1
  320. package/dist/input/ControlGroup.js +1 -1
  321. package/dist/input/ControlGroup.js.map +1 -1
  322. package/dist/input/FileDrop.d.ts +1 -1
  323. package/dist/input/FileDrop.js +1 -1
  324. package/dist/input/FileDrop.js.map +1 -1
  325. package/dist/input/ListPopover.d.ts +2 -2
  326. package/dist/input/ListPopover.js +1 -1
  327. package/dist/input/ListPopover.js.map +1 -1
  328. package/dist/input/Listbox.d.ts +2 -3
  329. package/dist/input/Listbox.js +8 -20
  330. package/dist/input/Listbox.js.map +1 -1
  331. package/dist/input/Mentions.d.ts +1 -1
  332. package/dist/input/Mentions.js +1 -1
  333. package/dist/input/Mentions.js.map +1 -1
  334. package/dist/input/NumberRangeField.d.ts +1 -1
  335. package/dist/input/NumberRangeField.js +1 -1
  336. package/dist/input/NumberRangeField.js.map +1 -1
  337. package/dist/input/OtpField.d.ts +1 -1
  338. package/dist/input/OtpField.js +1 -1
  339. package/dist/input/OtpField.js.map +1 -1
  340. package/dist/input/PeoplePicker.js +1 -1
  341. package/dist/input/PeoplePicker.js.map +1 -1
  342. package/dist/input/PeoplePickerPanel.d.ts +1 -1
  343. package/dist/input/PeoplePickerPanel.js +1 -1
  344. package/dist/input/PeoplePickerPanel.js.map +1 -1
  345. package/dist/input/Radio.d.ts +1 -1
  346. package/dist/input/Radio.js +1 -1
  347. package/dist/input/Radio.js.map +1 -1
  348. package/dist/input/Rating.d.ts +1 -1
  349. package/dist/input/Rating.js +1 -1
  350. package/dist/input/Rating.js.map +1 -1
  351. package/dist/input/Select.d.ts +2 -2
  352. package/dist/input/Select.js +1 -1
  353. package/dist/input/Select.js.map +1 -1
  354. package/dist/input/SelectedTags.d.ts +1 -1
  355. package/dist/input/SelectedTags.js +1 -1
  356. package/dist/input/SelectedTags.js.map +1 -1
  357. package/dist/input/Slider.d.ts +1 -1
  358. package/dist/input/Slider.js +1 -1
  359. package/dist/input/Slider.js.map +1 -1
  360. package/dist/input/Switch.d.ts +1 -1
  361. package/dist/input/Switch.js +1 -1
  362. package/dist/input/Switch.js.map +1 -1
  363. package/dist/input/TagsInput.d.ts +1 -1
  364. package/dist/input/TagsInput.js +1 -1
  365. package/dist/input/TagsInput.js.map +1 -1
  366. package/dist/input/Textarea.d.ts +1 -1
  367. package/dist/input/Textarea.js +1 -1
  368. package/dist/input/Textarea.js.map +1 -1
  369. package/dist/input/ToggleGroup.d.ts +1 -1
  370. package/dist/input/ToggleGroup.js +1 -1
  371. package/dist/input/ToggleGroup.js.map +1 -1
  372. package/dist/input/Transfer.d.ts +1 -1
  373. package/dist/input/Transfer.js +1 -1
  374. package/dist/input/Transfer.js.map +1 -1
  375. package/dist/input/TreeSelect.d.ts +1 -1
  376. package/dist/input/TreeSelect.js +1 -1
  377. package/dist/input/TreeSelect.js.map +1 -1
  378. package/dist/input/Upload.d.ts +1 -1
  379. package/dist/input/Upload.js +1 -1
  380. package/dist/input/Upload.js.map +1 -1
  381. package/dist/input/choice-styles.d.ts +1 -1
  382. package/dist/input/choice-styles.js +1 -1
  383. package/dist/input/choice-styles.js.map +1 -1
  384. package/dist/input/control.d.ts +1 -1
  385. package/dist/input/control.js +1 -1
  386. package/dist/input/control.js.map +1 -1
  387. package/dist/layout/Affix.d.ts +1 -1
  388. package/dist/layout/Affix.js +1 -1
  389. package/dist/layout/Affix.js.map +1 -1
  390. package/dist/layout/AsideLayout.d.ts +1 -1
  391. package/dist/layout/AsideLayout.js +1 -1
  392. package/dist/layout/AsideLayout.js.map +1 -1
  393. package/dist/layout/BackTop.d.ts +1 -1
  394. package/dist/layout/BackTop.js +1 -1
  395. package/dist/layout/BackTop.js.map +1 -1
  396. package/dist/layout/Container.d.ts +1 -1
  397. package/dist/layout/Container.js +1 -1
  398. package/dist/layout/Container.js.map +1 -1
  399. package/dist/layout/Flex.d.ts +1 -1
  400. package/dist/layout/Flex.js +1 -1
  401. package/dist/layout/Flex.js.map +1 -1
  402. package/dist/layout/Grid.d.ts +1 -1
  403. package/dist/layout/Grid.js +1 -1
  404. package/dist/layout/Grid.js.map +1 -1
  405. package/dist/layout/PageScrollbar.d.ts +1 -1
  406. package/dist/layout/PageScrollbar.js +1 -1
  407. package/dist/layout/PageScrollbar.js.map +1 -1
  408. package/dist/layout/Prose.d.ts +1 -1
  409. package/dist/layout/Prose.js +1 -1
  410. package/dist/layout/Prose.js.map +1 -1
  411. package/dist/layout/ResizeHandle.d.ts +1 -1
  412. package/dist/layout/ResizeHandle.js +1 -1
  413. package/dist/layout/ResizeHandle.js.map +1 -1
  414. package/dist/layout/ScrollArea.d.ts +1 -1
  415. package/dist/layout/ScrollArea.js +1 -1
  416. package/dist/layout/ScrollArea.js.map +1 -1
  417. package/dist/layout/Separator.d.ts +1 -1
  418. package/dist/layout/Separator.js +1 -1
  419. package/dist/layout/Separator.js.map +1 -1
  420. package/dist/layout/Splitter.d.ts +1 -1
  421. package/dist/layout/Splitter.js +1 -1
  422. package/dist/layout/Splitter.js.map +1 -1
  423. package/dist/layout/ViewportFill.d.ts +1 -1
  424. package/dist/layout/ViewportFill.js +1 -1
  425. package/dist/layout/ViewportFill.js.map +1 -1
  426. package/dist/navigation/Breadcrumbs.d.ts +1 -1
  427. package/dist/navigation/Breadcrumbs.js +1 -1
  428. package/dist/navigation/Breadcrumbs.js.map +1 -1
  429. package/dist/navigation/NavBar.d.ts +1 -1
  430. package/dist/navigation/NavBar.js +1 -1
  431. package/dist/navigation/NavBar.js.map +1 -1
  432. package/dist/navigation/NavList.d.ts +1 -1
  433. package/dist/navigation/NavList.js +1 -1
  434. package/dist/navigation/NavList.js.map +1 -1
  435. package/dist/navigation/PageJump.d.ts +1 -1
  436. package/dist/navigation/PageJump.js +1 -1
  437. package/dist/navigation/PageJump.js.map +1 -1
  438. package/dist/navigation/PageSizeSelect.d.ts +1 -1
  439. package/dist/navigation/PageSizeSelect.js +1 -1
  440. package/dist/navigation/PageSizeSelect.js.map +1 -1
  441. package/dist/navigation/Pager.d.ts +1 -1
  442. package/dist/navigation/Pager.js +1 -1
  443. package/dist/navigation/Pager.js.map +1 -1
  444. package/dist/navigation/Pagination.d.ts +1 -1
  445. package/dist/navigation/Pagination.js +1 -1
  446. package/dist/navigation/Pagination.js.map +1 -1
  447. package/dist/navigation/PaginationBar.d.ts +1 -1
  448. package/dist/navigation/PaginationBar.js +1 -1
  449. package/dist/navigation/PaginationBar.js.map +1 -1
  450. package/dist/navigation/SkipLink.d.ts +1 -1
  451. package/dist/navigation/SkipLink.js +1 -1
  452. package/dist/navigation/SkipLink.js.map +1 -1
  453. package/dist/navigation/Steps.d.ts +1 -1
  454. package/dist/navigation/Steps.js +1 -1
  455. package/dist/navigation/Steps.js.map +1 -1
  456. package/dist/navigation/TableOfContents.d.ts +1 -1
  457. package/dist/navigation/TableOfContents.js +1 -1
  458. package/dist/navigation/TableOfContents.js.map +1 -1
  459. package/dist/navigation/Tabs.d.ts +1 -1
  460. package/dist/navigation/Tabs.js +1 -1
  461. package/dist/navigation/Tabs.js.map +1 -1
  462. package/dist/navigation/Toolbar.d.ts +1 -1
  463. package/dist/navigation/Toolbar.js +1 -1
  464. package/dist/navigation/Toolbar.js.map +1 -1
  465. package/dist/overlay/CommandPalette.d.ts +2 -2
  466. package/dist/overlay/CommandPalette.js +1 -1
  467. package/dist/overlay/CommandPalette.js.map +1 -1
  468. package/dist/overlay/Dialog.d.ts +1 -1
  469. package/dist/overlay/Dialog.js +1 -1
  470. package/dist/overlay/Dialog.js.map +1 -1
  471. package/dist/overlay/Drawer.d.ts +1 -1
  472. package/dist/overlay/Drawer.js +1 -1
  473. package/dist/overlay/Drawer.js.map +1 -1
  474. package/dist/overlay/HoverCard.d.ts +1 -1
  475. package/dist/overlay/HoverCard.js +1 -1
  476. package/dist/overlay/HoverCard.js.map +1 -1
  477. package/dist/overlay/Lightbox.d.ts +1 -1
  478. package/dist/overlay/Lightbox.js +1 -1
  479. package/dist/overlay/Lightbox.js.map +1 -1
  480. package/dist/overlay/Menu.d.ts +1 -1
  481. package/dist/overlay/Menu.js +1 -1
  482. package/dist/overlay/Menu.js.map +1 -1
  483. package/dist/overlay/Popconfirm.d.ts +1 -1
  484. package/dist/overlay/Popconfirm.js +1 -1
  485. package/dist/overlay/Popconfirm.js.map +1 -1
  486. package/dist/overlay/Popover.d.ts +1 -1
  487. package/dist/overlay/Popover.js +1 -1
  488. package/dist/overlay/Popover.js.map +1 -1
  489. package/dist/overlay/Tooltip.d.ts +1 -1
  490. package/dist/overlay/Tooltip.js +1 -1
  491. package/dist/overlay/Tooltip.js.map +1 -1
  492. package/dist/overlay/Tour.d.ts +1 -1
  493. package/dist/overlay/Tour.js +1 -1
  494. package/dist/overlay/Tour.js.map +1 -1
  495. package/dist/overlay/detached.js +14 -1
  496. package/dist/overlay/detached.js.map +1 -1
  497. package/dist/patterns/ActionBar.d.ts +1 -1
  498. package/dist/patterns/ActionBar.js +1 -1
  499. package/dist/patterns/ActionBar.js.map +1 -1
  500. package/dist/patterns/AppShell.d.ts +1 -1
  501. package/dist/patterns/AppShell.js +1 -1
  502. package/dist/patterns/AppShell.js.map +1 -1
  503. package/dist/patterns/AuthLayout.d.ts +2 -2
  504. package/dist/patterns/AuthLayout.js +2 -2
  505. package/dist/patterns/AuthLayout.js.map +1 -1
  506. package/dist/patterns/CommentThread.d.ts +1 -1
  507. package/dist/patterns/CommentThread.js +1 -1
  508. package/dist/patterns/CommentThread.js.map +1 -1
  509. package/dist/patterns/DataImport.d.ts +1 -1
  510. package/dist/patterns/DataImport.js +1 -1
  511. package/dist/patterns/DataImport.js.map +1 -1
  512. package/dist/patterns/FilterBar.d.ts +1 -1
  513. package/dist/patterns/FilterBar.js +1 -1
  514. package/dist/patterns/FilterBar.js.map +1 -1
  515. package/dist/patterns/KanbanBoard.d.ts +1 -1
  516. package/dist/patterns/KanbanBoard.js +1 -1
  517. package/dist/patterns/KanbanBoard.js.map +1 -1
  518. package/dist/patterns/NotificationCenter.d.ts +1 -1
  519. package/dist/patterns/NotificationCenter.js +1 -1
  520. package/dist/patterns/NotificationCenter.js.map +1 -1
  521. package/dist/patterns/QueryTable.d.ts +1 -1
  522. package/dist/patterns/QueryTable.js +1 -3
  523. package/dist/patterns/QueryTable.js.map +1 -1
  524. package/dist/patterns/SlideCaptcha.d.ts +1 -1
  525. package/dist/patterns/SlideCaptcha.js +1 -1
  526. package/dist/patterns/SlideCaptcha.js.map +1 -1
  527. package/dist/patterns/StepsForm.d.ts +1 -1
  528. package/dist/patterns/StepsForm.js +1 -1
  529. package/dist/patterns/StepsForm.js.map +1 -1
  530. package/dist/table/ColumnHeaderActions.d.ts +1 -1
  531. package/dist/table/ColumnHeaderActions.js +1 -1
  532. package/dist/table/ColumnHeaderActions.js.map +1 -1
  533. package/dist/table/ColumnSettings.d.ts +1 -1
  534. package/dist/table/ColumnSettings.js +1 -1
  535. package/dist/table/ColumnSettings.js.map +1 -1
  536. package/dist/table/ColumnTable.d.ts +1 -1
  537. package/dist/table/ColumnTable.js +1 -1
  538. package/dist/table/ColumnTable.js.map +1 -1
  539. package/dist/table/DataTable.js +1 -1
  540. package/dist/table/DataTable.js.map +1 -1
  541. package/dist/table/DataTableView.d.ts +1 -4
  542. package/dist/table/DataTableView.js +33 -27
  543. package/dist/table/DataTableView.js.map +1 -1
  544. package/dist/table/PivotTable.d.ts +1 -1
  545. package/dist/table/PivotTable.js +1 -1
  546. package/dist/table/PivotTable.js.map +1 -1
  547. package/dist/table/SelectionBar.d.ts +1 -1
  548. package/dist/table/SelectionBar.js +1 -1
  549. package/dist/table/SelectionBar.js.map +1 -1
  550. package/dist/table/Table.d.ts +1 -1
  551. package/dist/table/Table.js +1 -1
  552. package/dist/table/Table.js.map +1 -1
  553. package/dist/table/TreeDataTable.d.ts +1 -1
  554. package/dist/table/TreeDataTable.js +1 -1
  555. package/dist/table/TreeDataTable.js.map +1 -1
  556. package/dist/table/table-styles.d.ts +2 -2
  557. package/dist/table/table-styles.js +1 -14
  558. package/dist/table/table-styles.js.map +1 -1
  559. package/dist/theme-customize/ThemeCustomizer.d.ts +1 -1
  560. package/dist/theme-customize/ThemeCustomizer.js +1 -1
  561. package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
  562. package/dist/theme-customize/ThemeThumbnail.d.ts +1 -1
  563. package/dist/theme-customize/ThemeThumbnail.js +1 -1
  564. package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
  565. package/dist/theme-customize/design-tokens.js +1 -1
  566. package/dist/theme-customize/design-tokens.js.map +1 -1
  567. package/dist/three/core/EffectSurface.d.ts +1 -1
  568. package/dist/three/core/EffectSurface.js +1 -1
  569. package/dist/three/core/EffectSurface.js.map +1 -1
  570. package/dist/three/core/ThreeCanvas.d.ts +1 -1
  571. package/dist/three/core/ThreeCanvas.js +1 -1
  572. package/dist/three/core/ThreeCanvas.js.map +1 -1
  573. package/dist/three/effects/Confetti.d.ts +1 -1
  574. package/dist/three/effects/Confetti.js +1 -1
  575. package/dist/three/effects/Confetti.js.map +1 -1
  576. package/dist/three/globe/Globe.d.ts +1 -1
  577. package/dist/three/globe/Globe.js +1 -1
  578. package/dist/three/globe/Globe.js.map +1 -1
  579. package/dist/three/model/ModelViewer.d.ts +1 -1
  580. package/dist/three/model/ModelViewer.js +1 -1
  581. package/dist/three/model/ModelViewer.js.map +1 -1
  582. package/dist/utils/dom/floating.d.ts +1 -1
  583. package/dist/utils/dom/floating.js +1 -1
  584. package/dist/utils/dom/floating.js.map +1 -1
  585. package/dist/utils/dom/ripple.d.ts +1 -1
  586. package/dist/utils/dom/ripple.js +1 -1
  587. package/dist/utils/dom/ripple.js.map +1 -1
  588. package/dist/utils/props.js +1 -1
  589. package/dist/utils/props.js.map +1 -1
  590. package/dist/utils/style/attached.d.ts +1 -1
  591. package/dist/utils/style/attached.js +1 -1
  592. package/dist/utils/style/attached.js.map +1 -1
  593. package/dist/utils/style/item-styles.d.ts +1 -1
  594. package/dist/utils/style/item-styles.js +1 -1
  595. package/dist/utils/style/item-styles.js.map +1 -1
  596. package/dist/utils/style/markers.d.ts +1 -1
  597. package/dist/utils/style/markers.js +1 -1
  598. package/dist/utils/style/markers.js.map +1 -1
  599. package/dist/utils/style/shimmer.d.ts +1 -1
  600. package/dist/utils/style/shimmer.js +1 -1
  601. package/dist/utils/style/shimmer.js.map +1 -1
  602. package/dist/utils/style/styles.d.ts +1 -1
  603. package/dist/utils/style/styles.js +1 -1
  604. package/dist/utils/style/styles.js.map +1 -1
  605. package/dist/utils/style/swatch-styles.d.ts +1 -1
  606. package/dist/utils/style/swatch-styles.js +1 -1
  607. package/dist/utils/style/swatch-styles.js.map +1 -1
  608. package/dist/utils/style/tone-styles.d.ts +1 -1
  609. package/dist/utils/style/tone-styles.js +1 -1
  610. package/dist/utils/style/tone-styles.js.map +1 -1
  611. package/dist/utils/style/transitions.d.ts +1 -1
  612. package/dist/utils/style/transitions.js +1 -1
  613. package/dist/utils/style/transitions.js.map +1 -1
  614. package/dist/utils/style/typography.d.ts +1 -1
  615. package/dist/utils/style/typography.js +1 -1
  616. package/dist/utils/style/typography.js.map +1 -1
  617. package/dist/utils/style/vars.d.ts +1 -1
  618. package/dist/utils/style/vars.js +1 -1
  619. package/dist/utils/style/vars.js.map +1 -1
  620. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"Listbox.js","names":["_isVNode","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_computed","_createVNode","_mergeProps","_Fragment","Text","_vtp_bindable","_vtp_childrenProp"],"sources":["../../src/input/Listbox.tsx"],"sourcesContent":["/**\n * 列表框(role=\"listbox\"):在一列选项里单选或多选。数据驱动,始终虚拟滚动(上万个选项也只渲染看得见的几十个):\n *\n * <Listbox items={cities} _value={city} aria-label=\"城市\" />\n * <Listbox items={tags} selectionMode=\"multiple\" _value={picked}>{(tag) => <Badge>{tag.label}</Badge>}</Listbox>\n * <Listbox items={users} toOption={(user) => ({ value: user.id, label: user.name })} _value={id} aria-label=\"成员\" />\n *\n * 选项是 { value, label, disabled?, description?, icon?, group? }(ListboxOption);别的形状的数据用 toOption 转换,\n * 自定义内容的渲染函数拿到的仍是原始数据。\n * 焦点在列表上,高亮项经 aria-activedescendant 告诉读屏:↑↓、Home / End、Page Up / Down 移动,\n * Enter / 空格选中,按字母跳到以它开头的项。状态与键盘见 list-state.ts;Select、Combobox 用同一个 ListboxView 渲染。\n *\n * 虚拟滚动(useVirtualizer):高亮项总在渲染范围里(aria-activedescendant 才指得到),键盘移动时滚进可见范围;\n * 选项带 aria-setsize / aria-posinset,读屏知道总数与位置。分组标题只是视觉上的一行(各行独立定位,没法用\n * role=\"group\" 包住组里的选项),组名经 aria-describedby 交给组里的每个选项。\n * loading:没有选项时显示骨架行;已有选项(刷新中)时顶部显示一条进度条;列表带 aria-busy。\n *\n * 部件:Root(div,role=\"listbox\")、GroupLabel、Option(div,role=\"option\")、Check(已选标记)、Skeleton(加载中的占位行)。\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 { useId, watch, withMemo, type VNode, type VNodeChild } from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { useDelayedLoading } from '../utils/motion/delayed-loading';\nimport { useLang } from '../config/context';\nimport { Empty, type EmptyProps } from '../feedback/Empty';\nimport { Progress } from '../feedback/Progress';\nimport { Skeleton, type SkeletonProps, type SkeletonShapeProps } from '../feedback/Skeleton';\nimport { SHIMMER_STAGGER } from '../utils/style/shimmer';\nimport { itemStyles } from '../utils/style/item-styles';\nimport {\n defaultLabelledBy,\n elementProps,\n mergeAttrs,\n mergePartProps,\n mergeProps,\n type PartProps,\n} from '../utils/props';\nimport { ScrollArea } from '../layout/ScrollArea';\nimport { selectedValues, type SelectionProps } from '../utils/data/selection';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { useVirtualizer } from '../utils/virtual/use-virtualizer';\nimport { defaultRangeExtractor } from '../utils/virtual/virtualizer';\nimport { useFieldControl } from '../form/Field';\nimport {\n handleListKeydown,\n useListState,\n type ListboxOption,\n type ListStateEntry,\n type ListState,\n type OptionMapping,\n toListboxOption,\n} from './list-state';\n\n/** 选项的渲染状态:渲染函数据此画高亮、已选的样子 */\nexport interface OptionRenderState {\n /** 已选 */\n selected: boolean;\n /** 高亮(键盘或指针所在) */\n active: boolean;\n}\n\n/** 选项的部件属性:可以按选项(items 里的原始数据)计算 */\ntype OptionProps<T> =\n | PartProps<'div', 'role' | 'id' | 'aria-selected' | 'aria-disabled'>\n | ((item: T, state: OptionRenderState) => PartProps<'div'>);\n\n/** ListboxView 的属性:Listbox、Select、Combobox 共用的渲染层 */\nexport interface ListboxViewProps<T> extends PartProps<'div', 'role'> {\n /** 列表状态(useListState) */\n list: ListState<T>;\n /** 列表的 id;选项的 id 是 `${id}-${序号}`(aria-activedescendant 指向它) */\n id: string;\n /** 多选:aria-multiselectable */\n multiple?: boolean;\n /** 滚动容器:Select、Combobox 的弹出层;不给时列表自己滚动(ScrollArea 的浮层滚动条,最高 20em,用 sx 改) */\n scroller?: HTMLElement | null;\n /** 加载中:没有选项时显示骨架行,有选项时顶部显示进度条 */\n loading?: boolean;\n /** 选项的估计高度(px),默认 36;渲染后以实际高度为准 */\n estimateSize?: number;\n /** 自定义选项内容:拿到 items 里的原始数据 */\n renderOption?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有选项时显示的内容;默认是 Empty(文案取语言包) */\n empty?: VNodeChild;\n /** 点选了一项(点击或 Enter,再选已选的那项也会调用):Select、弹层里的列表据此关闭 */\n onPick?: (value: string) => void;\n /** 选项的部件属性 */\n propsOption?: OptionProps<T>;\n /** 分组标题的部件属性 */\n propsGroupLabel?: Partial<TextProps>;\n /** 已选标记的部件属性 */\n propsCheck?: Partial<IconProps>;\n /** 空状态的部件属性 */\n propsEmpty?: Partial<EmptyProps>;\n /** 加载中占位行的部件属性 */\n propsSkeleton?: SkeletonShapeProps;\n}\n\n/** 渲染用的一行:分组标题或选项 */\ntype Row<T> =\n | { kind: 'group'; key: string; label: string; id: string }\n | {\n kind: 'option';\n key: string;\n option: ListStateEntry<T>;\n index: number;\n groupId: string | undefined;\n };\n\n/** 加载中显示几行骨架 */\nconst SKELETON_ROWS = 4;\n\n/** Listbox 的样式:root、scroll、sizer、row、groupLabel、content 等 */\nexport const listboxStyles = css.create({\n root: { position: 'relative', padding: '_xs', lineHeight: '_normal', outlineStyle: 'none' },\n // 自己是滚动容器时(单独使用的 Listbox):限制高度,滚动不传给页面\n scroll: { maxHeight: '20em', overflowY: 'auto', overscrollBehavior: 'contain' },\n sizer: { position: 'relative', width: '_full' },\n row: { position: 'absolute', top: 0, insetInline: 0 },\n groupLabel: {\n display: 'block',\n paddingTop: '_sm',\n paddingBottom: '_xs',\n paddingInline: '_sm',\n fontWeight: '_semibold',\n },\n content: { display: 'flex', flexDirection: 'column', flexGrow: 1, minWidth: 0 },\n description: { color: '_textMuted' },\n check: { flexShrink: 0 },\n hidden: { visibility: 'hidden' },\n // 刷新中的进度条贴在列表顶部,不占位\n progress: { position: 'absolute', top: 0, insetInline: 0, zIndex: 1 },\n skeleton: { display: 'block', height: '1em', marginBlock: '0.625em', marginInline: '_sm' },\n});\n\n// 行的位置是任意值,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Listbox 的样式:y、height、width */\nexport const listboxPositionStyles = css.create({\n y: (px: number) => ({ transform: `translateY(${px}px)` }),\n height: (px: number) => ({ height: px }),\n width: (percent: string) => ({ width: percent }),\n});\n\n/** 列表的渲染层:虚拟滚动的选项、分组标题、已选标记、空状态与加载中;不管焦点,指针悬停高亮、点击选中 */\nexport const ListboxView = _component(\n <T,>({\n list,\n id,\n multiple = false,\n scroller,\n loading = false,\n estimateSize = 36,\n renderOption,\n empty,\n onPick,\n propsOption,\n propsGroupLabel,\n propsCheck,\n propsEmpty,\n propsSkeleton,\n ...rest\n }: ListboxViewProps<T>) => {\n const lang = useLang();\n // 骨架、进度条防闪烁;aria-busy 按真实的 loading\n const indicator = useDelayedLoading(() => loading);\n let root = _state.raw<HTMLElement | null>(null);\n let sizer = _state.raw<HTMLElement | null>(null);\n\n /** 选项按分组排好后展开成行:每组前插一行标题 */\n const rows = _derived.by<Row<T>[]>(() => {\n const result: Row<T>[] = [];\n let group: string | undefined;\n let headerId: string | undefined;\n list.options.forEach((option, index) => {\n if (option.group != null && option.group !== group) {\n headerId = `${id}-group-${result.length}`;\n result.push({\n kind: 'group',\n key: `group:${option.group}`,\n label: option.group,\n id: headerId,\n });\n }\n group = option.group;\n result.push({\n kind: 'option',\n key: option.value,\n option,\n index,\n groupId: option.group != null ? headerId : undefined,\n });\n });\n return result;\n });\n\n /** 值 → 行号:高亮项的行号一次查到,不在每次渲染时扫一遍 */\n const rowOf = _derived.by(() => {\n const map = new Map<string, number>();\n rows.forEach((row, index) => {\n if (row.kind === 'option') map.set(row.option.value, index);\n });\n return map;\n });\n const activeRow = () => (list.active === undefined ? -1 : (rowOf.get(list.active) ?? -1));\n\n const virtual = useVirtualizer(() => {\n const current = rows;\n // 读一下高亮项:它变了要重新算渲染范围(高亮项总要渲染)\n const active = activeRow();\n // 先读出来:每一项都要调用一次估计高度,不要每次都经过 props 的响应式读取\n const size = estimateSize;\n return {\n count: current.length,\n scrollElement: scroller === undefined ? root : scroller,\n list: sizer,\n estimateSize: (index: number) => (current[index]?.kind === 'group' ? 30 : size),\n getItemKey: (index: number) => current[index]!.key,\n overscan: 6,\n rangeExtractor: (range) => {\n const indices = defaultRangeExtractor(range);\n if (active >= 0 && !indices.includes(active)) {\n indices.push(active);\n indices.sort((a, b) => a - b);\n }\n return indices;\n },\n };\n });\n\n // 高亮项变了(键盘移动)时滚进可见范围;已经完整可见就不动(指针悬停触发的不会滚)。\n // 高亮的是第一项、上面是组名时滚到最顶上:组名不被挡住(搜索过滤后高亮第一个匹配的)\n watch(\n () => list.active,\n () => {\n const index = activeRow();\n if (index < 0) return;\n virtual.scrollToIndex(index === 1 && rows[0]?.kind === 'group' ? 0 : index, {\n align: 'auto',\n });\n },\n { flush: 'post' },\n );\n\n /**\n * 选项行按“会影响它的值”缓存(Vue 的 withMemo,同模板的 v-memo):方向键移动高亮时只重建前后两行,\n * 不再重建全部可见行与其中的图标。自定义了 renderOption 或按项计算的 propsOption 时不缓存:\n * 使用方的函数可能读别的状态,缓存了会显示旧内容\n */\n const memoCache: VNode[] = [];\n function optionRow(row: Extract<Row<T>, { kind: 'option' }>) {\n if (renderOption || typeof propsOption === 'function') return renderOptionRow(row);\n const { option } = row;\n return withMemo(\n [\n option,\n row.index,\n row.groupId,\n list.isSelected(option.value),\n list.active === option.value,\n list.options.length,\n propsOption,\n propsCheck,\n ],\n () => renderOptionRow(row),\n memoCache,\n row.index,\n );\n }\n\n function renderOptionRow(row: Extract<Row<T>, { kind: 'option' }>) {\n const { option, index } = row;\n const state = {\n selected: list.isSelected(option.value),\n active: list.active === option.value,\n };\n const own = typeof propsOption === 'function' ? propsOption(option.item, state) : propsOption;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n itemStyles.row,\n state.active && itemStyles.highlighted,\n state.selected && itemStyles.selected,\n option.disabled && itemStyles.disabled,\n ],\n },\n own,\n {\n id: `${id}-${index}`,\n role: 'option',\n 'aria-selected': state.selected,\n 'aria-disabled': option.disabled || undefined,\n 'aria-setsize': list.options.length,\n 'aria-posinset': index + 1,\n 'aria-describedby': row.groupId,\n // 焦点留在列表、触发按钮或输入框上\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onPointermove: () => {\n if (!option.disabled && list.active !== option.value) list.setActive(option.value);\n },\n onClick: () => {\n if (option.disabled) return;\n list.select(option.value);\n onPick?.(option.value);\n },\n },\n )}\n data-state={state.selected ? 'checked' : 'unchecked'}\n data-active={state.active || undefined}\n data-disabled={option.disabled || undefined}\n >\n {renderOption ? (\n renderOption(option.item, state)\n ) : (\n <>\n {option.icon && <Icon icon={option.icon} />}\n <span {...css.attrs(listboxStyles.content)}>\n <span {...css.attrs(itemStyles.label)}>{option.label}</span>\n {option.description && (\n <Text size=\"sm\" sx={listboxStyles.description}>\n {option.description}\n </Text>\n )}\n </span>\n </>\n )}\n <Icon\n {...mergePartProps<IconProps>(\n { icon: Check, sx: [listboxStyles.check, !state.selected && listboxStyles.hidden] },\n propsCheck,\n )}\n />\n </div>\n );\n }\n\n function renderBody() {\n if (rows.length === 0) {\n if (loading) {\n if (!indicator.value) return null;\n return Array.from({ length: SKELETON_ROWS }, (_, index) => (\n <Skeleton\n key={index}\n {...mergePartProps<SkeletonProps>(\n {\n sx: [listboxStyles.skeleton, listboxPositionStyles.width(`${85 - index * 15}%`)],\n delay: index * SHIMMER_STAGGER,\n },\n propsSkeleton,\n )}\n />\n ));\n }\n return (\n empty ?? (\n <Empty\n {...mergePartProps<EmptyProps>(\n { size: 'sm', icon: false, description: lang.selectEmpty },\n propsEmpty,\n )}\n />\n )\n );\n }\n return (\n <div\n ref={_toRef(sizer)}\n role=\"presentation\"\n {...css.attrs(listboxStyles.sizer, listboxPositionStyles.height(virtual.total))}\n >\n {virtual.items.map((item) => {\n const row = rows[item.index]!;\n return (\n <div\n key={item.key}\n ref={virtual.measure}\n data-index={item.index}\n role=\"presentation\"\n {...css.attrs(listboxStyles.row, listboxPositionStyles.y(item.start))}\n >\n {row.kind === 'group' ? (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', size: 'sm', sx: listboxStyles.groupLabel },\n propsGroupLabel,\n // 只是视觉上的标题:组名经各选项的 aria-describedby 念出\n { id: row.id, 'aria-hidden': true },\n )}\n >\n {row.label}\n </Text>\n ) : (\n optionRow(row)\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return () => {\n const own = scroller === undefined;\n // 先不编译 sx:自己滚动时这些属性交给 ScrollArea 的视口,和视口自己的样式一次合并\n const props = mergeProps<'div'>(\n { sx: [listboxStyles.root, own && listboxStyles.scroll, focusRingStyles.visible] },\n rest,\n {\n ref: _toRef(root),\n id,\n role: 'listbox',\n 'aria-multiselectable': multiple || undefined,\n 'aria-busy': loading || undefined,\n },\n );\n const body = [\n indicator.value && rows.length > 0 && (\n <div aria-hidden=\"true\" {...css.attrs(listboxStyles.progress)}>\n <Progress size=\"xs\" aria-label={lang.loading} />\n </div>\n ),\n renderBody(),\n ];\n // 别处滚动(Select、Combobox 的弹出层):只渲染列表本身\n if (!own) return <div {...elementProps(props)}>{body}</div>;\n // 自己滚动:列表元素就是 ScrollArea 的视口,焦点与 aria-activedescendant 仍在它上面,滚动条换成浮层的\n return (\n <ScrollArea focusable={false} propsViewport={props as PartProps<'div'>}>\n {body}\n </ScrollArea>\n );\n };\n },\n { name: 'ListboxView' },\n);\n\n/** 高亮项的 id(给 aria-activedescendant);没有高亮时 undefined */\nexport function activeOptionId<T>(list: ListState<T>, id: string): string | undefined {\n const index = list.active === undefined ? -1 : list.indexOf(list.active);\n return index < 0 ? undefined : `${id}-${index}`;\n}\n\n/** 列表框共有的属性;未声明的属性落到 role=\"listbox\" 的 div 上 */\nexport interface ListboxBaseProps<T> extends Omit<\n ListboxViewProps<T>,\n 'list' | 'id' | 'multiple' | 'renderOption'\n> {\n /** 列表的 id;在 Field 里时默认用 Field 给的 */\n id?: string;\n /** 数据:ListboxOption、字符串,或任意数据加 toOption */\n items: readonly T[];\n /** 必须有选中项:单选时再点已选项不取消;在必填的 Field 里默认开启 */\n required?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 自定义选项内容:`{(item, { selected, active }) => …}`,拿到 items 里的原始数据 */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n}\n\n/** 单选或多选;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type ListboxProps<T = ListboxOption> = ListboxBaseProps<T> &\n SelectionProps &\n OptionMapping<T>;\n\n/** 列表框:焦点在列表上,方向键移动高亮、Enter / 空格选中 */\nexport const Listbox = _component(\n <T,>({\n items,\n toOption,\n selectionMode = 'single',\n _value: value = _bindable<string | string[] | null>(null),\n required,\n disabled,\n id,\n children,\n onPick,\n ...rest\n }: ListboxProps<T>) => {\n const generatedId = useId();\n const control = useFieldControl(() => ({ id, disabled, required }));\n const list = useListState({\n items: () => items,\n toOption: (item) => toListboxOption(item, toOption),\n selected: () => selectedValues(value),\n mode: () => selectionMode,\n required: () => control().required,\n onChange: (next) => (value = selectionMode === 'multiple' ? [...next] : (next[0] ?? null)),\n });\n\n function onKeydown(event: KeyboardEvent) {\n if (control().disabled) return;\n if (handleListKeydown(list, event, { space: true, typeahead: true }, onPick)) {\n event.preventDefault();\n }\n }\n\n return () => {\n const state = control();\n const prefix = state.id ?? generatedId;\n return (\n <ListboxView\n {...mergePartProps<ListboxViewProps<T>>(\n {\n list,\n id: prefix,\n multiple: selectionMode === 'multiple',\n renderOption: children,\n onPick,\n },\n rest as Partial<ListboxViewProps<T>>,\n {\n id: prefix,\n tabindex: state.disabled ? -1 : 0,\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n 'aria-disabled': state.disabled || undefined,\n 'aria-required': state.required || undefined,\n 'aria-activedescendant': activeOptionId(list, prefix),\n onFocus: () => {\n if (list.active === undefined) list.activateDefault();\n },\n onKeydown,\n },\n )}\n />\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"Listbox.js","names":["_isVNode","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_computed","_createVNode","_mergeProps","_Fragment","Text","_vtp_bindable","_vtp_childrenProp"],"sources":["../../src/input/Listbox.tsx"],"sourcesContent":["/**\n * 列表框(role=\"listbox\"):在一列选项里单选或多选。数据驱动,始终虚拟滚动(上万个选项也只渲染看得见的几十个):\n *\n * <Listbox items={cities} _value={city} aria-label=\"城市\" />\n * <Listbox items={tags} selectionMode=\"multiple\" _value={picked}>{(tag) => <Badge>{tag.label}</Badge>}</Listbox>\n * <Listbox items={users} toOption={(user) => ({ value: user.id, label: user.name })} _value={id} aria-label=\"成员\" />\n *\n * 选项是 { value, label, disabled?, description?, icon?, group? }(ListboxOption);别的形状的数据用 toOption 转换,\n * 自定义内容的渲染函数拿到的仍是原始数据。\n * 焦点在列表上,高亮项经 aria-activedescendant 告诉读屏:↑↓、Home / End、Page Up / Down 移动,\n * Enter / 空格选中,按字母跳到以它开头的项。状态与键盘见 list-state.ts;Select、Combobox 用同一个 ListboxView 渲染。\n *\n * 虚拟滚动(useVirtualizer):高亮项总在渲染范围里(aria-activedescendant 才指得到),键盘移动时滚进可见范围;\n * 选项带 aria-setsize / aria-posinset,读屏知道总数与位置。分组标题只是视觉上的一行(各行独立定位,没法用\n * role=\"group\" 包住组里的选项),组名经 aria-describedby 交给组里的每个选项。\n * loading:选项换成骨架行(首次加载与刷新一样,不再另加进度条);列表带 aria-busy。\n *\n * 部件:Root(div,role=\"listbox\")、GroupLabel、Option(div,role=\"option\")、Check(已选标记)、Skeleton(加载中的占位行)。\n */\nimport { Check } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useId, watch, withMemo, type VNode, type VNodeChild } from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { useDelayedLoading } from '../utils/motion/delayed-loading';\nimport { useLang } from '../config/context';\nimport { Empty, type EmptyProps } from '../feedback/Empty';\nimport { Skeleton, type SkeletonProps, type SkeletonShapeProps } from '../feedback/Skeleton';\nimport { SHIMMER_STAGGER } from '../utils/style/shimmer';\nimport { itemStyles } from '../utils/style/item-styles';\nimport {\n defaultLabelledBy,\n elementProps,\n mergeAttrs,\n mergePartProps,\n mergeProps,\n type PartProps,\n} from '../utils/props';\nimport { ScrollArea } from '../layout/ScrollArea';\nimport { selectedValues, type SelectionProps } from '../utils/data/selection';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { useVirtualizer } from '../utils/virtual/use-virtualizer';\nimport { defaultRangeExtractor } from '../utils/virtual/virtualizer';\nimport { useFieldControl } from '../form/Field';\nimport {\n handleListKeydown,\n useListState,\n type ListboxOption,\n type ListStateEntry,\n type ListState,\n type OptionMapping,\n toListboxOption,\n} from './list-state';\n\n/** 选项的渲染状态:渲染函数据此画高亮、已选的样子 */\nexport interface OptionRenderState {\n /** 已选 */\n selected: boolean;\n /** 高亮(键盘或指针所在) */\n active: boolean;\n}\n\n/** 选项的部件属性:可以按选项(items 里的原始数据)计算 */\ntype OptionProps<T> =\n | PartProps<'div', 'role' | 'id' | 'aria-selected' | 'aria-disabled'>\n | ((item: T, state: OptionRenderState) => PartProps<'div'>);\n\n/** ListboxView 的属性:Listbox、Select、Combobox 共用的渲染层 */\nexport interface ListboxViewProps<T> extends PartProps<'div', 'role'> {\n /** 列表状态(useListState) */\n list: ListState<T>;\n /** 列表的 id;选项的 id 是 `${id}-${序号}`(aria-activedescendant 指向它) */\n id: string;\n /** 多选:aria-multiselectable */\n multiple?: boolean;\n /** 滚动容器:Select、Combobox 的弹出层;不给时列表自己滚动(ScrollArea 的浮层滚动条,最高 20em,用 sx 改) */\n scroller?: HTMLElement | null;\n /** 加载中:选项换成骨架行 */\n loading?: boolean;\n /** 选项的估计高度(px),默认 36;渲染后以实际高度为准 */\n estimateSize?: number;\n /** 自定义选项内容:拿到 items 里的原始数据 */\n renderOption?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有选项时显示的内容;默认是 Empty(文案取语言包) */\n empty?: VNodeChild;\n /** 点选了一项(点击或 Enter,再选已选的那项也会调用):Select、弹层里的列表据此关闭 */\n onPick?: (value: string) => void;\n /** 选项的部件属性 */\n propsOption?: OptionProps<T>;\n /** 分组标题的部件属性 */\n propsGroupLabel?: Partial<TextProps>;\n /** 已选标记的部件属性 */\n propsCheck?: Partial<IconProps>;\n /** 空状态的部件属性 */\n propsEmpty?: Partial<EmptyProps>;\n /** 加载中占位行的部件属性 */\n propsSkeleton?: SkeletonShapeProps;\n}\n\n/** 渲染用的一行:分组标题或选项 */\ntype Row<T> =\n | { kind: 'group'; key: string; label: string; id: string }\n | {\n kind: 'option';\n key: string;\n option: ListStateEntry<T>;\n index: number;\n groupId: string | undefined;\n };\n\n/** 加载中显示几行骨架 */\nconst SKELETON_ROWS = 4;\n\n/** Listbox 的样式:root、scroll、sizer、row、groupLabel、content 等 */\nexport const listboxStyles = css.create({\n root: { position: 'relative', padding: '_xs', lineHeight: '_normal', outlineStyle: 'none' },\n // 自己是滚动容器时(单独使用的 Listbox):限制高度,滚动不传给页面\n scroll: { maxHeight: '20em', overflowY: 'auto', overscrollBehavior: 'contain' },\n sizer: { position: 'relative', width: '_full' },\n row: { position: 'absolute', top: 0, insetInline: 0 },\n groupLabel: {\n display: 'block',\n paddingTop: '_sm',\n paddingBottom: '_xs',\n paddingInline: '_sm',\n fontWeight: '_semibold',\n },\n content: { display: 'flex', flexDirection: 'column', flexGrow: 1, minWidth: 0 },\n description: { color: '_textMuted' },\n check: { flexShrink: 0 },\n hidden: { visibility: 'hidden' },\n skeleton: { display: 'block', height: '1em', marginBlock: '0.625em', marginInline: '_sm' },\n});\n\n// 行的位置是任意值,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Listbox 的样式:y、height、width */\nexport const listboxPositionStyles = css.create({\n y: (px: number) => ({ transform: `translateY(${px}px)` }),\n height: (px: number) => ({ height: px }),\n width: (percent: string) => ({ width: percent }),\n});\n\n/** 列表的渲染层:虚拟滚动的选项、分组标题、已选标记、空状态与加载中;不管焦点,指针悬停高亮、点击选中 */\nexport const ListboxView = _component(\n <T,>({\n list,\n id,\n multiple = false,\n scroller,\n loading = false,\n estimateSize = 36,\n renderOption,\n empty,\n onPick,\n propsOption,\n propsGroupLabel,\n propsCheck,\n propsEmpty,\n propsSkeleton,\n ...rest\n }: ListboxViewProps<T>) => {\n const lang = useLang();\n // 骨架防闪烁;aria-busy 按真实的 loading\n const indicator = useDelayedLoading(() => loading);\n let root = _state.raw<HTMLElement | null>(null);\n let sizer = _state.raw<HTMLElement | null>(null);\n\n /** 选项按分组排好后展开成行:每组前插一行标题 */\n const rows = _derived.by<Row<T>[]>(() => {\n const result: Row<T>[] = [];\n let group: string | undefined;\n let headerId: string | undefined;\n list.options.forEach((option, index) => {\n if (option.group != null && option.group !== group) {\n headerId = `${id}-group-${result.length}`;\n result.push({\n kind: 'group',\n key: `group:${option.group}`,\n label: option.group,\n id: headerId,\n });\n }\n group = option.group;\n result.push({\n kind: 'option',\n key: option.value,\n option,\n index,\n groupId: option.group != null ? headerId : undefined,\n });\n });\n return result;\n });\n\n /** 值 → 行号:高亮项的行号一次查到,不在每次渲染时扫一遍 */\n const rowOf = _derived.by(() => {\n const map = new Map<string, number>();\n rows.forEach((row, index) => {\n if (row.kind === 'option') map.set(row.option.value, index);\n });\n return map;\n });\n const activeRow = () => (list.active === undefined ? -1 : (rowOf.get(list.active) ?? -1));\n\n const virtual = useVirtualizer(() => {\n const current = rows;\n // 读一下高亮项:它变了要重新算渲染范围(高亮项总要渲染)\n const active = activeRow();\n // 先读出来:每一项都要调用一次估计高度,不要每次都经过 props 的响应式读取\n const size = estimateSize;\n return {\n count: current.length,\n scrollElement: scroller === undefined ? root : scroller,\n list: sizer,\n estimateSize: (index: number) => (current[index]?.kind === 'group' ? 30 : size),\n getItemKey: (index: number) => current[index]!.key,\n overscan: 6,\n rangeExtractor: (range) => {\n const indices = defaultRangeExtractor(range);\n if (active >= 0 && !indices.includes(active)) {\n indices.push(active);\n indices.sort((a, b) => a - b);\n }\n return indices;\n },\n };\n });\n\n // 高亮项变了(键盘移动)时滚进可见范围;已经完整可见就不动(指针悬停触发的不会滚)。\n // 高亮的是第一项、上面是组名时滚到最顶上:组名不被挡住(搜索过滤后高亮第一个匹配的)\n watch(\n () => list.active,\n () => {\n const index = activeRow();\n if (index < 0) return;\n virtual.scrollToIndex(index === 1 && rows[0]?.kind === 'group' ? 0 : index, {\n align: 'auto',\n });\n },\n { flush: 'post' },\n );\n\n /**\n * 选项行按“会影响它的值”缓存(Vue 的 withMemo,同模板的 v-memo):方向键移动高亮时只重建前后两行,\n * 不再重建全部可见行与其中的图标。自定义了 renderOption 或按项计算的 propsOption 时不缓存:\n * 使用方的函数可能读别的状态,缓存了会显示旧内容\n */\n const memoCache: VNode[] = [];\n function optionRow(row: Extract<Row<T>, { kind: 'option' }>) {\n if (renderOption || typeof propsOption === 'function') return renderOptionRow(row);\n const { option } = row;\n return withMemo(\n [\n option,\n row.index,\n row.groupId,\n list.isSelected(option.value),\n list.active === option.value,\n list.options.length,\n propsOption,\n propsCheck,\n ],\n () => renderOptionRow(row),\n memoCache,\n row.index,\n );\n }\n\n function renderOptionRow(row: Extract<Row<T>, { kind: 'option' }>) {\n const { option, index } = row;\n const state = {\n selected: list.isSelected(option.value),\n active: list.active === option.value,\n };\n const own = typeof propsOption === 'function' ? propsOption(option.item, state) : propsOption;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n itemStyles.row,\n state.active && itemStyles.highlighted,\n state.selected && itemStyles.selected,\n option.disabled && itemStyles.disabled,\n ],\n },\n own,\n {\n id: `${id}-${index}`,\n role: 'option',\n 'aria-selected': state.selected,\n 'aria-disabled': option.disabled || undefined,\n 'aria-setsize': list.options.length,\n 'aria-posinset': index + 1,\n 'aria-describedby': row.groupId,\n // 焦点留在列表、触发按钮或输入框上\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onPointermove: () => {\n if (!option.disabled && list.active !== option.value) list.setActive(option.value);\n },\n onClick: () => {\n if (option.disabled) return;\n list.select(option.value);\n onPick?.(option.value);\n },\n },\n )}\n data-state={state.selected ? 'checked' : 'unchecked'}\n data-active={state.active || undefined}\n data-disabled={option.disabled || undefined}\n >\n {renderOption ? (\n renderOption(option.item, state)\n ) : (\n <>\n {option.icon && <Icon icon={option.icon} />}\n <span {...css.attrs(listboxStyles.content)}>\n <span {...css.attrs(itemStyles.label)}>{option.label}</span>\n {option.description && (\n <Text size=\"sm\" sx={listboxStyles.description}>\n {option.description}\n </Text>\n )}\n </span>\n </>\n )}\n <Icon\n {...mergePartProps<IconProps>(\n { icon: Check, sx: [listboxStyles.check, !state.selected && listboxStyles.hidden] },\n propsCheck,\n )}\n />\n </div>\n );\n }\n\n function renderBody() {\n if (indicator.value) {\n return Array.from({ length: SKELETON_ROWS }, (_, index) => (\n <Skeleton\n key={index}\n {...mergePartProps<SkeletonProps>(\n {\n sx: [listboxStyles.skeleton, listboxPositionStyles.width(`${85 - index * 15}%`)],\n delay: index * SHIMMER_STAGGER,\n },\n propsSkeleton,\n )}\n />\n ));\n }\n if (rows.length === 0) {\n // 加载刚开始、骨架还没到显示的时候(防闪烁):先空着\n if (loading) return null;\n return (\n empty ?? (\n <Empty\n {...mergePartProps<EmptyProps>(\n { size: 'sm', icon: false, description: lang.selectEmpty },\n propsEmpty,\n )}\n />\n )\n );\n }\n return (\n <div\n ref={_toRef(sizer)}\n role=\"presentation\"\n {...css.attrs(listboxStyles.sizer, listboxPositionStyles.height(virtual.total))}\n >\n {virtual.items.map((item) => {\n const row = rows[item.index]!;\n return (\n <div\n key={item.key}\n ref={virtual.measure}\n data-index={item.index}\n role=\"presentation\"\n {...css.attrs(listboxStyles.row, listboxPositionStyles.y(item.start))}\n >\n {row.kind === 'group' ? (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', size: 'sm', sx: listboxStyles.groupLabel },\n propsGroupLabel,\n // 只是视觉上的标题:组名经各选项的 aria-describedby 念出\n { id: row.id, 'aria-hidden': true },\n )}\n >\n {row.label}\n </Text>\n ) : (\n optionRow(row)\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return () => {\n const own = scroller === undefined;\n // 先不编译 sx:自己滚动时这些属性交给 ScrollArea 的视口,和视口自己的样式一次合并\n const props = mergeProps<'div'>(\n { sx: [listboxStyles.root, own && listboxStyles.scroll, focusRingStyles.visible] },\n rest,\n {\n ref: _toRef(root),\n id,\n role: 'listbox',\n 'aria-multiselectable': multiple || undefined,\n 'aria-busy': loading || undefined,\n },\n );\n const body = renderBody();\n // 别处滚动(Select、Combobox 的弹出层):只渲染列表本身\n if (!own) return <div {...elementProps(props)}>{body}</div>;\n // 自己滚动:列表元素就是 ScrollArea 的视口,焦点与 aria-activedescendant 仍在它上面,滚动条换成浮层的\n return (\n <ScrollArea focusable={false} propsViewport={props as PartProps<'div'>}>\n {body}\n </ScrollArea>\n );\n };\n },\n { name: 'ListboxView' },\n);\n\n/** 高亮项的 id(给 aria-activedescendant);没有高亮时 undefined */\nexport function activeOptionId<T>(list: ListState<T>, id: string): string | undefined {\n const index = list.active === undefined ? -1 : list.indexOf(list.active);\n return index < 0 ? undefined : `${id}-${index}`;\n}\n\n/** 列表框共有的属性;未声明的属性落到 role=\"listbox\" 的 div 上 */\nexport interface ListboxBaseProps<T> extends Omit<\n ListboxViewProps<T>,\n 'list' | 'id' | 'multiple' | 'renderOption'\n> {\n /** 列表的 id;在 Field 里时默认用 Field 给的 */\n id?: string;\n /** 数据:ListboxOption、字符串,或任意数据加 toOption */\n items: readonly T[];\n /** 必须有选中项:单选时再点已选项不取消;在必填的 Field 里默认开启 */\n required?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 自定义选项内容:`{(item, { selected, active }) => …}`,拿到 items 里的原始数据 */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n}\n\n/** 单选或多选;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type ListboxProps<T = ListboxOption> = ListboxBaseProps<T> &\n SelectionProps &\n OptionMapping<T>;\n\n/** 列表框:焦点在列表上,方向键移动高亮、Enter / 空格选中 */\nexport const Listbox = _component(\n <T,>({\n items,\n toOption,\n selectionMode = 'single',\n _value: value = _bindable<string | string[] | null>(null),\n required,\n disabled,\n id,\n children,\n onPick,\n ...rest\n }: ListboxProps<T>) => {\n const generatedId = useId();\n const control = useFieldControl(() => ({ id, disabled, required }));\n const list = useListState({\n items: () => items,\n toOption: (item) => toListboxOption(item, toOption),\n selected: () => selectedValues(value),\n mode: () => selectionMode,\n required: () => control().required,\n onChange: (next) => (value = selectionMode === 'multiple' ? [...next] : (next[0] ?? null)),\n });\n\n function onKeydown(event: KeyboardEvent) {\n if (control().disabled) return;\n if (handleListKeydown(list, event, { space: true, typeahead: true }, onPick)) {\n event.preventDefault();\n }\n }\n\n return () => {\n const state = control();\n const prefix = state.id ?? generatedId;\n return (\n <ListboxView\n {...mergePartProps<ListboxViewProps<T>>(\n {\n list,\n id: prefix,\n multiple: selectionMode === 'multiple',\n renderOption: children,\n onPick,\n },\n rest as Partial<ListboxViewProps<T>>,\n {\n id: prefix,\n tabindex: state.disabled ? -1 : 0,\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n 'aria-disabled': state.disabled || undefined,\n 'aria-required': state.required || undefined,\n 'aria-activedescendant': activeOptionId(list, prefix),\n onFocus: () => {\n if (list.active === undefined) list.activateDefault();\n },\n onKeydown,\n },\n )}\n />\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { type VNodeChild } from 'vue';
3
3
  import { type OpenChangeProps } from '../utils/dom/open-change';
4
4
  import { type PartProps } from '../utils/props';
@@ -11,7 +11,7 @@ import { useRemoteItems } from "./remote-items.js";
11
11
  import { caretAnchor } from "../utils/dom/caret.js";
12
12
  import { Fragment, createVNode, nextTick, ref, shallowRef, useId, watch } from "vue";
13
13
  import { _component, bindable, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
14
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
14
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
15
  //#region src/input/Mentions.tsx
16
16
  /** 提及的弹出列表由组件管理 */
17
17
  /** Mentions 除 toOption 外的属性;未声明的属性落到 textarea 上(同 Textarea) */
@@ -1 +1 @@
1
- {"version":3,"file":"Mentions.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_vtp_bindable","_vtp_childrenProp","_vue_shallowRef","_vue_ref","_Fragment","_mergeProps"],"sources":["../../src/input/Mentions.tsx"],"sourcesContent":["/**\n * 提及:多行文本框里输入 @ 弹出人员(或岗位、群组)列表,选中后写成“@名字 ”。留言、审批意见、协商回复里通知相关的人。\n *\n * <Field label=\"留言\"><Mentions _value={text} items={people} _mentions={notified} /></Field>\n * <Mentions _value={text} load={(query, signal) => api.searchUsers(query, { signal })} toOption={…} />\n *\n * 值仍是文字;mentions 是文字里提到的选项的值(工号、岗位编号),随文字增删——删掉“@名字”就不再算提及。\n * 显示提及过的文字用 MentionText(提及高亮),拆分用 mentionSegments。\n *\n * - 弹出:@ 在开头或前面不是字母数字(邮箱里的 @ 不算),@ 与光标之间没有空白;列表贴在 @ 的位置(caretAnchor)。\n * - 过滤:本地按显示文字包含 @ 后面的文字;给 load 时按它远程搜索(同 Combobox)。\n * - 键盘:↑↓ 移动、Enter 或 Tab 选中、Esc 关闭(这个 @ 不再弹出,直到重新输入);焦点一直在文本框里,\n * 高亮项经 aria-activedescendant 告诉读屏,结果数量播报。中文输入法组合期间不弹出、不过滤。\n *\n * 外壳与自动增高同 Textarea。部件:Root(外壳)、Textarea、Popover、Listbox。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId, watch, type VNodeChild } from 'vue';\nimport { useLang, useTextMatcher } from '../config/context';\nimport { caretAnchor } from '../utils/dom/caret';\nimport { useAnchoredPopover } from '../utils/dom/floating';\nimport { isComposingKey } from '../utils/dom/hotkeys';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { activeOptionId, type ListboxViewProps, type OptionRenderState } from './Listbox';\nimport { ListPopover } from './ListPopover';\nimport {\n handleListKeydown,\n toListboxOption,\n useListState,\n useResultAnnouncement,\n type ListboxOption,\n type OptionMapping,\n} from './list-state';\nimport { useRemoteItems, type OptionsLoader } from './remote-items';\nimport { Textarea, type TextareaProps } from './Textarea';\n\n/** 提及的弹出列表由组件管理 */\nexport type MentionsManaged = 'aria-autocomplete' | 'aria-controls' | 'aria-activedescendant';\n\n/** Mentions 除 toOption 外的属性;未声明的属性落到 textarea 上(同 Textarea) */\nexport interface MentionsBaseProps<T>\n extends Omit<TextareaProps, MentionsManaged>, OpenChangeProps {\n /** 可以提及的人(ListboxOption、字符串,或任意数据加 toOption);有 load 时是第一次结果之前的选项 */\n items?: readonly T[];\n /** 远程搜索:按 @ 后面的文字调用,停下 300 ms 后请求,只采用最后一次 */\n load?: OptionsLoader<T>;\n /** 文字里提到的选项的值:父级写 _mentions={x},随文字更新 */\n _mentions?: string[];\n /** 触发的字符,默认 '@' */\n prefix?: string;\n /** 过滤:默认按显示文字包含 @ 后面的文字;false 不过滤(由调用方换 items) */\n filter?: false | ((item: T, query: string) => boolean);\n /** 列表是否打开:父级可以写 _open={x} */\n _open?: boolean;\n /** 正在取选项 */\n loading?: boolean;\n /** 自定义选项内容:`{(item, { active }) => …}`(头像、部门) */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有匹配的人时列表里显示的内容 */\n empty?: VNodeChild;\n /** 弹出层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover'>;\n /** 列表的部件属性 */\n propsListbox?: Partial<ListboxViewProps<T>>;\n}\n\n/** 提及输入框的属性;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type MentionsProps<T = ListboxOption> = MentionsBaseProps<T> & OptionMapping<T>;\n\n/** 拆开的一段文字:普通文字,或提及(带它的选项) */\nexport interface MentionSegment {\n /** 这一段的文字(提及时含 @) */\n text: string;\n /** 提及的选项;普通文字没有 */\n mention?: ListboxOption;\n}\n\n/** @ 前面是这些字符时不算提及(邮箱 name@example.com) */\nconst WORD_BEFORE = /[A-Za-z0-9_.]/;\n\n/**\n * 把文字拆成普通文字与提及:“@名字”里的名字是 options 里某一项的显示文字(有多个能匹配时取最长的)。\n * 提及的显示(MentionText)与找出提到了谁(mentionedValues)都用它\n */\nexport function mentionSegments(\n text: string,\n options: readonly ListboxOption[],\n prefix = '@',\n): MentionSegment[] {\n const byLength = options\n .filter((option) => option.label)\n .toSorted((a, b) => b.label.length - a.label.length);\n const segments: MentionSegment[] = [];\n let plain = '';\n let index = 0;\n while (index < text.length) {\n const mention =\n text.startsWith(prefix, index) && !WORD_BEFORE.test(text[index - 1] ?? '')\n ? byLength.find((option) => text.startsWith(option.label, index + prefix.length))\n : undefined;\n if (!mention) {\n plain += text[index];\n index += 1;\n continue;\n }\n if (plain) segments.push({ text: plain });\n plain = '';\n const length = prefix.length + mention.label.length;\n segments.push({ text: text.slice(index, index + length), mention });\n index += length;\n }\n if (plain) segments.push({ text: plain });\n return segments;\n}\n\n/** 文字里提到了哪些选项(值,按第一次出现的顺序,不重复) */\nexport function mentionedValues(\n text: string,\n options: readonly ListboxOption[],\n prefix = '@',\n): string[] {\n const values = mentionSegments(text, options, prefix).flatMap((segment) =>\n segment.mention ? [segment.mention.value] : [],\n );\n return [...new Set(values)];\n}\n\n/** MentionText 与 Mentions 的样式:mention、text、panel */\nexport const mentionStyles = css.create({\n // 提及:强调色的文字,浅底\n mention: {\n color: '_accentText',\n backgroundColor: '_accentSoft',\n borderRadius: '_sm',\n paddingInline: '0.125em',\n fontWeight: '_medium',\n },\n text: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' },\n // 弹层贴着光标、不跟文本框同宽:给个合适的宽度\n panel: { width: '16em' },\n});\n\n/** 未声明的属性落到 span 上 */\nexport interface MentionTextProps extends PartProps<'span'> {\n /** 文字 */\n text: string;\n /** 能被提及的选项:“@显示文字”高亮 */\n options: readonly ListboxOption[];\n /** 触发的字符,默认 '@' */\n prefix?: string;\n /** 提及的部件属性,可以按选项计算(做成链接、悬停卡片时用 renderMention) */\n propsMention?: PartProps<'span'> | ((mention: ListboxOption) => PartProps<'span'>);\n /** 自己渲染一个提及(链接到个人页、HoverCard);不写时是高亮的文字 */\n renderMention?: (mention: ListboxOption, text: string) => VNodeChild;\n}\n\n/** 带提及的文字:“@名字”高亮,换行照常(pre-wrap) */\nexport const MentionText = _component(\n ({ text, options, prefix = '@', propsMention, renderMention, ...rest }: MentionTextProps) =>\n () => (\n <span {...mergeAttrs<'span'>({ sx: mentionStyles.text }, rest)}>\n {mentionSegments(text, options, prefix).map((segment) => {\n if (!segment.mention) return segment.text;\n if (renderMention) return renderMention(segment.mention, segment.text);\n const own =\n typeof propsMention === 'function' ? propsMention(segment.mention) : propsMention;\n return (\n <span {...mergeAttrs<'span'>({ sx: mentionStyles.mention }, own)}>{segment.text}</span>\n );\n })}\n </span>\n ),\n);\n\n/** 提及输入框:多行文本框 + 跟着 @ 弹出的人员列表 */\nexport const Mentions = _component(\n <T,>({\n _value: value = _bindable(''),\n _mentions: mentions = _bindable<string[]>([]),\n items = [],\n toOption,\n load,\n prefix = '@',\n filter,\n _open: open = _bindable(false),\n onOpenChange,\n loading = false,\n children,\n empty,\n propsRoot,\n propsPopover,\n propsListbox,\n ...rest\n }: MentionsProps<T>) => {\n const lang = useLang();\n const textMatcher = useTextMatcher();\n const listId = useId();\n let shell = _state.raw<HTMLElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n // 正在提及:@ 在文字里的位置,与 @ 到光标之间的文字(过滤词)\n let trigger = _state<number | null>(null);\n let query = _state('');\n // 按 Esc 关掉的那个 @:光标还在它后面时不再弹出\n let dismissed: number | null = null;\n // 见过的选项(远程搜索换掉 items 之后,已提及的人仍能认出来)\n const known = new Map<string, ListboxOption>();\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const optionOf = (item: T) => toListboxOption(item, toOption);\n const textarea = () => shell?.querySelector('textarea') ?? null;\n\n const remote = useRemoteItems({\n load: () => load,\n query: () => query,\n open: () => open,\n items: () => items,\n });\n const list = useListState({\n items: () =>\n load || filter === false\n ? remote.items()\n : remote\n .items()\n .filter((item) =>\n !query\n ? true\n : filter\n ? filter(item, query)\n : textMatcher()(optionOf(item).label, query),\n ),\n toOption: optionOf,\n selected: () => [],\n mode: () => 'single',\n onChange: () => {},\n });\n useResultAnnouncement(() => ({\n query: open ? query || prefix : '',\n count: list.options.length,\n }));\n\n // 文字里提到的人:随文字与见过的选项更新\n watch(\n () => [value, remote.items()] as const,\n ([text, current]) => {\n for (const item of current) {\n const option = optionOf(item);\n known.set(option.value, option);\n }\n const next = mentionedValues(text, [...known.values()], prefix);\n if (next.join('\\n') !== mentions.join('\\n')) mentions = next;\n },\n { immediate: true },\n );\n\n // 远程结果后到:打开着又没有高亮项时高亮第一项(Enter 才能直接选中)\n watch(\n () => list.options.length,\n () => {\n if (open && list.active === undefined) list.move('first');\n },\n );\n\n /** 看光标前面是不是正在写的提及:是就按 @ 后面的文字过滤并打开,不是就关闭 */\n function detect(event?: Event) {\n const element = textarea();\n if (!element || rest.readonly || rest.disabled) return;\n const caret = element.selectionStart;\n const before = element.value.slice(0, caret);\n const at = before.lastIndexOf(prefix);\n const typed = at < 0 ? '' : before.slice(at + prefix.length);\n const mentioning =\n at >= 0 &&\n element.selectionEnd === caret &&\n !WORD_BEFORE.test(before[at - 1] ?? '') &&\n !/\\s/.test(typed) &&\n typed.length <= 30;\n if (!mentioning || at === dismissed) {\n if (!mentioning) dismissed = null;\n trigger = null;\n if (open) setOpen(false, 'focus', event);\n return;\n }\n const opening = trigger !== at || !open;\n trigger = at;\n query = typed;\n if (opening) setOpen(true, 'trigger', event);\n list.move('first');\n }\n\n /** 选中一项:把“@过滤词”换成“@名字 ”,光标放在后面 */\n function pick(choice: string, event?: Event) {\n const element = textarea();\n const option = list.options.find((entry) => entry.value === choice);\n if (!element || trigger === null || !option) return;\n known.set(option.value, option);\n const inserted = `${prefix}${option.label} `;\n const caret = element.selectionStart;\n const start = trigger;\n value = element.value.slice(0, start) + inserted + element.value.slice(caret);\n trigger = null;\n setOpen(false, 'select', event);\n void nextTick(() => {\n element.focus();\n element.setSelectionRange(start + inserted.length, start + inserted.length);\n });\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (!open || isComposingKey(event)) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n dismissed = trigger;\n setOpen(false, 'escape', event);\n return;\n }\n if (event.key === 'Tab' && list.active !== undefined) {\n event.preventDefault();\n pick(list.active, event);\n return;\n }\n if (handleListKeydown(list, event, { homeEnd: false }, (choice) => pick(choice, event)))\n event.preventDefault();\n }\n\n // 移动光标(方向键、Home / End)后重新判断;↑↓ 在列表打开时是移动高亮,不算\n function onKeyup(event: KeyboardEvent) {\n if (event.isComposing) return;\n if (open && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) return;\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key) || !open) detect(event);\n }\n\n const { onToggle } = useAnchoredPopover(\n () => {\n const element = textarea();\n return {\n open,\n anchor: element && caretAnchor(element, () => trigger ?? element.selectionStart),\n panel,\n floating: { placement: 'bottom-start', fitHeight: true },\n restoreFocus: false,\n };\n },\n {\n close: (reason, event) => {\n if (reason === 'escape') dismissed = trigger;\n setOpen(false, reason, event);\n },\n },\n );\n\n return () => (\n <>\n <Textarea\n {...mergePartProps<TextareaProps>(\n { propsRoot: mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: _toRef(shell) }) },\n rest,\n {\n 'aria-autocomplete': 'list',\n 'aria-controls': open ? listId : undefined,\n 'aria-activedescendant': open ? activeOptionId(list, listId) : undefined,\n onInput: (event: Event) => !(event as InputEvent).isComposing && detect(event),\n onCompositionend: (event: CompositionEvent) => detect(event),\n onClick: (event: MouseEvent) => detect(event),\n onKeydown,\n onKeyup,\n onBlur: (event: FocusEvent) => open && setOpen(false, 'focus', event),\n },\n )}\n _value={value}\n />\n <ListPopover\n panelRef={_toRef(panel)}\n onToggle={onToggle}\n size={rest.size}\n label={lang.mentionsList}\n loading={loading || remote.loading()}\n onPick={(choice) => pick(choice)}\n listbox={{\n list,\n id: listId,\n renderOption: children,\n empty: remote.failure() ?? empty ?? lang.mentionsEmpty,\n }}\n propsListbox={propsListbox}\n propsPopover={mergePartProps<PartProps<'div', 'id' | 'popover'>>(\n { sx: mentionStyles.panel },\n propsPopover,\n )}\n />\n </>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"Mentions.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_vtp_bindable","_vtp_childrenProp","_vue_shallowRef","_vue_ref","_Fragment","_mergeProps"],"sources":["../../src/input/Mentions.tsx"],"sourcesContent":["/**\n * 提及:多行文本框里输入 @ 弹出人员(或岗位、群组)列表,选中后写成“@名字 ”。留言、审批意见、协商回复里通知相关的人。\n *\n * <Field label=\"留言\"><Mentions _value={text} items={people} _mentions={notified} /></Field>\n * <Mentions _value={text} load={(query, signal) => api.searchUsers(query, { signal })} toOption={…} />\n *\n * 值仍是文字;mentions 是文字里提到的选项的值(工号、岗位编号),随文字增删——删掉“@名字”就不再算提及。\n * 显示提及过的文字用 MentionText(提及高亮),拆分用 mentionSegments。\n *\n * - 弹出:@ 在开头或前面不是字母数字(邮箱里的 @ 不算),@ 与光标之间没有空白;列表贴在 @ 的位置(caretAnchor)。\n * - 过滤:本地按显示文字包含 @ 后面的文字;给 load 时按它远程搜索(同 Combobox)。\n * - 键盘:↑↓ 移动、Enter 或 Tab 选中、Esc 关闭(这个 @ 不再弹出,直到重新输入);焦点一直在文本框里,\n * 高亮项经 aria-activedescendant 告诉读屏,结果数量播报。中文输入法组合期间不弹出、不过滤。\n *\n * 外壳与自动增高同 Textarea。部件:Root(外壳)、Textarea、Popover、Listbox。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId, watch, type VNodeChild } from 'vue';\nimport { useLang, useTextMatcher } from '../config/context';\nimport { caretAnchor } from '../utils/dom/caret';\nimport { useAnchoredPopover } from '../utils/dom/floating';\nimport { isComposingKey } from '../utils/dom/hotkeys';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { activeOptionId, type ListboxViewProps, type OptionRenderState } from './Listbox';\nimport { ListPopover } from './ListPopover';\nimport {\n handleListKeydown,\n toListboxOption,\n useListState,\n useResultAnnouncement,\n type ListboxOption,\n type OptionMapping,\n} from './list-state';\nimport { useRemoteItems, type OptionsLoader } from './remote-items';\nimport { Textarea, type TextareaProps } from './Textarea';\n\n/** 提及的弹出列表由组件管理 */\nexport type MentionsManaged = 'aria-autocomplete' | 'aria-controls' | 'aria-activedescendant';\n\n/** Mentions 除 toOption 外的属性;未声明的属性落到 textarea 上(同 Textarea) */\nexport interface MentionsBaseProps<T>\n extends Omit<TextareaProps, MentionsManaged>, OpenChangeProps {\n /** 可以提及的人(ListboxOption、字符串,或任意数据加 toOption);有 load 时是第一次结果之前的选项 */\n items?: readonly T[];\n /** 远程搜索:按 @ 后面的文字调用,停下 300 ms 后请求,只采用最后一次 */\n load?: OptionsLoader<T>;\n /** 文字里提到的选项的值:父级写 _mentions={x},随文字更新 */\n _mentions?: string[];\n /** 触发的字符,默认 '@' */\n prefix?: string;\n /** 过滤:默认按显示文字包含 @ 后面的文字;false 不过滤(由调用方换 items) */\n filter?: false | ((item: T, query: string) => boolean);\n /** 列表是否打开:父级可以写 _open={x} */\n _open?: boolean;\n /** 正在取选项 */\n loading?: boolean;\n /** 自定义选项内容:`{(item, { active }) => …}`(头像、部门) */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有匹配的人时列表里显示的内容 */\n empty?: VNodeChild;\n /** 弹出层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover'>;\n /** 列表的部件属性 */\n propsListbox?: Partial<ListboxViewProps<T>>;\n}\n\n/** 提及输入框的属性;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type MentionsProps<T = ListboxOption> = MentionsBaseProps<T> & OptionMapping<T>;\n\n/** 拆开的一段文字:普通文字,或提及(带它的选项) */\nexport interface MentionSegment {\n /** 这一段的文字(提及时含 @) */\n text: string;\n /** 提及的选项;普通文字没有 */\n mention?: ListboxOption;\n}\n\n/** @ 前面是这些字符时不算提及(邮箱 name@example.com) */\nconst WORD_BEFORE = /[A-Za-z0-9_.]/;\n\n/**\n * 把文字拆成普通文字与提及:“@名字”里的名字是 options 里某一项的显示文字(有多个能匹配时取最长的)。\n * 提及的显示(MentionText)与找出提到了谁(mentionedValues)都用它\n */\nexport function mentionSegments(\n text: string,\n options: readonly ListboxOption[],\n prefix = '@',\n): MentionSegment[] {\n const byLength = options\n .filter((option) => option.label)\n .toSorted((a, b) => b.label.length - a.label.length);\n const segments: MentionSegment[] = [];\n let plain = '';\n let index = 0;\n while (index < text.length) {\n const mention =\n text.startsWith(prefix, index) && !WORD_BEFORE.test(text[index - 1] ?? '')\n ? byLength.find((option) => text.startsWith(option.label, index + prefix.length))\n : undefined;\n if (!mention) {\n plain += text[index];\n index += 1;\n continue;\n }\n if (plain) segments.push({ text: plain });\n plain = '';\n const length = prefix.length + mention.label.length;\n segments.push({ text: text.slice(index, index + length), mention });\n index += length;\n }\n if (plain) segments.push({ text: plain });\n return segments;\n}\n\n/** 文字里提到了哪些选项(值,按第一次出现的顺序,不重复) */\nexport function mentionedValues(\n text: string,\n options: readonly ListboxOption[],\n prefix = '@',\n): string[] {\n const values = mentionSegments(text, options, prefix).flatMap((segment) =>\n segment.mention ? [segment.mention.value] : [],\n );\n return [...new Set(values)];\n}\n\n/** MentionText 与 Mentions 的样式:mention、text、panel */\nexport const mentionStyles = css.create({\n // 提及:强调色的文字,浅底\n mention: {\n color: '_accentText',\n backgroundColor: '_accentSoft',\n borderRadius: '_sm',\n paddingInline: '0.125em',\n fontWeight: '_medium',\n },\n text: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' },\n // 弹层贴着光标、不跟文本框同宽:给个合适的宽度\n panel: { width: '16em' },\n});\n\n/** 未声明的属性落到 span 上 */\nexport interface MentionTextProps extends PartProps<'span'> {\n /** 文字 */\n text: string;\n /** 能被提及的选项:“@显示文字”高亮 */\n options: readonly ListboxOption[];\n /** 触发的字符,默认 '@' */\n prefix?: string;\n /** 提及的部件属性,可以按选项计算(做成链接、悬停卡片时用 renderMention) */\n propsMention?: PartProps<'span'> | ((mention: ListboxOption) => PartProps<'span'>);\n /** 自己渲染一个提及(链接到个人页、HoverCard);不写时是高亮的文字 */\n renderMention?: (mention: ListboxOption, text: string) => VNodeChild;\n}\n\n/** 带提及的文字:“@名字”高亮,换行照常(pre-wrap) */\nexport const MentionText = _component(\n ({ text, options, prefix = '@', propsMention, renderMention, ...rest }: MentionTextProps) =>\n () => (\n <span {...mergeAttrs<'span'>({ sx: mentionStyles.text }, rest)}>\n {mentionSegments(text, options, prefix).map((segment) => {\n if (!segment.mention) return segment.text;\n if (renderMention) return renderMention(segment.mention, segment.text);\n const own =\n typeof propsMention === 'function' ? propsMention(segment.mention) : propsMention;\n return (\n <span {...mergeAttrs<'span'>({ sx: mentionStyles.mention }, own)}>{segment.text}</span>\n );\n })}\n </span>\n ),\n);\n\n/** 提及输入框:多行文本框 + 跟着 @ 弹出的人员列表 */\nexport const Mentions = _component(\n <T,>({\n _value: value = _bindable(''),\n _mentions: mentions = _bindable<string[]>([]),\n items = [],\n toOption,\n load,\n prefix = '@',\n filter,\n _open: open = _bindable(false),\n onOpenChange,\n loading = false,\n children,\n empty,\n propsRoot,\n propsPopover,\n propsListbox,\n ...rest\n }: MentionsProps<T>) => {\n const lang = useLang();\n const textMatcher = useTextMatcher();\n const listId = useId();\n let shell = _state.raw<HTMLElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n // 正在提及:@ 在文字里的位置,与 @ 到光标之间的文字(过滤词)\n let trigger = _state<number | null>(null);\n let query = _state('');\n // 按 Esc 关掉的那个 @:光标还在它后面时不再弹出\n let dismissed: number | null = null;\n // 见过的选项(远程搜索换掉 items 之后,已提及的人仍能认出来)\n const known = new Map<string, ListboxOption>();\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const optionOf = (item: T) => toListboxOption(item, toOption);\n const textarea = () => shell?.querySelector('textarea') ?? null;\n\n const remote = useRemoteItems({\n load: () => load,\n query: () => query,\n open: () => open,\n items: () => items,\n });\n const list = useListState({\n items: () =>\n load || filter === false\n ? remote.items()\n : remote\n .items()\n .filter((item) =>\n !query\n ? true\n : filter\n ? filter(item, query)\n : textMatcher()(optionOf(item).label, query),\n ),\n toOption: optionOf,\n selected: () => [],\n mode: () => 'single',\n onChange: () => {},\n });\n useResultAnnouncement(() => ({\n query: open ? query || prefix : '',\n count: list.options.length,\n }));\n\n // 文字里提到的人:随文字与见过的选项更新\n watch(\n () => [value, remote.items()] as const,\n ([text, current]) => {\n for (const item of current) {\n const option = optionOf(item);\n known.set(option.value, option);\n }\n const next = mentionedValues(text, [...known.values()], prefix);\n if (next.join('\\n') !== mentions.join('\\n')) mentions = next;\n },\n { immediate: true },\n );\n\n // 远程结果后到:打开着又没有高亮项时高亮第一项(Enter 才能直接选中)\n watch(\n () => list.options.length,\n () => {\n if (open && list.active === undefined) list.move('first');\n },\n );\n\n /** 看光标前面是不是正在写的提及:是就按 @ 后面的文字过滤并打开,不是就关闭 */\n function detect(event?: Event) {\n const element = textarea();\n if (!element || rest.readonly || rest.disabled) return;\n const caret = element.selectionStart;\n const before = element.value.slice(0, caret);\n const at = before.lastIndexOf(prefix);\n const typed = at < 0 ? '' : before.slice(at + prefix.length);\n const mentioning =\n at >= 0 &&\n element.selectionEnd === caret &&\n !WORD_BEFORE.test(before[at - 1] ?? '') &&\n !/\\s/.test(typed) &&\n typed.length <= 30;\n if (!mentioning || at === dismissed) {\n if (!mentioning) dismissed = null;\n trigger = null;\n if (open) setOpen(false, 'focus', event);\n return;\n }\n const opening = trigger !== at || !open;\n trigger = at;\n query = typed;\n if (opening) setOpen(true, 'trigger', event);\n list.move('first');\n }\n\n /** 选中一项:把“@过滤词”换成“@名字 ”,光标放在后面 */\n function pick(choice: string, event?: Event) {\n const element = textarea();\n const option = list.options.find((entry) => entry.value === choice);\n if (!element || trigger === null || !option) return;\n known.set(option.value, option);\n const inserted = `${prefix}${option.label} `;\n const caret = element.selectionStart;\n const start = trigger;\n value = element.value.slice(0, start) + inserted + element.value.slice(caret);\n trigger = null;\n setOpen(false, 'select', event);\n void nextTick(() => {\n element.focus();\n element.setSelectionRange(start + inserted.length, start + inserted.length);\n });\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (!open || isComposingKey(event)) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n dismissed = trigger;\n setOpen(false, 'escape', event);\n return;\n }\n if (event.key === 'Tab' && list.active !== undefined) {\n event.preventDefault();\n pick(list.active, event);\n return;\n }\n if (handleListKeydown(list, event, { homeEnd: false }, (choice) => pick(choice, event)))\n event.preventDefault();\n }\n\n // 移动光标(方向键、Home / End)后重新判断;↑↓ 在列表打开时是移动高亮,不算\n function onKeyup(event: KeyboardEvent) {\n if (event.isComposing) return;\n if (open && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) return;\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key) || !open) detect(event);\n }\n\n const { onToggle } = useAnchoredPopover(\n () => {\n const element = textarea();\n return {\n open,\n anchor: element && caretAnchor(element, () => trigger ?? element.selectionStart),\n panel,\n floating: { placement: 'bottom-start', fitHeight: true },\n restoreFocus: false,\n };\n },\n {\n close: (reason, event) => {\n if (reason === 'escape') dismissed = trigger;\n setOpen(false, reason, event);\n },\n },\n );\n\n return () => (\n <>\n <Textarea\n {...mergePartProps<TextareaProps>(\n { propsRoot: mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: _toRef(shell) }) },\n rest,\n {\n 'aria-autocomplete': 'list',\n 'aria-controls': open ? listId : undefined,\n 'aria-activedescendant': open ? activeOptionId(list, listId) : undefined,\n onInput: (event: Event) => !(event as InputEvent).isComposing && detect(event),\n onCompositionend: (event: CompositionEvent) => detect(event),\n onClick: (event: MouseEvent) => detect(event),\n onKeydown,\n onKeyup,\n onBlur: (event: FocusEvent) => open && setOpen(false, 'focus', event),\n },\n )}\n _value={value}\n />\n <ListPopover\n panelRef={_toRef(panel)}\n onToggle={onToggle}\n size={rest.size}\n label={lang.mentionsList}\n loading={loading || remote.loading()}\n onPick={(choice) => pick(choice)}\n listbox={{\n list,\n id: listId,\n renderOption: children,\n empty: remote.failure() ?? empty ?? lang.mentionsEmpty,\n }}\n propsListbox={propsListbox}\n propsPopover={mergePartProps<PartProps<'div', 'id' | 'popover'>>(\n { sx: mentionStyles.panel },\n propsPopover,\n )}\n />\n </>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgFA,IAAM,cAAc;;;;;AAMpB,SAAgB,gBACd,MACA,SACA,SAAS,KACS;CAClB,MAAM,WAAW,QACd,QAAQ,WAAW,OAAO,KAAK,CAAC,CAChC,UAAU,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,MAAM,MAAM;CACrD,MAAM,WAA6B,CAAA;CACnC,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,OAAO,QAAQ,KAAK,QAAQ;EAC1B,MAAM,UACJ,KAAK,WAAW,QAAQ,KAAK,KAAK,CAAC,YAAY,KAAK,KAAK,QAAQ,MAAM,EAAE,IACrE,SAAS,MAAM,WAAW,KAAK,WAAW,OAAO,OAAO,QAAQ,OAAO,MAAM,CAAC,IAC9E,KAAA;EACN,IAAI,CAAC,SAAS;GACZ,SAAS,KAAK;GACd,SAAS;GACT;EACF;EACA,IAAI,OAAO,SAAS,KAAK,EAAE,MAAM,MAAM,CAAC;EACxC,QAAQ;EACR,MAAM,SAAS,OAAO,SAAS,QAAQ,MAAM;EAC7C,SAAS,KAAK;GAAE,MAAM,KAAK,MAAM,OAAO,QAAQ,MAAM;GAAG;EAAQ,CAAC;EAClE,SAAS;CACX;CACA,IAAI,OAAO,SAAS,KAAK,EAAE,MAAM,MAAM,CAAC;CACxC,OAAO;AACT;;AAGA,SAAgB,gBACd,MACA,SACA,SAAS,KACC;CACV,MAAM,SAAS,gBAAgB,MAAM,SAAS,MAAM,CAAC,CAAC,SAAS,YAC7D,QAAQ,UAAU,CAAC,QAAQ,QAAQ,KAAK,IAAI,CAAA,CAC9C;CACA,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAC5B;;AAGA,IAAa,gBAAgB,IAAI,OAAO;CAEtC,SAAS;EACP,OAAO;EACP,iBAAiB;EACjB,cAAc;EACd,eAAe;EACf,YAAY;CACd;CACA,MAAM;EAAE,YAAY;EAAY,cAAc;CAAW;CAEzD,OAAO,EAAE,OAAO,OAAO;AACzB,CAAC;;;AAiBD,IAAa,cAAc,0BACzB,QAAA,SAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,MAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,UAA2B,GAAG;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAAkC,OAAIC,UAAA,QAAA,MAAA,IAAA;CAAA,aAClEC,YAAA,QACY,WAAmB,EAAE,IAAI,cAAc,KAAK,GAAG,IAAI,GAAC,CAC3D,gBAAe,KAAA,OAAA,QAAA,OAAA,OAAA,KAAsB,CAAC,CAAC,KAAK,YAAY;EACvD,IAAI,CAAC,QAAQ,SAAS,OAAO,QAAQ;EACrC,IAAA,cAAA,OAAmB,OAAO,cAAA,MAAc,QAAQ,SAAS,QAAQ,IAAI;EACrE,MAAM,MACJ,OAAA,aAAA,UAAwB,aAAa,aAAA,MAAa,QAAQ,OAAO,IAAC,aAAA;EACpE,OAAAA,YAAA,QACY,WAAmB,EAAE,IAAI,cAAc,QAAQ,GAAG,GAAG,GAAC,CAAG,QAAQ,IAAI,CAAA;CAEnF,CAAC,CAAC,CAAA;AAEL,GAAA;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACL;;AAGA,IAAa,WAAW,0BACtB,SAAA,UAiBwB;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,QAAAC,SAAA,SAAA,gBAhBI,IAAE,MAAA,IAAA;CAAA,MAAA,WAAAA,SAAA,SAAA,mBACc,CAAA,GAAE,MAAA,IAAA;CAAA,MAAA,QAAAH,aAAA,SAAA,eACpC,CAAA,CAAE;CAAA,MAAA,WAAAA,aAAA,SAAA,UAAA;CAAA,MAAA,OAAAA,aAAA,SAAA,MAAA;CAAA,MAAA,SAAAA,aAAA,SAAA,UAGD,GAAG;CAAA,MAAA,SAAAA,aAAA,SAAA,QAAA;CAAA,MAAA,OAAAG,SAAA,SAAA,eAEY,OAAK,MAAA,IAAA;CAAA,MAAA,eAAAH,aAAA,SAAA,cAAA;CAAA,MAAA,UAAAA,aAAA,SAAA,WAEnB,KAAK;CAAA,MAAA,WAAAI,aAAA,OAAA;CAAA,MAAA,QAAAJ,aAAA,SAAA,OAAA;CAAA,MAAA,YAAAA,aAAA,SAAA,WAAA;CAAA,MAAA,eAAAA,aAAA,SAAA,cAAA;CAAA,MAAA,eAAAA,aAAA,SAAA,cAAA;CAAA,MAMZ,OAAIC,UAAA,SAAA,OAAA,KAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,cAAc,eAAe;CACnC,MAAM,SAAS,MAAM;CACrB,IAAI,QAAKI,WAAkC,IAAI;CAC/C,IAAI,QAAKA,WAAkC,IAAI;CAE/C,IAAI,UAAOC,IAAyB,IAAI;CACxC,IAAI,QAAKA,IAAU,EAAE;CAErB,IAAI,YAA2B;CAE/B,MAAM,wBAAQ,IAAI,IAA2B;CAC7C,MAAM,UAAU,iBACd,KAAA,QACC,SAAU,KAAA,QAAO,YAClB,aAAA,KACF;CAEA,MAAM,YAAY,SAAY,gBAAgB,MAAI,SAAA,KAAU;CAC5D,MAAM,iBAAiB,MAAA,OAAO,cAAc,UAAU,KAAK;CAE3D,MAAM,SAAS,eAAe;EAC5B,YAAM,KAAA;EACN,aAAO,MAAA;EACP,YAAM,KAAA;EACN,aAAO,MAAA;CACT,CAAC;CACD,MAAM,OAAO,aAAa;EACxB,aACE,KAAA,SAAQ,OAAA,UAAW,QACf,OAAO,MAAM,IACb,OACG,MAAM,CAAC,CACP,QAAQ,SACP,CAAA,MAAA,QACI,OACA,OAAA,QACE,OAAA,MAAO,MAAI,MAAA,KAAO,IAClB,YAAY,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAK,MAAA,KAAO,CACjD;EACR,UAAU;EACV,gBAAgB,CAAA;EAChB,YAAY;EACZ,gBAAgB,CAAC;CACnB,CAAC;CACD,6BAA6B;EAC3B,OAAO,KAAA,QAAO,MAAA,SAAA,OAAA,QAAkB;EAChC,OAAO,KAAK,QAAQ;CACtB,EAAE;CAGF,YACQ,CAAA,MAAA,OAAQ,OAAO,MAAM,CAAC,IAC3B,CAAC,MAAM,aAAa;EACnB,KAAK,MAAM,QAAQ,SAAS;GAC1B,MAAM,SAAS,SAAS,IAAI;GAC5B,MAAM,IAAI,OAAO,OAAO,MAAM;EAChC;EACA,MAAM,OAAO,gBAAgB,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAC,OAAA,KAAQ;EAC9D,IAAI,KAAK,KAAK,IAAI,MAAM,SAAA,MAAS,KAAK,IAAI,GAAG,SAAA,QAAW;CAC1D,GACA,EAAE,WAAW,KAAK,CACpB;CAGA,YACQ,KAAK,QAAQ,cACb;EACJ,IAAI,KAAA,SAAQ,KAAK,WAAW,KAAA,GAAW,KAAK,KAAK,OAAO;CAC1D,CACF;;CAGA,SAAS,OAAO,OAAe;EAC7B,MAAM,UAAU,SAAS;EACzB,IAAI,CAAC,WAAW,KAAK,YAAY,KAAK,UAAU;EAChD,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,QAAQ,MAAM,MAAM,GAAG,KAAK;EAC3C,MAAM,KAAK,OAAO,YAAW,OAAA,KAAO;EACpC,MAAM,QAAQ,KAAK,IAAI,KAAK,OAAO,MAAM,KAAK,OAAA,MAAO,MAAM;EAC3D,MAAM,aACJ,MAAM,KACN,QAAQ,iBAAiB,SACzB,CAAC,YAAY,KAAK,OAAO,KAAK,MAAM,EAAE,KACtC,CAAC,KAAK,KAAK,KAAK,KAChB,MAAM,UAAU;EAClB,IAAI,CAAC,cAAc,OAAO,WAAW;GACnC,IAAI,CAAC,YAAY,YAAY;GAC7B,QAAA,QAAU;GACV,IAAA,KAAA,OAAU,QAAQ,OAAO,SAAS,KAAK;GACvC;EACF;EACA,MAAM,UAAU,QAAA,UAAY,MAAM,CAAA,KAAA;EAClC,QAAA,QAAU;EACV,MAAA,QAAQ;EACR,IAAI,SAAS,QAAQ,MAAM,WAAW,KAAK;EAC3C,KAAK,KAAK,OAAO;CACnB;;CAGA,SAAS,KAAK,QAAgB,OAAe;EAC3C,MAAM,UAAU,SAAS;EACzB,MAAM,SAAS,KAAK,QAAQ,MAAM,UAAU,MAAM,UAAU,MAAM;EAClE,IAAI,CAAC,WAAW,QAAA,UAAY,QAAQ,CAAC,QAAQ;EAC7C,MAAM,IAAI,OAAO,OAAO,MAAM;EAC9B,MAAM,WAAW,GAAA,OAAA,QAAY,OAAO,MAAK;EACzC,MAAM,QAAQ,QAAQ;EACtB,MAAM,QAAK,QAAA;EACX,MAAA,QAAQ,QAAQ,MAAM,MAAM,GAAG,KAAK,IAAI,WAAW,QAAQ,MAAM,MAAM,KAAK;EAC5E,QAAA,QAAU;EACV,QAAQ,OAAO,UAAU,KAAK;EAC9B,eAAoB;GAClB,QAAQ,MAAM;GACd,QAAQ,kBAAkB,QAAQ,SAAS,QAAQ,QAAQ,SAAS,MAAM;EAC5E,CAAC;CACH;CAEA,SAAS,UAAU,OAAsB;EACvC,IAAI,CAAA,KAAA,SAAS,eAAe,KAAK,GAAG;EACpC,IAAI,MAAM,QAAQ,UAAU;GAC1B,MAAM,eAAe;GACrB,YAAS,QAAA;GACT,QAAQ,OAAO,UAAU,KAAK;GAC9B;EACF;EACA,IAAI,MAAM,QAAQ,SAAS,KAAK,WAAW,KAAA,GAAW;GACpD,MAAM,eAAe;GACrB,KAAK,KAAK,QAAQ,KAAK;GACvB;EACF;EACA,IAAI,kBAAkB,MAAM,OAAO,EAAE,SAAS,MAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,CAAC,GACpF,MAAM,eAAe;CACzB;CAGA,SAAS,QAAQ,OAAsB;EACrC,IAAI,MAAM,aAAa;EACvB,IAAI,KAAA,UAAS,MAAM,QAAQ,aAAa,MAAM,QAAQ,cAAc;EACpE,IAAI;GAAC;GAAa;GAAc;GAAQ;EAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,CAAA,KAAA,OAAO,OAAO,KAAK;CAC3F;CAEA,MAAM,EAAE,aAAa,yBACb;EACJ,MAAM,UAAU,SAAS;EACzB,OAAO;GACL,MAAI,KAAA;GACJ,QAAQ,WAAW,YAAY,eAAe,QAAA,SAAW,QAAQ,cAAc;GAC/E,OAAK,MAAA;GACL,UAAU;IAAE,WAAW;IAAgB,WAAW;GAAK;GACvD,cAAc;EAChB;CACF,GACA,EACE,QAAQ,QAAQ,UAAU;EACxB,IAAI,WAAW,UAAU,YAAS,QAAA;EAClC,QAAQ,OAAO,QAAQ,KAAK;CAC9B,EACF,CACF;CAEA,aAAOJ,YAAAK,UAAA,MAAA,CAAAL,YAAA,UAAAM,cAGG,eACF,EAAE,WAAW,eAAiC,CAAC,GAAC,UAAA,OAAa,EAAE,KAAG,MAAgB,CAAC,EAAE,GACrF,MACA;EACE,qBAAqB;EACrB,iBAAiB,KAAA,QAAO,SAAS,KAAA;EACjC,yBAAyB,KAAA,QAAO,eAAe,MAAM,MAAM,IAAI,KAAA;EAC/D,UAAU,UAAiB,CAAE,MAAqB,eAAe,OAAO,KAAK;EAC7E,mBAAmB,UAA4B,OAAO,KAAK;EAC3D,UAAU,UAAsB,OAAO,KAAK;EAC5C;EACA;EACA,SAAS,UAAsB,KAAA,SAAQ,QAAQ,OAAO,SAAS,KAAK;CACtE,CACF,GAAC;EAAA,UAAA,MAAA;EAAA,mBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,QAAA;CAAA,CAAA,GAAA,IAAA,GAAAN,YAAA,aAAA;EAAA,YAAA;EAAA,YAKS;EAAQ,QACZ,KAAK;EAAI,SACR,KAAK;EAAY,WACf,QAAA,SAAW,OAAO,QAAQ;EAAC,UAAA,OAAA,OAAA,OAAA,MAC3B,WAAW,KAAK,MAAM;EAAC,WACvB;GACP;GACA,IAAI;GACJ,cAAY,SAAA;GACZ,OAAO,OAAO,QAAQ,KAAC,MAAA,SAAa,KAAK;EAC3C;EAAC,gBAAA,aAAA;EAAA,gBAEa,eACZ,EAAE,IAAI,cAAc,MAAM,GAAC,aAAA,KAE7B;CAAC,GAAA,IAAA,CAAA,CAAA;AAIT,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import type { VNodeChild } from 'vue';
3
3
  import type { NumericFormat } from '../config/lang/format';
4
4
  import { type NumericKind, type NumericValue } from '../utils/data/numeric';
@@ -6,7 +6,7 @@ import { useFieldControl } from "../form/Field.js";
6
6
  import { NumberField } from "./NumberField.js";
7
7
  import { createVNode } from "vue";
8
8
  import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
9
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
9
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
10
10
  //#region src/input/NumberRangeField.tsx
11
11
  /** 区间的值:[起, 止],空着的一端是 null */
12
12
  /** 角色由组件管理;原生的 placeholder、prefix 属性让给两个框的占位与前缀 */
@@ -1 +1 @@
1
- {"version":3,"file":"NumberRangeField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/input/NumberRangeField.tsx"],"sourcesContent":["/**\n * 数值区间(div role=\"group\"):两个 NumberField,最小到最大。预期收益量级、金额范围、数量区间的录入与筛选。\n *\n * <Field label=\"预期收益量级\">\n * <NumberRangeField _value={range} format={{ scale: 10_000 }} suffix=\"万元\" min={0} />\n * </Field>\n *\n * value 是 [起, 止],任一端可以为空(null,“10 万元以上”)。两端都填了、起比止大时自动对调,不用报错。\n * min、max、step、format、prefix、suffix、valueType 与外观(variant、size、radius)两端共用,同 NumberField。\n * 在 Field 里时:标签点了聚焦第一个框,组以标签为名称、关联说明与错误;两个框各自念“最小值”“最大值”。\n * 写了 name([起的名字, 止的名字])时两端各用一个隐藏的 input 随表单提交。\n *\n * 部件:Root(div)、Start、End(NumberField)、Separator(span)。\n */\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 { useLang } from '../config/context';\nimport type { NumericFormat } from '../config/lang/format';\nimport { useFieldControl } from '../form/Field';\nimport { compareNumeric, type NumericKind, type NumericValue } from '../utils/data/numeric';\nimport { defaultLabelledBy, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { fontSizeStyles } from '../utils/style/typography';\nimport type { ControlOptions } from './control';\nimport { NumberField, type NumberFieldProps } from './NumberField';\n\n/** 区间的值:[起, 止],空着的一端是 null */\nexport type NumberRange = readonly [NumericValue | null, NumericValue | null];\n\n/** 角色由组件管理;原生的 placeholder、prefix 属性让给两个框的占位与前缀 */\nexport type NumberRangeFieldManaged = 'role' | 'placeholder' | 'prefix';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface NumberRangeFieldProps\n extends PartProps<'div', NumberRangeFieldManaged>, ControlOptions {\n /** [起, 止]:父级写 _value={range};任一端可以为 null */\n _value?: NumberRange;\n /** 两端共同的最小值 */\n min?: NumericValue;\n /** 两端共同的最大值 */\n max?: NumericValue;\n /** 步长,同 NumberField */\n step?: NumericValue;\n /** 显示格式,同 NumberField(scale 时按缩放后的单位输入) */\n format?: NumericFormat;\n /** 一开始为空时写回的类型,同 NumberField */\n valueType?: NumericKind;\n /** 框里文字前的内容 */\n prefix?: VNodeChild;\n /** 框里文字后的单位 */\n suffix?: VNodeChild;\n /** 两个框的占位文字,默认取语言包(最小值、最大值) */\n placeholder?: readonly [string, string];\n /** 两端中间的内容,默认“–” */\n separator?: VNodeChild;\n /** 表单提交时两端的 name */\n name?: readonly [string, string];\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 起的那个框的部件属性 */\n propsStart?: Partial<NumberFieldProps>;\n /** 止的那个框的部件属性 */\n propsEnd?: Partial<NumberFieldProps>;\n /** 中间分隔的部件属性 */\n propsSeparator?: PartProps<'span', 'aria-hidden'>;\n}\n\n/** NumberRangeField 的样式:root、field、separator */\nexport const numberRangeFieldStyles = css.create({\n root: { display: 'flex', alignItems: 'center', gap: '_sm', minWidth: 0 },\n field: { flexGrow: 1, flexBasis: 0, minWidth: 0 },\n separator: { flexShrink: 0, color: '_textMuted' },\n});\n\n/** 数值区间:两个数字框,起比止大时自动对调 */\nexport const NumberRangeField = _component(\n ({\n _value: value = _bindable<NumberRange>([null, null]),\n min,\n max,\n step,\n format,\n valueType,\n prefix,\n suffix,\n placeholder,\n separator = '–',\n name,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsStart,\n propsEnd,\n propsSeparator,\n ...rest\n }: NumberRangeFieldProps) => {\n const lang = useLang();\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n\n /** 改一端:两端都有值且起比止大时对调 */\n function set(index: 0 | 1, next: NumericValue | null) {\n const pair: [NumericValue | null, NumericValue | null] = [value[0], value[1]];\n pair[index] = next;\n const [start, end] = pair;\n value = start != null && end != null && compareNumeric(start, end) > 0 ? [end, start] : pair;\n }\n\n return () => {\n const state = control();\n const shared = {\n min,\n max,\n step,\n format,\n valueType,\n prefix,\n suffix,\n variant,\n size,\n radius,\n disabled: state.disabled,\n readonly: state.readonly,\n invalid: state.invalid,\n stepper: false,\n propsRoot: { sx: numberRangeFieldStyles.field },\n };\n return (\n <div\n {...mergeAttrs<'div'>(\n // 分隔符跟两个框一样大\n { sx: [numberRangeFieldStyles.root, size && fontSizeStyles[size]] },\n rest,\n {\n role: 'group',\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n },\n )}\n data-disabled={state.disabled || undefined}\n data-invalid={state.invalid || undefined}\n >\n <NumberField\n {...mergePartProps<NumberFieldProps>(\n { ...shared, placeholder: placeholder?.[0] ?? lang.sliderMin },\n propsStart,\n {\n // 标签的 for 指向第一个框:点标签聚焦“起”\n id: state.id,\n required: state.required,\n name: name?.[0],\n 'aria-label': lang.sliderMin,\n },\n )}\n _value={value[0]}\n onUpdate:_value={(next: NumericValue | null) => set(0, next)}\n />\n <span\n {...mergeAttrs<'span'>({ sx: numberRangeFieldStyles.separator }, propsSeparator, {\n 'aria-hidden': true,\n })}\n >\n {separator}\n </span>\n <NumberField\n {...mergePartProps<NumberFieldProps>(\n { ...shared, placeholder: placeholder?.[1] ?? lang.sliderMax },\n propsEnd,\n {\n id: state.id ? `${state.id}-end` : undefined,\n name: name?.[1],\n 'aria-label': lang.sliderMax,\n },\n )}\n _value={value[1]}\n onUpdate:_value={(next: NumericValue | null) => set(1, next)}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"NumberRangeField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/input/NumberRangeField.tsx"],"sourcesContent":["/**\n * 数值区间(div role=\"group\"):两个 NumberField,最小到最大。预期收益量级、金额范围、数量区间的录入与筛选。\n *\n * <Field label=\"预期收益量级\">\n * <NumberRangeField _value={range} format={{ scale: 10_000 }} suffix=\"万元\" min={0} />\n * </Field>\n *\n * value 是 [起, 止],任一端可以为空(null,“10 万元以上”)。两端都填了、起比止大时自动对调,不用报错。\n * min、max、step、format、prefix、suffix、valueType 与外观(variant、size、radius)两端共用,同 NumberField。\n * 在 Field 里时:标签点了聚焦第一个框,组以标签为名称、关联说明与错误;两个框各自念“最小值”“最大值”。\n * 写了 name([起的名字, 止的名字])时两端各用一个隐藏的 input 随表单提交。\n *\n * 部件:Root(div)、Start、End(NumberField)、Separator(span)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { useLang } from '../config/context';\nimport type { NumericFormat } from '../config/lang/format';\nimport { useFieldControl } from '../form/Field';\nimport { compareNumeric, type NumericKind, type NumericValue } from '../utils/data/numeric';\nimport { defaultLabelledBy, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { fontSizeStyles } from '../utils/style/typography';\nimport type { ControlOptions } from './control';\nimport { NumberField, type NumberFieldProps } from './NumberField';\n\n/** 区间的值:[起, 止],空着的一端是 null */\nexport type NumberRange = readonly [NumericValue | null, NumericValue | null];\n\n/** 角色由组件管理;原生的 placeholder、prefix 属性让给两个框的占位与前缀 */\nexport type NumberRangeFieldManaged = 'role' | 'placeholder' | 'prefix';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface NumberRangeFieldProps\n extends PartProps<'div', NumberRangeFieldManaged>, ControlOptions {\n /** [起, 止]:父级写 _value={range};任一端可以为 null */\n _value?: NumberRange;\n /** 两端共同的最小值 */\n min?: NumericValue;\n /** 两端共同的最大值 */\n max?: NumericValue;\n /** 步长,同 NumberField */\n step?: NumericValue;\n /** 显示格式,同 NumberField(scale 时按缩放后的单位输入) */\n format?: NumericFormat;\n /** 一开始为空时写回的类型,同 NumberField */\n valueType?: NumericKind;\n /** 框里文字前的内容 */\n prefix?: VNodeChild;\n /** 框里文字后的单位 */\n suffix?: VNodeChild;\n /** 两个框的占位文字,默认取语言包(最小值、最大值) */\n placeholder?: readonly [string, string];\n /** 两端中间的内容,默认“–” */\n separator?: VNodeChild;\n /** 表单提交时两端的 name */\n name?: readonly [string, string];\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 起的那个框的部件属性 */\n propsStart?: Partial<NumberFieldProps>;\n /** 止的那个框的部件属性 */\n propsEnd?: Partial<NumberFieldProps>;\n /** 中间分隔的部件属性 */\n propsSeparator?: PartProps<'span', 'aria-hidden'>;\n}\n\n/** NumberRangeField 的样式:root、field、separator */\nexport const numberRangeFieldStyles = css.create({\n root: { display: 'flex', alignItems: 'center', gap: '_sm', minWidth: 0 },\n field: { flexGrow: 1, flexBasis: 0, minWidth: 0 },\n separator: { flexShrink: 0, color: '_textMuted' },\n});\n\n/** 数值区间:两个数字框,起比止大时自动对调 */\nexport const NumberRangeField = _component(\n ({\n _value: value = _bindable<NumberRange>([null, null]),\n min,\n max,\n step,\n format,\n valueType,\n prefix,\n suffix,\n placeholder,\n separator = '–',\n name,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsStart,\n propsEnd,\n propsSeparator,\n ...rest\n }: NumberRangeFieldProps) => {\n const lang = useLang();\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n\n /** 改一端:两端都有值且起比止大时对调 */\n function set(index: 0 | 1, next: NumericValue | null) {\n const pair: [NumericValue | null, NumericValue | null] = [value[0], value[1]];\n pair[index] = next;\n const [start, end] = pair;\n value = start != null && end != null && compareNumeric(start, end) > 0 ? [end, start] : pair;\n }\n\n return () => {\n const state = control();\n const shared = {\n min,\n max,\n step,\n format,\n valueType,\n prefix,\n suffix,\n variant,\n size,\n radius,\n disabled: state.disabled,\n readonly: state.readonly,\n invalid: state.invalid,\n stepper: false,\n propsRoot: { sx: numberRangeFieldStyles.field },\n };\n return (\n <div\n {...mergeAttrs<'div'>(\n // 分隔符跟两个框一样大\n { sx: [numberRangeFieldStyles.root, size && fontSizeStyles[size]] },\n rest,\n {\n role: 'group',\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n },\n )}\n data-disabled={state.disabled || undefined}\n data-invalid={state.invalid || undefined}\n >\n <NumberField\n {...mergePartProps<NumberFieldProps>(\n { ...shared, placeholder: placeholder?.[0] ?? lang.sliderMin },\n propsStart,\n {\n // 标签的 for 指向第一个框:点标签聚焦“起”\n id: state.id,\n required: state.required,\n name: name?.[0],\n 'aria-label': lang.sliderMin,\n },\n )}\n _value={value[0]}\n onUpdate:_value={(next: NumericValue | null) => set(0, next)}\n />\n <span\n {...mergeAttrs<'span'>({ sx: numberRangeFieldStyles.separator }, propsSeparator, {\n 'aria-hidden': true,\n })}\n >\n {separator}\n </span>\n <NumberField\n {...mergePartProps<NumberFieldProps>(\n { ...shared, placeholder: placeholder?.[1] ?? lang.sliderMax },\n propsEnd,\n {\n id: state.id ? `${state.id}-end` : undefined,\n name: name?.[1],\n 'aria-label': lang.sliderMax,\n },\n )}\n _value={value[1]}\n onUpdate:_value={(next: NumericValue | null) => set(1, next)}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import type { VNodeChild } from 'vue';
3
3
  import { type PartProps } from '../utils/props';
4
4
  import { type TextSize } from '../utils/style/typography';
@@ -4,7 +4,7 @@ import { fontSizeStyles } from "../utils/style/typography.js";
4
4
  import { useFieldControl } from "../form/Field.js";
5
5
  import { createVNode, ref } from "vue";
6
6
  import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
7
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
7
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
8
8
  //#region src/input/OtpField.tsx
9
9
  /** 能输入的字符 */
10
10
  /** 值、类型与状态由组件管理 */
@@ -1 +1 @@
1
- {"version":3,"file":"OtpField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/OtpField.tsx"],"sourcesContent":["/**\n * 验证码输入框:一格一个字符的短信验证码、动态口令、取件码。\n *\n * <Field label=\"短信验证码\"><OtpField _value={code} onComplete={verify} /></Field>\n * <OtpField length={8} type=\"alphanumeric\" groups={[4, 4]} aria-label=\"恢复码\" />\n *\n * 参考 input-otp(shadcn 的 InputOTP)的做法:只有一个真正的 input(透明、盖在格子上面),格子只是显示。\n * 所以短信验证码的自动填充(autocomplete=\"one-time-code\")、整段粘贴、退格、选中都是原生的,读屏看到的是一个输入框;\n * 输入时只留数字(或字母数字),填满时调用 onComplete。焦点在框里时当前格画焦点环,空格里有闪烁的光标。\n * 部件:Root(div:格子的容器)、Input(主元素)、Slot(div,每格一个)、Separator(groups 之间)。\n */\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 { useFieldControl } from '../form/Field';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { t } from '../config/theme/tokens';\n\n/** 能输入的字符 */\nexport interface OtpCharsets {\n /** 只有数字(默认),手机弹出数字键盘 */\n numeric: unknown;\n /** 字母与数字,字母转成大写 */\n alphanumeric: unknown;\n}\n\n/** 值、类型与状态由组件管理 */\nexport type OtpFieldManaged =\n 'value' | 'type' | 'maxlength' | 'inputmode' | 'pattern' | 'disabled' | 'readonly' | 'required';\n\n/** 未声明的属性落到 input(主元素)上;格子的容器用 propsRoot */\nexport interface OtpFieldProps extends PartProps<'input', OtpFieldManaged> {\n /** 输入的字符:父级写 _value={code} */\n _value?: string;\n /** 几位,默认 6 */\n length?: number;\n /** 能输入的字符,默认 numeric */\n type?: keyof OtpCharsets;\n /** 分组显示(如 [3, 3] 在中间加一道短横线);各组加起来要等于 length */\n groups?: readonly number[];\n /** 显示成圆点(动态口令、支付密码) */\n mask?: boolean;\n /** 填满时调用(输入、粘贴、自动填充都算) */\n onComplete?: (value: string) => void;\n /** 字号档位:格子随之缩放 */\n size?: TextSize;\n /** 不可用(不写时取 Field 的) */\n disabled?: boolean;\n /** 只读(不写时取 Field 的) */\n readonly?: boolean;\n /** 必填(不写时取 Field 的) */\n required?: boolean;\n /** 校验未通过(不写时取 Field 的) */\n invalid?: boolean;\n /** 格子的容器的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 每一格的部件属性 */\n propsSlot?: PartProps<'div'>;\n /** 分组之间的分隔的部件属性 */\n propsSeparator?: PartProps<'span'>;\n children?: VNodeChild;\n}\n\nconst blink = css.keyframes({ '50%': { opacity: 0 } });\n\n/** OtpField 的样式:root、input、slot、active、invalid、disabled、caret、separator */\nexport const otpFieldStyles = css.create({\n root: {\n position: 'relative',\n display: 'inline-flex',\n alignItems: 'center',\n gap: '_xs',\n },\n // 真正的输入框盖在格子上面:透明、光标与选中都不显示,点哪一格都是点它\n input: {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n outlineStyle: 'none',\n backgroundColor: 'transparent',\n appearance: 'none',\n color: 'transparent',\n caretColor: 'transparent',\n fontSize: '1em',\n letterSpacing: '-0.5em',\n cursor: 'text',\n '::selection': { backgroundColor: 'transparent' },\n },\n slot: {\n boxSizing: 'border-box',\n position: 'relative',\n display: 'grid',\n placeItems: 'center',\n width: '2.5em',\n height: `max(2.75em, ${t.sizes.minTarget})`,\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n backgroundColor: '_surface',\n color: '_text',\n fontSize: '1.15em',\n fontWeight: '_semibold',\n fontVariantNumeric: 'tabular-nums',\n transition: `border-color ${t.durations.sm} ${t.easings.standard}`,\n },\n // 当前格:同输入框聚焦时的强调描边与焦点环\n active: {\n borderColor: '_accent',\n outlineWidth: '_borderWidths.sm',\n outlineStyle: 'solid',\n outlineColor: '_accentBorder',\n outlineOffset: 0,\n },\n invalid: { borderColor: '_danger' },\n disabled: { opacity: '_disabled' },\n // 空的当前格里闪烁的光标;减少动态效果时常亮\n caret: {\n width: '1px',\n height: '1.1em',\n backgroundColor: '_text',\n animationName: { default: blink, '@media (prefers-reduced-motion: reduce)': 'none' },\n animationDuration: '1s',\n animationIterationCount: 'infinite',\n animationTimingFunction: 'steps(1)',\n },\n separator: { width: '0.6em', height: '2px', backgroundColor: '_borderStrong' },\n});\n\nconst SANITIZE = {\n numeric: (text: string) => text.replace(/\\D/g, ''),\n alphanumeric: (text: string) => text.replace(/[^0-9a-z]/gi, '').toUpperCase(),\n};\n\n/** 验证码输入框:一个原生 input + 显示用的格子 */\nexport const OtpField = _component(\n ({\n _value: value = _bindable(''),\n length = 6,\n type = 'numeric',\n groups,\n mask = false,\n onComplete,\n size,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsSlot,\n propsSeparator,\n ...rest\n }: OtpFieldProps) => {\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let focused = _state(false);\n\n function onInput(event: Event) {\n const input = event.target as HTMLInputElement;\n const next = SANITIZE[type](input.value).slice(0, length);\n // 过滤掉的字符不留在输入框里\n if (input.value !== next) input.value = next;\n if (next === value) return;\n value = next;\n if (next.length === length) onComplete?.(next);\n }\n\n /** 第 index 格后面是不是一组的结尾(要加分隔) */\n const groupEnds = () => {\n const ends = new Set<number>();\n let sum = 0;\n for (const size of groups ?? []) {\n sum += size;\n if (sum < length) ends.add(sum - 1);\n }\n return ends;\n };\n\n return () => {\n const state = control();\n // 值只有数字与字母(输入时已过滤),按字符拆开就是按格\n const chars = value.split('');\n const current = Math.min(chars.length, length - 1);\n const ends = groupEnds();\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [otpFieldStyles.root, size && fontSizeStyles[size]] },\n propsRoot,\n )}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {Array.from({ length }, (_, index) => {\n const char = chars[index];\n const active = focused && !state.readonly && index === current;\n return [\n <div\n key={`slot-${index}`}\n aria-hidden=\"true\"\n {...mergeAttrs<'div'>(\n {\n sx: [\n otpFieldStyles.slot,\n state.invalid && otpFieldStyles.invalid,\n active && otpFieldStyles.active,\n state.disabled && otpFieldStyles.disabled,\n ],\n },\n propsSlot,\n )}\n data-state={char ? 'filled' : 'empty'}\n >\n {char\n ? mask\n ? '•'\n : char\n : active && <span {...css.attrs(otpFieldStyles.caret)} />}\n </div>,\n ends.has(index) && (\n <span\n key={`separator-${index}`}\n aria-hidden=\"true\"\n {...mergeAttrs<'span'>({ sx: otpFieldStyles.separator }, propsSeparator)}\n />\n ),\n ];\n })}\n <input\n {...mergeAttrs<'input'>(\n { sx: otpFieldStyles.input, autocomplete: 'one-time-code', spellcheck: false },\n rest,\n {\n id: state.id,\n value,\n type: mask ? 'password' : 'text',\n inputmode: type === 'numeric' ? 'numeric' : 'text',\n pattern: type === 'numeric' ? `\\\\d{${length}}` : `[0-9A-Za-z]{${length}}`,\n maxlength: length,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-invalid': state.invalid || undefined,\n 'aria-describedby': state.describedBy,\n onInput,\n onFocus: () => (focused = true),\n onBlur: () => (focused = false),\n },\n )}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;AAgEA,IAAM,QAAQ,IAAI,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC;;AAGrD,IAAa,iBAAiB,IAAI,OAAO;CACvC,MAAM;EACJ,UAAU;EACV,SAAS;EACT,YAAY;EACZ,KAAK;CACP;CAEA,OAAO;EACL,UAAU;EACV,OAAO;EACP,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,YAAY;EACZ,OAAO;EACP,YAAY;EACZ,UAAU;EACV,eAAe;EACf,QAAQ;EACR,eAAe,EAAE,iBAAiB,cAAc;CAClD;CACA,MAAM;EACJ,WAAW;EACX,UAAU;EACV,SAAS;EACT,YAAY;EACZ,OAAO;EACP,QAAQ,eAAe,EAAE,MAAM,UAAS;EACxC,aAAa;EACb,aAAa;EACb,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,OAAO;EACP,UAAU;EACV,YAAY;EACZ,oBAAoB;EACpB,YAAY,gBAAgB,EAAE,UAAU,GAAE,GAAI,EAAE,QAAQ;CAC1D;CAEA,QAAQ;EACN,aAAa;EACb,cAAc;EACd,cAAc;EACd,cAAc;EACd,eAAe;CACjB;CACA,SAAS,EAAE,aAAa,UAAU;CAClC,UAAU,EAAE,SAAS,YAAY;CAEjC,OAAO;EACL,OAAO;EACP,QAAQ;EACR,iBAAiB;EACjB,eAAe;GAAE,SAAS;GAAO,2CAA2C;EAAO;EACnF,mBAAmB;EACnB,yBAAyB;EACzB,yBAAyB;CAC3B;CACA,WAAW;EAAE,OAAO;EAAS,QAAQ;EAAO,iBAAiB;CAAgB;AAC/E,CAAC;AAED,IAAM,WAAW;CACf,UAAU,SAAiB,KAAK,QAAQ,OAAO,EAAE;CACjD,eAAe,SAAiB,KAAK,QAAQ,eAAe,EAAE,CAAC,CAAC,YAAY;AAC9E;;AAGA,IAAa,WAAW,0BACtB,QAAA,SAiBqB;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAhBO,IAAE,KAAA,IAAA;CAAA,MAAA,SAAAC,aAAA,QAAA,UACnB,CAAC;CAAA,MAAA,OAAAA,aAAA,QAAA,QACH,SAAS;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,QAET,KAAK;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,MAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,KAAAA,aAAA,QAAA,IAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,iBAAAA,aAAA,QAAA,gBAAA;CAAA,MAWT,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,UAAU,uBAAuB;EAAE,IAAE,GAAA;EAAE,SAAO,QAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;CAAC,EAAE;CACrF,IAAI,UAAOC,IAAU,KAAK;CAE1B,SAAS,QAAQ,OAAc;EAC7B,MAAM,QAAQ,MAAM;EACpB,MAAM,OAAO,SAAQ,KAAA,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,GAAC,OAAA,KAAQ;EAExD,IAAI,MAAM,UAAU,MAAM,MAAM,QAAQ;EACxC,IAAI,SAAI,MAAA,OAAY;EACpB,MAAA,QAAQ;EACR,IAAI,KAAK,WAAM,OAAA,OAAa,WAAA,QAAa,IAAI;CAC/C;;CAGA,MAAM,kBAAkB;EACtB,MAAM,uBAAO,IAAI,IAAY;EAC7B,IAAI,MAAM;EACV,KAAK,MAAM,QAAQ,OAAA,SAAU,CAAA,GAAI;GAC/B,OAAO;GACP,IAAI,MAAG,OAAA,OAAW,KAAK,IAAI,MAAM,CAAC;EACpC;EACA,OAAO;CACT;CAEA,aAAa;EACX,MAAM,QAAQ,QAAQ;EAEtB,MAAM,QAAQ,MAAA,MAAM,MAAM,EAAE;EAC5B,MAAM,UAAU,KAAK,IAAI,MAAM,QAAQ,OAAA,QAAS,CAAC;EACjD,MAAM,OAAO,UAAU;EACvB,OAAAC,YAAA,OAAAC,cAEQ,WACF,EAAE,IAAI,CAAC,eAAe,MAAM,KAAA,SAAQ,eAAc,KAAA,MAAM,EAAE,GAAC,UAAA,KAE7D,GAAC;GAAA,gBACa,MAAM,WAAW,KAAA;GAAS,iBACzB,MAAM,YAAY,KAAA;EAAS,CAAA,GAAA,CAEzC,MAAM,KAAK,EAAE,QAAM,OAAA,MAAC,IAAI,GAAG,UAAU;GACpC,MAAM,OAAO,MAAM;GACnB,MAAM,SAAS,QAAA,SAAW,CAAC,MAAM,YAAY,UAAU;GACvD,OAAO,CAAAD,YAAA,OAAAC,cAAA;IAAA,OAEE,QAAQ;IAAO,eAAA;GAAA,GAEhB,WACF,EACE,IAAI;IACF,eAAe;IACf,MAAM,WAAW,eAAe;IAChC,UAAU,eAAe;IACzB,MAAM,YAAY,eAAe;GAAQ,EAE7C,GAAC,UAAA,KAEH,GAAC,EAAA,cACW,OAAO,WAAW,QAAO,CAAA,GAAA,CAEpC,OACG,KAAA,QACE,MACA,OACF,UAAMD,YAAA,QAAc,IAAI,MAAM,eAAe,KAAK,GAAC,IAAA,CAAI,CAAA,GAE7D,KAAK,IAAI,KAAK,KAACA,YAAA,QAAAC,cAAA;IAAA,OAEN,aAAa;IAAO,eAAA;GAAA,GAErB,WAAmB,EAAE,IAAI,eAAe,UAAU,GAAC,eAAA,KAAgB,CAAC,GAAA,IAAA,CAE3E;EAEL,CAAC,GAACD,YAAA,SAEI,WACF;GAAE,IAAI,eAAe;GAAO,cAAc;GAAiB,YAAY;EAAM,GAC7E,MACA;GACE,IAAI,MAAM;GACV,OAAK,MAAA;GACL,MAAM,KAAA,QAAO,aAAa;GAC1B,WAAW,KAAA,UAAS,YAAY,YAAY;GAC5C,SAAS,KAAA,UAAS,YAAY,OAAA,OAAA,MAAA,KAAmB,eAAA,OAAA,MAAA;GACjD,WAAS,OAAA;GACT,UAAU,MAAM;GAChB,UAAU,MAAM;GAChB,UAAU,MAAM;GAChB,gBAAgB,MAAM,WAAW,KAAA;GACjC,oBAAoB,MAAM;GAC1B;GACA,eAAgB,QAAA,QAAU;GAC1B,cAAe,QAAA,QAAU;EAC3B,CACF,GAAC,IAAA,CAAA,CAAA;CAIT;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
1
+ {"version":3,"file":"OtpField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/OtpField.tsx"],"sourcesContent":["/**\n * 验证码输入框:一格一个字符的短信验证码、动态口令、取件码。\n *\n * <Field label=\"短信验证码\"><OtpField _value={code} onComplete={verify} /></Field>\n * <OtpField length={8} type=\"alphanumeric\" groups={[4, 4]} aria-label=\"恢复码\" />\n *\n * 参考 input-otp(shadcn 的 InputOTP)的做法:只有一个真正的 input(透明、盖在格子上面),格子只是显示。\n * 所以短信验证码的自动填充(autocomplete=\"one-time-code\")、整段粘贴、退格、选中都是原生的,读屏看到的是一个输入框;\n * 输入时只留数字(或字母数字),填满时调用 onComplete。焦点在框里时当前格画焦点环,空格里有闪烁的光标。\n * 部件:Root(div:格子的容器)、Input(主元素)、Slot(div,每格一个)、Separator(groups 之间)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { useFieldControl } from '../form/Field';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { fontSizeStyles, type TextSize } from '../utils/style/typography';\nimport { t } from '../config/theme/tokens';\n\n/** 能输入的字符 */\nexport interface OtpCharsets {\n /** 只有数字(默认),手机弹出数字键盘 */\n numeric: unknown;\n /** 字母与数字,字母转成大写 */\n alphanumeric: unknown;\n}\n\n/** 值、类型与状态由组件管理 */\nexport type OtpFieldManaged =\n 'value' | 'type' | 'maxlength' | 'inputmode' | 'pattern' | 'disabled' | 'readonly' | 'required';\n\n/** 未声明的属性落到 input(主元素)上;格子的容器用 propsRoot */\nexport interface OtpFieldProps extends PartProps<'input', OtpFieldManaged> {\n /** 输入的字符:父级写 _value={code} */\n _value?: string;\n /** 几位,默认 6 */\n length?: number;\n /** 能输入的字符,默认 numeric */\n type?: keyof OtpCharsets;\n /** 分组显示(如 [3, 3] 在中间加一道短横线);各组加起来要等于 length */\n groups?: readonly number[];\n /** 显示成圆点(动态口令、支付密码) */\n mask?: boolean;\n /** 填满时调用(输入、粘贴、自动填充都算) */\n onComplete?: (value: string) => void;\n /** 字号档位:格子随之缩放 */\n size?: TextSize;\n /** 不可用(不写时取 Field 的) */\n disabled?: boolean;\n /** 只读(不写时取 Field 的) */\n readonly?: boolean;\n /** 必填(不写时取 Field 的) */\n required?: boolean;\n /** 校验未通过(不写时取 Field 的) */\n invalid?: boolean;\n /** 格子的容器的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 每一格的部件属性 */\n propsSlot?: PartProps<'div'>;\n /** 分组之间的分隔的部件属性 */\n propsSeparator?: PartProps<'span'>;\n children?: VNodeChild;\n}\n\nconst blink = css.keyframes({ '50%': { opacity: 0 } });\n\n/** OtpField 的样式:root、input、slot、active、invalid、disabled、caret、separator */\nexport const otpFieldStyles = css.create({\n root: {\n position: 'relative',\n display: 'inline-flex',\n alignItems: 'center',\n gap: '_xs',\n },\n // 真正的输入框盖在格子上面:透明、光标与选中都不显示,点哪一格都是点它\n input: {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n outlineStyle: 'none',\n backgroundColor: 'transparent',\n appearance: 'none',\n color: 'transparent',\n caretColor: 'transparent',\n fontSize: '1em',\n letterSpacing: '-0.5em',\n cursor: 'text',\n '::selection': { backgroundColor: 'transparent' },\n },\n slot: {\n boxSizing: 'border-box',\n position: 'relative',\n display: 'grid',\n placeItems: 'center',\n width: '2.5em',\n height: `max(2.75em, ${t.sizes.minTarget})`,\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n backgroundColor: '_surface',\n color: '_text',\n fontSize: '1.15em',\n fontWeight: '_semibold',\n fontVariantNumeric: 'tabular-nums',\n transition: `border-color ${t.durations.sm} ${t.easings.standard}`,\n },\n // 当前格:同输入框聚焦时的强调描边与焦点环\n active: {\n borderColor: '_accent',\n outlineWidth: '_borderWidths.sm',\n outlineStyle: 'solid',\n outlineColor: '_accentBorder',\n outlineOffset: 0,\n },\n invalid: { borderColor: '_danger' },\n disabled: { opacity: '_disabled' },\n // 空的当前格里闪烁的光标;减少动态效果时常亮\n caret: {\n width: '1px',\n height: '1.1em',\n backgroundColor: '_text',\n animationName: { default: blink, '@media (prefers-reduced-motion: reduce)': 'none' },\n animationDuration: '1s',\n animationIterationCount: 'infinite',\n animationTimingFunction: 'steps(1)',\n },\n separator: { width: '0.6em', height: '2px', backgroundColor: '_borderStrong' },\n});\n\nconst SANITIZE = {\n numeric: (text: string) => text.replace(/\\D/g, ''),\n alphanumeric: (text: string) => text.replace(/[^0-9a-z]/gi, '').toUpperCase(),\n};\n\n/** 验证码输入框:一个原生 input + 显示用的格子 */\nexport const OtpField = _component(\n ({\n _value: value = _bindable(''),\n length = 6,\n type = 'numeric',\n groups,\n mask = false,\n onComplete,\n size,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsSlot,\n propsSeparator,\n ...rest\n }: OtpFieldProps) => {\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let focused = _state(false);\n\n function onInput(event: Event) {\n const input = event.target as HTMLInputElement;\n const next = SANITIZE[type](input.value).slice(0, length);\n // 过滤掉的字符不留在输入框里\n if (input.value !== next) input.value = next;\n if (next === value) return;\n value = next;\n if (next.length === length) onComplete?.(next);\n }\n\n /** 第 index 格后面是不是一组的结尾(要加分隔) */\n const groupEnds = () => {\n const ends = new Set<number>();\n let sum = 0;\n for (const size of groups ?? []) {\n sum += size;\n if (sum < length) ends.add(sum - 1);\n }\n return ends;\n };\n\n return () => {\n const state = control();\n // 值只有数字与字母(输入时已过滤),按字符拆开就是按格\n const chars = value.split('');\n const current = Math.min(chars.length, length - 1);\n const ends = groupEnds();\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [otpFieldStyles.root, size && fontSizeStyles[size]] },\n propsRoot,\n )}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {Array.from({ length }, (_, index) => {\n const char = chars[index];\n const active = focused && !state.readonly && index === current;\n return [\n <div\n key={`slot-${index}`}\n aria-hidden=\"true\"\n {...mergeAttrs<'div'>(\n {\n sx: [\n otpFieldStyles.slot,\n state.invalid && otpFieldStyles.invalid,\n active && otpFieldStyles.active,\n state.disabled && otpFieldStyles.disabled,\n ],\n },\n propsSlot,\n )}\n data-state={char ? 'filled' : 'empty'}\n >\n {char\n ? mask\n ? '•'\n : char\n : active && <span {...css.attrs(otpFieldStyles.caret)} />}\n </div>,\n ends.has(index) && (\n <span\n key={`separator-${index}`}\n aria-hidden=\"true\"\n {...mergeAttrs<'span'>({ sx: otpFieldStyles.separator }, propsSeparator)}\n />\n ),\n ];\n })}\n <input\n {...mergeAttrs<'input'>(\n { sx: otpFieldStyles.input, autocomplete: 'one-time-code', spellcheck: false },\n rest,\n {\n id: state.id,\n value,\n type: mask ? 'password' : 'text',\n inputmode: type === 'numeric' ? 'numeric' : 'text',\n pattern: type === 'numeric' ? `\\\\d{${length}}` : `[0-9A-Za-z]{${length}}`,\n maxlength: length,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-invalid': state.invalid || undefined,\n 'aria-describedby': state.describedBy,\n onInput,\n onFocus: () => (focused = true),\n onBlur: () => (focused = false),\n },\n )}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -12,7 +12,7 @@ import { peopleKey } from "./people.js";
12
12
  import { PeoplePickerPanel } from "./PeoplePickerPanel.js";
13
13
  import { Fragment, createVNode, ref, shallowRef } from "vue";
14
14
  import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
15
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
15
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
16
16
  import { UsersRound } from "@lucide/icons";
17
17
  //#region src/input/PeoplePicker.tsx
18
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"PeoplePicker.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_ref","_vue_shallowRef","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/input/PeoplePicker.tsx"],"sourcesContent":["/**\n * 人员与组织选择器(表单字段):触发框里是已选的标签,点开对话框里的 PeoplePickerPanel 挑选,按“确定”才写回,“取消”放弃这次的改动。\n *\n * <Field label=\"抄送\"><PeoplePicker source={source} _value={cc} types={['user', 'department']} recentKey=\"cc\" /></Field>\n * <PeoplePicker source={source} _value={owner} max={1} placeholder=\"选择经办人\" /> 只选一个:值仍是数组,最多一项\n *\n * 触发框同 Select 的外壳:多选时已选的标签排在触发按钮前面(可移除),按钮里只留给读屏的文字;一个时直接显示名字。\n * 键盘:触发按钮上 Enter / 空格 / ↓ 打开,Backspace 移除最后一个;对话框里的键盘见 PeoplePickerPanel。\n * 部件:Root(外壳)、Tags、Trigger(button,主元素)、Value、Dialog、Panel。\n */\nimport { UsersRound } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { buttonBaseStyles } from '../base/button-core';\nimport { Icon } from '../base/Icon';\nimport { visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { Dialog, type DialogProps } from '../overlay/Dialog';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n clickOnShell,\n controlParts,\n focusOnShell,\n useControlAppearance,\n type ControlOptions,\n} from './control';\nimport { peopleKey, type PeopleEntry, type PeopleSource, type PeopleType } from './people';\nimport { PeoplePickerPanel, type PeoplePickerPanelProps } from './PeoplePickerPanel';\nimport { selectStyles, type SelectManaged } from './Select';\nimport { SelectedTags, type SelectedTagsProps } from './SelectedTags';\n\n/** 未声明的属性落到触发按钮(主元素)上,外壳用 propsRoot */\nexport interface PeoplePickerProps extends PartProps<'button', SelectManaged>, ControlOptions {\n /** 数据来源 */\n source: PeopleSource;\n /** 选中的:父级写 _value={list} 双向绑定 */\n _value?: readonly PeopleEntry[];\n /** 能选哪几种,默认只有人员 */\n types?: readonly PeopleType[];\n /** 最多选几个;1 时只选一个 */\n max?: number;\n /** 记“最近选过的”用的键(存在浏览器里) */\n recentKey?: string;\n /** 没有选时的占位,也是对话框的标题;默认“选择人员” */\n placeholder?: string;\n /** 多选时最多显示几个标签,其余收进“+N”;'responsive' 时排成一行按宽度放 */\n maxTagCount?: number | 'responsive';\n /** 不可用;也可由 Field 提供 */\n disabled?: boolean;\n /** 只读:不能打开、不能移除;也可由 Field 提供 */\n readonly?: boolean;\n /** 必填;也可由 Field 提供 */\n required?: boolean;\n /** 校验未通过;也可由 Field 提供 */\n invalid?: boolean;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 标签那一排的部件属性 */\n propsTags?: Partial<SelectedTagsProps>;\n /** 对话框的部件属性 */\n propsDialog?: Partial<DialogProps>;\n /** 面板的部件属性 */\n propsPanel?: Partial<PeoplePickerPanelProps>;\n}\n\n/** 人员与组织选择器 */\nexport const PeoplePicker = _component(\n ({\n source,\n _value: value = _bindable<readonly PeopleEntry[]>([]),\n types,\n max,\n recentKey,\n placeholder,\n maxTagCount,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsTags,\n propsDialog,\n propsPanel,\n ...rest\n }: PeoplePickerProps) => {\n const lang = useLang();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let open = _state(false);\n // 对话框里改的是草稿:确定才写回\n let draft = _state<readonly PeopleEntry[]>([]);\n let trigger = _state.raw<HTMLElement | null>(null);\n\n const locked = () => control().disabled || control().readonly;\n\n function show() {\n if (locked()) return;\n draft = [...value];\n open = true;\n }\n\n function remove(key: string) {\n value = value.filter((entry) => peopleKey(entry) !== key);\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (locked()) return;\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n show();\n } else if (event.key === 'Backspace' && value.length > 0) {\n event.preventDefault();\n value = value.slice(0, -1);\n }\n }\n\n return () => {\n const state = control();\n const s = controlParts(appearance(), state);\n const title = placeholder ?? lang.peoplePlaceholder;\n const tagged = max !== 1 && value.length > 0;\n const shown =\n value.length === 0 ? (\n <span {...css.attrs(selectStyles.placeholder)}>{title}</span>\n ) : tagged ? (\n <span {...css.attrs(visuallyHiddenStyles.hidden)}>\n {lang.selectSummary(value.map((entry) => entry.name))}\n </span>\n ) : (\n value[0]!.name\n );\n return (\n <>\n <div\n {...mergeAttrs<'div'>({ ...s.root, sx: [s.root.sx, selectStyles.root] }, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(() => trigger),\n onClick: locked() ? undefined : clickOnShell(() => trigger, show),\n })}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {tagged && (\n <SelectedTags\n {...mergePartProps<SelectedTagsProps>(\n {\n tags: value.map((entry) => ({ value: peopleKey(entry), label: entry.name })),\n maxTagCount,\n onRemove: locked() ? undefined : remove,\n },\n propsTags,\n )}\n />\n )}\n <button\n {...mergeAttrs<'button'>(\n {\n sx: [\n buttonBaseStyles.root,\n selectStyles.trigger,\n tagged && selectStyles.triggerBehindTags,\n ],\n },\n rest,\n {\n ref: (element: unknown) => (trigger = element as HTMLElement | null),\n id: state.id,\n type: 'button',\n disabled: state.disabled,\n 'aria-haspopup': 'dialog',\n 'aria-expanded': open,\n 'aria-invalid': state.invalid || undefined,\n 'aria-required': state.required || undefined,\n 'aria-readonly': state.readonly || undefined,\n 'aria-describedby': state.describedBy,\n onClick: () => {\n trigger?.focus();\n show();\n },\n onKeydown,\n },\n )}\n >\n <span {...css.attrs(selectStyles.value)}>{shown}</span>\n </button>\n <Icon {...s.icon} icon={UsersRound} />\n </div>\n <Dialog\n {...mergePartProps<DialogProps>(\n {\n size: 'lg',\n title,\n onConfirm: () => {\n value = draft;\n },\n },\n propsDialog,\n )}\n _open={open}\n >\n <PeoplePickerPanel\n {...mergePartProps<PeoplePickerPanelProps>(\n // 打开对话框时焦点在搜索框里,直接就能输入\n { source, types, max, recentKey, propsSearch: { autofocus: true } },\n propsPanel,\n )}\n _value={draft}\n />\n </Dialog>\n </>\n );\n };\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"PeoplePicker.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_ref","_vue_shallowRef","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/input/PeoplePicker.tsx"],"sourcesContent":["/**\n * 人员与组织选择器(表单字段):触发框里是已选的标签,点开对话框里的 PeoplePickerPanel 挑选,按“确定”才写回,“取消”放弃这次的改动。\n *\n * <Field label=\"抄送\"><PeoplePicker source={source} _value={cc} types={['user', 'department']} recentKey=\"cc\" /></Field>\n * <PeoplePicker source={source} _value={owner} max={1} placeholder=\"选择经办人\" /> 只选一个:值仍是数组,最多一项\n *\n * 触发框同 Select 的外壳:多选时已选的标签排在触发按钮前面(可移除),按钮里只留给读屏的文字;一个时直接显示名字。\n * 键盘:触发按钮上 Enter / 空格 / ↓ 打开,Backspace 移除最后一个;对话框里的键盘见 PeoplePickerPanel。\n * 部件:Root(外壳)、Tags、Trigger(button,主元素)、Value、Dialog、Panel。\n */\nimport { UsersRound } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { buttonBaseStyles } from '../base/button-core';\nimport { Icon } from '../base/Icon';\nimport { visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { Dialog, type DialogProps } from '../overlay/Dialog';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n clickOnShell,\n controlParts,\n focusOnShell,\n useControlAppearance,\n type ControlOptions,\n} from './control';\nimport { peopleKey, type PeopleEntry, type PeopleSource, type PeopleType } from './people';\nimport { PeoplePickerPanel, type PeoplePickerPanelProps } from './PeoplePickerPanel';\nimport { selectStyles, type SelectManaged } from './Select';\nimport { SelectedTags, type SelectedTagsProps } from './SelectedTags';\n\n/** 未声明的属性落到触发按钮(主元素)上,外壳用 propsRoot */\nexport interface PeoplePickerProps extends PartProps<'button', SelectManaged>, ControlOptions {\n /** 数据来源 */\n source: PeopleSource;\n /** 选中的:父级写 _value={list} 双向绑定 */\n _value?: readonly PeopleEntry[];\n /** 能选哪几种,默认只有人员 */\n types?: readonly PeopleType[];\n /** 最多选几个;1 时只选一个 */\n max?: number;\n /** 记“最近选过的”用的键(存在浏览器里) */\n recentKey?: string;\n /** 没有选时的占位,也是对话框的标题;默认“选择人员” */\n placeholder?: string;\n /** 多选时最多显示几个标签,其余收进“+N”;'responsive' 时排成一行按宽度放 */\n maxTagCount?: number | 'responsive';\n /** 不可用;也可由 Field 提供 */\n disabled?: boolean;\n /** 只读:不能打开、不能移除;也可由 Field 提供 */\n readonly?: boolean;\n /** 必填;也可由 Field 提供 */\n required?: boolean;\n /** 校验未通过;也可由 Field 提供 */\n invalid?: boolean;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 标签那一排的部件属性 */\n propsTags?: Partial<SelectedTagsProps>;\n /** 对话框的部件属性 */\n propsDialog?: Partial<DialogProps>;\n /** 面板的部件属性 */\n propsPanel?: Partial<PeoplePickerPanelProps>;\n}\n\n/** 人员与组织选择器 */\nexport const PeoplePicker = _component(\n ({\n source,\n _value: value = _bindable<readonly PeopleEntry[]>([]),\n types,\n max,\n recentKey,\n placeholder,\n maxTagCount,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsTags,\n propsDialog,\n propsPanel,\n ...rest\n }: PeoplePickerProps) => {\n const lang = useLang();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let open = _state(false);\n // 对话框里改的是草稿:确定才写回\n let draft = _state<readonly PeopleEntry[]>([]);\n let trigger = _state.raw<HTMLElement | null>(null);\n\n const locked = () => control().disabled || control().readonly;\n\n function show() {\n if (locked()) return;\n draft = [...value];\n open = true;\n }\n\n function remove(key: string) {\n value = value.filter((entry) => peopleKey(entry) !== key);\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (locked()) return;\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n show();\n } else if (event.key === 'Backspace' && value.length > 0) {\n event.preventDefault();\n value = value.slice(0, -1);\n }\n }\n\n return () => {\n const state = control();\n const s = controlParts(appearance(), state);\n const title = placeholder ?? lang.peoplePlaceholder;\n const tagged = max !== 1 && value.length > 0;\n const shown =\n value.length === 0 ? (\n <span {...css.attrs(selectStyles.placeholder)}>{title}</span>\n ) : tagged ? (\n <span {...css.attrs(visuallyHiddenStyles.hidden)}>\n {lang.selectSummary(value.map((entry) => entry.name))}\n </span>\n ) : (\n value[0]!.name\n );\n return (\n <>\n <div\n {...mergeAttrs<'div'>({ ...s.root, sx: [s.root.sx, selectStyles.root] }, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(() => trigger),\n onClick: locked() ? undefined : clickOnShell(() => trigger, show),\n })}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {tagged && (\n <SelectedTags\n {...mergePartProps<SelectedTagsProps>(\n {\n tags: value.map((entry) => ({ value: peopleKey(entry), label: entry.name })),\n maxTagCount,\n onRemove: locked() ? undefined : remove,\n },\n propsTags,\n )}\n />\n )}\n <button\n {...mergeAttrs<'button'>(\n {\n sx: [\n buttonBaseStyles.root,\n selectStyles.trigger,\n tagged && selectStyles.triggerBehindTags,\n ],\n },\n rest,\n {\n ref: (element: unknown) => (trigger = element as HTMLElement | null),\n id: state.id,\n type: 'button',\n disabled: state.disabled,\n 'aria-haspopup': 'dialog',\n 'aria-expanded': open,\n 'aria-invalid': state.invalid || undefined,\n 'aria-required': state.required || undefined,\n 'aria-readonly': state.readonly || undefined,\n 'aria-describedby': state.describedBy,\n onClick: () => {\n trigger?.focus();\n show();\n },\n onKeydown,\n },\n )}\n >\n <span {...css.attrs(selectStyles.value)}>{shown}</span>\n </button>\n <Icon {...s.icon} icon={UsersRound} />\n </div>\n <Dialog\n {...mergePartProps<DialogProps>(\n {\n size: 'lg',\n title,\n onConfirm: () => {\n value = draft;\n },\n },\n propsDialog,\n )}\n _open={open}\n >\n <PeoplePickerPanel\n {...mergePartProps<PeoplePickerPanelProps>(\n // 打开对话框时焦点在搜索框里,直接就能输入\n { source, types, max, recentKey, propsSearch: { autofocus: true } },\n propsPanel,\n )}\n _value={draft}\n />\n </Dialog>\n </>\n );\n };\n },\n);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';
1
+ import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
2
2
  import { type PartProps } from '../utils/props';
3
3
  import { type PeopleEntry, type PeopleSource, type PeopleType } from './people';
4
4
  import { type TextFieldProps } from './TextField';
@@ -16,7 +16,7 @@ import { usePersistentState } from "../utils/dom/storage.js";
16
16
  import { ToggleGroup, ToggleItem } from "./ToggleGroup.js";
17
17
  import { computed, createVNode, isVNode, nextTick, ref, shallowRef, watch } from "vue";
18
18
  import { _component, bindable, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
19
- import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
19
+ import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
20
20
  import { BriefcaseBusiness, Building, ChevronRight, Search, X } from "@lucide/icons";
21
21
  //#region src/input/PeoplePickerPanel.tsx
22
22
  /**