@manohub/kit 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CONTRACT.md +597 -0
  2. package/README.md +158 -0
  3. package/bin/kit.mjs +118 -0
  4. package/dist/composables/use-client-pagination.d.ts +43 -0
  5. package/dist/composables/use-client-pagination.js +28 -0
  6. package/dist/entry/create-query-client.d.ts +8 -0
  7. package/dist/entry/create-query-client.js +14 -0
  8. package/dist/entry/create-sub-app.d.ts +81 -0
  9. package/dist/entry/create-sub-app.js +111 -0
  10. package/dist/entry/index.d.ts +4 -0
  11. package/dist/entry/index.js +13 -0
  12. package/dist/entry/initial-guard.d.ts +12 -0
  13. package/dist/entry/initial-guard.js +23 -0
  14. package/dist/index.d.ts +19 -0
  15. package/dist/index.js +7 -0
  16. package/dist/providers/locale-detection.d.ts +35 -0
  17. package/dist/providers/locale-detection.js +44 -0
  18. package/dist/providers/setup-i18n.d.ts +50 -0
  19. package/dist/providers/setup-i18n.js +42 -0
  20. package/dist/services/app-container.d.ts +31 -0
  21. package/dist/services/app-container.js +22 -0
  22. package/dist/services/app-context.d.ts +4 -0
  23. package/dist/services/app-context.js +11 -0
  24. package/dist/services/index.d.ts +7 -0
  25. package/package.json +68 -0
  26. package/skills/README.md +78 -0
  27. package/skills/install.mjs +299 -0
  28. package/skills/kit/SKILL.md +85 -0
  29. package/skills/kit/references/adoption.md +170 -0
  30. package/skills/kit/references/contract-index.md +76 -0
  31. package/skills/kit-dev/SKILL.md +117 -0
  32. package/skills/kit-dev/references/page-recipes.md +350 -0
  33. package/skills/kit-dev/references/style-rules.md +47 -0
  34. package/skills/kit-migrate/SKILL.md +125 -0
  35. package/skills/kit-migrate/references/migration-map.md +294 -0
  36. package/skills/kit-migrate/references/migration-playbook.md +188 -0
@@ -0,0 +1,294 @@
1
+ # 替换映射表:`App*` / 底层组件库 → `@manohub/ui`
2
+
3
+ 0.6.0 起本包不再提供组件。**组件与服务一律从 `@manohub/ui` 引**(无前缀名),
4
+ farris(底层组件库)也不再是依赖。
5
+
6
+ 按类目查;查不到时按 `CONTRACT.md` §8 缺件处置流程办。**逐文件的操作口径与盘点登记格式见
7
+ `migration-playbook.md`。**
8
+
9
+ > 读法:`旧` → `新`。**只有一行的地方表示「零改动,只换名字」**;
10
+ > 带 ⚠️ 的是必须人工判断的语义差异。
11
+
12
+ ---
13
+
14
+ ## 零、0.6.0 增量(主题独立成包 + 容器锚改名 + kit 零样式)
15
+
16
+ 只在**已按 0.6.0 迁完**的仓上做,四步:
17
+
18
+ | 旧 | 新 | 说明 |
19
+ |---|---|---|
20
+ | `@import "@manohub/kit/styles.css"` | **删掉**,改引 `@manohub/theme/default.css` + `@manohub/ui/styles.css` | kit **不再发布任何样式**(`src/styles/` 整体删除):样式汇总入口、reset、富文本预设全没了 |
21
+ | `@import "@manohub/kit/reset.css"` | **删掉**(或应用自己补一份 reset) | 同上;reset 的归属随样式一并退场 |
22
+ | `@import "@manohub/ui/theme/default.css"` | `@import "@manohub/theme/default.css"` | 全局令牌已独立成 **`@manohub/theme`**;ui 的 `theme/*` 出口**已删**(无兼容指针) |
23
+ | `@import "@manohub/ui/theme/farris.css"` | `@import "@manohub/theme/farris.css"` | 同上;用非兜底主题时把它替换掉上面那条 ① |
24
+ | 容器上的 `data-app-container` | **`data-manohub-ui`** | 跨包唯一作用域锚,由入口层**无条件**写;旧属性不再被任何一方识别(无兼容别名) |
25
+ | 依赖里只有 `@manohub/{kit,ui}` | 再加 **`@manohub/theme`** | 样式链第一行由应用直接引它(kit 不再代引) |
26
+
27
+ - **样式链现在归应用自己**:两行(令牌 → 组件面)+ 应用自身一行,顺序不可换(契约 §1.2)。
28
+ - **reset 与富文本排版要自己补**:原来的 `@manohub/kit/reset.css` 与 `.app-markdown` 预设已删除;
29
+ 富文本排版目前没有合规归属(契约 §10「已知缺口」,其余样式纪律仍然生效)。
30
+ - **自建容器(不走 `createSubApp`)必须自己带 `data-manohub-ui`** —— 不带的话不只丢色,
31
+ 连 `--ui-button-height` 这类几何令牌也拿不到(组件令牌的基础值也锚在容器上)。
32
+ - 类名 `class="app-container"` **不必动**:0.6.0 起降级为 kit 内部命名,不再是跨包约定。
33
+ - 深引内部路径(`@manohub/theme/dist/...`、`@manohub/ui/dist/...`)属契约 §6 L3-1
34
+ **import 源白名单**之外 —— 一律改走公开入口。
35
+
36
+ ---
37
+
38
+ ## 一、页面骨架:`AppShell` → `Page`
39
+
40
+ `Page` 的能力**覆盖并超过** `AppShell`:成员按类型归位、`Split` 内建拖拽调宽与收起展开。
41
+
42
+ | 旧 | 新 | 说明 |
43
+ |---|---|---|
44
+ | `AppShell` | `Page` | 每页唯一 |
45
+ | `AppShell.Header` | `Page.Header` | |
46
+ | `AppShell.Header` 的 `toolbar` prop / `toolbar` 插槽 | `Page.Header` 的 **`extra`** | ⚠️ prop 与插槽**都改名** |
47
+ | `AppShell.Header` 的 `tabs` prop / `tabs` 插槽 | **无对应** | ⚠️ 页头下的页签区改到主体内:`Tabs`(纯页签条)或 `Tabset`(条 + 面板) |
48
+ | `AppShell.Toolbar` | **无对应** | ⚠️ 页面级工具条用 `Page.Filter`,或把控件放 `Page.Header.extra` |
49
+ | `AppShell.Filter` | `Page.Filter` | |
50
+ | `AppShell.Body` | `Page.Body` | `mode` 取值不变(`scroll` / `plain`) |
51
+ | `AppShell.Footer` | `Page.Footer` | |
52
+ | `AppShell.Split` | `Page.Split` | `sidebar` / `rightSidebar` 形状不变;多出「收起动画期内容定宽」 |
53
+ | — | `Page.Header` 的 `subTitle` / `icon` | 旧 `AppShell.Header` 没有这两项 |
54
+
55
+ **骨架本身不变**:高度仍取 `100%`(禁 `100vh`)、两级滚动归属仍在(契约 §5 组 4)。
56
+
57
+ ⚠️ **迁移期最容易踩的归位坑**:`Page` 的成员**不按书写顺序渲染**,且**必须是 `Page` 的直接子节点**。
58
+ 把成员包进 `<template v-if>` 会编译成 Fragment,归位认不出它 —— 该成员会被当自由内容挪进主体区
59
+ (契约 §5 组 2)。旧 `AppShell` 没有这个约束,迁移时要逐个核对。
60
+
61
+ ---
62
+
63
+ ## 二、组件对照
64
+
65
+ ### 2.1 零改动(只换名字)
66
+
67
+ | 旧 | 新 |
68
+ |---|---|
69
+ | `AppPanel` / `AppPanel.Header` / `.Body` / `.Footer` | `Panel` / `Panel.Header` / `.Body` / `.Footer` |
70
+ | `AppCard` / `AppCard.Header` / `.Body` / `.Footer` | `Card` / 同名成员 |
71
+ | `AppListView` / `AppListView.CardItem` | `ListView` / `ListView.CardItem` |
72
+ | `AppTree` | `Tree` |
73
+ | `AppNav` | `Nav` |
74
+ | `AppQueryState` | `QueryState` |
75
+ | `AppStateIllustrationEmpty` / `AppStateIllustrationError` | 不再有独立插画件:空 / 错误两态由 `QueryState` 内建(设计交付的 SVG 原样内联在其 `src/utils/state-illustration.ts`)。要成功 / 异常图形时走 `QueryState` 的 `illustration` 或自备图片 |
76
+ | `AppCheckbox` | `Checkbox`(+ `Checkbox.Group`) |
77
+ | `AppNotice` | `Notice` |
78
+ | `AppBadge` | `Badge` |
79
+ | `AppForm` / `AppForm.Item` | `Form` / `Form.Item` |
80
+
81
+ 可选新能力(不是必须改):`Card` 的根件 `title`/`subtitle`/`icon`、`Tree` 的 `defaultExpandAll`、
82
+ `Nav` 的 `bordered`、`ListView` 的 `columns`、`Badge` 的 `count`/`status`、
83
+ `QueryState` 的 `illustrationSize`、`Form.Item` 的 `name`(可拿 `{ value, setValue }`)。
84
+
85
+ ⚠️ `Card` 的**内距口径变了**:旧 `AppCard` 根件有 `padding`,新的 `Card` 根件不出内距
86
+ (内距只在 `Header`/`Body`/`Footer` 段上)。改写:把根件的 `padding` 移到三段,或改令牌 `--mh-card-padding`。
87
+
88
+ ### 2.2 有 prop 差异
89
+
90
+ #### Button
91
+
92
+ | 旧 | 新 | 说明 |
93
+ |---|---|---|
94
+ | `tone="primary"` | `variant="primary"` | 缺省档从 `primary` 变成 **`secondary`** |
95
+ | `tone="default"` / `"secondary"` | `variant="secondary"` | |
96
+ | `tone="error"` | `variant="primary" danger` | |
97
+ | `tone="success"` / `"warning"` / `"info"` | **无色档** | ⚠️ 改用 `variant="primary"`/`"secondary"`,或换件(`Badge` / `Tag` / `Notice` 承担语义色) |
98
+ | `shape="link"` | `variant="link"` | ⚠️ `shape` 换域了 |
99
+ | `shape="ghost"` | `variant="icon"`(纯图标)或 `variant="text"` | |
100
+ | `shape="solid"` / `"soft"` / `"outline"` | **无对应** | ⚠️ 由 `variant`(六型)表达 |
101
+
102
+ 新能力:`block` / `shape="round"|"circle"` / `icon` / `trailingIcon` / `caret` / `menu` / `href`。
103
+
104
+ #### Input / Textarea
105
+
106
+ | 旧 | 新 |
107
+ |---|---|
108
+ | 尾缀内容放默认插槽 | ⚠️ 改放 **`#suffix`**(单行不再渲染默认插槽);前置放 `#prefix` |
109
+ | `autoComplete` | **无对应** | ⚠️ 不落到控件上;确需防回填用原生 attrs(`controlAttrs`) |
110
+ | `Textarea` 的 `maxLength` | **`maxlength`** | ⚠️ 大小写 |
111
+ | — | `Input` 新增 `onEnter` / `showCount` / `invalid` / `status` / `bordered` |
112
+
113
+ #### Select
114
+
115
+ | 旧 | 新 |
116
+ |---|---|
117
+ | `placeholder` 缺省空串 | 缺省 `'请选择'` |
118
+ | `readonly` | **无对应** | ⚠️ 用 `disabled` 顶 |
119
+ | `popupHost` | **无对应** | ⚠️ 面板用原生 popover,宿主概念不再需要 |
120
+ | — | 新增 `multiple` / `searchable` / `allowCreate` / `loading` / `maxTagCount` / `status` |
121
+
122
+ #### Switch / Radio / Checkbox
123
+
124
+ - `AppSwitch` → `Switch`:⚠️ `size` 缺省从 `sm` 变成 `md`;⚠️ **`onChange` 的返回值契约消失**
125
+ (旧代码靠返回 `false` / reject 让开关回退视觉 —— 回退逻辑要搬进调用方:`onChange` 里判失败再改回 `modelValue`)。
126
+ - `AppRadioCard` → `Radio.Card`:⚠️ **缺省选中语义变了** —— `Radio.Card` 是单选组,
127
+ 「可全不选」的旧行为要显式处理(组件缺省会选中第一个可选项)。
128
+ - `AppCheckbox` → `Checkbox`:零改动。
129
+
130
+ #### Tooltip
131
+
132
+ | 旧 | 新 |
133
+ |---|---|
134
+ | `placement="top"` | `side="top"`(可加 `align`) |
135
+ | `width`(固定宽) | **无对应** | ⚠️ 用 `#content` 插槽内的元素自己限宽 |
136
+ | `disabled` | **无对应** | ⚠️ 不渲染触发器的提示即可 |
137
+
138
+ 新能力:`title` / `action` / `guide` / `onAction`。
139
+
140
+ #### Table(差异最大)
141
+
142
+ | 旧 | 新 | 说明 |
143
+ |---|---|---|
144
+ | `rows` | **`data`** | |
145
+ | `rowKey` 必填业务字段 | `rowKey` 缺省 `'id'` | |
146
+ | `stripe` | **`striped`** | |
147
+ | `selection={{ mode, selected, onSelectedChange, selectable, onSelectAll }}` | `selectable` + `modelValue`(keys 数组)+ `change` | ⚠️ **只有多选**;单选 / 谓词 / `onSelectAll` / 增量语义**无对应** |
148
+ | `columns[].title` 可以是函数 / `render` | `title` 只接受 string,单元格内容走 **`#cell` 插槽**(`{ row, column, value, index }`) | ⚠️ 渲染路径变了 |
149
+ | `columns[].width` 数字权重 | `width` 字符串(`'120px'` / `'20%'`) | |
150
+ | `error` / `errorTitle` / `emptyDescription` / `*ActionText` / `on*Action` | **无对应** | ⚠️ 错误态用 `QueryState` 包住表格;空态用 `emptyText` / `#empty` |
151
+ | `loading`(骨架替换整表) | `loading`(内容上盖罩 + 转圈,行高不塌) | ⚠️ 观感不同 |
152
+ | `rowNumber` / `rowHeight` / `headerHeight` / `framed` | **无对应** | ⚠️ 序号自加一列;外框由承载它的 `Panel` 给 |
153
+ | `refreshKey` / `rowHighlightKey` / `tableKey` / `onContainerResize` / `resizePollInterval` | **无对应** | ⚠️ 自绘表不吃上游「挂载时固化列宽」的问题,整组逃生舱一并退场 |
154
+ | `onRowClick` / `onRowDoubleClick` | `onRow(row, index) => ({ class, onClick })` | ⚠️ **无双击** |
155
+ | — | 新增 `sortKey` / `sortOrder` / `onSort` / `expandable` / `expandedKeys` / `stickyHead` / `stickyCol` / `pagination` | |
156
+
157
+ > 旧 `AppTable` 有一条「回调交回的行对象必须是消费方那一个」的契约(内部副本挂了非枚举回引)。
158
+ > 新 `Table` 不存在副本问题 —— 交回的就是 `data` 里的那一项。
159
+
160
+ #### Pagination
161
+
162
+ | 旧 | 新 | 说明 |
163
+ |---|---|---|
164
+ | `page`(**0 基**,必填) | `modelValue`(**1 基**,`v-model`) | ⚠️ **差 1**,是最容易漏的一处 |
165
+ | `onPageChange(page)` | `update:modelValue` / `change`(载荷是 **`number`**) | ⚠️ 不再是 `{ page, pageSize }` 对象 |
166
+ | `onPageSizeChange(size)` | `update:pageSize`(`v-model:page-size`) | 两个事件各管各的 |
167
+ | `showInfo` | **无对应** | ⚠️ 「共 n 条」默认就有;要改文案用 `#total` 槽 |
168
+ | — | 新增 `showSizeChanger` / `showQuickJumper` / `simple` / `boxed` / `hideOnSinglePage` | |
169
+
170
+ > 注意 `Table` 的 `pagination` prop 与独立的 `Pagination` **不是同一套入参**:
171
+ > 前者是 `{ total, current?, pageSize?, pageSizeOptions?, onChange? }`(`onChange` 收页码),
172
+ > 后者是受控的 `v-model` / `v-model:page-size`。
173
+
174
+ #### Dialog
175
+
176
+ | 旧 | 新 | 说明 |
177
+ |---|---|---|
178
+ | `width={640}`(数值,缺省 640) | `width` 缺省 **`'md'`(520)** | ⚠️ 缺省宽度变窄,要 640 就显式传 |
179
+ | `beforeClose`(关闭拦截) | **无对应** | ⚠️ 拦截逻辑移到 `onCancel` / `onClose` 里自己把关(组件只回调) |
180
+ | `height` / `minHeight` / `fitContent` / `showHeader` / `showButtons` | **无对应** | ⚠️ 固定高度用 `#default` 内的容器自己定高;不显示页头用 `:closable="false"` + 不给 `title` |
181
+ | — | 新增 `okText` / `cancelText` / `okDanger` / `confirmLoading` / `showFooter` / `onOk` / `onCancel` / `onClose` / `closeOnBackdrop` / `keyboard` | |
182
+
183
+ `Dialog` 走**原生 `<dialog>`**:遮罩、Esc、焦点陷阱归浏览器;**开合受控**
184
+ (关闭位 / Esc / 点遮罩都只回调,可见性归调用方)。`onOk` 返回 Promise 时确定按钮自动进加载态。
185
+
186
+ #### Steps
187
+
188
+ | 旧 | 新 | 说明 |
189
+ |---|---|---|
190
+ | `items` | **`steps`** | ⚠️ 形状变:丢 `key` / `disabled`,新增 `icon` |
191
+ | `modelValue`(0 基) | `current`(0 基,基址不变) | |
192
+ | `clickable` / `onBeforeChange` / `onChange` | **无对应** | ⚠️ 步骤条是**只读展现**;跳转与门控搬到页面(按钮 + 自己的校验) |
193
+ | `fill` | **无对应** | |
194
+ | — | 新增 `variant`(`node` / `bar`)/ `size` / `Steps.Progress` | |
195
+
196
+ #### Tabs
197
+
198
+ | 旧 | 新 | 说明 |
199
+ |---|---|---|
200
+ | `modelValue`(必填) | `value`(缺省第一项)/ `defaultValue` | |
201
+ | `items=[{ key, label }]` | `options=[{ label, value }]` | ⚠️ `key` → `value` |
202
+ | **按 `item.key` 命名的内容插槽**(自带面板切换) | `Tabs` **无内容槽** | ⚠️ 要「条 + 面板」用 `Tabset`(`default` 放面板 + `selector`);只要页签条用 `Tabs` |
203
+ | `fill` | **无对应** | |
204
+
205
+ #### Filter
206
+
207
+ | 旧 | 新 | 说明 |
208
+ |---|---|---|
209
+ | `fields=[…]` 声明式(必填) | **`Filter.Item` 子件**(`code` / `label` + 控件自放) | ⚠️ 模型从「声明字段表」变「写子件」 |
210
+ | `defaults` | `defaultValue`(键从「字段 id」变「条件名 code」) | |
211
+ | `searchFields` / `searchPlaceholder` / `keywordCodes` | **无对应** | ⚠️ 「关键字」写成普通 `Filter.Item` + `Input` |
212
+ | `appFilterSelect` / `appFilterInput` 工厂 | **无对应** | ⚠️ 控件直接写 `Select` / `Input` |
213
+ | `onChange(values, meta)` / `onQuery(values, meta)` | `onChange(values)` / `onQuery(values)` | ⚠️ **丢 `meta`**(关键字 / 查询态由页面自持) |
214
+ | `inline` / `expanded` / `readyTries` / `ignoreInitialEmpty` / `onReady` | **无对应** | ⚠️ 就绪时序归页面 |
215
+ | — | 新增 `title` / `description` / `queryText` / `resetText` / `showReset` / `onReset` | |
216
+
217
+ #### Input 的组合形态
218
+
219
+ `AppSearchBox` → **`Search`**:`modelValue` / `placeholder` / `disabled` / `size` / `clearable` /
220
+ `loading` / `searchText` 同名同义;`onChange` / `onSearch` / `onClear` 三条回调保留(`onClear` 的补发判据内建)。
221
+
222
+ #### 旧有新无的其余项
223
+
224
+ | 旧 | 处置 |
225
+ |---|---|
226
+ | `AppIconButton` | 改用 `Button variant="icon"`(⚠️ 缺省 `size` 从 `sm` 变 `md`,要小号显式传);无可见文案时给 `title` 或 `aria-label` |
227
+ | `AppSection` / `AppForm.Section` | 表单内区块头 → `Form.Header`(**单头**);区块分组 → `Panel` |
228
+ | `AppLayout` / `AppLayout.Row` / `.Column` | → `Layout` / `Layout.Row` / `.Column`(方向口径、间距档、`columns` / `span` 全同) |
229
+ | `AppDrawer` | → `Drawer`(`open` / `title` / `width` / 关闭受控同款;`position` → **`side`**;`beforeClose` 无对应,同 `Dialog`) |
230
+ | `AppTabs` 的 `fill`、`AppSteps` 的 `fill` | 无对应,自绘容器定高 |
231
+
232
+ ---
233
+
234
+ ## 三、命令式服务:重新设计过,不是改名
235
+
236
+ | 旧(kit) | 新(`@manohub/ui`) |
237
+ |---|---|
238
+ | `notify.success(text)` / `.info` / `.warning` / `.error` | `toast('success', text)` / `toast('info', …)` … |
239
+ | `notify.error(text, { action })` 之类配置对象 | `toast('error', text, { action: { text: '重试', onClick } })` |
240
+ | — | `toast('loading', text, { duration: 0 })` 返回句柄,`handle.close()` 收掉 |
241
+ | `messageBox.confirm({ title, description, confirmText, cancelText })` | `await confirm({ title, detail, okText, cancelText, okDanger })` → `Promise<boolean>` |
242
+ | `messageBox.show({ … })` 说明弹窗 | `await alert({ title, detail })` |
243
+ | `loading.show()` 返回 `Ref` | `showLoading(text?)` 返回**关闭句柄**(引用计数语义) |
244
+ | `modalService.open(component, options)` | 无对应:用 `Dialog` / `Drawer` 组件(受控),或 `confirm()` / `alert()` |
245
+ | `richText: true`(HTML 说明) | 无对应:`alert` / `confirm` 只收纯文本;长说明用 `Dialog` 组件的默认插槽 |
246
+
247
+ **服务层的宿主**:落回应用自己的 `[data-manohub-ui]` 容器(`createSubApp` 写的 `data-manohub-ui` 就是锚点)。
248
+ 门户里多应用并存时可在 `createSubApp({ onReady })` 里调 `configureHost(el)` 精确指定。
249
+
250
+ ---
251
+
252
+ ## 四、样式改写
253
+
254
+ | 旧 | 新 |
255
+ |---|---|
256
+ | `.ak-*` 选择器(覆写 kit 内部类) | **删掉**;要的效果按契约 §3「局部换肤」翻成主题令牌(在更深容器重设**已有**令牌的值)或组件的 prop |
257
+ | `.ak-markdown` | **删掉**;`.app-markdown` 预设已随 kit 的样式一并删除,富文本排版暂无合规归属(契约 §10「已知缺口」) |
258
+ | `src/style.css` 里引 `@farris/ui-vue/index.css` | **删掉**;组件库两行改由应用自己引(`@manohub/theme` → `@manohub/ui`,契约 §1.2) |
259
+ | `--f-theme-*` / farris 内部类的覆写 | **删掉**(farris 退场,桥接层一并退场) |
260
+ | 自绘遮罩 + 转圈 | `Loading`(`overlay="area"` / `"screen"`)或服务层 `showLoading()` |
261
+ | 自绘 `flex + gap` 排版 | `Layout.Row` / `Layout.Column` |
262
+ | 自绘 `margin-left:auto` 顶右 | `Panel.Header.actions` / `Layout` 的 `justify="between"` |
263
+ | `height: 100vh` | `height: 100%` |
264
+
265
+ > `.ak-*` 覆写与 `.mh-*` 覆写在新体系里同样违规(契约 §3 L1、§6 L3-2);
266
+ > 迁移时不要为了「先让它看起来一样」而保留覆写段 —— 那是把旧债换成新债。
267
+
268
+ ---
269
+
270
+ ## 五、入口与全局
271
+
272
+ | 旧 | 新 |
273
+ |---|---|
274
+ | `import { AppTable, AppButton } from '@manohub/kit'` | `import { Table, Button } from '@manohub/ui'` |
275
+ | `import '@farris/ui-vue'`(应用侧直连) | 删掉(契约 §6 L3-1 的 import 源白名单不含它) |
276
+ | 自己 `createI18n` | 删掉:实例由 `createSubApp({ i18n })` 装配(契约 §9) |
277
+ | 自己写 `app.use(Farris)` | 删掉(farris 退场) |
278
+ | `App*` 组件装在应用依赖里 | 换成 `@manohub/ui`(与 `@manohub/kit`、`@manohub/theme` 并列) |
279
+
280
+ ---
281
+
282
+ ## 六、迁移中暴露的坑与结论
283
+
284
+ 1. **`Table` 的三态与序号列要自己接**:把表格包进 `QueryState`(错误态),空态用 `emptyText`,
285
+ 序号列自加一列 —— 不要试图在组件里补回来。
286
+ 2. **分页基址差 1 是最容易漏的一处**:搜索 `page` 出现的地方(含 URL query 回填、请求参数拼装)。
287
+ 3. **不要给 `Radio.Card` 传「空值」当默认**:它是单选组,缺省会选中第一个可选项。
288
+ 4. **`Drawer` / `Dialog` 的关闭拦截**:旧 `beforeClose` 无处安放,改成「点确定前校验 + 失败就不关」
289
+ (受控语义下 `onOk` 里 return 即可)。
290
+ 5. **命令式服务要在 `finally` 里配对关闭**:`showLoading` 是引用计数,漏关会留下永久遮罩。
291
+ 6. **样式收口顺序**:先删 `.ak-*` 覆写(多半能直接删),再把残留的视觉意图翻成主题令牌 ——
292
+ 逐条「翻译」会把不该存在的样式留成新债。
293
+ 7. **`Page` 成员必须直接挂**:`<template v-if>` 包一层会让归位认不出成员(契约 §5 组 2)——
294
+ 旧 `AppShell` 时代的写法在这里会静默走样。
@@ -0,0 +1,188 @@
1
+ # 迁移剧本
2
+
3
+ `SKILL.md` 是流程骨架,本文件是**阶段细则 + 可直接抄的登记模板**。
4
+ 替换对照表见 `migration-map.md`;契约条款见 `node_modules/@manohub/kit/CONTRACT.md`。
5
+
6
+ > **0.6.0 起没有自动扫描了**:`kit lint` 与三条护栏已下线。本文件里原先「装护栏 → 跑出基线 →
7
+ > 逐文件归零 → 撤销豁免」的机械流程,改为**按契约条款人工盘点与收口** —— 判据仍是闭集,
8
+ > 但执行从「跑命令」变成「过清单」,成果必须落在应用文档上。
9
+
10
+ ---
11
+
12
+ ## 一、阶段 0 · 记录表(抄进应用文档,后面验收要用)
13
+
14
+ ```markdown
15
+ ## 改造前基线(YYYY-MM-DD)
16
+
17
+ - 应用:<app 目录>;入口:<src/main.ts 或等价>
18
+ - 依赖:@manohub/kit <版本> / @manohub/ui <版本> / 是否仍有 @farris/ui-vue
19
+ - 页面数:路由页 <n> 个;页面内 components/ 子件 <m> 个
20
+ - 用量(搜索计数):
21
+ - `App` 前缀组件名:<n> 处
22
+ - `.ak-` 样式:<n> 处
23
+ - `@farris/ui-vue` import:<n> 处
24
+ - 命令式服务(notify / messageBox / loading / modalService):<n> 处
25
+ - 构建:`pnpm build` 产物 <大小>;构建耗时 <秒>
26
+ ```
27
+
28
+ **存量源判定**(决定后面按哪条路走):
29
+
30
+ | 现状 | 走法 |
31
+ |---|---|
32
+ | 旧版 kit(`App*` 名 + `.ak-*` 样式) | 主路径:按 `migration-map.md` 逐件替换 |
33
+ | 直连底层组件库(farris)自绘页面 | 先按契约 §5 重建页面骨架,再替换组件 |
34
+ | 其它 UI 库 / 全自绘 | 同上:映射表查不到的按契约重建,不要照搬旧库词汇 |
35
+
36
+ ## 二、阶段 1 · 命名空间表与条款级盘点
37
+
38
+ ### 命名空间表(取代旧配置里的 `prefixes`)
39
+
40
+ `docs/kit-namespaces.md`:
41
+
42
+ ```markdown
43
+ # 类名命名空间表
44
+
45
+ > 本表只回答「这个类名前缀归谁」。样式属性本身合不合规由契约 §3 L1-5 判,与本表无关。
46
+ > 库锚 `[data-manohub-ui]` 恒允许、不必登记;类名 `.app-container` 是 kit 内部命名,不是跨包契约。
47
+
48
+ | 应用 | 目录 | 类名前缀 | 说明 |
49
+ |---|---|---|---|
50
+ | <app 名> | <apps/xxx> | `<前缀>-` | <这一层是干嘛的> |
51
+ ```
52
+
53
+ ### 条款级盘点(取代旧「护栏基线」)
54
+
55
+ 打开契约,**逐层逐条**对着代码盘,把命中记成表。条款号就用契约里的 `L0-n / L1-n / L1.5-n / L2-n / L3-n`:
56
+
57
+ ```markdown
58
+ ## 违规盘点(YYYY-MM-DD 迁移前)
59
+
60
+ | 层 | 条款 | 命中 | 说明 |
61
+ |---|---|---|---|
62
+ | L0 | L0-2 容器必须有 `data-manohub-ui` | <n> | 自建容器缺锚 |
63
+ | L1 | L1-5 属性白名单 | <n> | 视觉属性,翻成主题令牌后清零 |
64
+ | L2 | L2-1 路由页必须用 `Page` 承载 | <n> | 路由页未用骨架 |
65
+ | L3 | L3-1 import 源白名单 | <n> | 直连底层组件库 |
66
+ | … | … | … | … |
67
+
68
+ **合计**:<n> 条|本批承诺收口的层:<[L2]>|其余层待第 <N> 批
69
+ ```
70
+
71
+ - 盘点的是「改造前的事实」,不是「要修掉的清单」——数量本身没有对错,写清日期。
72
+ - **没有配置文件要改**:承诺层与未承诺层都写在应用文档里(旧版的 `pending` / `waivedRules` 机制已退场)。
73
+
74
+ ## 三、阶段 2 · 层级与批次
75
+
76
+ **层序(L0 → L1 → L1.5 → L2 → L3)是收口顺序**,但**施工顺序**按「先结构、后组件、最后样式」:
77
+
78
+ | 批次 | 做什么 | 本批承诺收口的层 | 未承诺(下一批起点) |
79
+ |---|---|---|---|
80
+ | ① 页面骨架 | `AppShell.*` → `Page.*` | **L2** | L1、L1.5、L3 |
81
+ | ② 组件逐件 | 按 `migration-map.md` 换名换 prop | 加上 **L3** | L1、L1.5 |
82
+ | ③ 图标 | 自绘 svg / 文字符号 → `<Icon>` | 加上 **L1.5** | L1 |
83
+ | ④ 样式收口 | 删 `.ak-*`,视觉意图翻成主题令牌 | 全部(含 **L1**) | — |
84
+
85
+ 只做 ① 时,就是「只迁骨架(Shell-only)」变体(见第九节)。
86
+
87
+ ## 四、阶段 3 · 单文件循环
88
+
89
+ ```text
90
+ 读文件 → 按对照表替换 → 对照契约对应层逐条改 → 类型检查
91
+ ```
92
+
93
+ - 契约该层的条款与「正误对照」段是改法的直接依据;**不要自创等价写法**。
94
+ - **样式违规的处理原则:能删就删**。旧 `.ak-*` 覆写多半是「当年为了补组件缺失的形态」,
95
+ 新组件自带那些形态 —— 直接删;删掉后视觉不对的,才按契约 §3「局部换肤」翻成主题令牌。
96
+ - 一次只改一个语义单元(一个页面 / 一个子件),改动面越小,逐层收口越好核对。
97
+
98
+ ## 五、阶段 4 · 逐层收口口径
99
+
100
+ | 检查 | 通过标准 |
101
+ |---|---|
102
+ | 已承诺的层 | 该层条款**逐条**对照代码过一遍、无命中(证据:清单里该层打勾 + 涉及文件清单) |
103
+ | 未承诺的层 | 照常记录、命中数不高于阶段 1 的盘点 |
104
+ | 类型 | `pnpm exec vue-tsc --noEmit` 0 错 |
105
+ | 构建 | `pnpm build` 成功;产物大小与阶段 0 记录值量级一致(差异要能解释) |
106
+
107
+ **「无命中」要能举证**:说某层已收口,就得说得出「哪几(十)个文件里没有它」。
108
+ 说不出就说明没真过一遍 —— 0.6.0 没有退出码帮你确认。
109
+
110
+ 定版例外(**不是通行证**,登记也只放行契约 §11 允许的范围):
111
+
112
+ ```markdown
113
+ ## 定版文件清单(按设计稿逐像素还原,改动需人工确认)
114
+
115
+ | 文件 | 设计节点 | 说明 |
116
+ |---|---|---|
117
+ | src/views/skill/components/skill-card.css | 0:2128 | 卡片间距与描边按设计稿还原;色值字面量只减不增 |
118
+
119
+ > 注意:契约 §11 列了**登记也不放行**的几类(导入越界 / 自绘页头 / 原生控件 /
120
+ > `!important` / `.mh-*` 覆写 / `:root`)—— 先读契约 §11 再登记。
121
+ ```
122
+
123
+ ## 六、阶段 5 · 验收清单
124
+
125
+ ```markdown
126
+ ## 二、验收(YYYY-MM-DD)
127
+
128
+ - [ ] 契约 §7 自检清单五层逐条过完(留痕:每层勾选 + 备注)
129
+ - [ ] 已承诺层的条款逐条举得出「没有它的文件清单」
130
+ - [ ] `pnpm exec vue-tsc --noEmit` 0 错
131
+ - [ ] `pnpm build` 成功(产物大小与阶段 0 对比:<差异及原因>)
132
+ - [ ] 浏览器逐个过页面:渲染 / 交互 / 样式 / 弹层落点
133
+ - [ ] 命令式提示落在应用容器内(`toast('success','ok')` 后 `[data-manohub-ui]` 内有 `.mh-toast`)
134
+ - [ ] `showLoading()` → 关闭句柄能收掉(引用计数配平)
135
+ - [ ] `index.html?xxx=1` 类入口已登记 `rootPathAliases`
136
+ - [ ] 语言切换一处生效
137
+ ```
138
+
139
+ **已知缺口**(本包侧,不算漏改):
140
+
141
+ - **没有任何工具替你检查结构** —— SFC 与 TSX 一律人工过契约 §7 自检清单,并按 §5 骨架条款核对。
142
+ - 组件库暂无 `DatePicker` / `Number`(契约 §8):按替代口径顶住并记录,不得自绘。
143
+
144
+ ## 七、阶段 6 · 收尾登记
145
+
146
+ ```markdown
147
+ ## 迁移完成(YYYY-MM-DD)
148
+
149
+ - 已承诺层:<L2 / L3 / …> 逐条收口(见清单)
150
+ - 未承诺层:<L1、L1.5…> 剩余 <n> 条,作为下一批起点
151
+ - 定版例外:<n> 条(见定版文件清单);无则写「无」
152
+ - 命名空间表:docs/kit-namespaces.md(已建 / 无变化)
153
+ - 遗留项:<列出来,并说明为什么不在本次范围>
154
+ ```
155
+
156
+ ## 八、已知缺口与边界
157
+
158
+ | 缺口 | 影响 | 处理 |
159
+ |---|---|---|
160
+ | 无自动扫描 | 结构 / 样式 / 图标三层都没有机械保障 | 人工过契约 §7 清单 + 评审查各层「正误对照」 |
161
+ | 组件库暂无 `DatePicker` / `Number` | 日期、数字输入要自己拼 | 契约 §8:用 `Input` 顶住 + 记录;或提缺件 |
162
+ | `class` 载荷可以写任意类 | 样式纪律只兜住 CSS 侧 | 评审把关(契约 §6 L3-2:外观走语义 prop) |
163
+ | 桥接层已随 farris 退场 | 不再有 `--ibp-popup-shift-*` 之类的弹层原点补偿 | 浮层一律用组件库的(`Dialog` / `Drawer` / 服务层),它们自带落点处理 |
164
+
165
+ ## 九、变体路径:只迁骨架(Shell-only)
166
+
167
+ 适用:本次只想把**页面结构**收口(承诺 L2),组件与样式留待下一批。
168
+
169
+ ### 步骤
170
+
171
+ 1. 阶段 1 的盘点里把 L1 / L1.5 / L3 的命中数单独留出来(那就是下一批的起点),
172
+ 应用文档里写明「本批只承诺 L2」。
173
+ 2. 阶段 2 只做批次 ①(`AppShell.*` → `Page.*`),不动组件与样式。
174
+ 3. 阶段 4 按分层口径验收(不要求其余层归零,但要求 **L2 逐条收口、举得出证据**)。
175
+
176
+ ### 里程碑 A 验收
177
+
178
+ | 检查 | 通过标准 |
179
+ |---|---|
180
+ | L2(20 条) | 逐条对照代码过一遍、无命中;涉及文件清单留痕 |
181
+ | 其它层 | 照常记录、命中数不高于阶段 1 的盘点 |
182
+ | 运行 | 页面能打开,视觉与改造前一致(这一批只动结构,视觉不该变) |
183
+
184
+ ### 下一批次怎么收
185
+
186
+ 1. 重新盘一次 L1 / L1.5 / L3 的命中数 —— 那是本批的起点;
187
+ 2. 按 `migration-map.md` 分批替换组件(先表格 / 分页 / 表单,它们的 prop 差异最大);
188
+ 3. 每收口一层就复跑一次 §7 自检清单,能全绿再动下一层。