@done-coding/admin-core 0.21.0 → 0.21.1-alpha.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.
- package/es/components/app-layout/AppLayout.vue.mjs +1 -1
- package/es/components/app-layout/AppLayout.vue2.mjs +51 -6
- package/es/components/app-layout/AppPage.vue.mjs +1 -1
- package/es/components/app-layout/AppPage.vue2.mjs +16 -9
- package/es/components/display/ShadowClone.vue.mjs +32 -0
- package/es/components/display/ShadowClone.vue2.mjs +4 -0
- package/es/components/display/use-shadow-target.mjs +76 -0
- package/es/components/form/FormActiveFilter.vue.mjs +7 -0
- package/es/components/form/FormActiveFilter.vue2.mjs +62 -0
- package/es/components/form/FormInput.vue.mjs +27 -0
- package/es/components/form/FormInput.vue2.mjs +4 -0
- package/es/components/form/FormInputShadowClone.vue.mjs +47 -0
- package/es/components/form/FormInputShadowClone.vue2.mjs +4 -0
- package/es/components/form/FormMain.vue.mjs +1 -1
- package/es/components/form/FormMain.vue2.mjs +5 -25
- package/es/components/form/FormSelectShadowClone.vue.mjs +57 -0
- package/es/components/form/FormSelectShadowClone.vue2.mjs +4 -0
- package/es/components/form/FormShadowCloneDispatch.vue.mjs +7 -0
- package/es/components/form/FormShadowCloneDispatch.vue2.mjs +74 -0
- package/es/components/form/FormSortSwitch.vue.mjs +7 -0
- package/es/components/form/FormSortSwitch.vue2.mjs +188 -0
- package/es/components/form/FormSortSwitchGroup.vue.mjs +7 -0
- package/es/components/form/FormSortSwitchGroup.vue2.mjs +68 -0
- package/es/components/form/FormUpload.vue.mjs +8 -0
- package/es/components/form/FormUpload.vue2.mjs +112 -0
- package/es/components/form/FormUploadAudio.vue.mjs +7 -0
- package/es/components/form/FormUploadAudio.vue2.mjs +88 -0
- package/es/components/form/FormUploadCard.vue.mjs +7 -0
- package/es/components/form/FormUploadCard.vue2.mjs +56 -0
- package/es/components/form/FormUploadFileInfo.vue.mjs +7 -0
- package/es/components/form/FormUploadFileInfo.vue2.mjs +36 -0
- package/es/components/form/FormUploadImage.vue.mjs +7 -0
- package/es/components/form/FormUploadImage.vue2.mjs +77 -0
- package/es/components/form/FormUploadTrigger.vue.mjs +7 -0
- package/es/components/form/FormUploadTrigger.vue2.mjs +34 -0
- package/es/components/form/FormUploadVideo.vue.mjs +7 -0
- package/es/components/form/FormUploadVideo.vue2.mjs +74 -0
- package/es/components/form/use-password-autofill.mjs +34 -0
- package/es/components/form/use-upload-state.mjs +98 -0
- package/es/components/list-layout/ListLayout.vue.mjs +1 -1
- package/es/components/list-layout/ListLayout.vue2.mjs +36 -9
- package/es/components/list-layout/use-active-filter.mjs +133 -0
- package/es/components/modal/ImagePreviewTrigger.vue.mjs +34 -0
- package/es/components/modal/ImagePreviewTrigger.vue2.mjs +4 -0
- package/es/components/modal/ModalImagePreview.vue.mjs +52 -0
- package/es/components/modal/ModalImagePreview.vue2.mjs +4 -0
- package/es/components/modal/ModalPorter.vue.mjs +49 -2
- package/es/components/modal/ModalShelf.vue.mjs +13 -4
- package/es/components/modal/ModalVideoPreview.vue.mjs +8 -0
- package/es/components/modal/ModalVideoPreview.vue2.mjs +93 -0
- package/es/components/modal/VideoPreviewTrigger.vue.mjs +7 -0
- package/es/components/modal/VideoPreviewTrigger.vue2.mjs +96 -0
- package/es/components/modal/modal-global-keys.mjs +11 -0
- package/es/components/modal/modal-global-symbol.mjs +6 -0
- package/es/components/modal/modal-shelf-core.mjs +53 -4
- package/es/components/table/TableEmpty.vue.mjs +36 -0
- package/es/components/table/TableEmpty.vue2.mjs +4 -0
- package/es/components/table/TableMain.vue.mjs +1 -1
- package/es/components/table/TableMain.vue2.mjs +21 -8
- package/es/components/view-layout/ViewLayout.vue.mjs +1 -1
- package/es/components/view-layout/ViewLayout.vue2.mjs +1 -1
- package/es/hooks/menus-dispatch.mjs +8 -3
- package/es/index.mjs +127 -91
- package/es/style.css +412 -33
- package/package.json +2 -2
- package/src/components/app-layout/docs/README-AppLayout.md +48 -0
- package/src/components/app-layout/docs/README-AppPage.md +40 -2
- package/src/components/display/README.md +9 -3
- package/src/components/display/docs/README-ShadowClone.md +75 -0
- package/src/components/form/README.md +15 -2
- package/src/components/form/docs/README-FormActiveFilter.md +57 -0
- package/src/components/form/docs/README-FormInput.md +66 -0
- package/src/components/form/docs/README-FormSelect.md +77 -0
- package/src/components/form/docs/README-FormShadowCloneDispatch.md +65 -0
- package/src/components/form/docs/README-FormSortSwitchGroup.md +131 -0
- package/src/components/form/docs/README-FormUpload.md +108 -0
- package/src/components/form/docs/README-FormUploadAudio.md +80 -0
- package/src/components/form/docs/README-FormUploadImage.md +83 -0
- package/src/components/form/docs/README-FormUploadVideo.md +82 -0
- package/src/components/list-layout/README.md +6 -2
- package/src/components/list-layout/docs/README-ListLayout.md +1 -0
- package/src/components/modal/README.md +7 -2
- package/src/components/modal/docs/README-ImagePreviewTrigger.md +78 -0
- package/src/components/modal/docs/README-ModalImagePreview.md +78 -0
- package/src/components/modal/docs/README-ModalPorter.md +10 -0
- package/src/components/modal/docs/README-ModalShelf.md +11 -2
- package/src/components/modal/docs/README-ModalVideoPreview.md +89 -0
- package/src/components/modal/docs/README-VideoPreviewTrigger.md +91 -0
- package/src/components/table/docs/README-TableMain.md +3 -0
- package/types/components/app-layout/AppLayout.vue.d.ts +31 -1
- package/types/components/app-layout/AppPage.vue.d.ts +7 -2
- package/types/components/app-layout/types.d.ts +25 -0
- package/types/components/display/ShadowClone.vue.d.ts +20 -0
- package/types/components/display/TabsTile.vue.d.ts +2 -2
- package/types/components/display/index.d.ts +8 -1
- package/types/components/display/types.d.ts +7 -0
- package/types/components/display/use-shadow-target.d.ts +9 -0
- package/types/components/form/FormActiveFilter.vue.d.ts +9 -0
- package/types/components/form/FormInput.vue.d.ts +3 -0
- package/types/components/form/FormInputShadowClone.vue.d.ts +7 -0
- package/types/components/form/FormSearch.vue.d.ts +1 -1
- package/types/components/form/FormSelectShadowClone.vue.d.ts +39 -0
- package/types/components/form/FormShadowCloneDispatch.vue.d.ts +44 -0
- package/types/components/form/FormSortSwitch.vue.d.ts +17 -0
- package/types/components/form/FormSortSwitchGroup.vue.d.ts +15 -0
- package/types/components/form/FormUpload.vue.d.ts +57 -0
- package/types/components/form/FormUploadAudio.vue.d.ts +30 -0
- package/types/components/form/FormUploadCard.vue.d.ts +24 -0
- package/types/components/form/FormUploadFileInfo.vue.d.ts +10 -0
- package/types/components/form/FormUploadImage.vue.d.ts +34 -0
- package/types/components/form/FormUploadTrigger.vue.d.ts +11 -0
- package/types/components/form/FormUploadVideo.vue.d.ts +34 -0
- package/types/components/form/index.d.ts +12 -1
- package/types/components/form/types.d.ts +158 -0
- package/types/components/form/use-password-autofill.d.ts +11 -0
- package/types/components/form/use-upload-state.d.ts +29 -0
- package/types/components/list-layout/ListLayout.vue.d.ts +3 -0
- package/types/components/list-layout/types.d.ts +16 -0
- package/types/components/list-layout/use-active-filter.d.ts +27 -0
- package/types/components/modal/ImagePreviewTrigger.vue.d.ts +41 -0
- package/types/components/modal/ModalConfirm.vue.d.ts +1 -1
- package/types/components/modal/ModalImagePreview.vue.d.ts +31 -0
- package/types/components/modal/ModalPorter.vue.d.ts +7 -0
- package/types/components/modal/ModalShelf.vue.d.ts +12 -3
- package/types/components/modal/ModalVideoPreview.vue.d.ts +40 -0
- package/types/components/modal/VideoPreviewTrigger.vue.d.ts +43 -0
- package/types/components/modal/index.d.ts +6 -1
- package/types/components/modal/modal-global-keys.d.ts +25 -0
- package/types/components/modal/modal-global-symbol.d.ts +8 -0
- package/types/components/modal/modal-shelf-core.d.ts +11 -3
- package/types/components/modal/modal-shelf-types.d.ts +50 -0
- package/types/components/table/TableEmpty.vue.d.ts +11 -0
- package/types/components/table/types.d.ts +11 -0
- package/types/components/view-layout/types.d.ts +1 -1
- package/types/injectInfo.json.d.ts +1 -1
- package/types/store/app.d.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# display 展示族
|
|
2
2
|
|
|
3
|
-
展示与交互原语:TabsMain(Tab 容器)/ ActionBtn 系列(确认闸门 + 自动 loading)/ 尺寸与高度工具(WatchSize / HeightProvider)/ BooleanTag
|
|
3
|
+
展示与交互原语:TabsMain(Tab 容器)/ ActionBtn 系列(确认闸门 + 自动 loading)/ 尺寸与高度工具(WatchSize / HeightProvider)/ BooleanTag / ShadowClone(影分身双渲染位)。
|
|
4
4
|
|
|
5
5
|
## 组件文档(docs/)
|
|
6
6
|
|
|
@@ -11,13 +11,19 @@
|
|
|
11
11
|
- [WatchSize](./docs/README-WatchSize.md) — 尺寸监听容器(mode / observeResize / debounce)
|
|
12
12
|
- [HeightProvider](./docs/README-HeightProvider.md) — 纯数值高度预算节点(available = viewportHeight − reserve)
|
|
13
13
|
- [BooleanTag](./docs/README-BooleanTag.md) — boolean 只读彩色标签
|
|
14
|
+
- [ShadowClone](./docs/README-ShadowClone.md) — 影分身(零 DOM 输出双渲染位:本体就地 + 分身 teleport,目标晚渲染自动等待)
|
|
14
15
|
|
|
15
16
|
## 关键类型
|
|
16
17
|
|
|
17
|
-
- `TabsMainProps` / `TabsMainItem` / `ActionBtnProps` / `ActionBtnConfirmConfig` / `ActionBtnConfigItem` / `ActionBtnGroupProps` / `ActionConfirmProps` / `BooleanTagProps`(经 `./types` 导出)
|
|
18
|
-
- 内部件不导出:`TabsHeader` / `TabsTile` / `TabsRefineFlow` / `TabsNaturalFlow` / `use-tabs-query-sync`
|
|
18
|
+
- `TabsMainProps` / `TabsMainItem` / `ActionBtnProps` / `ActionBtnConfirmConfig` / `ActionBtnConfigItem` / `ActionBtnGroupProps` / `ActionConfirmProps` / `BooleanTagProps` / `ShadowCloneProps`(经 `./types` 导出)
|
|
19
|
+
- 内部件不导出:`TabsHeader` / `TabsTile` / `TabsRefineFlow` / `TabsNaturalFlow` / `use-tabs-query-sync` / `use-shadow-target`
|
|
20
|
+
|
|
21
|
+
## 跨族依赖(被依赖)
|
|
22
|
+
|
|
23
|
+
- form 族 → display 族(单向):`FormSort` 依赖 `ShadowClone`(分身机制)、`FormActiveFilter` 依赖 `ActionBtn`(清除全部按钮)
|
|
19
24
|
|
|
20
25
|
## 范式页(apps/reference)
|
|
21
26
|
|
|
22
27
|
- `/display/tabs/showcase`(基础 + queryKey)、`/display/tabs/guide`(channel 嵌套最佳实践)、`/display/tabs/tile`(平铺)、`/display/tabs/fullpage`(顶级自撑)、`/display/tabs/nested-channel`
|
|
23
28
|
- `/display/action-btn/showcase`(16 场景)、`/display/action-btn-group/showcase`(5 场景)
|
|
29
|
+
- 影分身场景见 `/form/sort/showcase`(FormSort 分身到表格表头)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# ShadowClone(影分身)
|
|
2
|
+
|
|
3
|
+
> 零 DOM 输出双渲染位原语:插槽内容渲染两处——本体就地 + 分身 teleport 到 `to` 目标(`disabled` 关闭分身仅就地)。「分身」≠「瞬移」:官方 teleport 是搬移(源位置不留内容),本组件本体与分身同时存在。分身位内容可选 `clone` 具名槽**独立提供**(本体/分身可不同 props,如交互模式差异);未提供时 fallback 渲染默认槽(双份一致,向后兼容)。
|
|
4
|
+
> 范式页:`apps/reference/src/pages/display/shadow-clone/`(影分身专项展示)+ `apps/reference/src/pages/form/sort/showcase/`(FormSortSwitchGroup 排序分身到表格表头场景)。
|
|
5
|
+
|
|
6
|
+
## 定位
|
|
7
|
+
|
|
8
|
+
- **同一受控内容的多渲染位底层机制**:表单控件分身到表格表头(FormSortSwitchGroup `shadowClone` per-option 影分身)、配置化体系的「一处配置多处展示」等
|
|
9
|
+
- **独立裸用当**:任何「同一内容需要同时出现在两个位置」的场景(表头副本 / 悬浮副本等)
|
|
10
|
+
- **何时不用**:单处展示直接写;「搬移」语义用 Vue 原生 `<teleport>`
|
|
11
|
+
|
|
12
|
+
## 快速上手(最小可用)
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<ShadowClone to=".table-head">
|
|
16
|
+
<MySortWidget v-model="sortRules" />
|
|
17
|
+
</ShadowClone>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**要点**:
|
|
21
|
+
|
|
22
|
+
- `to` 传 CSS 选择器或 DOM 元素;**目标晚渲染是常态**(表格表头在表单下方)——组件内置 MutationObserver 等待目标出现后自动激活分身,零时序手控
|
|
23
|
+
- `to` 无效(空 / selector 未命中)时分身静默等待不挂载——**不会触发 Vue 的「Invalid Teleport target」warn**(peer vue ^3.4 无 teleport `defer`,此为自实现等价物)
|
|
24
|
+
- `disabled` 关闭分身(仅就地单处)
|
|
25
|
+
|
|
26
|
+
## 分身位独立内容(clone 具名槽)
|
|
27
|
+
|
|
28
|
+
本体与分身需要**不同 props / 内容**时(如排序本体整块循环、分身点小箭头),用 `clone` 具名槽独立提供分身内容:
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<ShadowClone to=".table-head">
|
|
32
|
+
<!-- 本体位:默认槽 -->
|
|
33
|
+
<FormSortSwitch v-model="dir" mode="cycle" />
|
|
34
|
+
<!-- 分身位:#clone 槽(未提供时 fallback 默认槽,双份一致) -->
|
|
35
|
+
<template #clone>
|
|
36
|
+
<FormSortSwitch v-model="dir" mode="dual-arrow" />
|
|
37
|
+
</template>
|
|
38
|
+
</ShadowClone>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **两处各自独立组件实例**(v-model 绑同一 ref 即同源同步、交互可不同)——与默认槽双份渲染同属「状态全外置」边界
|
|
42
|
+
- 未提供 `#clone` 时行为与旧版完全一致(分身位渲染默认槽内容)——**向后兼容,消费方可渐进升级**
|
|
43
|
+
|
|
44
|
+
## 使用边界([MUST] 消费方遵守)
|
|
45
|
+
|
|
46
|
+
- 两份 vnode 树 = **两个独立组件实例**——只适合「无内部状态 / 状态全外置的受控组件」(v-model 绑同一 ref 即同源同步);有内部状态组件会状态分叉
|
|
47
|
+
- 静态固定 id 内容双份渲染会撞 id(随机 id 各自生成不撞)——消费方负责
|
|
48
|
+
- 根类豁免(规则 17):组件无根元素(零 DOM 输出是语义核心),无 `dc-` 根类
|
|
49
|
+
|
|
50
|
+
## 依赖关系
|
|
51
|
+
|
|
52
|
+
- **被依赖**:form 族 `FormSortSwitchGroup`(`shadowClone` per-option 影分身,分身位 `#clone` 独立 mode)——form 族 → display 族单向依赖
|
|
53
|
+
- 内部件不导出:`use-shadow-target`(目标有效性判定 + MutationObserver 等待 hook)
|
|
54
|
+
|
|
55
|
+
## 测试
|
|
56
|
+
|
|
57
|
+
- 独立测试:`src/components/display/__tests__/ShadowClone.test.ts`(9 用例)——双渲染位 / 目标无效零 warn / MutationObserver 晚渲染自动激活 / disabled / Element 目标 / 空插槽 / **clone 槽 fallback 与独立内容**
|
|
58
|
+
- 集成消费:`FormSortSwitchGroup.test.ts`(per-option 分身、分身位 `#clone` 独立 mode)
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
62
|
+
|
|
63
|
+
### Props
|
|
64
|
+
|
|
65
|
+
| name | type | 默认 | 语义 |
|
|
66
|
+
| --- | --- | --- | --- |
|
|
67
|
+
| `to` | `string \| Element`(必填) | — | 分身 teleport 目标(CSS 选择器 / DOM 元素) |
|
|
68
|
+
| `disabled` | `boolean` | `false` | 关闭分身(仅就地渲染单处) |
|
|
69
|
+
|
|
70
|
+
### Slots
|
|
71
|
+
|
|
72
|
+
| name | 语义 |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `default` | 分身内容(本体 + 分身双渲染) |
|
|
75
|
+
| `clone` | 分身位**独立**内容(可选)——未提供时 fallback 渲染 `default` 槽(双份一致) |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# form 表单族
|
|
2
2
|
|
|
3
|
-
配置式表单核心(
|
|
3
|
+
配置式表单核心(13 组件,最大族):`list` 配置驱动渲染 / 校验 / 序列化,`data` 同引用绑定,generate / parse / stringify 三方法 round-trip。
|
|
4
4
|
|
|
5
5
|
## 组件文档(docs/)
|
|
6
6
|
|
|
@@ -10,7 +10,20 @@
|
|
|
10
10
|
- [FormSubmitBtn](./docs/README-FormSubmitBtn.md) — 提交按钮(validate → stringify → submitFn 管线)
|
|
11
11
|
- [FormItemNestForm](./docs/README-FormItemNestForm.md) — 嵌套子表单(C1,级联校验)
|
|
12
12
|
- [FormItemNestFormList](./docs/README-FormItemNestFormList.md) — 数组子表单(C4,行增删 + min/max)
|
|
13
|
-
-
|
|
13
|
+
- [FormActiveFilter](./docs/README-FormActiveFilter.md) — 生效筛选条件条(chips + × 移除 + 清除全部,纯 UI;投影逻辑在消费方 hook)
|
|
14
|
+
- [FormInput](./docs/README-FormInput.md) — 输入框原语(el-input 全透传 + password 自动填充治理;影分身版 FormInputShadowClone 表头漏斗)
|
|
15
|
+
- [FormSelect](./docs/README-FormSelect.md) — 选择器(options/remoteMethod/getOptions;影分身版 FormSelectShadowClone 表头漏斗)
|
|
16
|
+
- [FormSortSwitchGroup / FormSortSwitch](./docs/README-FormSortSwitchGroup.md) — 复合排序组 + 单字段排序切换器(group 有 key 视角 / switch 无 key;`mode` cycle 首击升序对齐主流 / dual-arrow 双三角;`textType` label/状态文字;`shadowClone` 影分身 per-option teleportTo;依赖 display 族 ShadowClone)
|
|
17
|
+
- [FormUpload](./docs/README-FormUpload.md) — 上传原语(ElUpload 封装,先传拿 URL 表单只提交 URL;`uploadFn` 注入不焊后端;上传中经 FORM_ITEM_CHANGE_LOADING 拦提交;进度 ElUpload 内置)
|
|
18
|
+
- [FormUploadImage](./docs/README-FormUploadImage.md) — 图片上传(薄封装:accept image/* + 方形缩略图卡片 + 点击直达放大 + 悬停删除)
|
|
19
|
+
- [FormUploadVideo](./docs/README-FormUploadVideo.md) — 视频上传(薄封装:accept video/* + 封面/占位 + 播放图标 + VideoPreviewTrigger 播放决策链)
|
|
20
|
+
- [FormUploadAudio](./docs/README-FormUploadAudio.md) — 音频上传(薄封装:accept audio/* + 内联 `<audio controls>` 播放条即时试听;**不建弹窗**——业界音频无 lightbox 形态)
|
|
21
|
+
- FormRadioGroup / FormTree / FormVerifyImage / FormVerifyCode — 文档待补
|
|
22
|
+
|
|
23
|
+
## 跨族依赖
|
|
24
|
+
|
|
25
|
+
- form 族 → display 族(单向):`FormSort` 依赖 `ShadowClone`(分身机制)、`FormActiveFilter` 依赖 `ActionBtn`(清除全部按钮)
|
|
26
|
+
- form 族 → modal 族(单向):`FormUploadImage` 依赖 `ImagePreviewTrigger`(点击直达放大)、`FormUploadVideo` 依赖 `VideoPreviewTrigger`(播放弹窗决策链)
|
|
14
27
|
|
|
15
28
|
## 关键类型与 helper
|
|
16
29
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# FormActiveFilter(生效筛选条件条)
|
|
2
|
+
|
|
3
|
+
> 当前已生效查询条件的投影展示条:条件 chips + 单项 × 移除 + 清除全部(可选)。纯 UI 组件——投影 / value→label / 表单值同步清除等逻辑在消费方 hook(ListLayout 内 `use-active-filter`)完成,本组件只收数据 + 发事件。
|
|
4
|
+
> 业界对标:SAP Fiori "Filter Feedback Bar" / react-admin `<FilterValue>` / MUI FilterChipBar。
|
|
5
|
+
> 范式页:`apps/reference/src/pages/list-layout/active-filter/`(ListLayout 集成场景);独立裸用见同页组件区。
|
|
6
|
+
|
|
7
|
+
## 定位
|
|
8
|
+
|
|
9
|
+
- **ListLayout 的生效条件展示位**:ListLayout 开 `formActiveFilter` 后,在表单卡片顶部一行渲染(条件条在上、表单在下),数据 = `use-active-filter` hook 从 query 投影的条目
|
|
10
|
+
- **独立裸用当**:任何「已生效筛选条件展示 + 移除」场景(非 ListLayout 体系、条件数据自持的页面/组件)
|
|
11
|
+
- **何时不用**:无生效条件概念的场景;仅需静态展示用 ElTag 直写
|
|
12
|
+
|
|
13
|
+
## 快速上手(最小可用)
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<FormActiveFilter
|
|
17
|
+
:filters="filters"
|
|
18
|
+
:allow-clear="true"
|
|
19
|
+
@remove="onRemove"
|
|
20
|
+
@clear="onClearAll"
|
|
21
|
+
/>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**要点**:
|
|
25
|
+
|
|
26
|
+
- `filters` 条目形状 `FormActiveFilterEntry`:`{ field, label, displayValue }`——`field` 是 query 字段名(× 移除事件的载荷),`label` 展示名,`displayValue` 展示值(枚举类应传 options 匹配后的 label,取不到传原值)
|
|
27
|
+
- × 移除 = `@remove(field)`;清除全部 = `@clear()`(仅 `allowClear` 开启时显示按钮)——事件是纯上抛,**同步清表单值 / 重查是消费方职责**
|
|
28
|
+
- **空态恒展示**:`filters` 为空时渲染灰字「暂无生效筛选条件」占位(行高与单条 tag 一致,新增生效条件不跳动);「清除全部」仅在至少一条生效条件时出现
|
|
29
|
+
|
|
30
|
+
## 能力边界 / 按需使用
|
|
31
|
+
|
|
32
|
+
- **默认即够用:`filters` 一个 prop 即为完整条件条**(chips + 单项 ×)。以下按需开:
|
|
33
|
+
- `allowClear`:默认关;仅当需要一键清空全部生效条件才开(通常与「清空后重查」配合)
|
|
34
|
+
- 单项移除始终可用(chips 自带 closable ×)——`allowClear` 只额外加「清除全部」按钮
|
|
35
|
+
- **value→label 不在组件内**:组件不持有表单字段 config(保持纯 UI)——投影逻辑放消费方 hook(ListLayout 的 `use-active-filter` 从 `config.props.options` 取 label,取不到原值兜底)
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
39
|
+
|
|
40
|
+
### Props
|
|
41
|
+
|
|
42
|
+
| name | type | 默认 | 语义 |
|
|
43
|
+
| --- | --- | --- | --- |
|
|
44
|
+
| `filters` | `FormActiveFilterEntry[]`(必填) | — | 生效条件条目(field / label / displayValue) |
|
|
45
|
+
| `allowClear` | `boolean` | `false` | 显示「清除全部」按钮(一键清空全部生效条件) |
|
|
46
|
+
|
|
47
|
+
### Emits
|
|
48
|
+
|
|
49
|
+
| name | 载荷 | 语义 |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `remove` | `field: string` | 点击单项 × ——消费方应移除 query 该字段 + 同步清表单值 + 重查 |
|
|
52
|
+
| `clear` | — | 点击清除全部——消费方应清空全部生效条件 + 重查 |
|
|
53
|
+
|
|
54
|
+
## 相关
|
|
55
|
+
|
|
56
|
+
- 投影与联动逻辑:`list-layout/use-active-filter.ts`(ListLayout 内部 hook,不导出)
|
|
57
|
+
- 集成组件:`ListLayout.formActiveFilter` / `ListLayout.allowClear`(见 list-layout docs)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# FormInput(输入框原语)
|
|
2
|
+
|
|
3
|
+
> el-input 全透传包装 + password 形态浏览器自动填充治理(`passwordAutoComplete` prop)。除治理点外 props / slots 全量透传 el-input,零收窄。
|
|
4
|
+
> 范式页:`apps/reference/src/pages/form/input/showcase/`(五形态对照 + 组合链路)。
|
|
5
|
+
|
|
6
|
+
## 定位
|
|
7
|
+
|
|
8
|
+
- **password 形态的浏览器自动填充治理点**:apiKey / 账号密码录入等非登录表单字段被 Chrome 误填时,用 `passwordAutoComplete` 治理
|
|
9
|
+
- **独立裸用当**:需要密码形态且与浏览器密码管理器交互受控的输入框
|
|
10
|
+
- **何时不用**:普通输入直接用 el-input;真登录页**接受**浏览器填充(用户主动保存 = 期望被填,拦它违背设计意图)
|
|
11
|
+
|
|
12
|
+
## 快速上手(最小可用)
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<FormInput v-model="secret" type="password" password-auto-complete="api-key" />
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**要点**:
|
|
19
|
+
|
|
20
|
+
- 字符串值(`api-key` / `new-password` / `off`)→ 密码输入框 `autocomplete` 设为此值。**默认推荐 `api-key`**——规范外词条 Chrome 不识别,实测全程未触发直接填充;`off` 是 el-input 密码形态默认值、Chrome 有意无视(不可靠);`new-password` 实测出现过直接填充
|
|
21
|
+
- `number N` → 不设置 autocomplete;透传 el-input 的 type 初始 `text`(无密码语义不触发填充),延迟 N ms 后恢复 `password`(避开 Chrome 加载期 autofill 探测窗口;点击填充拦不住,属浏览器正常交互)。text 窗口内组件内部屏蔽 EP `show-password` 强制坑(EP `showPassword=true` 会强制 type=password,恢复后显隐照常)
|
|
22
|
+
- 不传 → 不设置 autocomplete(保持 el-input 默认行为)
|
|
23
|
+
|
|
24
|
+
## 能力边界 / 按需使用
|
|
25
|
+
|
|
26
|
+
- **默认即够用:`passwordAutoComplete` 不传即为普通 el-input 包装**。以下按需开:
|
|
27
|
+
- `passwordAutoComplete="api-key"`:非登录表单密码字段防填充首选(规范外词条最可靠)
|
|
28
|
+
- `passwordAutoComplete={N}`(number):需要连「加载填充」也拦截时(api-key 词条已拦不住时);N=0 即挂载即切
|
|
29
|
+
- `show-password`:显隐切换照常透传(number 延迟窗口内被组件内部屏蔽、恢复后可用)
|
|
30
|
+
- **影分身(表头漏斗)用 `FormInputShadowClone`**(本组件 + 影分身包装,薄包装纯粹性——影分身能力不内嵌本组件):列表页表格头预埋容器内显示漏斗图标,点击 popover 弹输入框,同一 v-model 与本体同源同步(与 FormSelectShadowClone 统一漏斗语义;「表头漏斗 = 点这里筛选」)
|
|
31
|
+
- 实测反模式([MUST NOT] 重复踩):`autocomplete="off"`(Chrome 有意无视)/ `new-password`(有过直接填充记录)/ text→mounted 立即切换(Chrome 异步 autofill 补填)/ trap input(Chrome 可见性检查穿透)——全部实测证伪,组件只提供上述两个可靠机制
|
|
32
|
+
|
|
33
|
+
## 依赖关系
|
|
34
|
+
|
|
35
|
+
- form 族内部组件,无跨族依赖(仅透传 el-input);影分身版 `FormInputShadowClone` 依赖内部件 `FormShadowCloneDispatch` → display 族 `ShadowClone`(详见 README-FormShadowCloneDispatch.md)
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
39
|
+
|
|
40
|
+
### Props
|
|
41
|
+
|
|
42
|
+
| name | type | 默认 | 语义 |
|
|
43
|
+
| --- | --- | --- | --- |
|
|
44
|
+
| `type` | `string` | — | 透传 el-input(显式声明以判定密码形态) |
|
|
45
|
+
| `showPassword` | `boolean` | — | 透传 el-input 显隐切换(同上) |
|
|
46
|
+
| `passwordAutoComplete` | `"api-key" \| "new-password" \| "off" \| number` | — | 密码形态自动填充治理(见上) |
|
|
47
|
+
| 其余 | — | — | 全量 `$attrs` 透传 el-input(v-model / placeholder / clearable / 插槽等) |
|
|
48
|
+
|
|
49
|
+
### FormInputShadowClone(影分身版)
|
|
50
|
+
|
|
51
|
+
> 内部经 `FormShadowCloneDispatch` 实现:default 与 clone 两插槽各写一份 `<FormInput v-model="同一值" />` 同源绑定驱动双处视图一致;高亮判定在**本组件内部**(默认规则 + `isHighlighted` 覆盖)→ 经 dispatch `highlighted` 展示在漏斗 + 插槽作用域暴露。
|
|
52
|
+
|
|
53
|
+
| name | type | 默认 | 语义 |
|
|
54
|
+
| --- | --- | --- | --- |
|
|
55
|
+
| `modelValue` | `string \| number` | — | v-model(透传 FormInput;本体与分身弹层同源) |
|
|
56
|
+
| `shadowClone` | `boolean` | `false` | 影分身开关(本体 + 分身 label+漏斗,点击 popover 弹输入框,同一 v-model 同源同步) |
|
|
57
|
+
| `teleportTo` | `string \| Element` | — | 分身目标容器(表头预埋唯一选择器;`shadowClone` 时生效,未配置不分身) |
|
|
58
|
+
| `label` | `string` | — | 分身位字段文字(表头列名;label + 漏斗整块展示、高亮整块——表格 headerRender 只需留 teleportTo 容器,列名由分身自带) |
|
|
59
|
+
| `isHighlighted` | `(value: unknown) => boolean` | 默认判定 | 分身高亮判定方法(非必传),入参 modelValue;默认 = 非 `null` / 非 `undefined` / 非空字符串 → 高亮(label + 漏斗整块) |
|
|
60
|
+
| 其余 | — | — | 全量 `$attrs` 透传 FormInput(密码治理等能力完整继承) |
|
|
61
|
+
|
|
62
|
+
### Slots
|
|
63
|
+
|
|
64
|
+
| name | 语义 |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| 全部 | 透传 el-input 插槽(prefix / suffix / prepend / append 等) |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# FormSelect(选择器)
|
|
2
|
+
|
|
3
|
+
> el-select 包装(本地 options / 远程搜索 remoteMethod / 异步 getOptions)+ option 插槽自定义渲染 + 影分身(`shadowClone` 表头漏斗,点击 popover 弹选择器,同一 v-model 同源同步)。
|
|
4
|
+
> 范式页:`apps/reference/src/pages/list-layout/sort/`(状态列表头漏斗弹选择器)。
|
|
5
|
+
|
|
6
|
+
## 定位
|
|
7
|
+
|
|
8
|
+
- **配置化表单的选择字段**:FormMain / FormSearch 配置接入(`render: FormSelect`),options 业务注入
|
|
9
|
+
- **远程搜索**:`remoteMethod` 传入即自动开 filterable + remote(输入触发远程查询)
|
|
10
|
+
- **异步取选项**:`getOptions` 挂载后拉取
|
|
11
|
+
- **何时不用**:静态小选项集用原生 el-select 即可
|
|
12
|
+
|
|
13
|
+
## 快速上手(最小可用)
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<FormSelect v-model="status" :options="[{ label: '启用', value: 1 }, { label: '禁用', value: 0 }]" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**要点**:
|
|
20
|
+
|
|
21
|
+
- `options`(本地静态)/ `remoteMethod`(远程搜索)/ `getOptions`(异步拉取)三选一提供选项源
|
|
22
|
+
- `modelValue` = `OptionItem["value"]`;选中项经 `detailChange` 上抛完整选项(immediate 首发)
|
|
23
|
+
- `option` 插槽自定义选项渲染(`{ data }` 作用域)
|
|
24
|
+
- 其余 props / 事件全量 `$attrs` 透传 el-select(placeholder / clearable / size 等)
|
|
25
|
+
|
|
26
|
+
## 能力边界 / 按需使用
|
|
27
|
+
|
|
28
|
+
- **默认即够用:options + v-model 即为完整选择器**。以下按需开:
|
|
29
|
+
- `remoteMethod`:远程搜索(自动 filterable + remote,输入触发查询)
|
|
30
|
+
- `getOptions`:挂载后异步拉取选项
|
|
31
|
+
- `itemCls`:选项类名
|
|
32
|
+
- **影分身(表头漏斗)用 `FormSelectShadowClone`**(本组件 + 影分身包装,薄包装纯粹性):列表页表格头预埋容器内显示漏斗图标,点击 popover 弹选择器,同一 v-model 与本体同源同步(与 FormInputShadowClone 统一漏斗语义:「表头漏斗 = 点这里筛选」)
|
|
33
|
+
|
|
34
|
+
## 依赖关系
|
|
35
|
+
|
|
36
|
+
- form 族内部组件,无跨族依赖(仅透传 el-select);影分身版 `FormSelectShadowClone` 依赖内部件 `FormShadowCloneDispatch` → display 族 `ShadowClone`(详见 README-FormShadowCloneDispatch.md)
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
40
|
+
|
|
41
|
+
### Props
|
|
42
|
+
|
|
43
|
+
| name | type | 默认 | 语义 |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `modelValue` | `OptionItem["value"]` | — | v-model |
|
|
46
|
+
| `options` | `OptionItem[]` | `[]` | 本地选项集 |
|
|
47
|
+
| `remoteMethod` | `(query?) => Promise<OptionItem[]>` | — | 远程搜索(自动 filterable + remote) |
|
|
48
|
+
| `itemCls` | `string` | — | 选项类名 |
|
|
49
|
+
| `getOptions` | `() => Promise<OptionItem[]>` | — | 挂载后异步拉取选项 |
|
|
50
|
+
| 其余 | — | — | 全量 `$attrs` 透传 el-select(placeholder / clearable / size 等) |
|
|
51
|
+
|
|
52
|
+
### FormSelectShadowClone(影分身版)
|
|
53
|
+
|
|
54
|
+
> 内部经 `FormShadowCloneDispatch` 实现:default 与 clone 两插槽各写一份 `<FormSelect v-model="同一值" />` 同源绑定驱动双处视图一致;高亮判定在**本组件内部**(默认规则 + `isHighlighted` 覆盖)→ 经 dispatch `highlighted` 展示在漏斗 + 插槽作用域暴露。
|
|
55
|
+
|
|
56
|
+
| name | type | 默认 | 语义 |
|
|
57
|
+
| --- | --- | --- | --- |
|
|
58
|
+
| `modelValue` | `OptionItem["value"]` | — | v-model(透传 FormSelect;本体与分身弹层同源) |
|
|
59
|
+
| `shadowClone` | `boolean` | `false` | 影分身开关(本体 + 分身 label+漏斗,点击 popover 弹选择器,同一 v-model 同源同步) |
|
|
60
|
+
| `teleportTo` | `string \| Element` | — | 分身目标容器(表头预埋唯一选择器;`shadowClone` 时生效,未配置不分身) |
|
|
61
|
+
| `label` | `string` | — | 分身位字段文字(表头列名;label + 漏斗整块展示、高亮整块——表格 headerRender 只需留 teleportTo 容器,列名由分身自带) |
|
|
62
|
+
| `isHighlighted` | `(value: unknown) => boolean` | 默认判定 | 分身高亮判定方法(非必传),入参 modelValue;默认 = 非 `null` / 非 `undefined` / 非空字符串 → 高亮(label + 漏斗整块) |
|
|
63
|
+
| 其余 | — | — | 全量 `$attrs` 透传 FormSelect(options/remoteMethod/option 插槽等能力完整继承) |
|
|
64
|
+
|
|
65
|
+
### Emits
|
|
66
|
+
|
|
67
|
+
| name | 载荷 | 语义 |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `update:modelValue` | `OptionItem["value"]` | v-model 上抛(本体与分身弹层同源) |
|
|
70
|
+
| `detailChange` | `OptionItem \| undefined` | 选中项详情变更(immediate 首发) |
|
|
71
|
+
| 其余 | el-select events | `$attrs` 透传(change / blur 等) |
|
|
72
|
+
|
|
73
|
+
### Slots
|
|
74
|
+
|
|
75
|
+
| name | 语义 |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `option` | 选项自定义渲染(`{ data }` 作用域;本体与分身弹层内选择器共用) |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# FormShadowCloneDispatch(form 族 · 影分身骨架:漏斗开关 + popup)
|
|
2
|
+
|
|
3
|
+
## 定位
|
|
4
|
+
|
|
5
|
+
form 族系**通用影分身骨架**——本体就地渲染(default 槽)+ 分身位(label 字段文字 + 漏斗按钮整块,表头筛选惯例入口,点击漏斗 popover 弹层)+ popup 内容(clone 槽)。
|
|
6
|
+
|
|
7
|
+
**职责收敛**:双渲染位编排 + 漏斗展示(含高亮标识)+ popup 骨架。**零值逻辑**——不持有 v-model、不知道值本身;值由消费方插槽内容自己持有(同源绑定驱动双处视图一致)。
|
|
8
|
+
|
|
9
|
+
漏斗只是「影分身触发 popover 的开关」,非筛选语义组件。
|
|
10
|
+
|
|
11
|
+
## 快速上手(最小可用)
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<FormShadowCloneDispatch
|
|
15
|
+
shadow-clone
|
|
16
|
+
teleport-to=".head-slot"
|
|
17
|
+
label="标题"
|
|
18
|
+
:highlighted="hasValue"
|
|
19
|
+
>
|
|
20
|
+
<!-- 本体位:实际组件形态(消费方写死绑定,无需 scope) -->
|
|
21
|
+
<FormInput v-model="keyword" />
|
|
22
|
+
<!-- clone 槽(popup 内容):不传即自动显示 default 同款 -->
|
|
23
|
+
<template #clone>
|
|
24
|
+
<FormInput v-model="keyword" size="small" />
|
|
25
|
+
</template>
|
|
26
|
+
</FormShadowCloneDispatch>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 能力边界 / 按需使用
|
|
30
|
+
|
|
31
|
+
- **影分身**:`shadowClone` + `teleportTo` 开启 → 分身位 = **label(prop 传入)+ 漏斗按钮整块**(对齐排序 chip 形态:自带字段文字,表格 headerRender 只需留 teleportTo 容器、无需再写列名);未开启/未配置 teleportTo 时仅渲染 default 槽(单份,零行为变化)
|
|
32
|
+
- **高亮**:分身整块(label + 漏斗)按 `highlighted` 展示激活态(同 primary);插槽作用域同步暴露 `{ highlighted }` 供消费方在插槽内**同级处理**(包外层/加提示等),不影响插槽内实际组件(FormInput/FormSelect)的纯粹性——判定逻辑上移消费方(默认规则 + `isHighlighted` 方法覆盖,见 FormInputShadowClone)
|
|
33
|
+
- **晚渲染目标**:teleport 目标晚出现(表头在表单下方)由内部 ShadowClone(display 族)MutationObserver 等待自动激活,无需手控
|
|
34
|
+
|
|
35
|
+
## 依赖关系
|
|
36
|
+
|
|
37
|
+
- display 族 `ShadowClone`(影分身双渲染位机制,单向依赖);form 族 `FormInputShadowClone` / `FormSelectShadowClone` 基于本组件实现
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
41
|
+
|
|
42
|
+
### Props
|
|
43
|
+
|
|
44
|
+
| name | type | 默认 | 语义 |
|
|
45
|
+
| --- | --- | --- | --- |
|
|
46
|
+
| `shadowClone` | `boolean` | `false` | 影分身开关(本体 default 槽 + 分身 label+漏斗双渲染位,点击漏斗 popover 弹层展示 clone 槽内容) |
|
|
47
|
+
| `teleportTo` | `string \| Element` | — | 分身目标容器(表头预埋唯一选择器;`shadowClone` 时生效,未配置不分身) |
|
|
48
|
+
| `label` | `string` | — | 分身位字段文字(表头列名;label + 漏斗整块展示、高亮整块——不传仅漏斗,向后兼容) |
|
|
49
|
+
| `highlighted` | `boolean` | `false` | 分身整块高亮标识(外部判定后传入,如筛选有值;插槽作用域同步暴露) |
|
|
50
|
+
| `popoverWidth` | `number \| string` | `220` | popover 弹层宽度(表头空间内弹层,默认容纳输入框/选择器) |
|
|
51
|
+
|
|
52
|
+
### Emits
|
|
53
|
+
|
|
54
|
+
无(零值逻辑:v-model 由消费方组件持有,经插槽同源绑定驱动双处视图一致)。
|
|
55
|
+
|
|
56
|
+
### Slots
|
|
57
|
+
|
|
58
|
+
| name | 作用域参数 | 语义 |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `default` | `{ highlighted: boolean }` | 本体位内容(实际组件形态;一般直接写死绑定,无需 scope——scope 仅在需要拿高亮标识做同级处理时用) |
|
|
61
|
+
| `clone` | `{ highlighted: boolean }` | **popup 弹层内容**(漏斗点击后展示);**默认 fallback = default 插槽内容**(不传即与本体同形态) |
|
|
62
|
+
|
|
63
|
+
### Exposes
|
|
64
|
+
|
|
65
|
+
无(内部 ShadowClone / ElPopover 实例不对外暴露)。
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# FormSortSwitchGroup(复合排序组)& FormSortSwitch(单字段排序切换器)
|
|
2
|
+
|
|
3
|
+
> 两组件分工:**`FormSortSwitch`** = 单字段排序切换器(纯状态/展示件,v-model = 方向值 `"asc" | "desc" | undefined`,**无 key——不知道自己的字段**);**`FormSortSwitchGroup`** = 多字段容器(**key 视角在 group**,v-model = 有序 `FormSortRule[]`,依赖 Switch 组装)。交互 `mode` 双模式;`shadowClone` 影分身(per-option `teleportTo`);`textType` 展示文本模式(label / 状态文字)。
|
|
4
|
+
> 范式页:`apps/reference/src/pages/form/sort/showcase/`(FormMain 配置化接入 + 影分身 + 两模式对照)。
|
|
5
|
+
|
|
6
|
+
## 定位
|
|
7
|
+
|
|
8
|
+
- **复合排序表单元素**:FormMain / FormSearch 配置化接入(`render: FormSortSwitchGroup`),序列化交给消费方 `stringify`(如 `field:dir` 逗号复合串)
|
|
9
|
+
- **单字段排序开关**:直接裸用 `FormSortSwitch`(v-model 绑方向值,无需关心字段身份)
|
|
10
|
+
- **何时不用**:单字段单选排序(后端单 key 排序)用 ElSelect / 原生排序即可
|
|
11
|
+
|
|
12
|
+
## 快速上手(最小可用)
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<FormSortSwitchGroup :options="options" v-model="sortRules" />
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**要点**:
|
|
19
|
+
|
|
20
|
+
- `options` 业务注入(`{ field, label }[]`,条目可带非必传 `teleportTo`)——**组件不内置业务字段**
|
|
21
|
+
- Group v-model 协议 = 有序 `FormSortRule[]`(`{ field, dir: "asc" | "desc" }`,顺序即优先级);空数组 = 无排序
|
|
22
|
+
- FormMain 接入时 `stringify` 序列化(如 `list.map(r => `${r.field}:${r.dir}`).join(",")`);表单模型持有数组
|
|
23
|
+
- 状态全外置(v-model),组件零内部状态 → 可安全影分身双渲染
|
|
24
|
+
- **默认 `mode: "cycle"`**(首击升序,对齐主流)——零配置即主流交互
|
|
25
|
+
|
|
26
|
+
## 组件分工(Switch / Group)
|
|
27
|
+
|
|
28
|
+
| | `FormSortSwitch` | `FormSortSwitchGroup` |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| 职责 | 单字段 chip:方向状态 + 交互 + 展示(label / 状态文字) | 多字段容器:options 拆包 → N 个 Switch + 按 field 重组 v-model 数组 |
|
|
31
|
+
| v-model | 方向值 `"asc" \| "desc" \| undefined`(**无 key**,默认 `undefined`) | 有序 `FormSortRule[]`(**有 key**,顺序即优先级) |
|
|
32
|
+
| 是否知道自己的字段 | **不知道**(直接作表单元素无需知道;作 group 的 item 由 group 知道) | 知道(key 视角持有者) |
|
|
33
|
+
| 内部状态 | 零(状态全外置) | 零(组装逻辑纯派生) |
|
|
34
|
+
|
|
35
|
+
## 交互模式(mode)
|
|
36
|
+
|
|
37
|
+
| mode | 默认 | 交互语义 | 适用 |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `"cycle"` | ✅ | **点击整块三态循环**:`undefined → 升序 → 降序 → 取消`(循环往复)。**首击升序对齐主流**(Ant / Element Plus / MUI / Syncfusion 均为 asc first) | 默认全覆盖;与主流表头排序交互同构,EP 生态用户零学习成本 |
|
|
40
|
+
| `"dual-arrow"` | — | **上下双三角独立点击**:点 ↑ = 升序(升序态再点 = 取消)、点 ↓ = 降序(降序态再点 = 取消);方向互斥切换(激活一侧时点另一侧切向,优先级不动);点击 label 不触发 | 多字段复合排序、操作者需要「点一次即确定方向」的确定性交互场景 |
|
|
41
|
+
|
|
42
|
+
**cycle 状态转换表(核心机制)**:每次点击 = `NEXT[当前值]` 查表取下一个,**绝不依赖点击次数 / 历史推断**——状态可能被外部(影分身另一处操作 / 双向 v-model 同步)改写,计数推断会失配:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const NEXT = {
|
|
46
|
+
undefined: "asc", // 首击升序
|
|
47
|
+
asc: "desc",
|
|
48
|
+
desc: undefined, // 取消
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
例:cycle 点击第一下 = 升序;此时影分身(dual-arrow)关闭了升序(状态回 `undefined`);cycle 再点一下 = **仍从 `undefined` 出发 = 升序**(非计数推断的 desc)。
|
|
53
|
+
|
|
54
|
+
- 两模式 **v-model 协议完全一致**(方向值 / 规则数组),模式纯属 UI 交互层——切换 mode 对数据零影响、零迁移成本
|
|
55
|
+
- **模式视觉辨识**(一眼可判当前交互):dual-arrow 三角默认**中灰**(WCAG 1.4.11 对比度 ≥3:1 达标 + 「可点」信号)+ hover primary + 激活点亮对应三角;cycle 三角保持 placeholder 浅灰纯指示(整块 hover 变色是它的辨识信号)——两模式视觉语言分离
|
|
56
|
+
- 三角尺寸 12px(对齐 [Fluent UI 排序箭头规格](https://github.com/microsoft/fluentui/issues/25706))+ 伪元素透明热区扩展(命中面 > 视觉图标)
|
|
57
|
+
- 激活视觉两模式一致:chip primary 高亮 + 优先级序号 + 方向指示(cycle 整块点亮、dual-arrow 点亮对应三角)
|
|
58
|
+
|
|
59
|
+
## 展示文本模式(textType)
|
|
60
|
+
|
|
61
|
+
chip 上的文本内容两选:
|
|
62
|
+
|
|
63
|
+
| textType | 默认 | 展示内容 | 适用 |
|
|
64
|
+
| --- | --- | --- | --- |
|
|
65
|
+
| `"state"` | ✅ | 状态文字:「**默认**」(未排序)/「**升序**」/「**降序**」 | 独立作为表单元素(自身即状态展示);`label` 可不传 |
|
|
66
|
+
| `"label"` | — | 字段名(options 的 label) | **group 的 item 即此模式**(group 显式设置) |
|
|
67
|
+
|
|
68
|
+
## 影分身(shadowClone,能力内聚在 FormSortSwitch)
|
|
69
|
+
|
|
70
|
+
- **影分身是控件级通用能力,内聚在 `FormSortSwitch`**:任何排序开关(独立或 group 的 item)都可自带分身——`shadowClone` 开关 + `teleportTo` 目标 + `teleportMode` 分身交互模式
|
|
71
|
+
- **group 纯编排**:`shadowClone` 总开关 + `teleportMode` 透传 + **`FormSortOption` 条目级 `teleportTo`**(非必传)透传——配置了目标的条目分身到该目标(ShadowClone 双处渲染、**同一 model 同源同步**,操作任一处同步);**未配置 `teleportTo` 的条目不分身**(仅本体渲染)
|
|
72
|
+
- `teleportTo` 目标不限于表头,看指向哪个元素(`string \| Element`);表格体系可按列头容器逐列配置
|
|
73
|
+
- **分身位交互模式独立于本体**:`teleportMode`(默认 `"dual-arrow"` = 点小箭头升/降序);数据与本体同一 v-model,仅交互模式不同
|
|
74
|
+
- 目标晚渲染(表头容器在表单下方)无需手控:ShadowClone 内置 MutationObserver 等待目标出现后自动激活分身(「合适的时机打出去」)
|
|
75
|
+
- 优先级序号:chip 内右置小号 primary 数字(克制样式——不悬浮溢出 chip 外)
|
|
76
|
+
|
|
77
|
+
## 依赖关系
|
|
78
|
+
|
|
79
|
+
- **依赖**:display 族 `ShadowClone`(影分身机制,经 `FormSortSwitch` 内聚使用)——form 族 → display 族单向依赖
|
|
80
|
+
- 内部组装:`FormSortSwitchGroup` 依赖 `FormSortSwitch`(同族基础件,对外导出、可独立使用)
|
|
81
|
+
|
|
82
|
+
## API
|
|
83
|
+
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
84
|
+
|
|
85
|
+
### FormSortSwitchGroup(复合排序组)
|
|
86
|
+
|
|
87
|
+
#### Props
|
|
88
|
+
|
|
89
|
+
| name | type | 默认 | 必填 | 语义 |
|
|
90
|
+
| --- | --- | --- | --- | --- |
|
|
91
|
+
| `options` | `FormSortOption[]` | — | ✅ | 排序字段选项(`{ field, label, teleportTo? }[]`,业务注入;`teleportTo` 为影分身目标,非必传) |
|
|
92
|
+
| `modelValue` | `FormSortRule[]` | `[]` | — | 有序排序规则(v-model,顺序即优先级) |
|
|
93
|
+
| `mode` | `"cycle" \| "dual-arrow"` | `"cycle"` | — | 本体 item 交互模式 |
|
|
94
|
+
| `shadowClone` | `boolean` | `false` | — | 影分身开关(配置了 `teleportTo` 的条目分身到目标,同 model 同源同步) |
|
|
95
|
+
| `teleportMode` | `"cycle" \| "dual-arrow"` | `"dual-arrow"` | — | 分身 item 交互模式(独立于本体;默认点小箭头升/降序) |
|
|
96
|
+
|
|
97
|
+
#### Emits
|
|
98
|
+
|
|
99
|
+
| name | 载荷 | 语义 |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| `update:modelValue` | `FormSortRule[]` | v-model 上抛(item 激活 / 切向 / 取消 → 按 field 重组后新数组) |
|
|
102
|
+
|
|
103
|
+
#### Slots / Expose
|
|
104
|
+
|
|
105
|
+
无(状态全外置,组装逻辑纯派生)。
|
|
106
|
+
|
|
107
|
+
### FormSortSwitch(单字段排序切换器)
|
|
108
|
+
|
|
109
|
+
#### Props
|
|
110
|
+
|
|
111
|
+
| name | type | 默认 | 必填 | 语义 |
|
|
112
|
+
| --- | --- | --- | --- | --- |
|
|
113
|
+
| `modelValue` | `"asc" \| "desc" \| undefined` | `undefined` | — | v-model 方向值(三态:undefined=默认无排序 / asc / desc;**默认 undefined 非 null**) |
|
|
114
|
+
| `mode` | `"cycle" \| "dual-arrow"` | `"cycle"` | — | 交互模式 |
|
|
115
|
+
| `textType` | `"label" \| "state"` | `"state"` | — | 展示文本(state=「默认/升序/降序」状态文字 / label=字段名) |
|
|
116
|
+
| `label` | `string` | — | 仅 `textType="label"` | 字段显示名(state 模式可不传) |
|
|
117
|
+
| `showOrder` | `boolean` | `false` | — | 是否显示优先级序号(group 在 options>1 时传 true) |
|
|
118
|
+
| `order` | `number` | — | — | 优先级序号值(1-based,`showOrder` 时显示) |
|
|
119
|
+
| `shadowClone` | `boolean` | `false` | — | 影分身开关(本体就地 + 分身 teleport 到 `teleportTo`,同一 v-model 同源同步) |
|
|
120
|
+
| `teleportTo` | `string \| Element` | — | `shadowClone` 时 | 分身目标容器(未配置不分身) |
|
|
121
|
+
| `teleportMode` | `"cycle" \| "dual-arrow"` | `"dual-arrow"` | — | 分身位交互模式(独立于本体 mode) |
|
|
122
|
+
|
|
123
|
+
#### Emits
|
|
124
|
+
|
|
125
|
+
| name | 载荷 | 语义 |
|
|
126
|
+
| --- | --- | --- |
|
|
127
|
+
| `update:modelValue` | `"asc" \| "desc" \| undefined` | v-model 上抛(cycle 查 NEXT 表 / dual-arrow 方向两态;`undefined`=取消) |
|
|
128
|
+
|
|
129
|
+
#### Slots / Expose
|
|
130
|
+
|
|
131
|
+
无(状态全外置,零内部状态 → 可安全影分身双渲染)。
|