@manohub/ui 0.10.5 → 1.0.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 (70) hide show
  1. package/README.md +155 -155
  2. package/dist/components/form/index.js +8 -1
  3. package/dist/styles/components/avatar.css +131 -131
  4. package/dist/styles/components/avatar.tokens.css +24 -24
  5. package/dist/styles/components/badge.css +266 -266
  6. package/dist/styles/components/badge.tokens.css +24 -24
  7. package/dist/styles/components/button.css +460 -460
  8. package/dist/styles/components/capsule.css +128 -128
  9. package/dist/styles/components/capsule.tokens.css +27 -27
  10. package/dist/styles/components/card.css +198 -198
  11. package/dist/styles/components/checkbox.css +145 -145
  12. package/dist/styles/components/checkbox.tokens.css +26 -26
  13. package/dist/styles/components/code-block.css +216 -216
  14. package/dist/styles/components/code-block.tokens.css +40 -40
  15. package/dist/styles/components/collapse.css +62 -62
  16. package/dist/styles/components/collapse.tokens.css +20 -20
  17. package/dist/styles/components/dialog.css +158 -158
  18. package/dist/styles/components/dialog.tokens.css +24 -24
  19. package/dist/styles/components/divider.css +75 -75
  20. package/dist/styles/components/divider.tokens.css +22 -22
  21. package/dist/styles/components/drawer.css +143 -143
  22. package/dist/styles/components/drawer.tokens.css +22 -22
  23. package/dist/styles/components/filter.css +29 -29
  24. package/dist/styles/components/form.css +442 -425
  25. package/dist/styles/components/form.tokens.css +15 -15
  26. package/dist/styles/components/input.css +538 -538
  27. package/dist/styles/components/input.tokens.css +43 -43
  28. package/dist/styles/components/layout.css +200 -200
  29. package/dist/styles/components/list-view.css +244 -244
  30. package/dist/styles/components/loading.css +76 -76
  31. package/dist/styles/components/loading.tokens.css +23 -23
  32. package/dist/styles/components/nav.css +48 -48
  33. package/dist/styles/components/notice.css +153 -153
  34. package/dist/styles/components/notice.tokens.css +17 -17
  35. package/dist/styles/components/notification.css +159 -159
  36. package/dist/styles/components/notification.tokens.css +37 -37
  37. package/dist/styles/components/page.css +473 -473
  38. package/dist/styles/components/pagination.css +303 -303
  39. package/dist/styles/components/pagination.tokens.css +32 -32
  40. package/dist/styles/components/panel.css +77 -77
  41. package/dist/styles/components/query-state.css +88 -88
  42. package/dist/styles/components/radio.css +271 -271
  43. package/dist/styles/components/radio.tokens.css +26 -26
  44. package/dist/styles/components/search.css +34 -34
  45. package/dist/styles/components/select.css +326 -326
  46. package/dist/styles/components/select.tokens.css +44 -44
  47. package/dist/styles/components/skeleton.css +60 -60
  48. package/dist/styles/components/skeleton.tokens.css +27 -27
  49. package/dist/styles/components/steps.css +205 -205
  50. package/dist/styles/components/steps.tokens.css +44 -44
  51. package/dist/styles/components/switch.css +165 -165
  52. package/dist/styles/components/switch.tokens.css +26 -26
  53. package/dist/styles/components/tabbar.css +235 -235
  54. package/dist/styles/components/tabbar.tokens.css +30 -30
  55. package/dist/styles/components/table.css +504 -504
  56. package/dist/styles/components/table.tokens.css +44 -44
  57. package/dist/styles/components/tag.css +127 -127
  58. package/dist/styles/components/tag.tokens.css +24 -24
  59. package/dist/styles/components/toast.css +185 -185
  60. package/dist/styles/components/toast.tokens.css +26 -26
  61. package/dist/styles/components/tooltip.css +89 -89
  62. package/dist/styles/components/tooltip.tokens.css +25 -25
  63. package/dist/styles/components/tree.css +173 -173
  64. package/dist/styles/components/upload.css +151 -151
  65. package/dist/styles/components/upload.tokens.css +27 -27
  66. package/dist/styles/index.css +153 -153
  67. package/dist/styles/operations/collapse.css +84 -84
  68. package/dist/styles/operations/popup.css +193 -193
  69. package/dist/styles/operations/tabs.css +82 -82
  70. package/package.json +62 -62
package/README.md CHANGED
@@ -1,155 +1,155 @@
1
- # @manohub/ui
2
-
3
- AIHub **自绘组件层**:不依赖 farris 的手写 Vue TSX 组件 + 自带令牌层。
4
-
5
- 本包分三层,**可分别引用**:
6
-
7
- | 层 | 入口 | 内容 |
8
- |---|---|---|
9
- | ① 主题 | `@manohub/theme/default.css`(兜底)/ `@manohub/theme/farris.css`(Farris 规范) | **全局**令牌(值)—— 随主题包独立发布,换主题只换这一行 |
10
- | ② 组件面 | `@manohub/ui/styles.css` | **元素级 reset**(只有盒模型 + 容器基座两面,见下)+ 类与状态协议 + 组件令牌基础值,**无需 JS** 即可使用 |
11
- | ③ Vue 层 | `@manohub/ui` | Vue 组件:渲染 ② 的类 + 行为增强 |
12
- | ④ 服务层 | `@manohub/ui` | 命令式反馈:`toast()` / `confirm()` / `alert()` / `showLoading()`(宿主 + 队列 + 生命周期,共用 ③ 的组件) |
13
-
14
- - **视觉与几何**:《Farris Web 基础视觉规范》(`@aihub/theme` 的令牌与组件实测值)
15
- - **令牌命名**:daisyUI 式语义槽位(`--ui-primary` / `--ui-base-content` / `--ui-info*` / `--ui-warning*` …,`default ≠ primary`)
16
- - **组件 API**:shadcn 通行词汇(变体维度 `tone` × `shape` × `size`、compound 点号子件、受控 prop + 语义事件)
17
- - **实现**:零依赖手写 CSS,类名 `.mh-*`(bem-lite)
18
-
19
- > **0.5.0(破坏性变更)**:`Section` 组件已退役 —— 它的「标题行 + 右端操作位(`extra`)」能力并入
20
- > **`Form.Header`**(支持 `title` / `description` / `extra`,且成员归位到表单最前)。
21
- > 旧写法 `Section` / `Form.Section` 统一改为 `Form.Header`;需要「区块分组」时用 `Panel` 或嵌套容器。
22
-
23
- ## 安装
24
-
25
- ```bash
26
- pnpm add @manohub/ui @manohub/theme
27
- ```
28
-
29
- ## 接入
30
-
31
- 样式两行,顺序固定(先主题后组件面;若应用的样式链已级联本包,则不必单独引):
32
-
33
- ```css
34
- @import "@manohub/theme/default.css"; /* ① 全局令牌(值) */
35
- @import "@manohub/ui/styles.css"; /* ② 组件面(类 + 组件令牌值) */
36
- ```
37
-
38
- 只写静态页(不装 Vue)时引这两行即可 —— 类名与 `data-*` 状态协议直接可用。
39
-
40
- **② 的第一条 import 就是元素级 reset**(随包内置,不需要第三行),它只有两面:
41
-
42
- 1. **盒模型**:`box-sizing: border-box` 覆盖容器、全部后代与伪元素(本包所有面的几何前提);
43
- 2. **容器基座**:`[data-manohub-ui]` 上的字族 / 字号 / 行高 / 字色 / 底色 / 整链高度(令牌的落点)。
44
-
45
- 作用域锚 `[data-manohub-ui]` 且特异性为 0 —— 应用侧写任何元素选择器都能盖过它。
46
- **它有意不再归零标题字阶、列表序号、链接下划线、控件外观**:那些规则在 Tailwind 的层外
47
- (未分层 > 分层),会把消费方的工具类整片压住(`border*`、`img` 上的 `h-*`、`hidden` …);
48
- 需要归零的元素各自归到渲染它的组件面上(`img` 在 Avatar / Upload、`a` 在 Button、
49
- `textarea` 的 `resize` 在 `.mh-input--textarea`、`h1`-`h6` 在 `.mh-text`)。
50
- Tailwind 消费方另有 preflight 兜底,两者不冲突。
51
-
52
- 所以**不必再自己写一份全局 reset**;也**不要**用元素级选择器去补(那正是被压住的成因)。
53
-
54
- 本包**可独立发布**:组件与类型一律从 `@manohub/ui` 直接引;下游(如 `@manohub/kit`)若转出口,是下游自己的选择。
55
-
56
- ```tsx
57
- import { Card, Form, Tree, Checkbox } from '@manohub/ui'
58
- ```
59
-
60
- ## 组件清单
61
-
62
- | 分组 | 组件 |
63
- |---|---|
64
- | 容器与分区 | `Page`(页面级骨架:`.Header` / `.Body` / `.Footer` / `.Filter` / `.Toolbar` / `.Split`)、`Panel`(+ `.Header` / `.Body` / `.Footer`)、`Card`(+ 三件)、`Nav`、`Layout`(`Layout.Row` 排「行」/ `Layout.Column` 排「列」:轴向 × 间距档 × 对齐) |
65
- | 数据展示 | `Tree`、`ListView`(+ `.CardItem`)、`Badge`、`Tag`(`Badge` 的可关闭 / 可新增封装) |
66
- | 展示 | `Avatar`(+ `.Group`)、`Skeleton`(行 / 列表 / 块状) |
67
- | 表单基础(**自绘**) | `Button`(+ `.Group` / `.Divider`;五型 / 小号 / 加载 / 菜单按钮 / 连体切换)、`Input`(+ `.Group` / `.Chip` / `.Display` / `.Textarea`;清除 / 可见性切换 / 校验)、`Search`(搜索框:值 / 搜索 / 清空三条回调)、`Select`(单选 / 多选 / 搜索 / 加载;面板用原生 popover)、`SelectTree`(树形态:仅叶子可选 + 本地过滤 + 命中高亮;与 `Select` 平级导出、共用触发器与面板)、`Switch`(表格档 / 表单档) |
68
- | 表单与选择 | `Form`(+ `.Header` / `.Item`;标签体系、成员归位、`v-model` 值收集与命令式 `clear()`)、`Filter`(+ `.Item`;`Form` 的壳:条件字段写成子件、控件自放、查询/重置与快照归一)、`Checkbox`、`Radio`(+ `.Group` / `.Card`;卡片式单选)、`Capsule`(胶囊选择器;胶囊 / 方形两档外形,与 `Tabs` 组合即页签) |
69
- | 反馈与三态 | `Notice`(条状提示)、`Notification`(通知卡:标题 + 头像 / 标签 / 操作 / 关闭位)、`QueryState`(三态容器;内建空 / 错误插画取自设计交付的四张 SVG,原样内联在 `src/utils/state-illustration.ts`)、`Loading`(转圈 + 遮罩:行内 / 区域 / 全屏三形态) |
70
- | 反馈与引导(**自绘**) | `Toast`(消息提示:语义四档 / loading + 可选动作 + 自动消失计时 + `.Stack` 堆叠)、`Steps`(步骤条:节点式 / 燕尾段式 / `.Progress` 进度条) |
71
- | 数据展示(**自绘**) | `Table`(列 × 数据 + 选择列 + 排序事件 + 固定表头 / 固定列 + 批量栏 / 合计行;排序与列宽拖拽算法归调用方)、`Pagination`(总数 / 每页条数 / 页码窗口 / 简单档 / 外框档)、`TabBar`(下划线页签 + 「更多」收纳) |
72
- | 内容与文件 | `CodeBlock`(**一族三件**:组合件 `CodeBlock` 按 `editable` 切只读 / 编辑两形态;`.View` 只读展示 —— 行内 chip / 代码块 + 语言角标 + 图标复制位;`.Editor` 可编辑 —— 等宽多行 + 按行自适应 / 限高内滚 / 只读、禁用)、`Upload`(+ `.Thumbs`;拖拽 / 点击上传区 + 已传文件列表) |
73
- | 浮层(**自绘**) | `Dialog`(原生 `<dialog>` + 模态皮肤;关闭受控)、`Tooltip`(**零 JS**:显隐与定位全走操作层 hover 档) |
74
- | 操作层(跨件原语) | `Collapse`(+ `.Stack`)、`Tabs`(+ `TabPanel`,面板切换骨架 —— 显隐归组件层,非零 JS 原语);浮层只提供样式层(`styles/operations/popup.css`,零 JS 可直接用),Vue 浮层仍用 farris 适配件 |
75
-
76
- ## 三态的操作按钮
77
-
78
- `QueryState` / `Tree` / `ListView` 的空态·错误态操作按钮就是**本包的 `Button`**(`variant="primary"`),
79
- 与全站按钮同族 —— 应用**不需要**注入任何东西,只要把文案与回调给上:
80
-
81
- ```vue
82
- <QueryState
83
- :empty="list.length === 0"
84
- empty-action-text="新建"
85
- :on-empty-action="openCreate"
86
- >
87
- <MyList />
88
- </QueryState>
89
- ```
90
-
91
- - 要换外观:改主题令牌(`Button` 的外观档位是 `variant`);
92
- - 要换结构(多个按钮 / 自定义动作区):用 `actions` 插槽自绘。
93
-
94
- ## 服务层(组件树之外调反馈)
95
-
96
- 组件是**受控**的(可见性归调用方);组件树之外(请求回调、路由守卫、工具函数里)要弹提示时用服务层:
97
-
98
- ```ts
99
- import { toast, confirm, alert, showLoading, configureHost } from '@manohub/ui'
100
-
101
- toast('success', '保存成功') // 3 秒自动消失
102
- toast('error', '导出失败', { action: { text: '重试', onClick: retry } })
103
- const pending = toast('loading', '正在导入…', { duration: 0 }) // 常驻,完成后自己收
104
- pending.close()
105
-
106
- if (await confirm({ title: '删除确认', detail: '删除后不可恢复', okDanger: true })) await remove()
107
- await alert({ title: '导入完成', detail: '共 128 条' })
108
-
109
- const done = showLoading('保存中…') // 引用计数:并发调用要各关各的
110
- try { await save() } finally { done() }
111
- ```
112
-
113
- **四件必须知道的事**:
114
-
115
- 1. **服务层不新造浮层**:`toast()` 渲染的是本包的 `Toast`、`confirm()` 渲染的是本包的 `Dialog`、
116
- `showLoading()` 渲染的是本包的 `Loading` —— 外观改一处两处一起变。
117
- 2. **宿主即渲染位置**:解析顺序是「**显式 `configureHost(el)`** → 带 `[data-manohub-ui]` 作用域锚的容器
118
- → `document.body`」。微前端下**必须落回本应用自己的容器**:本包全部令牌(全局值 + 组件值)都锚在
119
- `[data-manohub-ui]` 上,落在容器外的浮层会「样式全丢」(变量解析为空 +
120
- 应用侧样式被 `scopecss` 前缀化后匹配不到)。骨架层只需在包裹节点上补一个
121
- `data-manohub-ui` 属性,服务层不必反向依赖它。
122
- 注:`.app-container` 是 `@manohub/kit` 的输出类名(内部命名),**不是**跨包契约,服务层不认它。
123
- 3. **按需挂载、自动收尾**:首次调用才建宿主与 Vue 实例(模块顶层零 DOM 操作);
124
- `toast` 队列空了、`loading` 计数归零即收掉宿主 —— 反复重挂不留悬挂实例。
125
- 4. **`loading` 是引用计数语义**:并发的两次「显示」只关一次时遮罩仍在(先结束的那个不会把
126
- 别人的遮罩一起收掉)。推荐用返回的句柄在 `finally` 里关掉自己那一次。
127
-
128
- ## 主题层
129
-
130
- 全局令牌(`--ui-primary` / `--ui-space-*` / `--ui-font-*` 这类跨件共用的值)**不在本包**,已拆成独立包
131
- **`@manohub/theme`**(值层与面层分开:值随主题变、面不随主题变)。每个主题分五片:
132
- `colors` / `typography` / `spacing` / `radius` / `shadows`,一律锚定 **`[data-manohub-ui]`**
133
- (库品牌作用域锚;micro-app 的 scopecss 不作用域化 `:root`,定义在 `:root` 会泄漏到宿主)。
134
-
135
- 只服务单一组件的令牌分两半落在本包:
136
-
137
- | 位置 | 内容 | 锚 |
138
- |---|---|---|
139
- | `styles/components/<件>.tokens.css` | **基础值**(唯一的、两套主题同值的那一条) | `[data-manohub-ui]` |
140
- | `styles/components/<件>.css` | **档位改写**(`.mh-<件>--<档>` 覆盖同一令牌)+ `--mh-*` 内部状态变量 | 元件根类 / 档位类 |
141
-
142
- 后一半必须在面里:它们靠「同一元素上两个选择器改写同一个令牌」生效,搬走就断链。
143
-
144
- 随包两套:
145
-
146
- | 主题 | 入口 | 锚点 | 取值来源 |
147
- |---|---|---|---|
148
- | `default` | `@manohub/theme/default.css` | `[data-manohub-ui]`(兜底套) | AIHub 品牌蓝(primary `#2660FF`)|
149
- | `farris` | `@manohub/theme/farris.css` | `[data-manohub-ui][data-theme='farris']` | 《Farris Web 基础视觉规范》(primary `#2a87ff`,色板编号 Th/Au/Ne/Te 逐条标注)|
150
-
151
- 换皮只需给容器加属性(`createSubApp({ theme: 'farris' })` 会写 `data-theme`),不动类名、不动组件代码、不重打包。
152
- 新增主题 = `packages/theme/src/<name>/` 新目录,令牌锚 `[data-manohub-ui][data-theme='<name>']`,
153
- 且必须**全量覆盖** default 的令牌。
154
-
155
- 局部换主题:在更深的容器上重设变量即可,例如 `.role-tree-pane { --ui-primary: #7C3AED; }`。
1
+ # @manohub/ui
2
+
3
+ AIHub **自绘组件层**:不依赖 farris 的手写 Vue TSX 组件 + 自带令牌层。
4
+
5
+ 本包分三层,**可分别引用**:
6
+
7
+ | 层 | 入口 | 内容 |
8
+ |---|---|---|
9
+ | ① 主题 | `@manohub/theme/default.css`(兜底)/ `@manohub/theme/farris.css`(Farris 规范) | **全局**令牌(值)—— 随主题包独立发布,换主题只换这一行 |
10
+ | ② 组件面 | `@manohub/ui/styles.css` | **元素级 reset**(只有盒模型 + 容器基座两面,见下)+ 类与状态协议 + 组件令牌基础值,**无需 JS** 即可使用 |
11
+ | ③ Vue 层 | `@manohub/ui` | Vue 组件:渲染 ② 的类 + 行为增强 |
12
+ | ④ 服务层 | `@manohub/ui` | 命令式反馈:`toast()` / `confirm()` / `alert()` / `showLoading()`(宿主 + 队列 + 生命周期,共用 ③ 的组件) |
13
+
14
+ - **视觉与几何**:《Farris Web 基础视觉规范》(`@aihub/theme` 的令牌与组件实测值)
15
+ - **令牌命名**:daisyUI 式语义槽位(`--ui-primary` / `--ui-base-content` / `--ui-info*` / `--ui-warning*` …,`default ≠ primary`)
16
+ - **组件 API**:shadcn 通行词汇(变体维度 `tone` × `shape` × `size`、compound 点号子件、受控 prop + 语义事件)
17
+ - **实现**:零依赖手写 CSS,类名 `.mh-*`(bem-lite)
18
+
19
+ > **0.5.0(破坏性变更)**:`Section` 组件已退役 —— 它的「标题行 + 右端操作位(`extra`)」能力并入
20
+ > **`Form.Header`**(支持 `title` / `description` / `extra`,且成员归位到表单最前)。
21
+ > 旧写法 `Section` / `Form.Section` 统一改为 `Form.Header`;需要「区块分组」时用 `Panel` 或嵌套容器。
22
+
23
+ ## 安装
24
+
25
+ ```bash
26
+ pnpm add @manohub/ui @manohub/theme
27
+ ```
28
+
29
+ ## 接入
30
+
31
+ 样式两行,顺序固定(先主题后组件面;若应用的样式链已级联本包,则不必单独引):
32
+
33
+ ```css
34
+ @import "@manohub/theme/default.css"; /* ① 全局令牌(值) */
35
+ @import "@manohub/ui/styles.css"; /* ② 组件面(类 + 组件令牌值) */
36
+ ```
37
+
38
+ 只写静态页(不装 Vue)时引这两行即可 —— 类名与 `data-*` 状态协议直接可用。
39
+
40
+ **② 的第一条 import 就是元素级 reset**(随包内置,不需要第三行),它只有两面:
41
+
42
+ 1. **盒模型**:`box-sizing: border-box` 覆盖容器、全部后代与伪元素(本包所有面的几何前提);
43
+ 2. **容器基座**:`[data-manohub-ui]` 上的字族 / 字号 / 行高 / 字色 / 底色 / 整链高度(令牌的落点)。
44
+
45
+ 作用域锚 `[data-manohub-ui]` 且特异性为 0 —— 应用侧写任何元素选择器都能盖过它。
46
+ **它有意不再归零标题字阶、列表序号、链接下划线、控件外观**:那些规则在 Tailwind 的层外
47
+ (未分层 > 分层),会把消费方的工具类整片压住(`border*`、`img` 上的 `h-*`、`hidden` …);
48
+ 需要归零的元素各自归到渲染它的组件面上(`img` 在 Avatar / Upload、`a` 在 Button、
49
+ `textarea` 的 `resize` 在 `.mh-input--textarea`、`h1`-`h6` 在 `.mh-text`)。
50
+ Tailwind 消费方另有 preflight 兜底,两者不冲突。
51
+
52
+ 所以**不必再自己写一份全局 reset**;也**不要**用元素级选择器去补(那正是被压住的成因)。
53
+
54
+ 本包**可独立发布**:组件与类型一律从 `@manohub/ui` 直接引;下游(如 `@manohub/kit`)若转出口,是下游自己的选择。
55
+
56
+ ```tsx
57
+ import { Card, Form, Tree, Checkbox } from '@manohub/ui'
58
+ ```
59
+
60
+ ## 组件清单
61
+
62
+ | 分组 | 组件 |
63
+ |---|---|
64
+ | 容器与分区 | `Page`(页面级骨架:`.Header` / `.Body` / `.Footer` / `.Filter` / `.Toolbar` / `.Split`)、`Panel`(+ `.Header` / `.Body` / `.Footer`)、`Card`(+ 三件)、`Nav`、`Layout`(`Layout.Row` 排「行」/ `Layout.Column` 排「列」:轴向 × 间距档 × 对齐) |
65
+ | 数据展示 | `Tree`、`ListView`(+ `.CardItem`)、`Badge`、`Tag`(`Badge` 的可关闭 / 可新增封装) |
66
+ | 展示 | `Avatar`(+ `.Group`)、`Skeleton`(行 / 列表 / 块状) |
67
+ | 表单基础(**自绘**) | `Button`(+ `.Group` / `.Divider`;五型 / 小号 / 加载 / 菜单按钮 / 连体切换)、`Input`(+ `.Group` / `.Chip` / `.Display` / `.Textarea`;清除 / 可见性切换 / 校验)、`Search`(搜索框:值 / 搜索 / 清空三条回调)、`Select`(单选 / 多选 / 搜索 / 加载;面板用原生 popover)、`SelectTree`(树形态:仅叶子可选 + 本地过滤 + 命中高亮;与 `Select` 平级导出、共用触发器与面板)、`Switch`(表格档 / 表单档) |
68
+ | 表单与选择 | `Form`(+ `.Header` / `.Item`;标签体系、成员归位、`v-model` 值收集与命令式 `clear()`)、`Filter`(+ `.Item`;`Form` 的壳:条件字段写成子件、控件自放、查询/重置与快照归一)、`Checkbox`、`Radio`(+ `.Group` / `.Card`;卡片式单选)、`Capsule`(胶囊选择器;胶囊 / 方形两档外形,与 `Tabs` 组合即页签) |
69
+ | 反馈与三态 | `Notice`(条状提示)、`Notification`(通知卡:标题 + 头像 / 标签 / 操作 / 关闭位)、`QueryState`(三态容器;内建空 / 错误插画取自设计交付的四张 SVG,原样内联在 `src/utils/state-illustration.ts`)、`Loading`(转圈 + 遮罩:行内 / 区域 / 全屏三形态) |
70
+ | 反馈与引导(**自绘**) | `Toast`(消息提示:语义四档 / loading + 可选动作 + 自动消失计时 + `.Stack` 堆叠)、`Steps`(步骤条:节点式 / 燕尾段式 / `.Progress` 进度条) |
71
+ | 数据展示(**自绘**) | `Table`(列 × 数据 + 选择列 + 排序事件 + 固定表头 / 固定列 + 批量栏 / 合计行;排序与列宽拖拽算法归调用方)、`Pagination`(总数 / 每页条数 / 页码窗口 / 简单档 / 外框档)、`TabBar`(下划线页签 + 「更多」收纳) |
72
+ | 内容与文件 | `CodeBlock`(**一族三件**:组合件 `CodeBlock` 按 `editable` 切只读 / 编辑两形态;`.View` 只读展示 —— 行内 chip / 代码块 + 语言角标 + 图标复制位;`.Editor` 可编辑 —— 等宽多行 + 按行自适应 / 限高内滚 / 只读、禁用)、`Upload`(+ `.Thumbs`;拖拽 / 点击上传区 + 已传文件列表) |
73
+ | 浮层(**自绘**) | `Dialog`(原生 `<dialog>` + 模态皮肤;关闭受控)、`Tooltip`(**零 JS**:显隐与定位全走操作层 hover 档) |
74
+ | 操作层(跨件原语) | `Collapse`(+ `.Stack`)、`Tabs`(+ `TabPanel`,面板切换骨架 —— 显隐归组件层,非零 JS 原语);浮层只提供样式层(`styles/operations/popup.css`,零 JS 可直接用),Vue 浮层仍用 farris 适配件 |
75
+
76
+ ## 三态的操作按钮
77
+
78
+ `QueryState` / `Tree` / `ListView` 的空态·错误态操作按钮就是**本包的 `Button`**(`variant="primary"`),
79
+ 与全站按钮同族 —— 应用**不需要**注入任何东西,只要把文案与回调给上:
80
+
81
+ ```vue
82
+ <QueryState
83
+ :empty="list.length === 0"
84
+ empty-action-text="新建"
85
+ :on-empty-action="openCreate"
86
+ >
87
+ <MyList />
88
+ </QueryState>
89
+ ```
90
+
91
+ - 要换外观:改主题令牌(`Button` 的外观档位是 `variant`);
92
+ - 要换结构(多个按钮 / 自定义动作区):用 `actions` 插槽自绘。
93
+
94
+ ## 服务层(组件树之外调反馈)
95
+
96
+ 组件是**受控**的(可见性归调用方);组件树之外(请求回调、路由守卫、工具函数里)要弹提示时用服务层:
97
+
98
+ ```ts
99
+ import { toast, confirm, alert, showLoading, configureHost } from '@manohub/ui'
100
+
101
+ toast('success', '保存成功') // 3 秒自动消失
102
+ toast('error', '导出失败', { action: { text: '重试', onClick: retry } })
103
+ const pending = toast('loading', '正在导入…', { duration: 0 }) // 常驻,完成后自己收
104
+ pending.close()
105
+
106
+ if (await confirm({ title: '删除确认', detail: '删除后不可恢复', okDanger: true })) await remove()
107
+ await alert({ title: '导入完成', detail: '共 128 条' })
108
+
109
+ const done = showLoading('保存中…') // 引用计数:并发调用要各关各的
110
+ try { await save() } finally { done() }
111
+ ```
112
+
113
+ **四件必须知道的事**:
114
+
115
+ 1. **服务层不新造浮层**:`toast()` 渲染的是本包的 `Toast`、`confirm()` 渲染的是本包的 `Dialog`、
116
+ `showLoading()` 渲染的是本包的 `Loading` —— 外观改一处两处一起变。
117
+ 2. **宿主即渲染位置**:解析顺序是「**显式 `configureHost(el)`** → 带 `[data-manohub-ui]` 作用域锚的容器
118
+ → `document.body`」。微前端下**必须落回本应用自己的容器**:本包全部令牌(全局值 + 组件值)都锚在
119
+ `[data-manohub-ui]` 上,落在容器外的浮层会「样式全丢」(变量解析为空 +
120
+ 应用侧样式被 `scopecss` 前缀化后匹配不到)。骨架层只需在包裹节点上补一个
121
+ `data-manohub-ui` 属性,服务层不必反向依赖它。
122
+ 注:`.app-container` 是 `@manohub/kit` 的输出类名(内部命名),**不是**跨包契约,服务层不认它。
123
+ 3. **按需挂载、自动收尾**:首次调用才建宿主与 Vue 实例(模块顶层零 DOM 操作);
124
+ `toast` 队列空了、`loading` 计数归零即收掉宿主 —— 反复重挂不留悬挂实例。
125
+ 4. **`loading` 是引用计数语义**:并发的两次「显示」只关一次时遮罩仍在(先结束的那个不会把
126
+ 别人的遮罩一起收掉)。推荐用返回的句柄在 `finally` 里关掉自己那一次。
127
+
128
+ ## 主题层
129
+
130
+ 全局令牌(`--ui-primary` / `--ui-space-*` / `--ui-font-*` 这类跨件共用的值)**不在本包**,已拆成独立包
131
+ **`@manohub/theme`**(值层与面层分开:值随主题变、面不随主题变)。每个主题分五片:
132
+ `colors` / `typography` / `spacing` / `radius` / `shadows`,一律锚定 **`[data-manohub-ui]`**
133
+ (库品牌作用域锚;micro-app 的 scopecss 不作用域化 `:root`,定义在 `:root` 会泄漏到宿主)。
134
+
135
+ 只服务单一组件的令牌分两半落在本包:
136
+
137
+ | 位置 | 内容 | 锚 |
138
+ |---|---|---|
139
+ | `styles/components/<件>.tokens.css` | **基础值**(唯一的、两套主题同值的那一条) | `[data-manohub-ui]` |
140
+ | `styles/components/<件>.css` | **档位改写**(`.mh-<件>--<档>` 覆盖同一令牌)+ `--mh-*` 内部状态变量 | 元件根类 / 档位类 |
141
+
142
+ 后一半必须在面里:它们靠「同一元素上两个选择器改写同一个令牌」生效,搬走就断链。
143
+
144
+ 随包两套:
145
+
146
+ | 主题 | 入口 | 锚点 | 取值来源 |
147
+ |---|---|---|---|
148
+ | `default` | `@manohub/theme/default.css` | `[data-manohub-ui]`(兜底套) | AIHub 品牌蓝(primary `#2660FF`)|
149
+ | `farris` | `@manohub/theme/farris.css` | `[data-manohub-ui][data-theme='farris']` | 《Farris Web 基础视觉规范》(primary `#2a87ff`,色板编号 Th/Au/Ne/Te 逐条标注)|
150
+
151
+ 换皮只需给容器加属性(`createSubApp({ theme: 'farris' })` 会写 `data-theme`),不动类名、不动组件代码、不重打包。
152
+ 新增主题 = `packages/theme/src/<name>/` 新目录,令牌锚 `[data-manohub-ui][data-theme='<name>']`,
153
+ 且必须**全量覆盖** default 的令牌。
154
+
155
+ 局部换主题:在更深的容器上重设变量即可,例如 `.role-tree-pane { --ui-primary: #7C3AED; }`。
@@ -111,7 +111,14 @@ const FormItem = /* @__PURE__ */ defineComponent({
111
111
  "data-invalid": props.error ? "true" : "false",
112
112
  "style": styles
113
113
  }, [showLabel ? createVNode("label", {
114
- "class": "mh-form-item__label"
114
+ "class": "mh-form-item__label",
115
+ "onClick": (
116
+ // 只在真有点击可转发(有 tip ⇒ label 里才有 labelable 元素)时挂;理由见下方 ③
117
+ props.tip ? (event) => {
118
+ if (event.target?.closest(".mh-form-item__tip-btn")) return;
119
+ event.preventDefault();
120
+ } : void 0
121
+ )
115
122
  }, [createVNode("span", {
116
123
  "class": "mh-form-item__label-text"
117
124
  }, [props.label]), props.required ? createVNode("span", {
@@ -1,131 +1,131 @@
1
- /**
2
- * Avatar —— 头像(四档尺寸 / 文字 / 图标 / 占位 / 方角 / 带框 / 计数 / 头像组 / 角标)。
3
- *
4
- * 出处:`@aihub/theme` 的 `playground/components/avatar.css` 与 `src/components/avatar.css`
5
- * (实测四档 24 / 36 / 60 / 80;字母底色取主色;角标高 20 白描边)。
6
- *
7
- * 两条来自规范的硬结论,改前先读:
8
- * 1. **圆形裁切归图片自身,容器不裁**:角上的角标(`__badge`)与徽章(`__chip`)是绝对定位件,
9
- * 容器若带 `overflow: hidden`,会沿圆弧把它们各切掉一半(实测反馈)。故容器 `overflow: visible`,
10
- * 图片用 `border-radius: inherit` 跟着形态自裁。
11
- * 2. **头像组靠负边距堆叠**(`.mh-avatar-group`),每个头像带 2px 的底描边把相邻项隔开。
12
- */
13
- .mh-avatar {
14
- display: inline-flex;
15
- align-items: center;
16
- justify-content: center;
17
- position: relative;
18
- flex-shrink: 0;
19
- overflow: visible; /* 见文件头第 1 条:裁切归图片 */
20
- border-radius: var(--ui-radius-full);
21
- background: var(--ui-base-400); /* Ne04 占位底 */
22
- color: var(--ui-base-100); /* 占位前景 */
23
- }
24
-
25
- /* 图片:撑满 + 跟随形态自裁(否则去掉容器 overflow 后长宽不符的图会外溢)。
26
- `display: block` 必须自己写:元素级基线不再把 `img` 转块级(那条会压消费方的 `h-*` / `hidden`),
27
- 否则行内基线间隙会把圆形头像顶偏。 */
28
- .mh-avatar > img {
29
- display: block;
30
- width: 100%;
31
- height: 100%;
32
- border-radius: inherit;
33
- object-fit: cover;
34
- }
35
-
36
- /* ===== 尺寸四档 ===== */
37
- .mh-avatar--sm {
38
- width: var(--ui-avatar-size-sm);
39
- height: var(--ui-avatar-size-sm);
40
- font-size: var(--ui-font-caption);
41
- }
42
- .mh-avatar--md {
43
- width: var(--ui-avatar-size-md);
44
- height: var(--ui-avatar-size-md);
45
- font-size: var(--ui-font-caption);
46
- }
47
- .mh-avatar--lg {
48
- width: var(--ui-avatar-size-lg);
49
- height: var(--ui-avatar-size-lg);
50
- font-size: var(--ui-font-title);
51
- }
52
- .mh-avatar--xl {
53
- width: var(--ui-avatar-size-xl);
54
- height: var(--ui-avatar-size-xl);
55
- font-size: var(--ui-font-display);
56
- }
57
-
58
- /* ===== 内容形态 ===== */
59
- /* 文字头像:底取主色(业务要按人名哈希换色时给 `.mh-avatar--letter` 覆盖 background 即可) */
60
- .mh-avatar--letter {
61
- background: var(--ui-primary);
62
- }
63
- /* 图标头像:图标由 @manohub/icon 渲染,这里只给尺寸档 */
64
- .mh-avatar--icon {
65
- color: var(--ui-base-100);
66
- }
67
- /* 占位:虚线框 + 说明字(虚线线色取线型档,口径「实线 base-300 / 虚线 base-400」) */
68
- .mh-avatar--placeholder {
69
- border: 1px dashed var(--ui-line-dashed);
70
- background: var(--ui-base-100);
71
- color: var(--ui-base-content-subtle);
72
- font-size: var(--ui-font-caption);
73
- }
74
- /* 方角(商业图像):圆角矩形 */
75
- .mh-avatar--square {
76
- border-radius: var(--ui-radius-control);
77
- }
78
- /* 带框:靠阴影画出 2px 底环(不占布局,避免与角标抢位) */
79
- .mh-avatar--framed {
80
- box-shadow: 0 0 0 2px var(--ui-base-100), var(--ui-shadow-card);
81
- }
82
- /* 计数档(头像组末位的「+N」) */
83
- .mh-avatar--count {
84
- background: var(--ui-base-200);
85
- color: var(--ui-base-content-muted);
86
- font-size: var(--ui-font-caption);
87
- }
88
-
89
- /* ===== 角上外挂件(见文件头第 1 条:容器不裁,故它们不会被切)===== */
90
- .mh-avatar__badge {
91
- position: absolute;
92
- top: 0;
93
- right: 0;
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- min-width: var(--ui-avatar-badge-size);
98
- height: var(--ui-avatar-badge-size);
99
- padding: 0 var(--ui-space-1);
100
- border-radius: var(--ui-radius-full);
101
- background: var(--ui-error); /* 红底(规范 Badge 专页实测) */
102
- border: 2px solid var(--ui-base-100); /* 白描边 */
103
- color: var(--ui-error-content);
104
- font-size: var(--ui-font-caption);
105
- }
106
- .mh-avatar__chip {
107
- position: absolute;
108
- right: -2px;
109
- bottom: -2px;
110
- display: flex;
111
- align-items: center;
112
- justify-content: center;
113
- width: 24px;
114
- height: 24px;
115
- border-radius: var(--ui-radius-full);
116
- background: var(--ui-primary);
117
- border: 2px solid var(--ui-base-100);
118
- cursor: pointer;
119
- }
120
-
121
- /* ===== 头像组:负边距堆叠,靠 2px 底描边分隔 ===== */
122
- .mh-avatar-group {
123
- display: inline-flex;
124
- align-items: center;
125
- }
126
- .mh-avatar-group .mh-avatar {
127
- border: 2px solid var(--ui-base-100);
128
- }
129
- .mh-avatar-group .mh-avatar + .mh-avatar {
130
- margin-left: calc(-1 * var(--ui-avatar-gap));
131
- }
1
+ /**
2
+ * Avatar —— 头像(四档尺寸 / 文字 / 图标 / 占位 / 方角 / 带框 / 计数 / 头像组 / 角标)。
3
+ *
4
+ * 出处:`@aihub/theme` 的 `playground/components/avatar.css` 与 `src/components/avatar.css`
5
+ * (实测四档 24 / 36 / 60 / 80;字母底色取主色;角标高 20 白描边)。
6
+ *
7
+ * 两条来自规范的硬结论,改前先读:
8
+ * 1. **圆形裁切归图片自身,容器不裁**:角上的角标(`__badge`)与徽章(`__chip`)是绝对定位件,
9
+ * 容器若带 `overflow: hidden`,会沿圆弧把它们各切掉一半(实测反馈)。故容器 `overflow: visible`,
10
+ * 图片用 `border-radius: inherit` 跟着形态自裁。
11
+ * 2. **头像组靠负边距堆叠**(`.mh-avatar-group`),每个头像带 2px 的底描边把相邻项隔开。
12
+ */
13
+ .mh-avatar {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ position: relative;
18
+ flex-shrink: 0;
19
+ overflow: visible; /* 见文件头第 1 条:裁切归图片 */
20
+ border-radius: var(--ui-radius-full);
21
+ background: var(--ui-base-400); /* Ne04 占位底 */
22
+ color: var(--ui-base-100); /* 占位前景 */
23
+ }
24
+
25
+ /* 图片:撑满 + 跟随形态自裁(否则去掉容器 overflow 后长宽不符的图会外溢)。
26
+ `display: block` 必须自己写:元素级基线不再把 `img` 转块级(那条会压消费方的 `h-*` / `hidden`),
27
+ 否则行内基线间隙会把圆形头像顶偏。 */
28
+ .mh-avatar > img {
29
+ display: block;
30
+ width: 100%;
31
+ height: 100%;
32
+ border-radius: inherit;
33
+ object-fit: cover;
34
+ }
35
+
36
+ /* ===== 尺寸四档 ===== */
37
+ .mh-avatar--sm {
38
+ width: var(--ui-avatar-size-sm);
39
+ height: var(--ui-avatar-size-sm);
40
+ font-size: var(--ui-font-caption);
41
+ }
42
+ .mh-avatar--md {
43
+ width: var(--ui-avatar-size-md);
44
+ height: var(--ui-avatar-size-md);
45
+ font-size: var(--ui-font-caption);
46
+ }
47
+ .mh-avatar--lg {
48
+ width: var(--ui-avatar-size-lg);
49
+ height: var(--ui-avatar-size-lg);
50
+ font-size: var(--ui-font-title);
51
+ }
52
+ .mh-avatar--xl {
53
+ width: var(--ui-avatar-size-xl);
54
+ height: var(--ui-avatar-size-xl);
55
+ font-size: var(--ui-font-display);
56
+ }
57
+
58
+ /* ===== 内容形态 ===== */
59
+ /* 文字头像:底取主色(业务要按人名哈希换色时给 `.mh-avatar--letter` 覆盖 background 即可) */
60
+ .mh-avatar--letter {
61
+ background: var(--ui-primary);
62
+ }
63
+ /* 图标头像:图标由 @manohub/icon 渲染,这里只给尺寸档 */
64
+ .mh-avatar--icon {
65
+ color: var(--ui-base-100);
66
+ }
67
+ /* 占位:虚线框 + 说明字(虚线线色取线型档,口径「实线 base-300 / 虚线 base-400」) */
68
+ .mh-avatar--placeholder {
69
+ border: 1px dashed var(--ui-line-dashed);
70
+ background: var(--ui-base-100);
71
+ color: var(--ui-base-content-subtle);
72
+ font-size: var(--ui-font-caption);
73
+ }
74
+ /* 方角(商业图像):圆角矩形 */
75
+ .mh-avatar--square {
76
+ border-radius: var(--ui-radius-control);
77
+ }
78
+ /* 带框:靠阴影画出 2px 底环(不占布局,避免与角标抢位) */
79
+ .mh-avatar--framed {
80
+ box-shadow: 0 0 0 2px var(--ui-base-100), var(--ui-shadow-card);
81
+ }
82
+ /* 计数档(头像组末位的「+N」) */
83
+ .mh-avatar--count {
84
+ background: var(--ui-base-200);
85
+ color: var(--ui-base-content-muted);
86
+ font-size: var(--ui-font-caption);
87
+ }
88
+
89
+ /* ===== 角上外挂件(见文件头第 1 条:容器不裁,故它们不会被切)===== */
90
+ .mh-avatar__badge {
91
+ position: absolute;
92
+ top: 0;
93
+ right: 0;
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ min-width: var(--ui-avatar-badge-size);
98
+ height: var(--ui-avatar-badge-size);
99
+ padding: 0 var(--ui-space-1);
100
+ border-radius: var(--ui-radius-full);
101
+ background: var(--ui-error); /* 红底(规范 Badge 专页实测) */
102
+ border: 2px solid var(--ui-base-100); /* 白描边 */
103
+ color: var(--ui-error-content);
104
+ font-size: var(--ui-font-caption);
105
+ }
106
+ .mh-avatar__chip {
107
+ position: absolute;
108
+ right: -2px;
109
+ bottom: -2px;
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ width: 24px;
114
+ height: 24px;
115
+ border-radius: var(--ui-radius-full);
116
+ background: var(--ui-primary);
117
+ border: 2px solid var(--ui-base-100);
118
+ cursor: pointer;
119
+ }
120
+
121
+ /* ===== 头像组:负边距堆叠,靠 2px 底描边分隔 ===== */
122
+ .mh-avatar-group {
123
+ display: inline-flex;
124
+ align-items: center;
125
+ }
126
+ .mh-avatar-group .mh-avatar {
127
+ border: 2px solid var(--ui-base-100);
128
+ }
129
+ .mh-avatar-group .mh-avatar + .mh-avatar {
130
+ margin-left: calc(-1 * var(--ui-avatar-gap));
131
+ }