x-next 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/AI_CODING.md +6 -5
  2. package/AI_USAGE/catalog.md +106 -105
  3. package/AI_USAGE/components/alert-api.md +48 -0
  4. package/AI_USAGE/components/alert.md +222 -3
  5. package/AI_USAGE/components/bar-chart-api.md +177 -0
  6. package/AI_USAGE/components/bar-chart.md +297 -3
  7. package/AI_USAGE/components/boxicons.md +147 -0
  8. package/AI_USAGE/components/button-api.md +144 -0
  9. package/AI_USAGE/components/button.md +447 -3
  10. package/AI_USAGE/components/charts.md +81 -0
  11. package/AI_USAGE/components/checkbox-api.md +145 -0
  12. package/AI_USAGE/components/checkbox.md +365 -3
  13. package/AI_USAGE/components/color-picker-api.md +52 -0
  14. package/AI_USAGE/components/color-picker.md +211 -3
  15. package/AI_USAGE/components/config-provider-api.md +38 -0
  16. package/AI_USAGE/components/config-provider.md +250 -3
  17. package/AI_USAGE/components/date-picker-api.md +1114 -0
  18. package/AI_USAGE/components/date-picker.md +378 -3
  19. package/AI_USAGE/components/dialog-api.md +142 -0
  20. package/AI_USAGE/components/dialog.md +284 -3
  21. package/AI_USAGE/components/draggable-api.md +146 -0
  22. package/AI_USAGE/components/draggable.md +259 -0
  23. package/AI_USAGE/components/drawer-api.md +78 -0
  24. package/AI_USAGE/components/drawer.md +227 -0
  25. package/AI_USAGE/components/dropdown-api.md +529 -0
  26. package/AI_USAGE/components/dropdown.md +392 -3
  27. package/AI_USAGE/components/empty-api.md +36 -0
  28. package/AI_USAGE/components/empty.md +227 -3
  29. package/AI_USAGE/components/finicon.md +88 -0
  30. package/AI_USAGE/components/form-api.md +524 -0
  31. package/AI_USAGE/components/form.md +454 -0
  32. package/AI_USAGE/components/grid-api.md +527 -0
  33. package/AI_USAGE/components/grid.md +224 -0
  34. package/AI_USAGE/components/heatmap-api.md +122 -0
  35. package/AI_USAGE/components/heatmap.md +220 -0
  36. package/AI_USAGE/components/icon-api.md +4707 -0
  37. package/AI_USAGE/components/icon.md +257 -0
  38. package/AI_USAGE/components/image-api.md +440 -0
  39. package/AI_USAGE/components/image.md +465 -0
  40. package/AI_USAGE/components/input-api.md +184 -0
  41. package/AI_USAGE/components/input-number-api.md +66 -0
  42. package/AI_USAGE/components/input-number.md +294 -0
  43. package/AI_USAGE/components/input-tag-api.md +114 -0
  44. package/AI_USAGE/components/input-tag.md +482 -0
  45. package/AI_USAGE/components/input.md +293 -3
  46. package/AI_USAGE/components/layout-api.md +147 -0
  47. package/AI_USAGE/components/layout.md +230 -0
  48. package/AI_USAGE/components/line-chart-api.md +197 -0
  49. package/AI_USAGE/components/line-chart.md +279 -3
  50. package/AI_USAGE/components/link-api.md +42 -0
  51. package/AI_USAGE/components/link.md +197 -0
  52. package/AI_USAGE/components/menu-api.md +516 -0
  53. package/AI_USAGE/components/menu.md +268 -0
  54. package/AI_USAGE/components/message-api.md +215 -0
  55. package/AI_USAGE/components/message-box-api.md +108 -0
  56. package/AI_USAGE/components/message-box.md +268 -3
  57. package/AI_USAGE/components/message.md +231 -3
  58. package/AI_USAGE/components/network-api.md +91 -0
  59. package/AI_USAGE/components/network.md +378 -0
  60. package/AI_USAGE/components/notification-api.md +236 -0
  61. package/AI_USAGE/components/notification.md +275 -3
  62. package/AI_USAGE/components/pagination-api.md +62 -0
  63. package/AI_USAGE/components/pagination.md +386 -5
  64. package/AI_USAGE/components/pie-chart-api.md +109 -0
  65. package/AI_USAGE/components/pie-chart.md +245 -3
  66. package/AI_USAGE/components/popconfirm-api.md +75 -0
  67. package/AI_USAGE/components/popconfirm.md +231 -3
  68. package/AI_USAGE/components/popover-api.md +75 -0
  69. package/AI_USAGE/components/popover.md +208 -3
  70. package/AI_USAGE/components/popup-api.md +75 -0
  71. package/AI_USAGE/components/popup.md +52 -0
  72. package/AI_USAGE/components/progress-api.md +44 -0
  73. package/AI_USAGE/components/progress.md +248 -3
  74. package/AI_USAGE/components/radio-api.md +165 -0
  75. package/AI_USAGE/components/radio.md +259 -3
  76. package/AI_USAGE/components/rate-api.md +54 -0
  77. package/AI_USAGE/components/rate.md +233 -3
  78. package/AI_USAGE/components/resize-box-api.md +56 -0
  79. package/AI_USAGE/components/resize-box.md +231 -0
  80. package/AI_USAGE/components/scrollbar-api.md +77 -0
  81. package/AI_USAGE/components/scrollbar.md +218 -0
  82. package/AI_USAGE/components/select-api.md +758 -0
  83. package/AI_USAGE/components/select.md +640 -3
  84. package/AI_USAGE/components/skeleton-api.md +85 -0
  85. package/AI_USAGE/components/skeleton.md +150 -0
  86. package/AI_USAGE/components/slider-api.md +51 -0
  87. package/AI_USAGE/components/slider.md +233 -3
  88. package/AI_USAGE/components/space-api.md +38 -0
  89. package/AI_USAGE/components/space.md +145 -0
  90. package/AI_USAGE/components/spin-api.md +43 -0
  91. package/AI_USAGE/components/spin.md +205 -0
  92. package/AI_USAGE/components/steps-api.md +111 -0
  93. package/AI_USAGE/components/steps.md +201 -3
  94. package/AI_USAGE/components/switch-api.md +58 -0
  95. package/AI_USAGE/components/switch.md +290 -3
  96. package/AI_USAGE/components/table-api.md +2919 -0
  97. package/AI_USAGE/components/table.md +1414 -0
  98. package/AI_USAGE/components/tabs-api.md +135 -0
  99. package/AI_USAGE/components/tabs.md +308 -3
  100. package/AI_USAGE/components/tag-api.md +124 -0
  101. package/AI_USAGE/components/tag.md +292 -0
  102. package/AI_USAGE/components/textarea-api.md +55 -0
  103. package/AI_USAGE/components/textarea.md +326 -3
  104. package/AI_USAGE/components/time-picker-api.md +137 -0
  105. package/AI_USAGE/components/time-picker.md +271 -3
  106. package/AI_USAGE/components/time-range-selector-api.md +44 -0
  107. package/AI_USAGE/components/time-range-selector.md +355 -0
  108. package/AI_USAGE/components/timeline-api.md +93 -0
  109. package/AI_USAGE/components/timeline.md +312 -0
  110. package/AI_USAGE/components/tooltip-api.md +77 -0
  111. package/AI_USAGE/components/tooltip.md +182 -0
  112. package/AI_USAGE/components/trend-chart-api.md +119 -0
  113. package/AI_USAGE/components/trend-chart.md +335 -0
  114. package/AI_USAGE/components/trigger-api.md +124 -0
  115. package/AI_USAGE/components/trigger.md +185 -0
  116. package/AI_USAGE/components/upload-api.md +200 -0
  117. package/AI_USAGE/components/upload.md +711 -3
  118. package/AI_USAGE/components/watermark-api.md +87 -0
  119. package/AI_USAGE/components/watermark.md +200 -0
  120. package/AI_USAGE/core.md +1 -1
  121. package/AI_USAGE/index.md +35 -7
  122. package/AI_USAGE/recipes/form-on-demand.md +1 -1
  123. package/AI_USAGE.md +33657 -7
  124. package/CHANGELOG.md +40 -0
  125. package/dist/_utils/inherit-component-type.d.ts +11 -0
  126. package/dist/components/date-picker/index.d.ts +420 -5
  127. package/dist/components/form-input/index.d.ts +617 -2
  128. package/dist/components/layout/index.d.ts +689 -1
  129. package/dist/components/menu/index.d.ts +786 -1
  130. package/dist/components/network/Network.vue.d.ts +7 -3
  131. package/dist/components/network/index.d.ts +10 -2
  132. package/dist/components/network/props.d.ts +5 -0
  133. package/dist/components/network/utils.d.ts +3 -3
  134. package/dist/components/pagination/page-item-ellipsis.vue.d.ts +4 -1
  135. package/dist/components/pagination/page-item-step.vue.d.ts +101 -130
  136. package/dist/components/pagination/page-item.vue.d.ts +1 -0
  137. package/dist/components/pagination/page-jumper.vue.d.ts +1 -1
  138. package/dist/components/pagination/page-options.vue.d.ts +6 -4
  139. package/dist/components/pagination/utils.d.ts +3 -0
  140. package/dist/components/time-range-selector/index.d.ts +6 -6
  141. package/dist/es/_container/resize-observer-v2.js +1 -1
  142. package/dist/es/_container/resize-observer.js +1 -1
  143. package/dist/es/_hooks/use-resize-observer.js +1 -1
  144. package/dist/es/_styles/palette-aliases.js +4 -4
  145. package/dist/es/_utils/inherit-component-type.js +6 -0
  146. package/dist/es/_virtual/advancedFormat.js +1 -1
  147. package/dist/es/_virtual/customParseFormat.js +1 -1
  148. package/dist/es/_virtual/dayjs.min.js +1 -1
  149. package/dist/es/_virtual/isBetween.js +1 -1
  150. package/dist/es/_virtual/quarterOfYear.js +1 -1
  151. package/dist/es/_virtual/weekOfYear.js +1 -1
  152. package/dist/es/_virtual/weekYear.js +1 -1
  153. package/dist/es/_virtual/zh-cn.js +1 -1
  154. package/dist/es/components/button/Button.js +53 -42
  155. package/dist/es/components/date-picker/index.js +18 -17
  156. package/dist/es/components/draggable/useDraggable.js +1 -1
  157. package/dist/es/components/form/Form.vue2.js +1 -1
  158. package/dist/es/components/form/FormItem.vue2.js +1 -1
  159. package/dist/es/components/form-input/index.js +12 -11
  160. package/dist/es/components/form-input-number/InputNumber.js +1 -1
  161. package/dist/es/components/form-slider/Slider.vue2.js +1 -1
  162. package/dist/es/components/form-slider/slider-ticks.vue2.js +1 -1
  163. package/dist/es/components/form-slider/utils.js +1 -1
  164. package/dist/es/components/layout/index.js +10 -9
  165. package/dist/es/components/menu/MenuItem.js +1 -1
  166. package/dist/es/components/menu/hooks/use-level.js +5 -5
  167. package/dist/es/components/menu/index.js +13 -10
  168. package/dist/es/components/menu/overflow-wrap.js +1 -1
  169. package/dist/es/components/network/Network.vue.js +17 -12
  170. package/dist/es/components/network/Network.vue2.js +78 -70
  171. package/dist/es/components/network/utils.js +112 -71
  172. package/dist/es/components/pagination/Pagination.js +132 -123
  173. package/dist/es/components/pagination/page-item-ellipsis.vue.js +10 -10
  174. package/dist/es/components/pagination/page-item-ellipsis.vue2.js +24 -19
  175. package/dist/es/components/pagination/page-item-step.vue.js +14 -11
  176. package/dist/es/components/pagination/page-item-step.vue2.js +20 -22
  177. package/dist/es/components/pagination/page-item.vue.js +10 -9
  178. package/dist/es/components/pagination/page-item.vue2.js +24 -19
  179. package/dist/es/components/pagination/page-jumper.vue2.js +23 -23
  180. package/dist/es/components/pagination/page-options.vue.js +15 -10
  181. package/dist/es/components/pagination/page-options.vue2.js +21 -17
  182. package/dist/es/components/pagination/utils.js +4 -2
  183. package/dist/es/components/progress/circle.vue2.js +1 -1
  184. package/dist/es/components/progress/line.vue2.js +1 -1
  185. package/dist/es/components/progress/steps.vue2.js +1 -1
  186. package/dist/es/components/rate/Rate.js +1 -1
  187. package/dist/es/components/virtual-list-v2/virtual-list-item.js +1 -1
  188. package/dist/es/locale/en-US.js +2 -0
  189. package/dist/es/locale/zh-CN.js +2 -0
  190. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/dayjs.min.js +1 -1
  191. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/locale/zh-cn.js +1 -1
  192. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/advancedFormat.js +1 -1
  193. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/customParseFormat.js +1 -1
  194. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/isBetween.js +1 -1
  195. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/quarterOfYear.js +1 -1
  196. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/weekOfYear.js +1 -1
  197. package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/dayjs@1.11.21/node_modules/dayjs/plugin/weekYear.js +1 -1
  198. package/dist/es/style.css +1 -1
  199. package/dist/index.cjs +3 -3
  200. package/dist/index.umd.js +3 -3
  201. package/dist/locale/interface.d.ts +3 -0
  202. package/dist/style/base.css +1 -1
  203. package/dist/style/button.css +1 -1
  204. package/dist/style/form-select.css +1 -1
  205. package/dist/style/network.css +1 -1
  206. package/dist/style/pagination.css +1 -1
  207. package/dist/style/table.css +1 -1
  208. package/dist/style.css +1 -1
  209. package/package.json +10 -5
  210. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/index.js +0 -0
  211. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/is.js +0 -0
  212. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/locale/en-US.js +0 -0
  213. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/array.js +0 -0
  214. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/base.js +0 -0
  215. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/boolean.js +0 -0
  216. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/custom.js +0 -0
  217. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/number.js +0 -0
  218. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/object.js +0 -0
  219. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/string.js +0 -0
  220. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/rules/type.js +0 -0
  221. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/b-validate@1.5.3/node_modules/b-validate/es/util.js +0 -0
  222. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/compute-scroll-into-view@3.1.1/node_modules/compute-scroll-into-view/dist/index.js +0 -0
  223. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/number-precision@1.6.0/node_modules/number-precision/build/index.es.js +0 -0
  224. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/resize-observer-polyfill@1.5.1/node_modules/resize-observer-polyfill/dist/ResizeObserver.es.js +0 -0
  225. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/scroll-into-view-if-needed@3.1.0/node_modules/scroll-into-view-if-needed/dist/index.js +0 -0
  226. /package/dist/es/{Users/xuyu/Code/x-next/node_modules → node_modules}/.pnpm/sortablejs@1.15.7/node_modules/sortablejs/modular/sortable.esm.js +0 -0
@@ -1,12 +1,14 @@
1
1
  <!-- Generated by pnpm generate:ai-usage. Edit script/ai-usage/content.md and script/ai-usage/. -->
2
2
  # Select AI 使用
3
3
 
4
- 适用版本:x-next@1.12.0;来源指纹:`9f9adf42b42dc1e551f500aabdcb7fb07b69a93ea44ff3dc1d16dab1a4c85843`。
4
+ 适用版本:x-next@1.14.0;来源指纹:`014984639d816a2c7e25eb22690c586b0b2e8efba6846bec8a4e424db41a09e9`。
5
5
 
6
- 先读 [通用接入](../core.md)。公开导出:`Select`;模型:v-model、v-model:popup-visible;已核对事件:change、popupVisibleChange。
6
+ 先读 [通用接入](../core.md)。公开导出:`Select, SelectDropdown, SelectOption, SelectOptionGroup`;主要模型:v-model、v-model:popup-visible。完整 Props、Events、Slots、实例方法与服务签名见 [本地 API](./select-api.md),包含本组件族全部子组件和别名。
7
7
 
8
8
  按需样式:`x-next/style/form-select`(包含 base.css、empty.css、form-checkbox.css、form-select.css、scrollbar-v2.css、spin.css、trigger.css)。代码块未单独引样式时在应用入口加载全量样式,或按实际所有组件加载 JS 入口;不要仅因复制一个组件页就漏掉其中的 Button 等组合依赖。
9
9
 
10
+ ## 已核验行为与示例
11
+
10
12
  [组件文档与 live demo](https://x-next.yjmf.com/components/select)。`v-model` 返回选项的 `value`;单选通常为标量,多选为数组,也支持对象值。`multiple=false`、`allowClear=false`;单选搜索默认关闭,多选默认开启。`options` 是选项对象数组,常用字段是 `label`、`value`、`disabled`。静态数组可直接传入;动态选项用 `ref` / `reactive` 等响应式状态更新,支持替换数组,不要求原地修改;公开类型不接受 readonly 数组时先复制成普通数组。
11
13
 
12
14
  `change(value)` 返回新值,`clear(event)` 返回 `Event`;单选清空通常为 `''`,多选为 `[]`,已选禁用项可能保留。`v-model:popup-visible` 控制弹层,`option` / `empty` / `header` / `footer` 等插槽见组件文档。
@@ -35,4 +37,639 @@ function changed(value: unknown) {
35
37
  </template>
36
38
  ```
37
39
 
38
- 返回 [AI 索引](../index.md)。精选示例不是完整 API 表,新能力先查同版本公开类型与组件文档。
40
+ ## 场景用法
41
+
42
+ 以下示例从本地 `src/docs/components/select.md` 显式导入到独立 AI 源,补齐局部注册、状态和样式后进行严格模板检查。上方已核验行为优先;原始 prop 默认值、包装透传和示例业务适配分别查 [完整 API](./select-api.md) 与场景说明。类型通过不代表所有散文和交互已验证。
43
+
44
+ ### 用途与选型
45
+
46
+ 用于从选项集合中选择单个或多个值,适合枚举、状态、人员、城市、分类等字段。
47
+
48
+
49
+ ### 何时使用
50
+
51
+ 候选项有限且需要保证值来自集合时使用 Select;多选适合成员、标签等集合字段。远程候选项用 `allowSearch`、`filterOption=false` 和 `search` 事件组合;自由文本用 Input,层级选择用 Cascader / TreeSelect。
52
+
53
+
54
+ ### 基础用法
55
+
56
+ 右侧共用一个操作位置:未选择时是展开 / 收起图标;选中且 `allowClear` 时是 ×,无需悬浮。点击文字仍能展开,点击 × 只清空并保留当前面板状态;禁用项不可清空,加载时优先显示加载图标。
57
+
58
+ ```vue
59
+ <script setup lang="ts">
60
+ import 'x-next/style.css';
61
+ import { Select, SelectOption } from 'x-next';
62
+ import { ref } from 'vue';
63
+
64
+ const value = ref('pending');
65
+ const clearCount = ref(0);
66
+ </script>
67
+ <template>
68
+ <Select v-model="value" placeholder="请选择" allow-clear @clear="clearCount++">
69
+ <SelectOption value="pending">待处理</SelectOption>
70
+ <SelectOption value="processing">处理中</SelectOption>
71
+ <SelectOption value="done">已完成</SelectOption>
72
+ <SelectOption value="disabled" disabled>禁用项</SelectOption>
73
+ </Select>
74
+ <p>当前值:{{ value || '未选择' }},清除次数:{{ clearCount }}</p>
75
+ </template>
76
+ ```
77
+
78
+ ### 多选
79
+
80
+ 点击已选项可取消选择;标签关闭按钮或空输入时的 Backspace 删除可关闭项。清空保留禁用项。`maxTagCount` 只折叠展示,不限制选择数量;数量限制使用 `limit`。
81
+
82
+ ```vue
83
+ <script setup lang="ts">
84
+ import 'x-next/style.css';
85
+ import { Select, SelectOption } from 'x-next';
86
+ import { ref } from 'vue';
87
+
88
+ const values = ref(['design', 'frontend']);
89
+ </script>
90
+ <template>
91
+ <Select
92
+ v-model="values"
93
+ multiple
94
+ allow-clear
95
+ :max-tag-count="2"
96
+ placeholder="请选择成员"
97
+ >
98
+ <SelectOption value="design" :tag-props="{ color: 'blue' }">设计</SelectOption>
99
+ <SelectOption value="frontend" :tag-props="{ color: 'green' }">前端</SelectOption>
100
+ <SelectOption value="backend">后端</SelectOption>
101
+ <SelectOption value="qa">测试</SelectOption>
102
+ </Select>
103
+ </template>
104
+ ```
105
+
106
+ ### 搜索和自定义过滤
107
+
108
+ ```vue
109
+ <script setup lang="ts">
110
+ import 'x-next/style.css';
111
+ import { Select } from 'x-next';
112
+ import { ref } from 'vue';
113
+
114
+ const city = ref('');
115
+ const cities = [
116
+ { label: '北京 Beijing', value: 'beijing' },
117
+ { label: '上海 Shanghai', value: 'shanghai' },
118
+ { label: '广州 Guangzhou', value: 'guangzhou' },
119
+ { label: '深圳 Shenzhen', value: 'shenzhen' },
120
+ ];
121
+
122
+ const filterCity = (input: string, option: { label?: string }) =>
123
+ option.label?.toLowerCase().includes(input.toLowerCase()) ?? false;
124
+ </script>
125
+ <template>
126
+ <Select
127
+ v-model="city"
128
+ allow-search
129
+ :options="cities"
130
+ :filter-option="filterCity"
131
+ placeholder="搜索城市"
132
+ />
133
+ </template>
134
+ ```
135
+
136
+ ### 允许创建
137
+
138
+ ```vue
139
+ <script setup lang="ts">
140
+ import 'x-next/style.css';
141
+ import { Select, SelectOption } from 'x-next';
142
+ import { ref } from 'vue';
143
+
144
+ const tags = ref(['vue']);
145
+ </script>
146
+ <template>
147
+ <Select v-model="tags" multiple allow-create placeholder="输入后选择新标签">
148
+ <SelectOption value="vue">Vue</SelectOption>
149
+ <SelectOption value="typescript">TypeScript</SelectOption>
150
+ <SelectOption value="vite">Vite</SelectOption>
151
+ </Select>
152
+ </template>
153
+ ```
154
+
155
+ ### 选择数量限制
156
+
157
+ ```vue
158
+ <script setup lang="ts">
159
+ import 'x-next/style.css';
160
+ import { Select } from 'x-next';
161
+ import { ref } from 'vue';
162
+
163
+ const members = ref(['pm']);
164
+ const message = ref('');
165
+ const memberOptions = [
166
+ { label: '产品', value: 'pm' },
167
+ { label: '设计', value: 'design' },
168
+ { label: '前端', value: 'frontend' },
169
+ { label: '后端', value: 'backend' },
170
+ ];
171
+ </script>
172
+ <template>
173
+ <Select
174
+ v-model="members"
175
+ multiple
176
+ :limit="2"
177
+ :options="memberOptions"
178
+ placeholder="最多选择 2 项"
179
+ @exceed-limit="message = '最多只能选择 2 项'"
180
+ />
181
+ <p>{{ message }}</p>
182
+ </template>
183
+ ```
184
+
185
+ ### 通过 options 渲染
186
+
187
+ ```vue
188
+ <script setup lang="ts">
189
+ import 'x-next/style.css';
190
+ import { Select } from 'x-next';
191
+ import { ref } from 'vue';
192
+
193
+ const value = ref('beijing');
194
+ const options = [
195
+ { label: '北京', value: 'beijing' },
196
+ { label: '上海', value: 'shanghai' },
197
+ { label: '禁用项', value: 'disabled', disabled: true },
198
+ ];
199
+ </script>
200
+ <template>
201
+ <Select v-model="value" :options="options" placeholder="请选择城市" />
202
+ </template>
203
+ ```
204
+
205
+ ### 自定义字段名
206
+
207
+ ```vue
208
+ <script setup lang="ts">
209
+ import 'x-next/style.css';
210
+ import { Select } from 'x-next';
211
+ import { ref } from 'vue';
212
+
213
+ const city = ref('bj');
214
+ const options = [
215
+ { id: 'bj', name: '北京' },
216
+ { id: 'sh', name: '上海' },
217
+ { id: 'gz', name: '广州', locked: true },
218
+ ];
219
+ </script>
220
+ <template>
221
+ <Select
222
+ v-model="city"
223
+ :options="options"
224
+ :field-names="{ value: 'id', label: 'name', disabled: 'locked' }"
225
+ placeholder="请选择城市"
226
+ />
227
+ </template>
228
+ ```
229
+
230
+ ### 选项分组
231
+
232
+ ```vue
233
+ <script setup lang="ts">
234
+ import 'x-next/style.css';
235
+ import { Select, SelectOptionGroup, SelectOption } from 'x-next';
236
+ import { ref } from 'vue';
237
+
238
+ const city = ref('');
239
+ </script>
240
+ <template>
241
+ <Select v-model="city" placeholder="请选择城市">
242
+ <SelectOptionGroup label="华北">
243
+ <template #label><strong>华北 · 2 个城市</strong></template>
244
+ <SelectOption value="beijing">北京</SelectOption>
245
+ <SelectOption value="tianjin">天津</SelectOption>
246
+ </SelectOptionGroup>
247
+ <SelectOptionGroup label="华东">
248
+ <SelectOption value="shanghai">上海</SelectOption>
249
+ <SelectOption value="hangzhou">杭州</SelectOption>
250
+ </SelectOptionGroup>
251
+ </Select>
252
+ </template>
253
+ ```
254
+
255
+ ### 状态和尺寸
256
+
257
+ ```vue
258
+ <script setup lang="ts">
259
+ import 'x-next/style.css';
260
+ import { Space, Select } from 'x-next';
261
+ import { ref } from 'vue';
262
+
263
+ const value = ref('');
264
+ const options = [
265
+ { label: '选项 A', value: 'a' },
266
+ { label: '选项 B', value: 'b' },
267
+ ];
268
+ </script>
269
+ <template>
270
+ <Space direction="vertical">
271
+ <Select v-model="value" size="small" :options="options" placeholder="小尺寸" />
272
+ <Select v-model="value" :options="options" disabled placeholder="禁用状态" />
273
+ <Select v-model="value" :options="options" error placeholder="错误状态" />
274
+ <Select v-model="value" :options="options" loading placeholder="加载中" />
275
+ <Select v-model="value" :options="options" :bordered="false" placeholder="无边框" />
276
+ </Space>
277
+ </template>
278
+ ```
279
+
280
+ ### 自定义内容和插槽
281
+
282
+ ```vue
283
+ <script setup lang="ts">
284
+ import 'x-next/style.css';
285
+ import { Select, SelectOption } from 'x-next';
286
+ import { ref } from 'vue';
287
+ import { Icon } from 'x-next';
288
+
289
+ const value = ref('pending');
290
+ </script>
291
+ <template>
292
+ <Select v-model="value" placeholder="请选择">
293
+ <template #prefix>状态</template>
294
+ <template #header>
295
+ <div style="padding: 8px 12px">常用状态</div>
296
+ </template>
297
+ <template #footer>
298
+ <div style="padding: 8px 12px">没有合适选项时可联系管理员</div>
299
+ </template>
300
+ <template #label="{ data }">
301
+ {{ data.label }} / {{ data.value }}
302
+ </template>
303
+ <SelectOption value="pending" label="待处理">
304
+ 待处理
305
+ <template #icon><Icon name="clock" /></template>
306
+ <template #suffix>3</template>
307
+ </SelectOption>
308
+ <SelectOption value="done" label="已完成">
309
+ 已完成
310
+ <template #suffix>8</template>
311
+ </SelectOption>
312
+ </Select>
313
+ </template>
314
+ ```
315
+
316
+ ### 虚拟列表和滚动事件
317
+
318
+ 虚拟与非虚拟列表共用 `scrollbar` 配置,并触发相同的滚动事件;传 `scrollbar=false` 可使用原生滚动条。
319
+
320
+ ```vue
321
+ <script setup lang="ts">
322
+ import 'x-next/style.css';
323
+ import { Select } from 'x-next';
324
+ import { ref } from 'vue';
325
+
326
+ const value = ref('');
327
+ const reached = ref(false);
328
+ const options = Array.from({ length: 100 }, (_, index) => ({
329
+ label: `选项 ${index + 1}`,
330
+ value: index + 1,
331
+ }));
332
+ </script>
333
+ <template>
334
+ <Select
335
+ v-model="value"
336
+ :options="options"
337
+ :virtual-list-props="{ height: 200 }"
338
+ placeholder="大量数据"
339
+ @dropdown-reach-bottom="reached = true"
340
+ />
341
+ <p>{{ reached ? '已滚动到底部' : '继续滚动查看更多' }}</p>
342
+ </template>
343
+ ```
344
+
345
+ ### 局部容器滚动
346
+
347
+ 打开下拉后滚动下面的容器:默认跟随触发器。开启「滚动关闭」后,从打开时的位置滚动 24px 即收起;不需要同时设置 `updateAtScroll`。若需要固定在原位置,可传 `triggerProps: { updateAtScroll: false }`。
348
+
349
+ ```vue
350
+ <script setup lang="ts">
351
+ import 'x-next/style.css';
352
+ import { ref } from 'vue';
353
+ import { Select, Switch } from 'x-next';
354
+
355
+ const value = ref('a');
356
+ const popup = ref(false);
357
+ const closeOnScroll = ref(false);
358
+ const host = ref<HTMLElement>();
359
+ const switchAttrs = { 'aria-label': '滚动关闭' };
360
+ const options = [{ label: '选项 A', value: 'a' }, { label: '选项 B', value: 'b' }];
361
+ </script>
362
+ <template>
363
+ <section class="scroll-scope">
364
+ <Switch v-model="closeOnScroll" v-bind="switchAttrs" />
365
+ <span>{{ popup ? '下拉已打开' : '下拉已关闭' }}</span>
366
+ <div class="scroll-region">
367
+ <div class="scroll-content">
368
+ <Select
369
+ v-if="host"
370
+ v-model="value"
371
+ v-model:popup-visible="popup"
372
+ :options="options"
373
+ :popup-container="host"
374
+ :trigger-props="{ scrollToClose: closeOnScroll, scrollToCloseDistance: 24 }"
375
+ style="width: 220px"
376
+ />
377
+ </div>
378
+ </div>
379
+ <div ref="host" class="scroll-overlay" />
380
+ </section>
381
+ </template>
382
+ <style scoped>
383
+ .scroll-region { height: 200px; overflow: auto; }
384
+ .scroll-content { min-height: 480px; padding: 80px 16px 0; }
385
+ .scroll-overlay { position: fixed; inset: 0; pointer-events: none; }
386
+ </style>
387
+ ```
388
+
389
+ ### 键盘、焦点与父级 Escape
390
+
391
+ 用 `Tab` 聚焦下面的选择器,再按 `↓` / `↑` 打开面板。没有已选的启用项时,`↓` 激活首个启用项,`↑` 激活最后一个启用项;已有选中项时优先激活该项。展开后上下键跳过禁用项并循环,`Enter` 选择活动项。通过方向键打开时会激活选项,即使设置了 `defaultActiveFirstOption=false`。
392
+
393
+ `Enter` 单选或 `Esc` 关闭面板后,焦点保留在选择器上。展开时第一次 `Esc` 只关闭选项面板,继续按 `Esc` 才到达父级;闭合选择器不会拦截 `Esc`,可供外层 Dialog 关闭。`Tab` / `Shift+Tab` 关闭面板并保留浏览器的焦点移动,点击外部也可正常转移焦点。禁用状态和输入法组合输入期间不执行上述键盘操作;加载期间不通过 Enter 或上下键选择 / 移动选项,仍可用 Escape 或 Tab 关闭已打开面板。
394
+
395
+ 默认触发器会自动关联 `combobox`、`listbox` 和 `option` 的 ARIA 状态。使用 `trigger` 自定义触发器时,插槽提供 `onKeydown` 键盘代理和对应的 ARIA 状态,完整示例见下方「自定义触发器与方法」。
396
+
397
+ ```vue
398
+ <script setup lang="ts">
399
+ import 'x-next/style.css';
400
+ import { Select, Button } from 'x-next';
401
+ import { ref } from 'vue';
402
+
403
+ const value = ref('');
404
+ const popupVisible = ref(false);
405
+ const focused = ref(false);
406
+ const keyboardInputAttrs = { 'aria-label': '键盘选择城市' };
407
+ const parentEscapeCount = ref(0);
408
+ const options = [
409
+ { label: '不可用的起始项', value: 'disabled-first', disabled: true },
410
+ { label: '北京', value: 'beijing' },
411
+ { label: '上海', value: 'shanghai' },
412
+ { label: '不可用的末尾项', value: 'disabled-last', disabled: true },
413
+ ];
414
+ const handleParentEscape = (event: KeyboardEvent) => {
415
+ if (event.key === 'Escape' && !event.isComposing && event.keyCode !== 229) {
416
+ parentEscapeCount.value++;
417
+ }
418
+ };
419
+ </script>
420
+ <template>
421
+ <div @keydown="handleParentEscape">
422
+ <Select
423
+ v-model="value"
424
+ v-model:popup-visible="popupVisible"
425
+ :options="options"
426
+ v-bind="keyboardInputAttrs"
427
+ placeholder="Tab 聚焦后按 ↑ / ↓"
428
+ @focus="focused = true"
429
+ @blur="focused = false"
430
+ />
431
+ <Button>下一个焦点目标</Button>
432
+ <p role="status">
433
+ 当前值:{{ value || '未选择' }};面板:{{ popupVisible ? '展开' : '关闭' }};
434
+ Select 聚焦:{{ focused ? '是' : '否' }};父级收到 Escape:{{ parentEscapeCount }} 次
435
+ </p>
436
+ </div>
437
+ </template>
438
+ ```
439
+
440
+ ### 在 Form 中校验
441
+
442
+ 组件放进 `x-form-item` 后会自动继承 Form 的尺寸与禁用状态,并按 FormItem 的校验规则展示错误。默认 `validateTrigger` 为 `change`,即值变化时触发校验。
443
+
444
+ ```vue
445
+ <script setup lang="ts">
446
+ import 'x-next/style.css';
447
+ import { Form, FormItem, Select, Space, Button } from 'x-next';
448
+ import { reactive, ref } from 'vue';
449
+ import type { FormInstance, FieldRule } from 'x-next';
450
+
451
+ const formState = reactive<{ city: string | undefined }>({ city: undefined });
452
+ const formRules: Record<string, FieldRule[]> = {
453
+ city: [{ required: true, message: '请选择城市' }],
454
+ };
455
+ const formRef = ref<FormInstance>();
456
+ const validateResult = ref('');
457
+ const cityOptions = [
458
+ { value: 'beijing', label: '北京 Beijing' },
459
+ { value: 'shanghai', label: '上海 Shanghai' },
460
+ { value: 'guangzhou', label: '广州 Guangzhou' },
461
+ { value: 'shenzhen', label: '深圳 Shenzhen' },
462
+ ];
463
+
464
+ const handleValidate = async () => {
465
+ const errors = await formRef.value!.validate();
466
+ validateResult.value = errors
467
+ ? `校验失败:${Object.values(errors).map((error) => error.message).join(';')}`
468
+ : '校验通过';
469
+ };
470
+ const handleReset = () => {
471
+ formRef.value!.resetFields();
472
+ validateResult.value = '已重置';
473
+ };
474
+ </script>
475
+ <template>
476
+ <Form ref="formRef" :model="formState" :rules="formRules">
477
+ <FormItem field="city" label="城市">
478
+ <Select v-model="formState.city" :options="cityOptions" placeholder="请选择城市" allow-clear />
479
+ </FormItem>
480
+ <FormItem>
481
+ <Space>
482
+ <Button type="primary" @click="handleValidate">校验</Button>
483
+ <Button @click="handleReset">重置</Button>
484
+ </Space>
485
+ </FormItem>
486
+ </Form>
487
+ <p role="status">{{ validateResult }}</p>
488
+ </template>
489
+ ```
490
+
491
+ ### 对象值与缺失选项回显
492
+
493
+ 对象值使用 `valueKey` 指定稳定、唯一的键。候选项因分页或搜索暂时消失时,`fallbackOption` 可继续显示已选值;`showExtraOptions=false` 只隐藏下拉中的兜底项,不隐藏回显。设置 `fallbackOption=false` 会隐藏缺失项的标签,但多选更新仍保留其原始值。
494
+
495
+ ```vue
496
+ <script setup lang="ts">
497
+ import 'x-next/style.css';
498
+ import { ref } from 'vue';
499
+ import { Select, Button } from 'x-next';
500
+ import type { SelectOptionValue } from 'x-next';
501
+
502
+ const value = ref<SelectOptionValue>({ id: 2, name: '林悦' });
503
+ const visible = ref(true);
504
+ const people = [{ id: 1, name: '陈晨' }, { id: 2, name: '林悦' }];
505
+ const options = people.map(person => ({ value: person, label: person.name }));
506
+ const fallback = (value: SelectOptionValue) => ({
507
+ value, label: typeof value === 'object' ? String(value.name) : String(value),
508
+ });
509
+ </script>
510
+ <template>
511
+ <Select
512
+ v-model="value" :options="visible ? options : []" value-key="id"
513
+ :fallback-option="fallback" :show-extra-options="false" allow-clear
514
+ placeholder="选择成员"
515
+ />
516
+ <Button @click="visible = !visible">{{ visible ? '移除候选数据' : '恢复候选数据' }}</Button>
517
+ <p>选中对象:{{ JSON.stringify(value) }}</p>
518
+ </template>
519
+ ```
520
+
521
+ ### 远程搜索与受控输入
522
+
523
+ 这个示例模拟网络延迟,使用三组受控状态:选中值、搜索输入和面板显示。`filterOption=false` 把结果筛选交给业务;`searchDelay` 只延迟 `search` 事件,输入更新立即发生。业务需取消旧请求或校验请求序号,避免旧响应覆盖新关键词。
524
+
525
+ ```vue
526
+ <script setup lang="ts">
527
+ import 'x-next/style.css';
528
+ import { onBeforeUnmount, ref, watch } from 'vue';
529
+ import { Select } from 'x-next';
530
+ import type { SelectOptionData } from 'x-next';
531
+
532
+ const value = ref('');
533
+ const input = ref('');
534
+ const popup = ref(false);
535
+ const loading = ref(false);
536
+ const options = ref<SelectOptionData[]>([]);
537
+ const cities = [
538
+ { value: 'beijing', label: '北京 Beijing' },
539
+ { value: 'shanghai', label: '上海 Shanghai' },
540
+ ];
541
+ let revision = 0;
542
+ let timer: ReturnType<typeof setTimeout> | undefined;
543
+ const cancel = () => {
544
+ revision++;
545
+ clearTimeout(timer);
546
+ loading.value = false;
547
+ };
548
+ watch(input, cancel, { flush: 'sync' });
549
+ onBeforeUnmount(cancel);
550
+ const search = (query: string) => {
551
+ cancel();
552
+ const current = revision;
553
+ if (!query.trim()) {
554
+ options.value = [];
555
+ return;
556
+ }
557
+ loading.value = true;
558
+ timer = setTimeout(() => {
559
+ if (current !== revision || query !== input.value) return;
560
+ options.value = cities.filter(city => city.label.toLowerCase().includes(query.toLowerCase()));
561
+ loading.value = false;
562
+ }, 400);
563
+ };
564
+ </script>
565
+ <template>
566
+ <Select
567
+ v-model="value" v-model:input-value="input" v-model:popup-visible="popup"
568
+ :options="options" :loading="loading" allow-search allow-clear
569
+ :filter-option="false" :search-delay="120" :show-extra-options="false"
570
+ show-header-on-empty show-footer-on-empty placeholder="输入城市名搜索" @search="search"
571
+ >
572
+ <template #header>模拟远程城市服务</template>
573
+ <template #empty>没有匹配城市,试试「北京」</template>
574
+ <template #footer>结果由业务返回,不做二次过滤</template>
575
+ </Select>
576
+ <p>选中:{{ value || '未选择' }};输入:{{ input || '空' }}</p>
577
+ </template>
578
+ ```
579
+
580
+ ### 自定义触发器与方法
581
+
582
+ 将插槽提供的 `onKeydown` 绑定到触发节点,即可复用方向键、Enter、Escape、Tab 和 Home / End。Home / End 在面板展开且搜索输入为空时定位首 / 末启用项;有输入时保留光标移动。自定义节点需要设置可聚焦状态和 ARIA;`focus()` / `blur()` 用于默认输入触发器。
583
+
584
+ ```vue
585
+ <script setup lang="ts">
586
+ import 'x-next/style.css';
587
+ import { ref } from 'vue';
588
+ import { Select, Button } from 'x-next';
589
+ import type { SelectInstance } from 'x-next';
590
+
591
+ const value = ref('');
592
+ const popup = ref(false);
593
+ const select = ref<SelectInstance>();
594
+ const options = [{ value: 'beijing', label: '北京' }, { value: 'shanghai', label: '上海' }];
595
+ </script>
596
+ <template>
597
+ <Select v-model="value" v-model:popup-visible="popup" :options="options">
598
+ <template #trigger="{ popupVisible, disabled, listboxId, activeDescendant, onKeydown }">
599
+ <button
600
+ type="button" role="combobox" :disabled="disabled" aria-label="自定义城市选择"
601
+ aria-haspopup="listbox" :aria-expanded="popupVisible" :aria-controls="listboxId"
602
+ :aria-activedescendant="activeDescendant" @keydown="onKeydown"
603
+ >{{ value || '选择城市' }}</button>
604
+ </template>
605
+ </Select>
606
+ <Select ref="select" :options="options" />
607
+ <Button @click="select?.focus()">聚焦</Button>
608
+ <Button @click="select?.blur()">失焦</Button>
609
+ <p>当前值:{{ value }};面板:{{ popup }}</p>
610
+ </template>
611
+ ```
612
+
613
+ ### 自定义渲染与状态图标
614
+
615
+ `options.render` 自定义候选项,`option` 插槽存在时优先使用插槽;标签使用 `label` 插槽或 `formatLabel`。图标优先级为:加载 > 可清空的选中值 > 展开搜索图标 > 箭头。
616
+
617
+ ```vue
618
+ <script setup lang="ts">
619
+ import 'x-next/style.css';
620
+ import { h, ref } from 'vue';
621
+ import { Select, Button, Icon } from 'x-next';
622
+
623
+ const value = ref('a');
624
+ const input = ref('');
625
+ const loading = ref(false);
626
+ const options = [
627
+ { value: 'a', label: '产品方案', render: () => h('strong', '产品方案 · 推荐') },
628
+ { value: 'b', label: '研发计划', render: () => h('span', '研发计划 · 进行中') },
629
+ ];
630
+ </script>
631
+ <template>
632
+ <Select
633
+ v-model="value" v-model:input-value="input" :options="options" :loading="loading"
634
+ allow-search allow-clear :format-label="data => `已选:${data.label}`"
635
+ >
636
+ <template #prefix>方案</template>
637
+ <template #arrow-icon><Icon name="chevron-down" /></template>
638
+ <template #search-icon><Icon name="search" /></template>
639
+ <template #loading-icon><Icon name="loader-circle" spin /></template>
640
+ </Select>
641
+ <Button @click="loading = !loading">{{ loading ? '结束加载' : '模拟加载' }}</Button>
642
+ <Select v-model="value" :options="options">
643
+ <template #option="{ data }"><Icon name="check-circle" /> {{ data.label }} · 插槽渲染</template>
644
+ </Select>
645
+ <p>值:{{ value }};加载:{{ loading }}</p>
646
+ </template>
647
+ ```
648
+
649
+ ### 交互与数据边界
650
+
651
+ - `modelValue`、`inputValue`、`popupVisible` 分别控制选中值、输入和面板。只传 prop 时上层必须处理对应更新事件;`default*` 仅初始化非受控值。
652
+ - 单选清空为 `''`;若候选项包含值 `''`,清空为 `undefined`,以区分「空字符串选项」和「未选择」。多选清空为数组,保留禁用项。`0`、`false` 是有效值。
653
+ - 候选值 / 对象 `valueKey` 必须唯一;插槽选项动态改变顺序时,可用 `index` 明确键盘顺序。默认标签取正文,不含 `icon` / `suffix`。
654
+ - 虚拟列表使用 `options` 数据,分组会逐行虚拟化。存在默认选项插槽时退回普通列表,避免插槽选项丢失;`itemKey` 由 Select 管理。
655
+ - 未开启搜索时,默认输入是只读的选择触发器;Select 目前没有独立 `readonly` 业务态。查看态可展示标签,禁止操作使用 `disabled`。
656
+ - 原生 `id`、`name`、`tabindex`、`autocomplete` 和 `aria-*` 落在实际输入上;`class`、`style`、`data-*` 落在外层。原生输入值是搜索文本,提交选中值应读取 `v-model`;必填校验使用 FormItem 的 `required` 规则,Select 不提供原生表单选中值提交和 constraint validation。
657
+
658
+
659
+ ### 选项数据
660
+
661
+ `SelectOptionData` 和 `SelectOptionGroupData` 可从根入口导入。自定义字段名只映射选项数据,分组结构仍使用 `isGroup`、`label`、`options`。
662
+
663
+ | 字段 | 说明 | 类型 |
664
+ | --- | --- | --- |
665
+ | `value` | 选项值;对象值需配合 `valueKey` | `string \| number \| boolean \| object` |
666
+ | `label` | 用于回显和默认搜索的纯文本 | `string` |
667
+ | `disabled` | 禁止选择 / 取消 / 删除 / 清空此项 | `boolean` |
668
+ | `tagProps` | 多选标签属性;`closable=false` 隐藏此标签的删除入口,不代替选项禁用 | `object` |
669
+ | `render` | 选项渲染函数,不改变搜索文本或回显 label | `RenderFunction` |
670
+
671
+ 分组为 `{ isGroup: true, label: string, options: [...] }`。`fieldNames` 可映射 `value`、`label`、`disabled`、`tagProps`、`render`,未传的字段使用同名默认字段。
672
+
673
+
674
+
675
+ 返回 [AI 索引](../index.md)。先查本页与 [本地 API](./select-api.md);需要更深类型时查 [公开组件导航](../catalog.md),不默认上网查找本包用法。