x-next 1.2.0 → 1.3.1

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 (35) hide show
  1. package/AI_USAGE.md +647 -0
  2. package/CHANGELOG.md +22 -0
  3. package/README.md +8 -0
  4. package/dist/components/dropdown/Dropdown.vue.d.ts +27 -1
  5. package/dist/components/dropdown/DropdownButton.vue.d.ts +27 -1
  6. package/dist/components/dropdown/DropdownOption.vue.d.ts +2 -0
  7. package/dist/components/dropdown/DropdownSubmenu.vue.d.ts +158 -1
  8. package/dist/components/dropdown/context.d.ts +14 -1
  9. package/dist/components/dropdown/dropdown-panel.vue.d.ts +7 -1
  10. package/dist/components/dropdown/index.d.ts +588 -6
  11. package/dist/components/dropdown/use-keyboard.d.ts +10 -0
  12. package/dist/components/form-select/hooks/use-select.d.ts +2 -1
  13. package/dist/es/_hooks/use-overflow.js +45 -40
  14. package/dist/es/components/_components/select-view/select-view.js +49 -55
  15. package/dist/es/components/dialog/Dialog.js +106 -97
  16. package/dist/es/components/dropdown/Dropdown.vue.js +18 -15
  17. package/dist/es/components/dropdown/Dropdown.vue2.js +52 -31
  18. package/dist/es/components/dropdown/DropdownOption.vue.js +22 -21
  19. package/dist/es/components/dropdown/DropdownOption.vue2.js +23 -19
  20. package/dist/es/components/dropdown/DropdownSubmenu.vue.js +49 -36
  21. package/dist/es/components/dropdown/DropdownSubmenu.vue2.js +45 -24
  22. package/dist/es/components/dropdown/context.js +3 -2
  23. package/dist/es/components/dropdown/dropdown-panel.vue.js +24 -21
  24. package/dist/es/components/dropdown/dropdown-panel.vue2.js +83 -31
  25. package/dist/es/components/dropdown/use-keyboard.js +45 -0
  26. package/dist/es/components/form-checkbox/Checkbox.js +49 -49
  27. package/dist/es/components/form-select/Select.js +25 -24
  28. package/dist/es/components/form-select/hooks/use-select.js +128 -128
  29. package/dist/es/style.css +1 -1
  30. package/dist/index.cjs +4 -4
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.umd.js +4 -4
  33. package/dist/style/base.css +1 -1
  34. package/dist/style.css +1 -1
  35. package/package.json +9 -3
package/AI_USAGE.md ADDED
@@ -0,0 +1,647 @@
1
+ <!-- Generated by pnpm generate:ai-usage. Edit src/docs/guide/ai-usage-recipes.md and script/ai-usage/manifest.js. -->
2
+ # x-next AI 使用手册
3
+
4
+ 适用版本:**x-next@1.3.1**。Vue:`^3.5.0`;Node:`>=20.19.0`。
5
+
6
+ 来源指纹(精选示例、映射、版本与公开类型声明):`026780d75893368a0a1da6edd95df58545bcfefe87f3a5390756065500e73fe7`。
7
+
8
+ 先按业务需要选择组件,不要求全部迁移。本手册限定在用户确认的 22 个组件及必要的同族子组件,未覆盖的导出不表示已完成业务验收。
9
+
10
+ 读取入口:`node_modules/x-next/AI_USAGE.md`;可用 `require.resolve('x-next/AI_USAGE.md')` 定位。这个文件名不会自动让所有 AI 工具加载,消费项目应在自己的指令中明确引用。
11
+
12
+ ## 组件选择索引
13
+
14
+ | 组件/服务 | 公共导出 | 全局标签/形式 | 受控模型 | 详细文档 |
15
+ | --- | --- | --- | --- | --- |
16
+ | Button | `Button` | `<x-button>` | 无 | [组件文档](https://x-next.ztes.com/components/button) |
17
+ | Checkbox | `Checkbox` | `<x-checkbox>` | `v-model` | [组件文档](https://x-next.ztes.com/components/checkbox) |
18
+ | Radio | `Radio` | `<x-radio>` | `v-model` | [组件文档](https://x-next.ztes.com/components/radio) |
19
+ | Select | `Select` | `<x-select>` | `v-model`, `v-model:popup-visible` | [组件文档](https://x-next.ztes.com/components/select) |
20
+ | Slider | `Slider` | `<x-slider>` | `v-model` | [组件文档](https://x-next.ztes.com/components/slider) |
21
+ | Rate | `Rate` | `<x-rate>` | `v-model` | [组件文档](https://x-next.ztes.com/components/rate) |
22
+ | Switch | `Switch` | `<x-switch>` | `v-model` | [组件文档](https://x-next.ztes.com/components/switch) |
23
+ | DatePicker | `DatePicker` | `<x-date-picker>` | `v-model`, `v-model:popup-visible` | [组件文档](https://x-next.ztes.com/components/date-picker) |
24
+ | TimePicker | `TimePicker` | `<x-time-picker>` | `v-model`, `v-model:popup-visible` | [组件文档](https://x-next.ztes.com/components/time-picker) |
25
+ | Alert | `Alert` | `<x-alert>` | `v-model:visible` | [组件文档](https://x-next.ztes.com/components/alert) |
26
+ | Dialog | `DialogComponent`, `Dialog` | `<x-dialog>` | `v-model` | [组件文档](https://x-next.ztes.com/components/dialog) |
27
+ | Message | `Message`, `MessageComponent` | 命令式服务 | 无 | [组件文档](https://x-next.ztes.com/components/message) |
28
+ | MessageBox | `MessageBox` | 命令式服务 | 无 | [组件文档](https://x-next.ztes.com/components/message-box) |
29
+ | Notification | `Notification`, `NotificationComponent` | 命令式服务 | 无 | [组件文档](https://x-next.ztes.com/components/notification) |
30
+ | Popconfirm | `Popconfirm` | `<x-popconfirm>` | `v-model` | [组件文档](https://x-next.ztes.com/components/popconfirm) |
31
+ | Popover | `Popover` | `<x-popover>` | `v-model:popup-visible` | [组件文档](https://x-next.ztes.com/components/popover) |
32
+ | Progress | `Progress` | `<x-progress>` | 无 | [组件文档](https://x-next.ztes.com/components/progress) |
33
+ | Dropdown | `Dropdown` | `<x-dropdown>` | `v-model:popup-visible` | [组件文档](https://x-next.ztes.com/components/dropdown) |
34
+ | Pagination | `Pagination` | `<x-pagination>` | `v-model:current`, `v-model:page-size` | [组件文档](https://x-next.ztes.com/components/pagination) |
35
+ | Steps | `Steps` | `<x-steps>` | `v-model:current` | [组件文档](https://x-next.ztes.com/components/steps) |
36
+ | Tabs | `Tabs` | `<x-tabs>` | `v-model:active-key` | [组件文档](https://x-next.ztes.com/components/tabs) |
37
+ | Empty | `Empty` | `<x-empty>` | 无 | [组件文档](https://x-next.ztes.com/components/empty) |
38
+ 这是一份给业务开发者和 AI Coding 使用的中文代码手册。以下 22 个入口是本手册选定的常用组件与服务;公开导出还有其他能力,不能据此推断所有导出都具有相同成熟度,也不要求每个项目全部使用。
39
+
40
+ 每节提供一个可复制到 `App.vue` 的独立 Vue SFC,显式从 `x-next` 根入口导入,并包含全量 CSS。实际项目可将重复的 CSS 导入统一移到应用入口。本文是代码配方,不新增 live demo;每节链接的既有组件文档提供可交互示例和完整 API。
41
+
42
+ 根目录生成的 `AI_USAGE.md` 随 npm 包分发,可将它提供给 AI 作为消费方用法上下文。编写页面时先选相应配方,再按链接核对所需能力,避免套用其他组件库的属性名。
43
+
44
+ ## 安装与初始化
45
+
46
+ ```sh
47
+ npm install x-next
48
+ ```
49
+
50
+ 应用需已有 Vue 3、TypeScript 和 Vue SFC 构建支持。在 `main.ts` 全局安装插件;`App.vue` 使用下方任一配方即可。
51
+
52
+ ```ts
53
+ import { createApp } from 'vue';
54
+ import XNext from 'x-next';
55
+ import App from './App.vue';
56
+ import 'x-next/dist/style.css';
57
+
58
+ createApp(App).use(XNext).mount('#app');
59
+ ```
60
+
61
+ `app.use(XNext)` 注册全局组件;下方局部具名导入也可独立使用。根入口的 `Dialog` 是服务,模板组件入口是 `DialogComponent`;MessageBox 使用服务函数。
62
+
63
+ 接入时遵循这些约定:
64
+
65
+ - **原生属性不是组件 props**:部分公开类型没有列出所有原生 `id/name/aria-*`。配方通过明确的属性对象 `v-bind` 传递已核对可用的原生属性,组件 props 和事件仍直接绑定并接受严格模板检查;不要用属性对象绕过对未知组件 API 的核对。
66
+ - **保持受控值稳定**:`v-model` 要初始化为明确的布尔值、字符串、数字或数组。`defaultValue` / `defaultChecked` 用于非受控初始化;将受控值改为 `undefined` 可能切换到内部状态。清空日期、时间时,本手册统一保存 `''`。
67
+ - **选择正确的弹层宿主**:Select、DatePicker、TimePicker、Popover、Dropdown 使用 `popupContainer`;Dialog、Message、MessageBox、Notification、Popconfirm 使用 `renderTo`。容器须已挂载,局部容器需留意定位、滚动和裁剪;Teleport 到 `body` 的弹层不继承原局部容器的主题变量。
68
+ - **先用公开主题变量**:参考[样式与主题](https://x-next.ztes.com/guide/theme)。暗色容器上的 alias 链会重新声明;更深子容器只改语义变量仍可能继承祖先已解析的 alias。`themeColor` 写入的内联 primary alias 也有覆盖边界,需按主题文档设置相关公开 alias。
69
+ - **约束业务全局 CSS**:reset 可用 `:where(...)` 降低优先级,并限定业务作用域;宽泛的原生元素选择器可能覆盖组件样式。自定义内容用插槽和公开属性,不依赖内部结构类名。
70
+ - **清理页面创建的服务**:保留句柄,在路由页面卸载时调用 `close()`;KeepAlive 页面可在停用时清理。Dialog / MessageBox 的命令式关闭不触发确认、取消回调,业务取消逻辑需自行调用;Message / Notification 的关闭会触发各自 `onClose`。
71
+ - **本地链接要刷新产物**:链接源码仓库时,消费方仍可能读取 `dist`;修改后需重新构建库并刷新消费方依赖缓存。本手册的代码使用包根入口与 `dist/style.css`。
72
+
73
+ ## Button
74
+
75
+ [组件文档与 live demo](https://x-next.ztes.com/components/button)。`type` 默认 `'default'`,视觉主按钮用 `'primary'`;`htmlType` 默认 `'button'`,原生提交用 `'submit'`。独立使用时尺寸回退为 `'medium'`,`disabled` / `loading` 默认关闭。
76
+
77
+ `click` 载荷为 `MouseEvent`,禁用或加载中不会触发。`default`、`prefix`、`suffix`、`icon` 插槽可组合内容;异步业务自行维护 `loading`。
78
+
79
+ ```vue
80
+ <script setup lang="ts">
81
+ import { ref } from 'vue';
82
+ import { Button } from 'x-next';
83
+ import 'x-next/dist/style.css';
84
+ const loading = ref(false);
85
+ const result = ref('尚未保存');
86
+ async function save(_event: MouseEvent) {
87
+ loading.value = true;
88
+ try {
89
+ await Promise.resolve();
90
+ result.value = '保存完成';
91
+ } finally { loading.value = false; }
92
+ }
93
+ </script>
94
+ <template>
95
+ <Button type="primary" html-type="button" :loading="loading" @click="save">保存</Button>
96
+ <p role="status">{{ result }}</p>
97
+ </template>
98
+ ```
99
+
100
+ ## Checkbox
101
+
102
+ [组件文档与 live demo](https://x-next.ztes.com/components/checkbox)。使用普通 `v-model`;模型支持 `boolean` 或 `(string | number | boolean)[]`,数组模式配合 `value`。`defaultChecked`、`disabled`、`indeterminate` 默认 `false`;半选状态不会替代模型值。
103
+
104
+ `change(value, event)` 返回新值和原生 `Event`。默认插槽是文案,`checkbox` 插槽提供 `checked` / `disabled`。`id`、`name`、`required`、`form`、`tabindex`、`autofocus`、`autocomplete` 和 `aria-*` 传给原生复选框。
105
+
106
+ ```vue
107
+ <script setup lang="ts">
108
+ import { ref } from 'vue';
109
+ import { Checkbox } from 'x-next';
110
+ import 'x-next/dist/style.css';
111
+ const accepted = ref(false);
112
+ const inputAttrs = { id: 'accept-terms', name: 'terms', required: true };
113
+ const feedback = ref('尚未选择');
114
+ function changed(value: boolean | (string | number | boolean)[], event: Event) {
115
+ feedback.value = `${value === true ? '已同意' : '未同意'}(${event.type})`;
116
+ }
117
+ </script>
118
+ <template>
119
+ <Checkbox v-model="accepted" v-bind="inputAttrs" @change="changed">
120
+ 我已阅读使用说明
121
+ </Checkbox>
122
+ <p role="status">{{ feedback }}</p>
123
+ </template>
124
+ ```
125
+
126
+ ## Radio
127
+
128
+ [组件文档与 live demo](https://x-next.ztes.com/components/radio)。`Radio` / `RadioGroup` 的模型和选项值支持 `string | number | boolean`,保留值类型;布尔选项写 `:value="true"`。单个 Radio 的 `value` 默认 `true`,组的非受控默认值为 `''`。
129
+
130
+ 组默认 `type='radio'`、`direction='horizontal'`、`disabled=false`;`change(value, event)` 返回选项值和 `Event`。Radio 默认插槽是文案,组也支持 `options` 和 `label` / `radio` 插槽。
131
+
132
+ ```vue
133
+ <script setup lang="ts">
134
+ import { ref } from 'vue';
135
+ import { Radio, RadioGroup } from 'x-next';
136
+ import 'x-next/dist/style.css';
137
+ const enabled = ref<string | number | boolean>(true);
138
+ const controlAttrs = { name: 'delivery-mode', 'aria-label': '是否开启通知' };
139
+ const feedback = ref('当前开启');
140
+ function changed(value: string | number | boolean, _event: Event) {
141
+ feedback.value = value === true ? '当前开启' : '当前关闭';
142
+ }
143
+ </script>
144
+ <template>
145
+ <RadioGroup v-model="enabled" v-bind="controlAttrs" @change="changed">
146
+ <Radio :value="true">开启</Radio>
147
+ <Radio :value="false">关闭</Radio>
148
+ </RadioGroup>
149
+ <p role="status">{{ feedback }}</p>
150
+ </template>
151
+ ```
152
+
153
+ ## Select
154
+
155
+ [组件文档与 live demo](https://x-next.ztes.com/components/select)。`v-model` 返回选项的 `value`;单选通常为标量,多选为数组,也支持对象值。`multiple=false`、`allowClear=false`;单选搜索默认关闭,多选默认开启。`options` 使用可变数组,常用字段是 `label`、`value`、`disabled`。
156
+
157
+ `change(value)` 返回新值,`clear(event)` 返回 `Event`;单选清空通常为 `''`,多选为 `[]`,已选禁用项可能保留。`v-model:popup-visible` 控制弹层,`option` / `empty` / `header` / `footer` 等插槽见组件文档。
158
+
159
+ ```vue
160
+ <script setup lang="ts">
161
+ import { ref } from 'vue';
162
+ import { Select } from 'x-next';
163
+ import 'x-next/dist/style.css';
164
+ const city = ref('');
165
+ const options = [
166
+ { label: '杭州', value: 'hangzhou' },
167
+ { label: '上海', value: 'shanghai' },
168
+ { label: '暂未开放', value: 'pending', disabled: true },
169
+ ];
170
+ const feedback = ref('尚未选择');
171
+ function changed(value: unknown) {
172
+ feedback.value = typeof value === 'string' && value ? `城市代码:${value}` : '已清空';
173
+ }
174
+ </script>
175
+ <template>
176
+ <Select v-model="city" :options="options" allow-search allow-clear placeholder="选择城市" @change="changed" />
177
+ <p role="status">{{ feedback }}</p>
178
+ </template>
179
+ ```
180
+
181
+ ## Slider
182
+
183
+ [组件文档与 live demo](https://x-next.ztes.com/components/slider)。普通模型为 `number`,`range` 模式为 `[number, number]`。默认 `min=0`、`max=100`、`step=1`、`range=false`、`disabled=false`、`showTooltip=true`;范围端点按大小排序并按步长归一化。
184
+
185
+ `change(value)` 表示值变化,`change-end(value)` 表示一次拖拽、点击、键盘或输入提交结束,载荷均为 `number | [number, number]`。`marks` 是数值键到文字的映射,`formatTooltip` 可格式化提示。
186
+
187
+ ```vue
188
+ <script setup lang="ts">
189
+ import { ref } from 'vue';
190
+ import { Slider } from 'x-next';
191
+ import 'x-next/dist/style.css';
192
+ const volume = ref(40);
193
+ const controlAttrs = { 'aria-label': '音量' };
194
+ const committed = ref('尚未调整');
195
+ function finish(value: number | [number, number]) {
196
+ committed.value = typeof value === 'number' ? `已提交音量 ${value}` : value.join(' ~ ');
197
+ }
198
+ </script>
199
+ <template>
200
+ <div style="max-width: 320px">
201
+ <Slider v-model="volume" :step="10" :marks="{ 0: '静音', 100: '最大' }" v-bind="controlAttrs" @change-end="finish" />
202
+ <p role="status">当前 {{ volume }};{{ committed }}</p>
203
+ </div>
204
+ </template>
205
+ ```
206
+
207
+ ## Rate
208
+
209
+ [组件文档与 live demo](https://x-next.ztes.com/components/rate)。数值模型默认非受控值为 `0`,`count=5`;`allowHalf`、`allowClear`、`readonly`、`disabled` 默认关闭。启用半星后步长为 `0.5`,值限制在有效数量内;没有 `size` 属性。
210
+
211
+ `change(value)` 返回 `number`,`hover-change(value)` 返回 `number | undefined`。`character` 插槽提供 `index`、`value`、`count`、`disabled`;`tooltips` 为提示数组。
212
+
213
+ ```vue
214
+ <script setup lang="ts">
215
+ import { ref } from 'vue';
216
+ import { Rate } from 'x-next';
217
+ import 'x-next/dist/style.css';
218
+ const score = ref(3.5);
219
+ const controlAttrs = { 'aria-label': '服务评分' };
220
+ const feedback = ref('请评分');
221
+ function changed(value: number) { feedback.value = value ? `评分 ${value}` : '已清除评分'; }
222
+ </script>
223
+ <template>
224
+ <Rate v-model="score" allow-half allow-clear v-bind="controlAttrs" @change="changed" />
225
+ <p role="status">{{ feedback }}</p>
226
+ </template>
227
+ ```
228
+
229
+ ## Switch
230
+
231
+ [组件文档与 live demo](https://x-next.ztes.com/components/switch)。普通 `v-model` 支持 `boolean | string | number`;`checkedValue=true`、`uncheckedValue=false`、`defaultChecked=false`,默认 `type='circle'`。`disabled` / `loading` 阻止切换。
232
+
233
+ `change(value, event)` 返回新值和 `Event`;`beforeChange(newValue)` 可返回布尔值或 Promise,`false` 或拒绝阻止切换。`checked` / `unchecked` 插槽及 `checkedText` / `uncheckedText` 显示两态文案,line 类型不显示文案。
234
+
235
+ ```vue
236
+ <script setup lang="ts">
237
+ import { ref } from 'vue';
238
+ import { Switch } from 'x-next';
239
+ import 'x-next/dist/style.css';
240
+ const enabled = ref(false);
241
+ const controlAttrs = { 'aria-label': '通知开关' };
242
+ const feedback = ref('通知关闭');
243
+ function changed(value: boolean | string | number, _event: Event) {
244
+ feedback.value = value === true ? '通知开启' : '通知关闭';
245
+ }
246
+ </script>
247
+ <template>
248
+ <Switch v-model="enabled" checked-text="开" unchecked-text="关" v-bind="controlAttrs" @change="changed" />
249
+ <p role="status">{{ feedback }}</p>
250
+ </template>
251
+ ```
252
+
253
+ ## DatePicker
254
+
255
+ [组件文档与 live demo](https://x-next.ztes.com/components/date-picker)。默认 `type='date'`、`allowClear=true`、`showToday=true`、`showTime=false`、`position='bl'`。`format` 控制显示,`valueFormat` 控制输出;本例使用 `'YYYY-MM-DD'` 字符串。公开 `DatePickerModelValue` 还包含数字、Date、数组和 `undefined`。
256
+
257
+ `change(value, date, dateString)` 为提交值,`select` 是面板选择;后两个参数声明为 `unknown`。清空返回 `undefined`,本例归一化为 `''` 保持受控。支持 `cell` / `extra` / `prefix` / `suffix-icon` 插槽;带时间选择需确认后提交。
258
+
259
+ ```vue
260
+ <script setup lang="ts">
261
+ import { ref } from 'vue';
262
+ import { DatePicker, type DatePickerModelValue } from 'x-next';
263
+ import 'x-next/dist/style.css';
264
+ const date = ref('');
265
+ const feedback = ref('尚未选择日期');
266
+ function update(value: DatePickerModelValue) { date.value = typeof value === 'string' ? value : ''; }
267
+ function changed(value: DatePickerModelValue, _date: unknown, _text: unknown) {
268
+ update(value);
269
+ feedback.value = date.value ? `日期:${date.value}` : '已清空日期';
270
+ }
271
+ </script>
272
+ <template>
273
+ <DatePicker :model-value="date" value-format="YYYY-MM-DD" placeholder="选择日期"
274
+ @update:model-value="update" @change="changed" />
275
+ <p role="status">{{ feedback }}</p>
276
+ </template>
277
+ ```
278
+
279
+ ## TimePicker
280
+
281
+ [组件文档与 live demo](https://x-next.ztes.com/components/time-picker)。默认 `type='time'`、`allowClear=true`、`disableConfirm=false`,默认格式为 `'HH:mm:ss'`。`format` 同时决定显示与输出;`step` 用 `{ hour, minute, second }`,各步长默认 `1`。
282
+
283
+ `change(timeString, time)` 是确认值变化,`select` 是面板选择;字符串载荷为 `string | (string | undefined)[] | undefined`,第二参数为 `unknown`。清空归一化为 `''`;支持 `prefix` / `suffix-icon` / `extra` 插槽及 `disabledHours` 等限制。
284
+
285
+ ```vue
286
+ <script setup lang="ts">
287
+ import { ref } from 'vue';
288
+ import { TimePicker } from 'x-next';
289
+ import 'x-next/dist/style.css';
290
+ const time = ref('');
291
+ const feedback = ref('尚未选择时间');
292
+ function update(value: unknown) { time.value = typeof value === 'string' ? value : ''; }
293
+ function changed(value: string | (string | undefined)[] | undefined, _time: unknown) {
294
+ update(value);
295
+ feedback.value = time.value ? `时间:${time.value}` : '已清空时间';
296
+ }
297
+ </script>
298
+ <template>
299
+ <TimePicker :model-value="time" format="HH:mm" :step="{ minute: 15 }" placeholder="选择时间"
300
+ @update:model-value="update" @change="changed" />
301
+ <p role="status">{{ feedback }}</p>
302
+ </template>
303
+ ```
304
+
305
+ ## Alert
306
+
307
+ [组件文档与 live demo](https://x-next.ztes.com/components/alert)。用 `v-model:visible` 控制显示;`defaultVisible=true`、`type='info'`、`showIcon=true`、`closable=false`。常用类型为 info、success、warning、error、normal。
308
+
309
+ `close(event)` 返回 `MouseEvent`,`after-close` 在关闭动画结束后触发且无参数。默认插槽放正文,`title` / `icon` / `action` / `close-element` 插槽可自定义对应内容。
310
+
311
+ ```vue
312
+ <script setup lang="ts">
313
+ import { ref } from 'vue';
314
+ import { Alert, Button } from 'x-next';
315
+ import 'x-next/dist/style.css';
316
+ const visible = ref(true);
317
+ const feedback = ref('提示显示中');
318
+ function closed(_event: MouseEvent) { feedback.value = '已点击关闭'; }
319
+ function restore() { visible.value = true; feedback.value = '提示显示中'; }
320
+ </script>
321
+ <template>
322
+ <Alert v-model:visible="visible" type="warning" title="检查待提交内容" closable @close="closed">
323
+ 提交前请核对所选日期。
324
+ </Alert>
325
+ <Button @click="restore">重新显示</Button>
326
+ <p role="status">{{ feedback }}</p>
327
+ </template>
328
+ ```
329
+
330
+ ## Dialog
331
+
332
+ [组件文档与 live demo](https://x-next.ztes.com/components/dialog)。从根入口导入 `DialogComponent as XDialog`,普通 `v-model` 为布尔值且默认 `false`。`renderTo='body'`、`mask=true`、`maskToClose=true`、`escToClose=true`、`destroyOnClosed=true`;`width` 支持数字或 CSS 长度。
333
+
334
+ `title`、默认正文、`footer` 是公开插槽,默认不生成业务按钮。`close(action, event?)` 的 action 为 `'cancel' | 'ok'`,`closed` 表示关闭动画结束;直接改模型不会调用业务取消逻辑。根入口服务 `Dialog(options)` 返回 `close()` / `update(options)` 句柄。
335
+
336
+ ```vue
337
+ <script setup lang="ts">
338
+ import { ref } from 'vue';
339
+ import { Button, DialogComponent as XDialog } from 'x-next';
340
+ import 'x-next/dist/style.css';
341
+ const visible = ref(false);
342
+ const feedback = ref('尚未确认');
343
+ function confirm() { feedback.value = '已确认'; visible.value = false; }
344
+ function cancel() { feedback.value = '已取消'; visible.value = false; }
345
+ </script>
346
+ <template>
347
+ <Button @click="visible = true">打开对话框</Button>
348
+ <XDialog v-model="visible" title="确认安排" :width="420">
349
+ <p>核对安排后确认。</p>
350
+ <template #footer>
351
+ <Button @click="cancel">取消</Button>
352
+ <Button type="primary" @click="confirm">确认</Button>
353
+ </template>
354
+ </XDialog>
355
+ <p role="status">{{ feedback }}</p>
356
+ </template>
357
+ ```
358
+
359
+ ## Message
360
+
361
+ [组件文档与 live demo](https://x-next.ztes.com/components/message)。`Message(options)` 或 `.success()` / `.error()` / `.loading()` 等显示提示。默认 `type='info'`、`duration=3000` 毫秒、`position='top'`、`showClose=false`;`duration=0` 持续显示,内容用 `message` 或 `content`。
362
+
363
+ 返回句柄只有 `close()`;同一容器和位置下再次传相同 `id` 更新消息,没有句柄 `update()`。`onClose(id?)` 在自动或手动关闭时触发;自定义内容可用 VNode / 渲染函数。页面只清理自己持有的句柄。
364
+
365
+ ```vue
366
+ <script setup lang="ts">
367
+ import { onBeforeUnmount, ref } from 'vue';
368
+ import { Button, Message } from 'x-next';
369
+ import 'x-next/dist/style.css';
370
+ const feedback = ref('尚未显示提示');
371
+ let handle: ReturnType<typeof Message> | undefined;
372
+ function show() {
373
+ handle?.close();
374
+ handle = Message({ message: '保存完成', type: 'success', duration: 0, showClose: true,
375
+ onClose: () => { feedback.value = '提示已关闭'; } });
376
+ feedback.value = '提示显示中';
377
+ }
378
+ onBeforeUnmount(() => handle?.close());
379
+ </script>
380
+ <template>
381
+ <Button @click="show">显示提示</Button>
382
+ <Button @click="handle?.close()">关闭提示</Button>
383
+ <p role="status">{{ feedback }}</p>
384
+ </template>
385
+ ```
386
+
387
+ ## MessageBox
388
+
389
+ [组件文档与 live demo](https://x-next.ztes.com/components/message-box)。调用 `MessageBox(options)`,默认类型为 `'success'`、宽度 `360`、居中、显示遮罩和关闭按钮、点击遮罩不关闭。`title` / `content` 支持文字、VNode 或渲染函数;`footer=false` 隐藏页脚。
390
+
391
+ 返回 `close()` / `update(options)` 句柄,结果通过 `onOk(event)` / `onCancel(event)` 回调处理。`beforeOnOk` / `beforeOnCancel` 返回 `boolean | Promise<boolean>`,必须返回 `true` 才放行;异步业务放在前置钩子。它不是 Promise,没有 `confirm()`;`.warning(title, content)` 等返回的 `.ok()` / `.cancel()` 用于注册链式回调。
392
+
393
+ ```vue
394
+ <script setup lang="ts">
395
+ import { onBeforeUnmount, ref } from 'vue';
396
+ import { Button, MessageBox } from 'x-next';
397
+ import 'x-next/dist/style.css';
398
+ const feedback = ref('尚未确认');
399
+ let handle: ReturnType<typeof MessageBox> | undefined;
400
+ function ask() {
401
+ handle?.close();
402
+ feedback.value = '等待确认';
403
+ handle = MessageBox({ title: '确认保存?', content: '确认后保存当前安排。', type: 'warning',
404
+ beforeOnOk: () => true,
405
+ onOk: (_event: Event) => { feedback.value = '已确认保存'; },
406
+ onCancel: (_event: Event) => { feedback.value = '用户已取消'; } });
407
+ }
408
+ function close() { handle?.close(); feedback.value = '已主动关闭'; }
409
+ onBeforeUnmount(() => handle?.close());
410
+ </script>
411
+ <template>
412
+ <Button @click="ask">请求确认</Button>
413
+ <Button @click="close">主动关闭</Button>
414
+ <p role="status">{{ feedback }}</p>
415
+ </template>
416
+ ```
417
+
418
+ ## Notification
419
+
420
+ [组件文档与 live demo](https://x-next.ztes.com/components/notification)。`Notification(options)` 或 `.success()` 等显示通知。服务默认 `type='info'`、`duration=3000` 毫秒、`position='top-right'`、`offset=20`、`showClose=true`;四角位置可选,`duration=0` 持续显示。
421
+
422
+ `title` 和 `message` / `content` 是内容,`footer` / `icon` 可用 VNode 或渲染函数。返回句柄只有 `close()`;同一容器与位置下复用 `id` 更新。`onClick()` 无参数,`onClose(id?)` 接收标识;`.remove(id)` / `.clear(position?)` 是服务级方法。
423
+
424
+ ```vue
425
+ <script setup lang="ts">
426
+ import { onBeforeUnmount, ref } from 'vue';
427
+ import { Button, Notification } from 'x-next';
428
+ import 'x-next/dist/style.css';
429
+ const feedback = ref('尚未显示通知');
430
+ let handle: ReturnType<typeof Notification> | undefined;
431
+ function show() {
432
+ handle?.close();
433
+ handle = Notification({ title: '任务完成', message: '结果已准备好。', type: 'success', duration: 0,
434
+ onClick: () => { feedback.value = '已点击通知'; },
435
+ onClose: () => { feedback.value = '通知已关闭'; } });
436
+ feedback.value = '通知显示中';
437
+ }
438
+ onBeforeUnmount(() => handle?.close());
439
+ </script>
440
+ <template>
441
+ <Button @click="show">显示通知</Button>
442
+ <Button @click="handle?.close()">关闭通知</Button>
443
+ <p role="status">{{ feedback }}</p>
444
+ </template>
445
+ ```
446
+
447
+ ## Popconfirm
448
+
449
+ [组件文档与 live demo](https://x-next.ztes.com/components/popconfirm)。普通布尔 `v-model` 控制显示,`defaultVisible=false`、`type='danger'`、`position='top'`、`width=150`,点击默认插槽触发。`content` / `icon` 插槽可自定义确认内容;按钮文字用 `okText` / `cancelText`。
450
+
451
+ `ok(event)` / `cancel(event)` 返回 `Event`,`change(visible)` 返回布尔值。`onBeforeOk` / `onBeforeCancel` 支持布尔、void 或 Promise,返回 `false` 可阻止关闭;异步钩子可自动等待,普通 `ok` 监听器不会自动阻止关闭。
452
+
453
+ ```vue
454
+ <script setup lang="ts">
455
+ import { ref } from 'vue';
456
+ import { Button, Popconfirm } from 'x-next';
457
+ import 'x-next/dist/style.css';
458
+ const visible = ref(false);
459
+ const feedback = ref('记录保留中');
460
+ function remove(_event: Event) { feedback.value = '已确认删除'; }
461
+ function cancel(_event: Event) { feedback.value = '已取消删除'; }
462
+ </script>
463
+ <template>
464
+ <Popconfirm v-model="visible" content="删除这条记录?" ok-text="删除" cancel-text="保留"
465
+ @ok="remove" @cancel="cancel">
466
+ <Button status="danger">删除记录</Button>
467
+ </Popconfirm>
468
+ <p role="status">{{ feedback }}</p>
469
+ </template>
470
+ ```
471
+
472
+ ## Popover
473
+
474
+ [组件文档与 live demo](https://x-next.ztes.com/components/popover)。使用 `v-model:popup-visible`;默认 `trigger='click'`、`position='bottom'`、`showArrow=false`、`defaultPopupVisible=false`、`unmountOnClose=true`。默认插槽是触发器,`title` / `content` 插槽放浮层内容。
475
+
476
+ `popup-visible-change(visible)` 返回布尔值,`show` / `hide` 无参数。点击触发器或外部默认可以关闭;`popupContainer` 和 `renderToBody` 决定宿主,局部主题下按实际挂载位置核对样式。
477
+
478
+ ```vue
479
+ <script setup lang="ts">
480
+ import { ref } from 'vue';
481
+ import { Button, Popover } from 'x-next';
482
+ import 'x-next/dist/style.css';
483
+ const visible = ref(false);
484
+ const feedback = ref('说明未打开');
485
+ function changed(value: boolean) { feedback.value = value ? '说明已打开' : '说明已关闭'; }
486
+ </script>
487
+ <template>
488
+ <Popover v-model:popup-visible="visible" title="安排说明" show-arrow @popup-visible-change="changed">
489
+ <Button>查看说明</Button>
490
+ <template #content>
491
+ <p>时间以页面所选值为准。</p>
492
+ <Button @click="visible = false">关闭说明</Button>
493
+ </template>
494
+ </Popover>
495
+ <p role="status">{{ feedback }}</p>
496
+ </template>
497
+ ```
498
+
499
+ ## Progress
500
+
501
+ [组件文档与 live demo](https://x-next.ztes.com/components/progress)。`percent` 为 **0 到 1** 的比例,默认 `0`,不是 0 到 100;超出范围会裁剪,非有限值显示为 0。默认 `type='line'`、`showText=true`、`animation=false`,`steps>0` 使用分段模式。
502
+
503
+ 无模型和业务 change 事件,由业务更新 `percent`。`status` 为 normal、success、warning、danger,未设置时达到 1 自动为 success;`text` 插槽提供 `{ percent }`。
504
+
505
+ ```vue
506
+ <script setup lang="ts">
507
+ import { ref } from 'vue';
508
+ import { Button, Progress } from 'x-next';
509
+ import 'x-next/dist/style.css';
510
+ const percent = ref(0.25);
511
+ function advance() { percent.value = Math.min(1, percent.value + 0.25); }
512
+ </script>
513
+ <template>
514
+ <div style="max-width: 320px">
515
+ <Progress :percent="percent">
516
+ <template #text="scope">已完成 {{ Math.round(scope.percent * 100) }}%</template>
517
+ </Progress>
518
+ <Button :disabled="percent >= 1" @click="advance">推进任务</Button>
519
+ </div>
520
+ </template>
521
+ ```
522
+
523
+ ## Dropdown
524
+
525
+ [组件文档与 live demo](https://x-next.ztes.com/components/dropdown)。使用 `v-model:popup-visible`,默认 `trigger='click'`、`position='bottom'`、`hideOnSelect=true`。根入口导出 `DropdownOption`、`DropdownGroup`、`DropdownSubmenu`;菜单内容放 `content` 插槽,另有 `empty` / `footer` 插槽。
526
+
527
+ `select(value, event)` 返回 `string | number | Record<string, any> | undefined` 和 `Event`,`popup-visible-change` 返回布尔值。选项支持 `disabled`;字符搜索 typeahead、自定义控件的通用键盘代理及 Tab 自动关闭仍有边界,不能据方向键导航推断这些能力已实现。
528
+
529
+ ```vue
530
+ <script setup lang="ts">
531
+ import { ref } from 'vue';
532
+ import { Button, Dropdown, DropdownOption } from 'x-next';
533
+ import 'x-next/dist/style.css';
534
+ const visible = ref(false);
535
+ const feedback = ref('尚未选择操作');
536
+ function select(value: unknown, _event: Event) {
537
+ feedback.value = value === 'copy' ? '已选择复制' : '已选择下载';
538
+ }
539
+ </script>
540
+ <template>
541
+ <Dropdown v-model:popup-visible="visible" @select="select">
542
+ <Button>更多操作</Button>
543
+ <template #content>
544
+ <DropdownOption value="copy">复制</DropdownOption>
545
+ <DropdownOption value="download">下载</DropdownOption>
546
+ <DropdownOption value="archive" disabled>归档暂不可用</DropdownOption>
547
+ </template>
548
+ </Dropdown>
549
+ <p role="status">{{ feedback }}</p>
550
+ </template>
551
+ ```
552
+
553
+ ## Pagination
554
+
555
+ [组件文档与 live demo](https://x-next.ztes.com/components/pagination)。`total` 必填且表示记录总数。使用 `v-model:current` 和 `v-model:page-size`;默认非受控值为页码 `1`、每页 `10`,`showTotal` / `showPageSize` / `showJumper` 默认关闭,`autoAdjust=true`。
556
+
557
+ `change(current)` 和 `page-size-change(pageSize)` 各返回一个数字;不会请求数据。页码按总数裁剪,每页条数应为正数。`total` 插槽提供总数,`page-item` 提供页码;改变条数后的业务重新查询需自行实现。
558
+
559
+ ```vue
560
+ <script setup lang="ts">
561
+ import { ref } from 'vue';
562
+ import { Pagination } from 'x-next';
563
+ import 'x-next/dist/style.css';
564
+ const current = ref(1);
565
+ const pageSize = ref(10);
566
+ const feedback = ref('当前第 1 页');
567
+ function changed(page: number) { feedback.value = `当前第 ${page} 页`; }
568
+ function resized(size: number) { current.value = 1; feedback.value = `每页 ${size} 条,返回第一页`; }
569
+ </script>
570
+ <template>
571
+ <Pagination v-model:current="current" v-model:page-size="pageSize" :total="95" show-total show-page-size
572
+ :page-size-options="[10, 20, 50]" @change="changed" @page-size-change="resized" />
573
+ <p role="status">{{ feedback }};每页 {{ pageSize }} 条</p>
574
+ </template>
575
+ ```
576
+
577
+ ## Steps
578
+
579
+ [组件文档与 live demo](https://x-next.ztes.com/components/steps)。子组件的公开名称是 `Step`。使用 `v-model:current`,序号从 **1** 开始,`defaultCurrent=1`、`status='process'`、`type='default'`、`direction='horizontal'`;点击切换需开启 `changeable`,默认关闭。
580
+
581
+ `change(step, event)` 返回步骤号和 `Event`。Step 支持 `title`、`description`、`disabled`、`status`;`node` / `icon` 插槽提供步骤与状态,默认 / `description` 插槽可替换文案。业务完成状态由业务自身维护。
582
+
583
+ ```vue
584
+ <script setup lang="ts">
585
+ import { ref } from 'vue';
586
+ import { Steps, Step } from 'x-next';
587
+ import 'x-next/dist/style.css';
588
+ const current = ref(1);
589
+ const feedback = ref('正在填写');
590
+ function changed(step: number, _event: Event) { feedback.value = `已切换到第 ${step} 步`; }
591
+ </script>
592
+ <template>
593
+ <Steps v-model:current="current" changeable @change="changed">
594
+ <Step title="填写" description="准备安排" />
595
+ <Step title="核对" description="检查内容" />
596
+ <Step title="完成" description="提交结果" />
597
+ </Steps>
598
+ <p role="status">{{ feedback }}</p>
599
+ </template>
600
+ ```
601
+
602
+ ## Tabs
603
+
604
+ [组件文档与 live demo](https://x-next.ztes.com/components/tabs)。使用 `v-model:active-key`,类型为 `string | number`;TabPane 用 Vue 的 `key` 标识页签,键类型须与模型一致。默认 `type='line'`、`position='top'`、`trigger='click'`、`lazyLoad=false`、`destroyOnHide=false`。
605
+
606
+ `change(key)` 返回键值,`tab-click(key, event)` 还返回 `Event`。禁用配置放在 TabPane;TabPane 默认插槽放正文,`title` 插槽自定义标题,Tabs 的 `extra` 放额外内容。可编辑模式的 `add` / `delete` 事件需要业务维护页签数据。
607
+
608
+ ```vue
609
+ <script setup lang="ts">
610
+ import { ref } from 'vue';
611
+ import { Tabs, TabPane } from 'x-next';
612
+ import 'x-next/dist/style.css';
613
+ const active = ref<string | number>('overview');
614
+ const feedback = ref('当前概览');
615
+ function changed(key: string | number) { feedback.value = `当前页签:${key}`; }
616
+ </script>
617
+ <template>
618
+ <Tabs v-model:active-key="active" @change="changed">
619
+ <TabPane key="overview" title="概览">查看当前安排。</TabPane>
620
+ <TabPane key="history" title="历史">查看已完成记录。</TabPane>
621
+ <TabPane key="restricted" title="未开放" disabled>此内容暂不可选。</TabPane>
622
+ </Tabs>
623
+ <p role="status">{{ feedback }}</p>
624
+ </template>
625
+ ```
626
+
627
+ ## Empty
628
+
629
+ [组件文档与 live demo](https://x-next.ztes.com/components/empty)。`description` 未传时使用语言包默认文案,`null` 或 `''` 隐藏描述;`imgSrc` 自定义图片,`image` 插槽优先于图片地址。默认插槽替代描述,可放业务操作按钮。
630
+
631
+ 没有模型或业务事件;刷新、创建等动作由插槽中的业务控件处理。显式提供描述、图片或插槽时采用调用方配置;裸 Empty 才会交由外层 ConfigProvider 的 `empty` 插槽接管。
632
+
633
+ ```vue
634
+ <script setup lang="ts">
635
+ import { ref } from 'vue';
636
+ import { Button, Empty } from 'x-next';
637
+ import 'x-next/dist/style.css';
638
+ const refreshed = ref(false);
639
+ function refresh() { refreshed.value = true; }
640
+ </script>
641
+ <template>
642
+ <Empty>
643
+ <p>{{ refreshed ? '刷新完成,仍无记录' : '暂无记录' }}</p>
644
+ <Button @click="refresh">刷新记录</Button>
645
+ </Empty>
646
+ </template>
647
+ ```