@done-coding/admin-core 0.30.0 → 0.30.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/bridge/badge.mjs +7 -1
- package/es/components/app-layout/AppPage.vue.mjs +1 -1
- package/es/components/app-layout/AppPage.vue2.mjs +15 -8
- package/es/components/app-layout/app-page-geometry.mjs +7 -3
- package/es/components/app-layout/use-slot-misuse-warn.mjs +40 -0
- package/es/components/data-view/DataGridView.vue.mjs +1 -1
- package/es/components/data-view/DataGridView.vue2.mjs +83 -32
- package/es/components/data-view/DataGridViewCard.vue.mjs +41 -0
- package/es/components/data-view/DataGridViewCard.vue2.mjs +4 -0
- package/es/components/data-view/InfiniteListView.vue.mjs +1 -1
- package/es/components/data-view/InfiniteListView.vue2.mjs +38 -11
- package/es/components/display/BadgeMark.vue.mjs +1 -1
- package/es/components/display/BadgeMark.vue2.mjs +31 -33
- package/es/components/display/use-badge.mjs +37 -33
- package/es/components/form/FormGroupTitle.vue.mjs +1 -1
- package/es/components/form/FormItem.vue.mjs +1 -1
- package/es/components/form/FormItemNestForm.vue.mjs +1 -1
- package/es/components/form/FormItemNestFormList.vue.mjs +1 -1
- package/es/components/form/FormTree.vue.mjs +5 -30
- package/es/components/form/FormTree.vue2.mjs +30 -1
- package/es/components/form/FormUpload.vue.mjs +1 -1
- package/es/components/modal/ModalPorter.vue.mjs +2 -0
- package/es/components/modal/use-slot-misuse-warn.mjs +22 -0
- package/es/components/page-layout/AppPageListDetailSplit.vue.mjs +1 -1
- package/es/components/page-layout/AppPageListDetailSplit.vue2.mjs +7 -7
- package/es/components/view-layout/ViewLayout.vue.mjs +1 -1
- package/es/components/view-layout/ViewLayout.vue2.mjs +71 -91
- package/es/components/view-layout/ViewLayoutToolbar.vue.mjs +7 -0
- package/es/components/view-layout/ViewLayoutToolbar.vue2.mjs +189 -0
- package/es/config/slot-region.mjs +23 -1
- package/es/hooks/use-custom-breakpoint.mjs +12 -2
- package/es/hooks/use-is-dev.mjs +16 -0
- package/es/hooks/use-theme-apply.mjs +2 -2
- package/es/index.mjs +90 -88
- package/es/style.css +138 -87
- package/package.json +2 -2
- package/src/bridge/docs/README.md +34 -4
- package/src/components/app-layout/docs/README-AppPage.md +68 -0
- package/src/components/data-view/docs/README-DataGridView.md +83 -1
- package/src/components/data-view/docs/README-DataListView.md +5 -2
- package/src/components/display/docs/README-BadgeMark.md +102 -41
- package/src/components/form/README.md +14 -0
- package/src/components/form/docs/README-FormItemNestForm.md +3 -0
- package/src/components/form/docs/README-FormItemNestFormList.md +3 -0
- package/src/components/form/docs/README-FormUpload.md +3 -0
- package/src/components/modal/docs/README-ModalPorter.md +26 -0
- package/src/components/page-layout/docs/README-AppPageListDetailLayout.md +1 -1
- package/src/components/view-layout/docs/README-ViewLayout.md +152 -9
- package/src/hooks/docs/README.md +37 -1
- package/types/bridge/badge.d.ts +38 -2
- package/types/components/app-layout/AppPage.vue.d.ts +16 -0
- package/types/components/app-layout/app-page-geometry.d.ts +26 -2
- package/types/components/app-layout/use-slot-misuse-warn.d.ts +19 -0
- package/types/components/data-view/DataGridView.vue.d.ts +9 -0
- package/types/components/data-view/DataGridViewCard.vue.d.ts +25 -0
- package/types/components/data-view/types.d.ts +63 -0
- package/types/components/display/BadgeMark.vue.d.ts +9 -8
- package/types/components/display/use-badge.d.ts +22 -14
- package/types/components/modal/use-slot-misuse-warn.d.ts +21 -0
- package/types/components/view-layout/ViewLayout.vue.d.ts +16 -0
- package/types/components/view-layout/ViewLayoutToolbar.vue.d.ts +52 -0
- package/types/components/view-layout/types.d.ts +56 -0
- package/types/config/slot-region.d.ts +12 -0
- package/types/hooks/use-custom-breakpoint.d.ts +1 -12
- package/types/hooks/use-is-dev.d.ts +24 -0
- package/types/injectInfo.json.d.ts +1 -1
|
@@ -84,14 +84,33 @@
|
|
|
84
84
|
但守两条纪律 —— **通栏**(零圆角)· **不加高**(零上下呼吸)。
|
|
85
85
|
此前「工具条成卡」被否的根因不是「有面」,而是面顺带塞进 12px 内呼吸把 32px 的条撑到 56px。
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
不补第二份的话文字读起来像贴着色条(实测只剩 5px)。
|
|
87
|
+
横向呼吸**左右同值**:各 **一份**(甲方 2026-09-19:「对齐右侧 都是 8」)。
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
⚠️ 此前左缘是**两份**,理由是「左缘那条 3px 主色条占住了第一层留白,只给一份时
|
|
90
|
+
文字距色条只剩 5px、读起来像贴着」。那条理由有两个问题:**「5 不够 ⇒ 那就 ×2」是拍的、
|
|
91
|
+
不是推的**;而且**内容区根本没有色条**,那多出来的一份在内容区完全没有出处。
|
|
92
|
+
⇒ 现在色条**已从左侧文字带挪到顶缘**(见下「主色起点标记」),左缘不再有占用者,
|
|
93
|
+
左右各取一份、每一分都有出处。
|
|
94
|
+
|
|
95
|
+
🔴 **这一份是 toolbar 与内容区\*\*共用\*\*的一个值**(源码 `padXPx`),[MUST NOT] 只给其中一侧加倍:
|
|
96
|
+
它标识的是**整个组件的横向留白**、不是 toolbar 一个人的,只给它加倍会让**标题比正文右移一份**
|
|
92
97
|
(实测错开 8px,甲方 2026-09-17 排查色条内外侧时撞出)。标题与正文左对齐是排版底线,
|
|
93
|
-
[MUST NOT]
|
|
94
|
-
|
|
98
|
+
[MUST NOT] 为装饰破坏它。
|
|
99
|
+
|
|
100
|
+
### 主色起点标记(`&::before`)
|
|
101
|
+
|
|
102
|
+
甲方 2026-09-16 要的是「给这条**结构分区**一个可辨识的**起点**」。原先做成左缘一条 3px 竖条,
|
|
103
|
+
它站在文字带里 ⇒ 要么文字贴着它、要么左缘得多让一份。现改为**左上角一小段横条**
|
|
104
|
+
(高 3px、长三份、贴 `top:0 left:0`),意图原样保住、左侧文字带彻底空出来。
|
|
105
|
+
|
|
106
|
+
🔴 **[MUST NOT] 改用负偏移把它挂到盒外去「让出整一份」**:实测 `ViewLayout` /
|
|
107
|
+
`.app-page-shim` / `.app-page` 四层左缘**全在同一条线上**(逐层 `padding-left: 0`)——
|
|
108
|
+
盒外没有余量,负偏移会画到**宿主**身上,与「[MUST NOT] 反向伸手改宿主」的既定边界冲突。
|
|
109
|
+
|
|
110
|
+
🔴 仍走**伪元素 absolute** 而非 `border-top`:本条的高度账量的是 `clientHeight`
|
|
111
|
+
(含 padding、不含 border),border 会直接进高度账、吃掉 refine 的可用高。
|
|
112
|
+
|
|
113
|
+
`appBar` 形态下它**不出现**(四项 gate 之一,见下)。
|
|
95
114
|
|
|
96
115
|
## 底部区(`#bottom`)
|
|
97
116
|
|
|
@@ -125,9 +144,8 @@
|
|
|
125
144
|
| 段 | 归属 | 值 |
|
|
126
145
|
| --- | --- | --- |
|
|
127
146
|
| toolbar ↔ 内容 | **内容区的上 padding** | 一份 |
|
|
128
|
-
| 内容区上 / 下
|
|
129
|
-
|
|
|
130
|
-
| toolbar 右侧 | toolbar 的右 padding | 一份 |
|
|
147
|
+
| 内容区上 / 下 | 内容区自己的 padding(`box-sizing: border-box`) | 一份 |
|
|
148
|
+
| **组件横向留白**(toolbar 与内容区**共用**一个值 `padXPx`) | 两者各自的左右 padding | 一份(**左右同值**) |
|
|
131
149
|
|
|
132
150
|
「一份」= 间距阶梯的**模块档**(`APP_LAYOUT_GAP_CONFIG.size` × 密度系数 × 1,默认 **8px**),
|
|
133
151
|
随 `bridge.APP_LAYOUT_GAP_CONFIG.size` 与主题密度档自动缩放,[MUST NOT] 在消费侧写死像素补偿。
|
|
@@ -168,6 +186,121 @@
|
|
|
168
186
|
- `AppPageListDetailLayout` 的 `#detailBottom` **自动开**(用了那个槽就是要贴底),
|
|
169
187
|
仍可经 `viewLayoutProps.fillHeight` 关掉。
|
|
170
188
|
|
|
189
|
+
## `appBar` —— toolbar 的第二形态:移动端 app bar(opt-in)
|
|
190
|
+
|
|
191
|
+
甲方 2026-09-19 口述:「为啥不使用真 header?因为**当前 toolbar 支持展示 title 很平滑**,
|
|
192
|
+
没必要强行对齐。」⇒ 本能力是给现有 toolbar **加一个形态开关**,
|
|
193
|
+
[MUST NOT] 另造 `AppBar` 组件、[MUST NOT] 去动 `AppHeader`(那是布局四区的全局顶栏,不是页面级的)。
|
|
194
|
+
|
|
195
|
+
```vue
|
|
196
|
+
<ViewLayout
|
|
197
|
+
:api="api"
|
|
198
|
+
title="订单详情"
|
|
199
|
+
appBar
|
|
200
|
+
:back="() => router.back()"
|
|
201
|
+
:moreOptions="[{ label: '分享', value: 'share' }, { label: '删除', value: 'remove' }]"
|
|
202
|
+
:onMoreSelect="(item) => handle(item.value)"
|
|
203
|
+
/>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 开关打开后变了什么(逐条)
|
|
207
|
+
|
|
208
|
+
| # | 变化 | 关闭时 |
|
|
209
|
+
| --- | --- | --- |
|
|
210
|
+
| ① | 左缘 3px 主色条**去掉** | 色条在 |
|
|
211
|
+
| ② | 下边缘加 `box-shadow` | 无投影 |
|
|
212
|
+
| ③ | `min-height: 44px` | 无高度下限(内容自撑) |
|
|
213
|
+
| ④ | 给了 `back` ⇒ 渲染左侧返回箭头(热区 ≥44×44) | **传了也不渲染** |
|
|
214
|
+
| ⑤ | 给了 `moreOptions` / `onMore` / `#more` ⇒ 渲染右侧「更多」位 | **传了也不渲染** |
|
|
215
|
+
|
|
216
|
+
### 🔴 四项全部由开关 gate,[MUST NOT] 漏 gate 任何一项
|
|
217
|
+
|
|
218
|
+
甲方明确:「左侧的 `back`、右侧的三个点、chrome 最小高度 44、无圆角,
|
|
219
|
+
**都是通过 props 开启移动端模式才有的**」。
|
|
220
|
+
|
|
221
|
+
⇒ **不开 `appBar` 时**:`back` 传了也不渲染箭头、`moreOptions` 传了也不渲染 ⋮、
|
|
222
|
+
高度不加 44 下限、圆角处理一律不变。
|
|
223
|
+
漏 gate 的典型写法是「传了就生效」,而漏了之后在默认形态下**看起来只是多了个按钮、不会报错** ——
|
|
224
|
+
故守卫逐项带了阴性对照。
|
|
225
|
+
|
|
226
|
+
### 🔴 只由消费方显式开启,[MUST NOT] 自动检测
|
|
227
|
+
|
|
228
|
+
甲方原话:「是**开启**,不是检测是移动端」。
|
|
229
|
+
|
|
230
|
+
本形态 [MUST NOT] 用 `matchMedia` / UA / 视口宽 / 容器断点去「自动判断是移动端就切」:
|
|
231
|
+
同一套 core 要服务多形态应用(见产品定位),**「窄就是移动端」不成立**
|
|
232
|
+
(分栏详情 / 侧栏 / 弹窗里都窄),自动切会让消费方在完全没配置的情况下突然换一套 chrome。
|
|
233
|
+
|
|
234
|
+
### 高度是 `min-height: 44px`,不是固定高
|
|
235
|
+
|
|
236
|
+
甲方两次修订后的终稿。**为什么不是 `height: 44px`**:固定高会把「44」这个**后果**写成
|
|
237
|
+
**原因**,且本组件的 chrome 卡方案当初被毙的根因正是「面顺带塞进 12px 内呼吸、
|
|
238
|
+
把 32px 的条撑到 56px」—— 硬钉是同一动作换个数字;内容真超过 44 时还会被压。
|
|
239
|
+
**为什么不是「纯内容自撑」**:会让有 `back` 的页(≈44)与没有的页(≈32)头部高度不一致,
|
|
240
|
+
而真移动端 header 是恒高的,来回切页看得见跳动。
|
|
241
|
+
|
|
242
|
+
`min-height` 两头都吃到:**下限恒 44**(视觉恒高,也正好容得下 44×44 触控热区),
|
|
243
|
+
**内容超出照常撑高**。
|
|
244
|
+
🔴 本形态下它是必须项,[MUST NOT] 以「条不加高」纪律为由删掉 —— 那条约束的是**默认形态**。
|
|
245
|
+
|
|
246
|
+
### 右侧「更多」位:插槽 + 配置驱动菜单
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
<span class="…__more" @click="…"> ← 点击绑这里,热区靠它的 padding 撑到 ≥44×44
|
|
250
|
+
<slot name="more"><MoreFilled /></slot> ← 默认 ⋮,插槽可换
|
|
251
|
+
</span>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
- ⋮ 取 element-plus 的 `MoreFilled`。⚠️ v0.30 删掉的是 core **自绘**的 icon 族,
|
|
255
|
+
EP 图标集照常可用,[MUST NOT] 因此又自绘一个。
|
|
256
|
+
- 菜单复用 `ElDropdown`,[MUST NOT] 自研浮层。
|
|
257
|
+
- **渲染条件**:`moreOptions`(非空)**或** `onMore` **或** `#more` 插槽,三者有其一即渲染;
|
|
258
|
+
**三者皆无则整块不渲染** —— [MUST NOT] 渲一个点不动的 ⋮。
|
|
259
|
+
- **位置**:在右区**最末**(导航 / `rightExtraButtons` / `AutoRefreshGroup` 之后)。
|
|
260
|
+
⚠️ appBar 形态**不会**自动隐藏右区既有内容 —— 那是没被要求的行为变更;
|
|
261
|
+
移动端 header 里按钮多显得挤,是消费方自己少配的事。
|
|
262
|
+
|
|
263
|
+
### 🔴 两个回调各自单义,[MUST NOT] 合成一个带可选参数的
|
|
264
|
+
|
|
265
|
+
| 回调 | 何时可能触发 | 入参 |
|
|
266
|
+
| --- | --- | --- |
|
|
267
|
+
| `onMoreSelect(item)` | **配了** `moreOptions` ⇒ 点击开菜单,选中某项 | **恒有**,是整条 item 配置(不是 `value`) |
|
|
268
|
+
| `onMore()` | **没配** `moreOptions` ⇒ 点击直接触发,不出菜单 | 无 |
|
|
269
|
+
|
|
270
|
+
两者**由配置互斥**。之所以不留单回调:消费方写代码时**静态就知道**自己配没配菜单,
|
|
271
|
+
可选参数会强迫他处理一个在他那份配置里**根本不可能发生**的分支;
|
|
272
|
+
且文档只能靠脚注补救(「没配菜单时 item 为 undefined」)——
|
|
273
|
+
**需要脚注解释的签名通常是该拆了**。
|
|
274
|
+
|
|
275
|
+
### ⚠️ `#more` 插槽的双触发坑
|
|
276
|
+
|
|
277
|
+
点击绑在**外层 `span`** 上 ⇒ 插槽内容若自带点击(比如往里塞了 `ActionBtn`),
|
|
278
|
+
其事件会冒泡到 `span`、与回调**同时触发**。
|
|
279
|
+
|
|
280
|
+
⇒ 契约:**`#more` 的内容按「哑内容」设计(图标 / 文字),点击统一走外层**。
|
|
281
|
+
要自己接管点击就**别传 `onMore` / `moreOptions`**,或在插槽内 `@click.stop`。
|
|
282
|
+
|
|
283
|
+
### 关于「去圆角」:本组件内**没有圆角可去**(已实测)
|
|
284
|
+
|
|
285
|
+
从 toolbar 一路向上到 `<body>` 的祖先链**逐层 `border-radius` 都是 `0`**
|
|
286
|
+
(toolbar 自己早就写死 `border-radius: 0`:「条贴边通栏」)。
|
|
287
|
+
⇒ `appBar` 形态在常态落点(`AppPage` 默认槽 / 独立使用)下**不需要任何去圆角动作**。
|
|
288
|
+
|
|
289
|
+
唯一在圆角的是 **`AppPage` 四向槽的 shim**(`#top`/`#bottom`/`#left`/`#right`,实测 `4px`)——
|
|
290
|
+
那属于**宿主**,`ViewLayout` [MUST NOT] 反向去改它,也 [MUST NOT] 用负 margin 挣脱宿主 padding
|
|
291
|
+
(会让高度账与几何同时失真)。
|
|
292
|
+
|
|
293
|
+
**要贴边时的出口**:那圈圆角是**随背景画的** ⇒ 把该槽的 `topBg` / `bottomBg` / `leftBg` /
|
|
294
|
+
`rightBg` 传 `"transparent"`,圆角即不可见(用现成 prop、零新增 API);
|
|
295
|
+
要连背景一起保留又想直角,则消费方自行覆盖该槽 shim 的 `border-radius`。
|
|
296
|
+
|
|
297
|
+
### 高度账仍然成立
|
|
298
|
+
|
|
299
|
+
toolbar 在 `HeightProvider` 的 `#header` 槽、经 `WatchSize` 量 `clientHeight` 得 reserve。
|
|
300
|
+
本形态改高(箭头热区 + 44 下限)是**被量到的**,机制上安全。
|
|
301
|
+
🔴 阴影 [MUST] 用 `box-shadow`(不占布局),[MUST NOT] 用 `border-bottom`(占宽高账)
|
|
302
|
+
或 margin(`clientHeight` 抓不到)。refine 零溢出在「开 / 关 × 有 back / 无 back」四种组合下都实测过。
|
|
303
|
+
|
|
171
304
|
## API
|
|
172
305
|
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
173
306
|
|
|
@@ -189,6 +322,11 @@
|
|
|
189
322
|
| `showNavigation` | `boolean?` | `true` | 是否显示内置「上一条 / 下一条」导航。⚠️ **真正的显隐判据是可选 inject 探测**:只有置于 `AppPageListDetailLayout` 内才渲染,单独使用 ViewLayout 时无论本值为何都不渲染(老用法零变化);本 prop 用于在门面内显式关掉 |
|
|
190
323
|
| `leftExtraButtons` | `ViewLayoutButtonConfig[]` | `[]` | 左侧额外按钮(`ActionBtnGroup` 配置,ctx = `{ loading, refresh }`,`default-size="small"` 对齐 table-toolbar) |
|
|
191
324
|
| `rightExtraButtons` | `ViewLayoutButtonConfig[]` | `[]` | 右侧额外按钮(置于 AutoRefreshGroup 之前) |
|
|
325
|
+
| `appBar` | `boolean?` | `false` | **移动端 app bar 形态**(见上):去色条 + 下边缘阴影 + `min-height:44px`,并**解锁** `back` / 更多位。🔴 只由消费方显式开,[MUST NOT] 自动检测 |
|
|
326
|
+
| `back` | `(() => void)?` | — | 返回回调;**仅 `appBar` 下**渲染左侧箭头(热区 ≥44×44)。不开 appBar 时传了也不渲染 |
|
|
327
|
+
| `moreOptions` | `ViewLayoutMoreOption[]?` | — | 更多菜单项(`{ label, value }`);**仅 `appBar` 下**生效。配了即点击开 `ElDropdown` |
|
|
328
|
+
| `onMoreSelect` | `((item: ViewLayoutMoreOption) => void)?` | — | 选中菜单项,入参**恒是整条 item 配置**。仅在配了 `moreOptions` 时可能触发 |
|
|
329
|
+
| `onMore` | `(() => void)?` | — | **没配** `moreOptions` 时点击更多位直接触发(不出菜单)。与 `onMoreSelect` 由配置互斥 |
|
|
192
330
|
|
|
193
331
|
### Slots
|
|
194
332
|
|
|
@@ -197,6 +335,7 @@
|
|
|
197
335
|
| 默认 | `{ data, loading, refresh, viewportHeight, fetchSeq }`(`ViewLayoutScope<R>`) | 展示内容;PanelMain 或自由编排皆可;viewportHeight refine 时给可用高(**已扣内容区自身 padding**)、自然流 undefined;`fetchSeq` = **成功**拉取次数(失败不递增),供下游懒加载块判「该重拉了」 |
|
|
198
336
|
| `#header` | `{ data, loading }` | 标题行(见上「标题行」段);不传且无 `title` 时不渲染 |
|
|
199
337
|
| `#bottom` | `{ data, loading, fetchSeq }` | 底部区:refine 固定在底部(计入 reserve)/ 自然流平铺在内容之后;不传不渲染。比 `#header` 多 `fetchSeq`(本槽放操作条,提交后要判「真的重拉成功了」) |
|
|
338
|
+
| `#more` | 无 | **仅 `appBar` 下**:替换右侧「更多」位的内容(默认 `MoreFilled` ⋮)。⚠️ 点击绑在外层 `span` 上 ⇒ 内容按**哑内容**设计,[MUST NOT] 在里面再挂点击(会与回调双触发) |
|
|
200
339
|
|
|
201
340
|
### 内置上/下一条导航(仅列表详情范式内出现)
|
|
202
341
|
|
|
@@ -224,6 +363,10 @@
|
|
|
224
363
|
- **指望 `#bottom` 默认就贴容器底**:默认不贴(内容盒只有上限、不定高)——要贴底开 `fillHeight`
|
|
225
364
|
- **为了贴底把 `max-height` 改写成 `height`**:[MUST NOT]——那波及所有 refine 页面,是本 prop 存在的理由掉
|
|
226
365
|
- **在消费侧写死像素补偿 toolbar / 内容区的间距**:[MUST NOT]——间距由 gap 阶梯派生,写死会在改 `gap` / 换密度档时脱钩
|
|
366
|
+
- **指望 `back` / `moreOptions` 不开 `appBar` 也生效**:[MUST NOT]——四项能力**全部由开关 gate**,不开时传了也不渲染(甲方明确要求)
|
|
367
|
+
- **往 `#more` 插槽里塞带点击的组件**:[MUST NOT]——点击绑在外层 `span`,会与 `onMore` / 菜单双触发;插槽内容按哑内容设计
|
|
368
|
+
- **指望 `appBar` 自动在窄屏打开**:[MUST NOT]——只由消费方显式开(甲方:「是开启,不是检测是移动端」);分栏详情 / 侧栏 / 弹窗里都窄,「窄 = 移动端」不成立
|
|
369
|
+
- **让 `ViewLayout` 去关宿主的圆角**:[MUST NOT] 跨组件伸手,也 [MUST NOT] 用负 margin 挣脱宿主 padding;`AppPage` 四向槽的圆角由消费方把该槽 `*Bg` 传 `"transparent"` 自行处理
|
|
227
370
|
- **toolbar 不含表格能力全集**:对齐的是 table-toolbar 的**结构与视觉惯例**(左右分栏 + extra 按钮 + AutoRefreshGroup),[MUST NOT] 期待导出 / 批量下载 / 视图切换等表格特有能力出现在 ViewLayout——需要表格能力用 `ListLayout` / `TableMain`
|
|
228
371
|
|
|
229
372
|
## 关联
|
package/src/hooks/docs/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| `useActivated` | 激活态 hook:mounted/activated/deactivated/unmounted 四时机**直接派发** watchFn(`activatedInfo.isActivated` 分流),卸载必派发 | **组件内「随激活态绑解」副作用一律用它**(绑解成对写一处,天然覆盖 KeepAlive 失活/卸载);发布库组件 [MUST] 用它(无宿主假设) |
|
|
8
8
|
| `useFeelSize` | 感知元素尺寸(ResizeObserver):`watchDom(dom)` / `unwatchDom()` + `sizeInfo` | 需要感知某元素宽高变化 |
|
|
9
9
|
| `useBreakpoint` | 视口断点:xs<768 / sm≥768 / md≥992 / lg≥1200 / xl≥1920(matchMedia,SSR 守护) | 响应式 span 默认走视口(与 ElCol 同引擎) |
|
|
10
|
-
| `useCustomBreakpoint` | 容器宽断点:`useCustomBreakpoint()`
|
|
10
|
+
| `useCustomBreakpoint` | 容器宽断点:`useCustomBreakpoint()`(出 `elRef` / `activeBreakpoint` / `measured`)+ `resolveBreakpointByWidth(width)` + `resolveRootEl`(EP 栅格同源阈值) | **容器断点**(非视口):FormMain `layoutByContainer`、compact 搜索等 |
|
|
11
11
|
| `useObserveSize` | 激活态感知 RO 观测原语:`getTarget` / `onResize` / `enabled` / `debounce`(默认 100ms,leading+trailing) | 需要「捕获渲染后尺寸变化」(CSS 折叠/异步撑开),WatchSize `observeResize` 底层 |
|
|
12
12
|
| `useChannelViewportHeight` | 视口可用最大高解析:`viewportHeight` > scope 链(parentChannel 定向/就近)> fallback;返回 `viewportHeightFinal` + `nearestScope` | 列表/表格/弹窗的高度计算核心消费契约 |
|
|
13
13
|
| `useCoreThemeApply` | 主题挂值:JS → root CSS var(`--dc-core-*` + `--el-*` 双命名空间)+ **全局底**(`:root{background}`)+ elevation 三档(底 `--el-bg-color-page` / 面 `--el-bg-color`=bodyColor / 抬升面 `--dc-core-surface`+`--el-bg-color-overlay`)+ `buildRhythmCss`(density/motion 节奏) | 由 AppLayout 启动;业务一般不直接调 |
|
|
@@ -48,6 +48,42 @@ const { viewportHeightFinal } = useChannelViewportHeight({ scope: "my-scope" });
|
|
|
48
48
|
- `useActivated` 详细语义见 `docs/specs/` 相关任务文档与 CLAUDE.md 规则 21
|
|
49
49
|
- 断点体系:`useBreakpoint`(视口)与 `useCustomBreakpoint`(容器)双源,见 FormMain `layoutByContainer` 文档
|
|
50
50
|
|
|
51
|
+
## `useCustomBreakpoint` 量到容器之前用什么档
|
|
52
|
+
|
|
53
|
+
### 🔴 第一帧**必然**是估计值,这点改不掉
|
|
54
|
+
|
|
55
|
+
Vue 的模板 ref 要到**第一次 render 之后**才有值,而 `activeBreakpoint` 在第一次 render
|
|
56
|
+
时就要被读走(它决定 span)⇒ **首帧没有元素可量**。
|
|
57
|
+
⇒ [MUST NOT] 声称 / 期待「首帧即容器实际档」;能改的只是**估得准不准**。
|
|
58
|
+
|
|
59
|
+
(顺带纠一处常见误解:卡点**不是**「要等 `ResizeObserver` 回调」——
|
|
60
|
+
`attach()` 在建 RO **之前**就同步 `evaluate` 了一次,且那个 watcher 是 `flush:"post"` + `immediate`。)
|
|
61
|
+
|
|
62
|
+
### 估计值 = **视口档**(原先是写死的 `"lg"`)
|
|
63
|
+
|
|
64
|
+
| 依据 | 说明 |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| 是上界、且对通栏容器**精确** | 容器恒为视口的后代;多数页面的容器就是通栏 ⇒ 首帧估计值即终态值,零重排 |
|
|
67
|
+
| 与「关掉这个功能」完全一致 | 视口档正是 `layoutByContainer` 关闭时会用的那个档 ⇒ 未量到之前**开着不会比关着更差**(原实现会:通栏 `xl` 容器首帧被按 `lg` 排) |
|
|
68
|
+
| 不是布局自反馈 | 视口宽是外部给定量,与本组件解算出的布局无关 —— 本仓踩过一次自反馈(`AppPage` 反测自身可用宽算 gutter),这条单向 [MUST] 保持 |
|
|
69
|
+
|
|
70
|
+
🔴 [MUST NOT] 改回任何**写死的档位**:常量对「不是该档」的容器一律是错的,只是错的方向不同。
|
|
71
|
+
|
|
72
|
+
⚠️ **窄栏仍会经历一次重排**(如侧栏容器 `xs`、视口 `xl`)——
|
|
73
|
+
那是上面那条「首帧必然是估计值」的必然结果,不是遗漏。
|
|
74
|
+
|
|
75
|
+
### `measured`:区分「估计」与「实测」
|
|
76
|
+
|
|
77
|
+
`activeBreakpoint` 当前这个值**是不是量自容器**。一旦量到就恒为 `true`
|
|
78
|
+
(解绑 / 失活后值仍是那次实测的结果)。
|
|
79
|
+
|
|
80
|
+
🔴 语义是**值的来源**,不是「RO 此刻连着没有」 ⇒ [MUST NOT] 在 `detach` 里把它复位成
|
|
81
|
+
`false`:那等于告诉消费方「这是个估计值」,而它明明是实测值。
|
|
82
|
+
|
|
83
|
+
拿不到视口宽(SSR / 脱离文档的 iframe,`innerWidth` 为 `0`)⇒ 退回 `"lg"`。
|
|
84
|
+
🔴 判据 [MUST] 落在**宽度值**上而非只判 `typeof window`:
|
|
85
|
+
`0` 直接喂给 `resolveBreakpointByWidth` 会静默得到 `"xs"` —— 一个看着合理实则凭空的档。
|
|
86
|
+
|
|
51
87
|
## elevation 三档怎么取值(`useCoreThemeApply`)
|
|
52
88
|
|
|
53
89
|
| 档 | CSS var | 取值 |
|
package/types/bridge/badge.d.ts
CHANGED
|
@@ -89,6 +89,22 @@ export type BadgeEntry = {
|
|
|
89
89
|
* @example { kind: "new", description: "批量导出…", version: 2 }
|
|
90
90
|
*/
|
|
91
91
|
version?: string | number;
|
|
92
|
+
/**
|
|
93
|
+
* 角标**显不显示**;缺省 = 跟随全局默认 {@link CoreBadgeModule.defaultVisible}(本身缺省 `true`)。
|
|
94
|
+
*
|
|
95
|
+
* 动因:徽标当初是拿来做新手引导的,有了 `forge-plugin-guide` 之后**不再必须显示**。
|
|
96
|
+
*
|
|
97
|
+
* 🔴 **「配置了但不展示」与「没配置」是两回事**(这正是本字段存在的理由):
|
|
98
|
+
* 前者照常渲染 `ElBadge` + `data-dc-badge-key` 挂点,引导插件**仍能定位**;
|
|
99
|
+
* 后者渲染裸插槽、连挂点都没有。⇒ 要藏角标 [MUST] 用本字段,
|
|
100
|
+
* [MUST NOT] 改成「把这条 key 从表里删掉」或在消费侧 `v-if` 掉 —— 那会连锚点一起没掉。
|
|
101
|
+
*
|
|
102
|
+
* 🔴 **遮挡档({@link BADGE_MASK_KINDS},现仅 `locked`)拒绝隐藏**:本字段对它无效,
|
|
103
|
+
* 全局默认的「不展示」也不作用到它,dev 下会 `console.warn` 一句。
|
|
104
|
+
* 依据:遮挡是**功能**不是资讯 —— 藏了只会落进「点不动又没说明的按钮」
|
|
105
|
+
* 或「未开通却能点」两种更坏的形态之一。
|
|
106
|
+
*/
|
|
107
|
+
visible?: boolean;
|
|
92
108
|
} & ({
|
|
93
109
|
/** 数字角标 */
|
|
94
110
|
kind: "count";
|
|
@@ -112,9 +128,14 @@ export type BadgeEntry = {
|
|
|
112
128
|
kind: "locked";
|
|
113
129
|
}
|
|
114
130
|
/**
|
|
115
|
-
* **伪标 /
|
|
131
|
+
* **伪标 / 纯锚点**:角标**恒隐藏**,只在 DOM 上留一个带 key 的挂点,
|
|
116
132
|
* 供 `forge-plugin-guide` 这类消费方**定位**到这个宿主。
|
|
117
133
|
*
|
|
134
|
+
* 与 {@link BadgeEntry.visible} `false` 的关系([MUST] 按此口径,[MUST NOT] 留两套说法):
|
|
135
|
+
* **两者都保留、语义不同** —— 本档是「这里**本来就没有标**」(kind 无资讯语义 + 恒隐藏),
|
|
136
|
+
* `visible:false` 是「**有标**,只是此刻不显示」。两者**共用同一套藏法**
|
|
137
|
+
* (0 尺寸 + `overflow:hidden` + 事件屏蔽),[MUST NOT] 各走一种机制。
|
|
138
|
+
*
|
|
118
139
|
* 用途:想给某个菜单项 / 按钮做新手引导,但它本身**没有**「新 / 更新」之类的标要显示。
|
|
119
140
|
* [MUST NOT] 为此硬挂一个 `new` 标——那会在界面上多出一个用户看不懂的角标。
|
|
120
141
|
*
|
|
@@ -125,7 +146,7 @@ export type BadgeEntry = {
|
|
|
125
146
|
| {
|
|
126
147
|
kind: "anchor";
|
|
127
148
|
} | {
|
|
128
|
-
/**
|
|
149
|
+
/** 自定义标:内置七档不够用时才用 */
|
|
129
150
|
kind: "custom";
|
|
130
151
|
/** 标签文案 */
|
|
131
152
|
text: string;
|
|
@@ -149,6 +170,14 @@ export declare const BADGE_MASK_KINDS: readonly ["locked"];
|
|
|
149
170
|
export interface BridgeBadgeInit {
|
|
150
171
|
/** 初始标记表(如随版本发布的静态 NEW 标);缺省空表 */
|
|
151
172
|
marks?: BadgeMarkMap;
|
|
173
|
+
/**
|
|
174
|
+
* 角标显不显示的**全局默认**,缺省 `true`(展示)。
|
|
175
|
+
*
|
|
176
|
+
* 缺省取 `true` 是刻意的:本开关是 additive,**[MUST NOT] 改变现有下游观感**;
|
|
177
|
+
* 把默认关成不展示是消费方的选择。逐条 {@link BadgeEntry.visible} 恒优先
|
|
178
|
+
* (与本仓所有 config-hook 同口径:显式 > 默认)。
|
|
179
|
+
*/
|
|
180
|
+
defaultVisible?: boolean;
|
|
152
181
|
}
|
|
153
182
|
/**
|
|
154
183
|
* 徽标注册表模块(bridge 公开面 `bridge.badge`)。
|
|
@@ -165,6 +194,13 @@ export interface CoreBadgeModule {
|
|
|
165
194
|
set: (key: string, entry: BadgeEntry) => void;
|
|
166
195
|
/** 单点移除 */
|
|
167
196
|
remove: (key: string) => void;
|
|
197
|
+
/**
|
|
198
|
+
* 角标显不显示的全局默认(响应式只读,缺省 `true`)。
|
|
199
|
+
* 逐条 {@link BadgeEntry.visible} 恒优先;遮挡档不受它影响。
|
|
200
|
+
*/
|
|
201
|
+
readonly defaultVisible: Readonly<ShallowRef<boolean>>;
|
|
202
|
+
/** 改全局默认(也可在 `createCoreBridge({ badge: { defaultVisible } })` 初始化时给) */
|
|
203
|
+
setDefaultVisible: (visible: boolean) => void;
|
|
168
204
|
}
|
|
169
205
|
/** bridge 徽标 hook 工厂返回(聚合到 `bridge.badge`) */
|
|
170
206
|
export interface BridgeBadgeHook {
|
|
@@ -34,6 +34,22 @@ type __VLS_Props = {
|
|
|
34
34
|
leftObserveResize?: boolean;
|
|
35
35
|
/** right 插槽 RO 观测开关 */
|
|
36
36
|
rightObserveResize?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* `#left` 槽的**显式宽度**(CSS 长度串);缺省不写 ⇒ 槽宽**跟内容走**(shrink-to-fit,
|
|
39
|
+
* 与本 prop 引入前逐字一致)。
|
|
40
|
+
*
|
|
41
|
+
* 🔴 **槽内内容要用百分比宽时 [MUST] 改用本 prop**(vr8kd2):侧槽是 `position: fixed`
|
|
42
|
+
* 且只给了 `left` ⇒ 宽度跟内容走,而**百分比在这种包含块上没有稳定基数** ——
|
|
43
|
+
* 算内在尺寸时百分比按 `auto` 处理、槽被撑到 max-content,之后百分比才按那个
|
|
44
|
+
* 被撑出来的宽解析 ⇒ 解出来远小于槽 ⇒ **槽里剩一大片死白,且随内容变大**。
|
|
45
|
+
* 放到本 prop 上则包含块是**视口**,百分比有稳定且不循环的基数。
|
|
46
|
+
*
|
|
47
|
+
* ⚠️ 写在这里的宽度会被 `WatchSize` 量到并回写进内容区的让位 padding(实测跟得上),
|
|
48
|
+
* 几何链不受影响。
|
|
49
|
+
*/
|
|
50
|
+
leftWidth?: string;
|
|
51
|
+
/** `#right` 槽的显式宽度(CSS 长度串);语义同 {@link leftWidth} */
|
|
52
|
+
rightWidth?: string;
|
|
37
53
|
/**
|
|
38
54
|
* 超宽屏适配:默认 slot 内容限宽居中(默认关)。开启后内容盒宽收敛到 `contentMaxWidth`
|
|
39
55
|
* 并居中于「两侧槽之间的可用区」,同时同步收窄对后代公布的内容几何(inset / viewport-width)。
|
|
@@ -64,14 +64,38 @@ export declare const APP_PAGE_SLOT_Z_INDEX = 1;
|
|
|
64
64
|
* 全 viewport 坐标、scroll 不变;调用方传响应式快照即随 chrome 跟。
|
|
65
65
|
*
|
|
66
66
|
* @param slotSizes 四区量得尺寸(本函数只用 topH/bottomH —— left/right 只减宽、不影响竖向跨度)。
|
|
67
|
-
* @param outerGap 外圈档(`gapScaleValue(基数,"outer")`)——**槽 ↔ 槽**的间隔。
|
|
67
|
+
* @param options.outerGap 外圈档(`gapScaleValue(基数,"outer")`)——**槽 ↔ 槽**的间隔。
|
|
68
|
+
* @param options.sideWidth 侧向槽(left/right)的**显式宽度**(CSS 长度串;缺省 `undefined` =
|
|
69
|
+
* 不写 `width` ⇒ 保持 shrink-to-fit,与本参引入前逐字一致)。
|
|
70
|
+
*
|
|
71
|
+
* 🔴 **为什么需要它**(vr8kd2):侧槽是 `position: fixed` 且只给了 `left`/`right`
|
|
72
|
+
* ⇒ 宽度**跟内容走**(shrink-to-fit)。槽内内容若用**百分比**宽,会两趟算出自相矛盾的结果:
|
|
73
|
+
* 算内在尺寸时百分比按 `auto` 处理 ⇒ 槽被撑到 max-content;之后百分比才解析、基数是
|
|
74
|
+
* **刚被内容撑出来的那个宽** ⇒ 解出来往往远小于槽 ⇒ **槽里剩一大片死白**
|
|
75
|
+
* (实测默认 `clamp(280px,28%,420px)` 在 1280 视口下死白 229px,且**随内容变大**)。
|
|
76
|
+
*
|
|
77
|
+
* 把宽度放到**槽这一层**即根治:槽是 fixed ⇒ 包含块是**视口**(初始包含块),
|
|
78
|
+
* 百分比有稳定且**不循环**的基数(实测 `28%` 在 1280 下精确得 358px)。
|
|
79
|
+
* ⚠️ [MUST NOT] 改用 `--dc-page-content-viewport-width` 之类的内容区宽做基数 ——
|
|
80
|
+
* 那个量本身就在「内容区宽 ← 侧槽宽 ← 槽内内容宽」这条循环链上。
|
|
68
81
|
*
|
|
69
82
|
* 🔴 让位量走 {@link appPageSlotInset}(`v ? v + outerGap : 0`),与 `shimStyle`
|
|
70
83
|
* (槽 ↔ 默认内容)**同式同源**。huhyx7 只改了 shim 那一处、漏了本函数,导致
|
|
71
84
|
* 「默认内容让了一个外圈档、而 left/right 紧贴 top/bottom 零间隙」——同一页里
|
|
72
85
|
* 两种让位口径并存。[MUST NOT] 只改一处。
|
|
73
86
|
*/
|
|
74
|
-
export declare function computeAppPageSlotStyles(rect: AppPageRectInset, slotSizes: AppPageSlotSizes,
|
|
87
|
+
export declare function computeAppPageSlotStyles(rect: AppPageRectInset, slotSizes: AppPageSlotSizes,
|
|
88
|
+
/**
|
|
89
|
+
* 第 3 参收成配置对象(coding-dna:参数超 3 个 / 多数可选 ⇒ 配置对象;
|
|
90
|
+
* 同时满足 `max-params` 上限 3)。
|
|
91
|
+
*/
|
|
92
|
+
options: {
|
|
93
|
+
outerGap: number;
|
|
94
|
+
sideWidth?: {
|
|
95
|
+
left?: string;
|
|
96
|
+
right?: string;
|
|
97
|
+
};
|
|
98
|
+
}): AppPageSlotStyles;
|
|
75
99
|
/**
|
|
76
100
|
* AppPage 四区内层 shim 的四边 padding(纯函数)。
|
|
77
101
|
*
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppPage 方位槽「空壳」检测(**非主干功能**,规则 22:删本文件 + AppPage 里那一行
|
|
3
|
+
* 委托即零残留;[MUST NOT] 出桶导出)。
|
|
4
|
+
*
|
|
5
|
+
* 要防的错:往 `#top`/`#bottom`/`#left`/`#right` 里放**不占版面**的东西(弹窗 /
|
|
6
|
+
* `ModalPorter`),理由是「它经弹层挂载、不占版面 ⇒ 放哪都行」。
|
|
7
|
+
* 那句话**只对了一半**:内容 teleport 走了,但**槽本身**照样渲染
|
|
8
|
+
* (fixed + padding + 背景)并从默认内容里扣掉让位 —— 实测白占一条 16px。
|
|
9
|
+
*
|
|
10
|
+
* 🔴 **只报,[MUST NOT] 顺手改成「空槽就不渲染」** —— 那是行为变更、会动已有页面布局,
|
|
11
|
+
* 与「报出来」是两件事,真要做得单独一版走 migrations。
|
|
12
|
+
*
|
|
13
|
+
* 误报边界:`v-if` 为假时也是注释节点,那是**合法的动态状态** ⇒ dev-only +
|
|
14
|
+
* **每槽只报一次** + 文案给出口(而非只指责)。
|
|
15
|
+
*/
|
|
16
|
+
export declare const useAppPageSlotMisuseWarn: (options: {
|
|
17
|
+
/** AppPage 根元素 getter(`.app-page`,四向槽容器是它的直系子元素) */
|
|
18
|
+
root: () => HTMLElement | undefined;
|
|
19
|
+
}) => void;
|
|
@@ -31,6 +31,15 @@ declare const _default: <T extends Record<string, any>, SQ extends Record<string
|
|
|
31
31
|
active: boolean;
|
|
32
32
|
setActive: () => void;
|
|
33
33
|
}): any;
|
|
34
|
+
'custom-view-item'?(_: {
|
|
35
|
+
fieldComponentMap: Record<string, import('vue').Component>;
|
|
36
|
+
row: T;
|
|
37
|
+
index: number;
|
|
38
|
+
selected: boolean;
|
|
39
|
+
toggleSelect: () => void;
|
|
40
|
+
active: boolean;
|
|
41
|
+
setActive: () => void;
|
|
42
|
+
}): any;
|
|
34
43
|
};
|
|
35
44
|
emit: {
|
|
36
45
|
(e: "pageChange" | "pageSizeChange", page: number): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
import { ElTableColumnProps } from '../table';
|
|
3
|
+
declare const _default: <T extends Record<string, any>, F extends Record<string, any>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, never> & {
|
|
5
|
+
row: T;
|
|
6
|
+
/** 扁平序号(瀑布流支路 = 虚拟项 index;等高行支路 = 行序 × 列数 + 列内序) */
|
|
7
|
+
index: number;
|
|
8
|
+
columns: ElTableColumnProps<T, F>[];
|
|
9
|
+
/** 列 → 稳定字段组件(`useDataViewFieldMap` 产,跨渲染不 remount) */
|
|
10
|
+
fieldComponentMap: Record<string, Component>;
|
|
11
|
+
fieldKeyOf: (column: ElTableColumnProps<T, F>) => string;
|
|
12
|
+
isSelected: (row: T) => boolean;
|
|
13
|
+
toggleSelect: (row: T) => void;
|
|
14
|
+
} & Partial<{}>> & import('vue').PublicProps;
|
|
15
|
+
expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
|
|
16
|
+
attrs: any;
|
|
17
|
+
slots: {};
|
|
18
|
+
emit: {};
|
|
19
|
+
}>) => import('vue').VNode & {
|
|
20
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
21
|
+
};
|
|
22
|
+
export default _default;
|
|
23
|
+
type __VLS_PrettifyLocal<T> = {
|
|
24
|
+
[K in keyof T]: T[K];
|
|
25
|
+
} & {};
|
|
@@ -189,6 +189,28 @@ export interface InfiniteListViewProps<T extends Record<string, any> = Record<st
|
|
|
189
189
|
maxHeight?: number | string;
|
|
190
190
|
/** opt-in 触摸下拉刷新(默认关) */
|
|
191
191
|
pullRefresh?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* **多列(瀑布流)列数**,默认 `1`(单列,与本 prop 引入前逐字一致)。
|
|
194
|
+
*
|
|
195
|
+
* > 1 时走 `@tanstack/virtual-core` 的 **`lanes`**:前 `lanes` 项按 `i % lanes`
|
|
196
|
+
* 铺满首行(**顺序行优先**),之后逐项落**当前最矮的那一列** ⇒ 这就是瀑布流装箱,
|
|
197
|
+
* 且 `getTotalSize()` 仍给得出总高 ⇒ **虚拟化照常成立**。
|
|
198
|
+
*
|
|
199
|
+
* 🔴 [MUST NOT] 自己写装箱 —— virtual-core 已经做完,重写只会多一份会漂移的真相源。
|
|
200
|
+
*/
|
|
201
|
+
lanes?: number;
|
|
202
|
+
/**
|
|
203
|
+
* **逐项预估高**(px);给了即覆盖 {@link estimateSize} 这个常量估值。
|
|
204
|
+
*
|
|
205
|
+
* 瀑布流的前提正是它:不渲染也要知道每项多高,否则装不了箱。
|
|
206
|
+
* ⚠️ 估值只是**起点** —— 渲染到的项会被 `measureElement` 量准并替换掉估值
|
|
207
|
+
* (见 `DataGridView.estimateItemHeight` 的文档)。
|
|
208
|
+
*/
|
|
209
|
+
estimateSizeAt?: (index: number) => number;
|
|
210
|
+
/** 多列时的列间距(px,默认 0);纵向间距走 {@link itemGap} */
|
|
211
|
+
laneGap?: number;
|
|
212
|
+
/** 同列相邻项的纵向间距(px,默认 0)——透传 virtual-core 的 `gap` */
|
|
213
|
+
itemGap?: number;
|
|
192
214
|
}
|
|
193
215
|
/** InfiniteListView 实例 */
|
|
194
216
|
export interface InfiniteListViewInstance {
|
|
@@ -235,6 +257,47 @@ export interface DataGridViewProps<T extends Record<string, any>, SQ extends Rec
|
|
|
235
257
|
* 落在 cell 上后**给不给插槽都有壳**,且 DOM 层级恒定(消费方的 `:deep()` 不会跟着变)。
|
|
236
258
|
*/
|
|
237
259
|
card?: boolean;
|
|
260
|
+
/**
|
|
261
|
+
* **瀑布流**(默认关):卡片不等高、跨行装箱。
|
|
262
|
+
*
|
|
263
|
+
* 🔴 **[MUST] 与 {@link estimateItemHeight} 同开同关** —— 本路径是虚拟化的,
|
|
264
|
+
* 缺了「不渲染也知道多高」这个前提就装不了箱。只给 `masonry`、不给估高 ⇒
|
|
265
|
+
* **保持等高行**(与本 prop 引入前逐字一致),[MUST NOT] 半开。
|
|
266
|
+
*
|
|
267
|
+
* ⚠️ 与 `DataListView`(分页路径)的同名 prop **机制不同**:那条不虚拟化,
|
|
268
|
+
* 可以**直接量**卡片实际高;本条必须**先算**。
|
|
269
|
+
*/
|
|
270
|
+
masonry?: boolean;
|
|
271
|
+
/**
|
|
272
|
+
* **逐项预估高**(px)—— 瀑布流的前提。与 {@link masonry} 同开同关。
|
|
273
|
+
*
|
|
274
|
+
* ```ts
|
|
275
|
+
* estimateItemHeight: (row, columnWidth) =>
|
|
276
|
+
* columnWidth * (row.coverHeight / row.coverWidth) + 72 // 封面 + 文字区
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* 🔴 **`columnWidth` 由组件回传**:断点解析(`gridColumns` → 列数)在组件内部,
|
|
280
|
+
* 消费方算不出来,[MUST NOT] 让它自己去猜容器宽。
|
|
281
|
+
*
|
|
282
|
+
* ## 估不准会怎样([MUST] 知情)
|
|
283
|
+
*
|
|
284
|
+
* 估值只是**起点**:渲染到的项会被**量准**并替换掉估值(virtual-core 的
|
|
285
|
+
* `measureElement` → `itemSizeCache`)⇒ **不会长期留白**。
|
|
286
|
+
* 代价是视口**下方**未渲染项的位置会随上方项被量准而轻微浮动 —— 这是
|
|
287
|
+
* 「估算 + 校准」的固有代价,[MUST NOT] 期待零跳动。
|
|
288
|
+
*
|
|
289
|
+
* 卡片**不会**在量准后跳到另一列(列归属按估值定下来就缓存住),
|
|
290
|
+
* 那比一点留白刺眼得多。
|
|
291
|
+
*
|
|
292
|
+
* ⚠️ 最容易估偏的**不是图、是文字区**(标题 1~3 行浮动)——
|
|
293
|
+
* 消费方实测栽过:估值偏大 ⇒ 每张卡底下多一截空白。
|
|
294
|
+
*
|
|
295
|
+
* ## 限制
|
|
296
|
+
*
|
|
297
|
+
* 🔴 `gridColumns` 取 **`{ min }` 流体档时本能力不生效** —— 那条的列数是浏览器算的、
|
|
298
|
+
* JS 拿不到,而装箱必须先知道列数。用**断点表**或**定列数**。
|
|
299
|
+
*/
|
|
300
|
+
estimateItemHeight?: (row: T, columnWidth: number) => number;
|
|
238
301
|
/**
|
|
239
302
|
* 自持面(默认 `true`):面色 + 内呼吸 + 圆角,单独用也观感一致。
|
|
240
303
|
* 置于 `ModalConfirm` 正文时经上下文自动取 `false`;显式传值恒优先。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentPublicInstance } from 'vue';
|
|
2
2
|
import { BadgeKeyInput } from './use-badge';
|
|
3
3
|
type __VLS_Props = {
|
|
4
4
|
/**
|
|
@@ -30,9 +30,10 @@ type __VLS_Props = {
|
|
|
30
30
|
* (标题 / label 文字),10px 内嵌直接压住最后一个字(14px 字号下≈3/4 个汉字)。故归零 + 2px 让位。
|
|
31
31
|
*
|
|
32
32
|
* **代价([MUST] 知悉)**:绝对定位不占位,角标必然向右**逃逸出宿主边界**,逃逸量
|
|
33
|
-
* = 角标宽 − 13px
|
|
34
|
-
*
|
|
35
|
-
* [MUST]
|
|
33
|
+
* = 角标宽 − 13px。三字内置标实测逃逸 37px,可能顶到水平相邻的宿主。
|
|
34
|
+
* ⚠️ 原「内置标文案 [MUST] ≤2 个汉字」那条约束**已作废**(甲方 2026-09-19 明示
|
|
35
|
+
* 「不用关心太长」);逃逸的代价由消费方的布局间距承担,core [MUST NOT] 声称能保证不重叠,
|
|
36
|
+
* 也 [MUST NOT] 拿它回推「所以该用图标 / 该截断」。
|
|
36
37
|
*
|
|
37
38
|
* ⚠️ 换英文**不能**减宽:实测 12px 字号下 NEW=41 > 新=26、UPDATED=70 > 更新=38、
|
|
38
39
|
* BETA=45 > 内测=38——汉字表意密度远高于大写字母。[MUST NOT] 为「更短」而改英文。
|
|
@@ -83,7 +84,7 @@ declare function __VLS_template(): {
|
|
|
83
84
|
value: string | number;
|
|
84
85
|
max: number;
|
|
85
86
|
showZero: boolean;
|
|
86
|
-
badgeStyle: string | false | CSSProperties | import('vue').StyleValue[] | null;
|
|
87
|
+
badgeStyle: string | false | import('vue').CSSProperties | import('vue').StyleValue[] | null;
|
|
87
88
|
}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
|
|
88
89
|
beforeCreate?: (() => void) | (() => void)[];
|
|
89
90
|
created?: (() => void) | (() => void)[];
|
|
@@ -110,7 +111,7 @@ declare function __VLS_template(): {
|
|
|
110
111
|
value: string | number;
|
|
111
112
|
max: number;
|
|
112
113
|
showZero: boolean;
|
|
113
|
-
badgeStyle: string | false | CSSProperties | import('vue').StyleValue[] | null;
|
|
114
|
+
badgeStyle: string | false | import('vue').CSSProperties | import('vue').StyleValue[] | null;
|
|
114
115
|
}> & Omit<Readonly<import('element-plus').BadgeProps> & Readonly<{}>, "offset" | "type" | "value" | "max" | "content" | "showZero" | "badgeStyle"> & {
|
|
115
116
|
content: string;
|
|
116
117
|
} & {} & import('vue').ComponentCustomProperties & {} & {
|
|
@@ -162,7 +163,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
|
|
|
162
163
|
value: string | number;
|
|
163
164
|
max: number;
|
|
164
165
|
showZero: boolean;
|
|
165
|
-
badgeStyle: string | false | CSSProperties | import('vue').StyleValue[] | null;
|
|
166
|
+
badgeStyle: string | false | import('vue').CSSProperties | import('vue').StyleValue[] | null;
|
|
166
167
|
}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
|
|
167
168
|
beforeCreate?: (() => void) | (() => void)[];
|
|
168
169
|
created?: (() => void) | (() => void)[];
|
|
@@ -189,7 +190,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
|
|
|
189
190
|
value: string | number;
|
|
190
191
|
max: number;
|
|
191
192
|
showZero: boolean;
|
|
192
|
-
badgeStyle: string | false | CSSProperties | import('vue').StyleValue[] | null;
|
|
193
|
+
badgeStyle: string | false | import('vue').CSSProperties | import('vue').StyleValue[] | null;
|
|
193
194
|
}> & Omit<Readonly<import('element-plus').BadgeProps> & Readonly<{}>, "offset" | "type" | "value" | "max" | "content" | "showZero" | "badgeStyle"> & {
|
|
194
195
|
content: string;
|
|
195
196
|
} & {} & import('vue').ComponentCustomProperties & {} & {
|