@manohub/ui 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +12 -4
  2. package/dist/components/button/index.d.ts +8 -8
  3. package/dist/components/capsule/index.d.ts +13 -9
  4. package/dist/components/capsule/index.js +1 -1
  5. package/dist/components/card/index.js +7 -4
  6. package/dist/components/checkbox/index.js +1 -0
  7. package/dist/components/dialog/index.d.ts +58 -6
  8. package/dist/components/dialog/index.js +45 -8
  9. package/dist/components/drawer/index.d.ts +18 -6
  10. package/dist/components/drawer/index.js +11 -5
  11. package/dist/components/form/index.d.ts +115 -17
  12. package/dist/components/form/index.js +39 -9
  13. package/dist/components/input/index.d.ts +4 -4
  14. package/dist/components/input/index.js +1 -1
  15. package/dist/components/layout/index.d.ts +43 -1
  16. package/dist/components/layout/index.js +22 -2
  17. package/dist/components/notice/index.d.ts +24 -11
  18. package/dist/components/notice/index.js +11 -5
  19. package/dist/components/notification/index.d.ts +2 -2
  20. package/dist/components/page/index.js +4 -4
  21. package/dist/components/panel/index.js +4 -4
  22. package/dist/components/part-padding.d.ts +9 -6
  23. package/dist/components/part-padding.js +2 -1
  24. package/dist/components/radio/index.d.ts +1 -1
  25. package/dist/components/radio/index.js +1 -0
  26. package/dist/components/search/index.d.ts +26 -6
  27. package/dist/components/search/index.js +22 -4
  28. package/dist/components/steps/index.d.ts +232 -6
  29. package/dist/components/steps/index.js +84 -26
  30. package/dist/components/switch/index.d.ts +29 -5
  31. package/dist/components/switch/index.js +8 -2
  32. package/dist/components/tabbar/index.d.ts +184 -0
  33. package/dist/components/tabbar/index.js +161 -0
  34. package/dist/components/table/index.d.ts +74 -8
  35. package/dist/components/table/index.js +69 -16
  36. package/dist/components/tabs/index.d.ts +145 -125
  37. package/dist/components/tabs/index.js +93 -117
  38. package/dist/components/tag/index.d.ts +2 -2
  39. package/dist/components/text/index.d.ts +120 -0
  40. package/dist/components/text/index.js +55 -0
  41. package/dist/components/toast/index.d.ts +8 -8
  42. package/dist/components/toast/index.js +11 -2
  43. package/dist/components/upload/index.d.ts +30 -0
  44. package/dist/components/upload/index.js +7 -1
  45. package/dist/index.d.ts +6 -5
  46. package/dist/index.js +6 -3
  47. package/dist/services/dialog.d.ts +20 -5
  48. package/dist/services/dialog.js +8 -1
  49. package/dist/styles/components/capsule.css +4 -4
  50. package/dist/styles/components/dialog.css +40 -1
  51. package/dist/styles/components/form.css +206 -26
  52. package/dist/styles/components/input.css +29 -2
  53. package/dist/styles/components/layout.css +2 -0
  54. package/dist/styles/components/select.css +11 -0
  55. package/dist/styles/components/steps.css +48 -0
  56. package/dist/styles/components/{tabs.css → tabbar.css} +66 -65
  57. package/dist/styles/components/tabbar.tokens.css +30 -0
  58. package/dist/styles/components/table.css +50 -1
  59. package/dist/styles/components/table.tokens.css +3 -0
  60. package/dist/styles/components/text.css +101 -0
  61. package/dist/styles/components/toast.css +12 -6
  62. package/dist/styles/index.css +8 -4
  63. package/dist/styles/operations/tabs.css +73 -0
  64. package/dist/styles/reset.css +205 -0
  65. package/package.json +2 -2
  66. package/dist/components/tabset/index.d.ts +0 -105
  67. package/dist/components/tabset/index.js +0 -68
  68. package/dist/styles/components/tabs.tokens.css +0 -30
  69. package/dist/styles/operations/tabset.css +0 -57
@@ -42,10 +42,13 @@
42
42
  * 跨件共用的值一律进 `@manohub/theme`;面上的 `--ui-*` 只允许出现在**修饰符块**里
43
43
  * (护栏会拦「面里出现不含修饰符类的 `--ui-*` 声明」)。
44
44
  *
45
- * 层序:**值在前、面在后**;面内部**操作层在前**(零 JS 原语、规则走 `:where()` 零特异性,
45
+ * 层序:**基线(`./reset.css`,元素级、零特异性)→ 值 → 面**;面内部**操作层在前**(零 JS 原语、规则走 `:where()` 零特异性,
46
46
  * 永远给皮肤让位),组件面在后。
47
47
  */
48
48
 
49
+ /* ===== 基线:元素级 reset(特异性最低;先于值 → 面,消费方写任何元素选择器都能盖过它) ===== */
50
+ @import './reset.css';
51
+
49
52
  /* ===== 值:组件令牌基础值(锚 `[data-manohub-ui]`,与主题令牌同层序) ===== */
50
53
  /* 容器与分区 */
51
54
  @import './components/collapse.tokens.css';
@@ -83,7 +86,7 @@
83
86
  /* 数据与反馈 */
84
87
  @import './components/table.tokens.css';
85
88
  @import './components/pagination.tokens.css';
86
- @import './components/tabs.tokens.css';
89
+ @import './components/tabbar.tokens.css';
87
90
  @import './components/steps.tokens.css';
88
91
  @import './components/toast.tokens.css';
89
92
 
@@ -94,7 +97,7 @@
94
97
  /* 操作层(零 JS 原语,自身不带面;面由下面的皮肤族并列组合提供) */
95
98
  @import './operations/collapse.css';
96
99
  @import './operations/popup.css';
97
- @import './operations/tabset.css';
100
+ @import './operations/tabs.css';
98
101
 
99
102
  /* 容器与分区 */
100
103
  @import './components/page.css'; /* 页面级骨架(唯一;区域级是 Panel) */
@@ -104,6 +107,7 @@
104
107
  @import './components/divider.css'; /* 内容之间的分隔线(设计稿内容区 44 处在用;不是各件自己的框线) */
105
108
  @import './components/nav.css';
106
109
  @import './components/layout.css'; /* 布局原子件族(Layout.Row 排「行」/ Layout.Column 排「列」);与任何件都无层序耦合 */
110
+ @import './components/text.css'; /* 排版原子件:`--ui-font-*` 档位令牌的第一个消费者;叶子件,与任何件都无层序耦合 */
107
111
 
108
112
  /* 数据展示 */
109
113
  @import './components/tree.css';
@@ -141,7 +145,7 @@
141
145
  /* 数据与反馈(表格 / 分页条 / 页签条 / 步骤条 / 消息提示) */
142
146
  @import './components/table.css';
143
147
  @import './components/pagination.css';
144
- @import './components/tabs.css';
148
+ @import './components/tabbar.css';
145
149
  @import './components/steps.css';
146
150
  @import './components/toast.css';
147
151
 
@@ -0,0 +1,73 @@
1
+ /**
2
+ * 操作层 · 面板切换骨架(把「一组互斥选项 + 按顺序排列的面板」接起来;只给骨架、不给面)。
3
+ *
4
+ * 出处:`@aihub/theme` 的 `playground/components/tabset.css`(本件当时叫 `Tabset`,0.7.1 起改名 `Tabs`)。
5
+ * 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀。
6
+ *
7
+ * 本层只做三件事 ——
8
+ * ① 操作根(轨道 → 面板组 的呼吸位);
9
+ * ② 面板组与面板的**弹性链**(供抽屉 / 区域容器里的「填满」用法);
10
+ * ③ 面板的**收起态**(`hidden`)。
11
+ *
12
+ * **显隐只有一条路径:组件路径。** `Tabs` 按受控值给非选中面板下发 `hidden`,
13
+ * 与选择控件形态无关(页签条 / 胶囊 / 分段按钮 / 单选卡片都一样)。本层因此:
14
+ * · 收起态写在 `.mh-tabs-panel[hidden]` 上(UA 的 `[hidden]` 是**元素级**规则,
15
+ * 作者源里任何自带 `display` 的类都能压过它,故这里显式落下一次);
16
+ * · **显形态一条规则都不写** —— 面板显形就是它自己的 `display`(块 / 弹性 / 网格归消费方与皮肤)。
17
+ *
18
+ * ⚠️ 历史缺陷一(0.7.0 及以前):当时只有「零 JS 档位表」、没有上面那条收起规则 ⇒ 面板被基线按住,
19
+ * 而档位表在 `TabBar` 下恒不命中 ⇒ 三块面板全不显示(`apps/mcp` 配置抽屉实测踩到)。
20
+ * ⚠️ 历史缺陷二(0.7.1 一度这么修、已改回):组件路径的显形**不能**写成
21
+ * `.mh-tabs-panel:not([hidden]) { display: block }` —— 它把面板的 `display` 钉死成 `block`,
22
+ * 连带顶掉消费方/皮肤给面板的布局(面板里是弹性列时整条高度链当场断掉)。
23
+ * ⚠️ 已退役(2026-09-24 拍板删除):**零 JS 路径(原生 radio ↔ 档位表)整段移除**。原写法
24
+ * `.mh-tabs:has(input:nth-of-type(n):checked) .mh-tabs-panels > :nth-child(n)` 逐档一条写不出通式,
25
+ * 且同时受三条硬限制:① 上限 8 档;② 开关必须与面板**同序**,且按「同一父级里第 n 个 input」计数;
26
+ * ③ 面板必须是 `.mh-tabs-panels` 的**直接子级**。局限远大于它省下的那点 JS —— 取消。
27
+ * (`TabBar` / `Capsule` 各自面向**静态页**的原生 `:checked` 选中态与本文件无关,仍然有效。)
28
+ *
29
+ * **与皮肤零互指**:本层不认任何皮肤类名(退役后也不再认识 `input`)。
30
+ *
31
+ * 结构契约(轨道项与面板组顺序**一一对应**;面板壳由 `Tabs` 出,消费方不必手写):
32
+ * <div class="mh-tabs">
33
+ * <div class="[皮肤:轨道 / 选择控件]">…</div>
34
+ * <div class="mh-tabs-panels">
35
+ * <section class="mh-tabs-panel [皮肤类]" hidden>…</section>
36
+ * </div>
37
+ * </div>
38
+ *
39
+ * 禁写(与折叠 / 浮层同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 —— 写了就顶掉皮肤族属性面。
40
+ * 面板的面与几何由皮肤族给(卡片一类);本层只写「收起态」「弹性链」与根上的呼吸位。
41
+ */
42
+
43
+ /* ===== 一、操作根:选择控件在上、面板在下 ===== */
44
+ .mh-tabs {
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: var(--ui-space-4); /* 控件 → 面板的呼吸位 12px */
48
+ }
49
+
50
+ /* ===== 二、弹性链:面板组 → 面板 =====
51
+ 只声明「吃满面板组的剩余高度」,**不动面板的 `display`**。
52
+ 用途:抽屉 / 面板级容器里要「页签条固定 + 面板填满 + 面板内部自己滚」时,消费方在自己加到
53
+ 根上的类里写 `height: 100%` 即启用 —— 本层不设任何绝对高度,高度归属始终在消费方容器手里。
54
+ 根高 auto(桌面普通用法)时这些声明不产生高度变化(无剩余空间可分),与块级布局等价。 */
55
+ .mh-tabs-panels {
56
+ display: flex;
57
+ flex-direction: column;
58
+ flex: 1 1 auto;
59
+ min-height: 0;
60
+ }
61
+
62
+ .mh-tabs-panel {
63
+ flex: 1 1 auto;
64
+ min-height: 0;
65
+ }
66
+
67
+ /* ===== 三、收起态:本层唯一一条显隐规则 =====
68
+ 非选中面板一律带 `hidden`(由 `Tabs` 下发,与控件形态无关)。显式落一次「收起 = 不显示」——
69
+ 不依赖 UA 那条 `[hidden]`(它是元素级规则,消费方/皮肤里任何自带 `display` 的类都能压过它)。
70
+ **不写显形规则**:面板显形就是它自己的 `display`(见文件头「历史缺陷二」)。 */
71
+ .mh-tabs-panel[hidden] {
72
+ display: none;
73
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * 基础重置(reset)—— 元素级基线,随 `@manohub/ui/styles.css` 一起到达消费方。
3
+ *
4
+ * ## 为什么基线归本包
5
+ *
6
+ * 接入契约(`@manohub/kit/CONTRACT.md` §3)禁应用侧写裸元素选择器与字号字面量,
7
+ * 于是「把浏览器默认值归零」在应用侧**没有合规落点**:0.6.0 之前它寄在入口层的
8
+ * `reset.css` 里,随入口层零样式化一并删除后就成了缺口(契约 §10 记在案)。
9
+ * 本包是样式面(② 面层)的唯一来源,元素基线因此归这里 —— 位于「值」之后、「面」之前。
10
+ *
11
+ * ## 参照口径
12
+ *
13
+ * 主体对齐 **Tailwind Preflight**(消费方 `apps/<app>/src/style.css` 一直在引的那份):
14
+ * 覆盖的元素清单一致,**唯一的有意差异是表单控件的底色** —— Preflight 把 `input` / `select` /
15
+ * `textarea` 也清成透明,本文件保留浏览器原生底色(裸输入框若连底都没有就完全不可见);
16
+ * 挂类的控件(`.mh-input` 等)有自己的面,不受这条影响。本包组件面本来就是按「已清零」的环境写的 ——
17
+ * 全部 33 处挂类的 `<button>` 合并后都自带 border / background / padding ——
18
+ * 所以本文件**不改变任何组件的外观**;它的作用是:
19
+ *
20
+ * 1. 让文档站 / 静态页也站到与真实应用同一个起跑线(此前只有真实应用有 preflight);
21
+ * 2. 让裸元素(`ul` / `a` / `p` / `button` …)不再带浏览器的默认内外距、列表序号与链接色 ——
22
+ * 页面骨架由应用的 tsx 摆放时,不必再为每个原生元素写一次归零。
23
+ *
24
+ * 与旧实现(`app-kit` 的 reset)相比,多了按钮外观归零、列表序号归零、链接继承色去下划线、
25
+ * 标题字阶归位、媒体元素转块级 —— 那几条正是「应用侧各写各的」在补齐的部分。
26
+ *
27
+ * ## 特异性纪律(改本文件前必读)
28
+ *
29
+ * **作用域一律用 `:where([data-manohub-ui])` 包裹**:`:where()` 特异性为 0,
30
+ * 故每条规则等价于纯元素选择器(0,0,1)甚至更低(`:where(X) *` 即 0,0,0)。
31
+ * 写成 `.container button` 这类高特异性选择器(0,1,1)会**反压本包组件面**(普遍是单类 0,1,0)——
32
+ * 本仓踩过:主按钮文字变成 `color: inherit` 的黑色。**新增任何 reset 级样式都要遵守这条。**
33
+ * 也正因为它的特异性最低,消费方在自己的样式里写任何元素选择器都能盖过它。
34
+ *
35
+ * 唯一一条不带 `:where()` 的是**容器基座**(下面的 `[data-manohub-ui]`):它描述容器自身而非其后代,
36
+ * 且要能在消费方「同名选择器后写即胜」的规则里被覆盖,故保持 (0,1,0)(与旧实现一致)。
37
+ *
38
+ * ## 四条不做
39
+ *
40
+ * 1. **不碰 `html` / `body` / `#app`**:micro-app 的 scopecss **不作用域化**它们,
41
+ * 写进去会泄漏到宿主应用的全局样式。
42
+ * **整链高度由消费方承担,且契约明确它是合法的** —— 写在应用的 `app.css` 或入口 HTML 的 `<style>` 里
43
+ * (`@manohub/kit/CONTRACT.md` §1.2「入口基线」,是 L1-6「不得用裸元素选择器」的**唯一例外**);
44
+ * 容器自身在这里给 `height: 100%`,`Page` 的 `height: 100%` 依赖上面那条链存在。
45
+ * 2. **不定义任何 `--ui-*` 令牌**:值一律归 `@manohub/theme`,本文件只**消费**(两处定义必然漂)。
46
+ * 3. **不出现任何类选择器**:本层是元素基线,类归各组件面(`styles/components/`)。
47
+ * 4. **不写 `appearance`**:作者一旦声明了 `background` / `border`,浏览器即放弃原生控件绘制。
48
+ * 实测(无头 Chrome,只引 theme + ui/styles.css):裸 `button` 的计算值是透明底 /
49
+ * `border-width: 0` / `border-radius: 0` / 内距 0 / 字色与字族继承容器 —— 已经是清零态。
50
+ * Safari / iOS 是否还需 `appearance: none` 未在真机核对,故不动(补它前请先在真机取证)。
51
+ *
52
+ * ## 富文本须知
53
+ *
54
+ * 重置掉 `ul` / `ol` 的序号、`a` 的下划线之后,**富文本(markdown)需要自行复权** ——
55
+ * 富文本排版目前没有合规归属(见 `@manohub/kit/CONTRACT.md` §10 的已知缺口),
56
+ * 消费方要为自己的富文本容器类补回 `list-style`、链接色与下划线、段落边距。
57
+ * 本文件有意**不含** `.mh-markdown` 一类的富文本预设:那是独立的一件事,不混进元素基线。
58
+ */
59
+
60
+ /* ===== 盒模型与边框:边框属性归零(对齐 Preflight,`border: 1px solid …` 写法不受影响) ===== */
61
+ :where([data-manohub-ui]),
62
+ :where([data-manohub-ui]) *,
63
+ :where([data-manohub-ui]) *::before,
64
+ :where([data-manohub-ui]) *::after {
65
+ box-sizing: border-box;
66
+ border-width: 0;
67
+ border-style: solid;
68
+ }
69
+
70
+ /* ===== 容器基座:字族 / 字号 / 行高 / 字色 / 底色 / 整链高度(本文件唯一不带 :where() 的一条) ===== */
71
+ [data-manohub-ui] {
72
+ font-family: var(--ui-font-family);
73
+ font-size: var(--ui-font-body);
74
+ line-height: var(--ui-line-body);
75
+ color: var(--ui-base-content);
76
+ background: var(--ui-base-100);
77
+ height: 100%;
78
+ min-width: 320px;
79
+ font-synthesis: none;
80
+ text-rendering: optimizeLegibility;
81
+ -webkit-font-smoothing: antialiased;
82
+ -moz-osx-font-smoothing: grayscale;
83
+ }
84
+
85
+ /* ===== 块级元素的默认外边距归零 ===== */
86
+ :where([data-manohub-ui]) h1,
87
+ :where([data-manohub-ui]) h2,
88
+ :where([data-manohub-ui]) h3,
89
+ :where([data-manohub-ui]) h4,
90
+ :where([data-manohub-ui]) h5,
91
+ :where([data-manohub-ui]) h6,
92
+ :where([data-manohub-ui]) p,
93
+ :where([data-manohub-ui]) figure,
94
+ :where([data-manohub-ui]) blockquote,
95
+ :where([data-manohub-ui]) dl,
96
+ :where([data-manohub-ui]) dd,
97
+ :where([data-manohub-ui]) pre,
98
+ :where([data-manohub-ui]) hr {
99
+ margin: 0;
100
+ }
101
+
102
+ /* 标题回归正文档:字阶一律由使用方(组件面 / 页面样式)决定,浏览器默认的 2em / bold 不再参与 */
103
+ :where([data-manohub-ui]) h1,
104
+ :where([data-manohub-ui]) h2,
105
+ :where([data-manohub-ui]) h3,
106
+ :where([data-manohub-ui]) h4,
107
+ :where([data-manohub-ui]) h5,
108
+ :where([data-manohub-ui]) h6 {
109
+ font-size: inherit;
110
+ font-weight: inherit;
111
+ }
112
+
113
+ /* ===== 列表:去序号、去缩进(富文本自行复权,见文件头「富文本须知」) ===== */
114
+ :where([data-manohub-ui]) ul,
115
+ :where([data-manohub-ui]) ol,
116
+ :where([data-manohub-ui]) menu {
117
+ margin: 0;
118
+ padding: 0;
119
+ list-style: none;
120
+ }
121
+
122
+ /* ===== 链接:继承文字色,下划线交还使用方(链接态由使用方叠加) ===== */
123
+ :where([data-manohub-ui]) a {
124
+ color: inherit;
125
+ text-decoration: inherit;
126
+ }
127
+
128
+ /* ===== 表单控件:清掉浏览器默认外观,字体与颜色继承上下文 ===== */
129
+ :where([data-manohub-ui]) button,
130
+ :where([data-manohub-ui]) input,
131
+ :where([data-manohub-ui]) optgroup,
132
+ :where([data-manohub-ui]) select,
133
+ :where([data-manohub-ui]) textarea {
134
+ margin: 0;
135
+ padding: 0;
136
+ font: inherit;
137
+ color: inherit;
138
+ }
139
+
140
+ :where([data-manohub-ui]) button,
141
+ :where([data-manohub-ui]) [type='button'],
142
+ :where([data-manohub-ui]) [type='reset'],
143
+ :where([data-manohub-ui]) [type='submit'] {
144
+ background-color: transparent;
145
+ background-image: none;
146
+ text-transform: none;
147
+ cursor: pointer;
148
+ }
149
+
150
+ :where([data-manohub-ui]) select {
151
+ text-transform: none;
152
+ }
153
+
154
+ :where([data-manohub-ui]) textarea {
155
+ resize: vertical;
156
+ }
157
+
158
+ :where([data-manohub-ui]) :disabled {
159
+ cursor: default;
160
+ }
161
+
162
+ :where([data-manohub-ui]) [type='search'] {
163
+ outline-offset: -2px;
164
+ }
165
+
166
+ /* ===== 媒体元素:转块级(消除行内基线间隙),宽度不溢出容器 ===== */
167
+ :where([data-manohub-ui]) img,
168
+ :where([data-manohub-ui]) svg,
169
+ :where([data-manohub-ui]) video,
170
+ :where([data-manohub-ui]) canvas,
171
+ :where([data-manohub-ui]) audio,
172
+ :where([data-manohub-ui]) iframe,
173
+ :where([data-manohub-ui]) embed,
174
+ :where([data-manohub-ui]) object {
175
+ display: block;
176
+ vertical-align: middle;
177
+ }
178
+
179
+ :where([data-manohub-ui]) img,
180
+ :where([data-manohub-ui]) video {
181
+ max-width: 100%;
182
+ height: auto;
183
+ }
184
+
185
+ /* ===== 行内语义与文本节点 ===== */
186
+ :where([data-manohub-ui]) b,
187
+ :where([data-manohub-ui]) strong {
188
+ font-weight: bolder;
189
+ }
190
+
191
+ :where([data-manohub-ui]) code,
192
+ :where([data-manohub-ui]) kbd,
193
+ :where([data-manohub-ui]) samp,
194
+ :where([data-manohub-ui]) pre {
195
+ font-family: var(--ui-font-mono);
196
+ font-size: 1em;
197
+ }
198
+
199
+ :where([data-manohub-ui]) small {
200
+ font-size: 80%;
201
+ }
202
+
203
+ :where([data-manohub-ui]) summary {
204
+ display: list-item;
205
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manohub/ui",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "AIHub 自绘组件层:不依赖 farris 的手写 Vue TSX 组件 + 自带令牌层(Farris 规范视觉 · daisyUI 式语义令牌 · shadcn 式 API 词汇)。",
@@ -46,7 +46,7 @@
46
46
  "vue": "^3.5.0"
47
47
  },
48
48
  "dependencies": {
49
- "@manohub/icon": "^0.6.1"
49
+ "@manohub/icon": "^0.7.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^24.0.0",
@@ -1,105 +0,0 @@
1
- import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
- export interface TabsetOption {
3
- /** 项文字 */
4
- label: string;
5
- /** 项值(受控值就是它) */
6
- value: string | number;
7
- /** 禁用项:不可选(原生 radio 路径下方向键会跳过) */
8
- disabled?: boolean;
9
- }
10
- export interface TabsetProps {
11
- /** 轨道项(顺序即「第 n 项 ↔ 第 n 块面板」的档位表) */
12
- options: TabsetOption[];
13
- /** 受控选中值;不传即非受控(由 `defaultValue` 起) */
14
- value?: string | number;
15
- /** 非受控初始选中值,缺省第一项 */
16
- defaultValue?: string | number;
17
- /** 选中变化回调(受控与非受控都会调) */
18
- onChange?: (value: string | number) => void;
19
- }
20
- /**
21
- * 面板切换(**操作层骨架 + 组件路径显隐**)。
22
- *
23
- * ## 它是什么
24
- * 把「一组互斥选项」与「按顺序排列的面板」接起来:第 n 个选项对应第 n 块面板。
25
- * 骨架(根、面板组、档位表)在操作层 `styles/operations/tabset.css`,本件负责:
26
- * 受控值、面板包装与显隐、把 `select` 交给选择控件。
27
- *
28
- * ## 两条显隐路径(结论一致,不冲突)
29
- * - **原生路径**(推荐):选择控件用**原生 radio**(如 `Capsule`)→ 操作层的档位表
30
- * `:has(input:nth-of-type(n):checked)` 直接显隐,**零 JS**;
31
- * - **组件路径**:控件不是 radio 时,本件按受控值给非选中面板下发 `hidden`。
32
- * 两条路径都由同一个值驱动,故同时成立不会互相打架。
33
- *
34
- * ## 与皮肤零互指
35
- * 本件不认识任何选择控件的类名 —— 轨道由 `selector` 插槽提供(作用域参数 `{ value, options, select }`),
36
- * 放胶囊、分段按钮、单选卡片都行;面板内容由默认插槽按 `options` 顺序给出。
37
- *
38
- * @example 胶囊 + 面板(`Capsule` 提供原生 radio,故走零 JS 路径)
39
- * <Tabset :options="tabs" v-model:value="current">
40
- * {{
41
- * selector: ({ value, select }) => <Capsule :options="tabs" modelValue={value} onChange={select} />,
42
- * default: () => [
43
- * <Card key="all">全部:15 条</Card>,
44
- * <Card key="doing">进行中:3 条</Card>,
45
- * ],
46
- * }}
47
- * </Tabset>
48
- */
49
- export declare const Tabset: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
50
- options: {
51
- type: PropType<TabsetOption[]>;
52
- required: true;
53
- };
54
- value: {
55
- type: PropType<string | number | undefined>;
56
- default: undefined;
57
- };
58
- defaultValue: {
59
- type: PropType<string | number | undefined>;
60
- default: undefined;
61
- };
62
- onChange: {
63
- type: PropType<(value: string | number) => void>;
64
- default: undefined;
65
- };
66
- /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
67
- lazy: {
68
- type: BooleanConstructor;
69
- default: boolean;
70
- };
71
- }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
72
- options: {
73
- type: PropType<TabsetOption[]>;
74
- required: true;
75
- };
76
- value: {
77
- type: PropType<string | number | undefined>;
78
- default: undefined;
79
- };
80
- defaultValue: {
81
- type: PropType<string | number | undefined>;
82
- default: undefined;
83
- };
84
- onChange: {
85
- type: PropType<(value: string | number) => void>;
86
- default: undefined;
87
- };
88
- /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
89
- lazy: {
90
- type: BooleanConstructor;
91
- default: boolean;
92
- };
93
- }>> & Readonly<{}>, {
94
- value: string | number | undefined;
95
- onChange: (value: string | number) => void;
96
- defaultValue: string | number | undefined;
97
- lazy: boolean;
98
- }, SlotsType<{
99
- default?: () => VNodeChild;
100
- selector?: (context: {
101
- value: string | number | undefined;
102
- options: TabsetOption[];
103
- select: (value: string | number) => void;
104
- }) => VNodeChild;
105
- }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,68 +0,0 @@
1
- import { defineComponent, ref, computed, createVNode } from "vue";
2
- const Tabset = /* @__PURE__ */ defineComponent({
3
- name: "Tabset",
4
- inheritAttrs: false,
5
- props: {
6
- options: {
7
- type: Array,
8
- required: true
9
- },
10
- value: {
11
- type: [String, Number],
12
- default: void 0
13
- },
14
- defaultValue: {
15
- type: [String, Number],
16
- default: void 0
17
- },
18
- onChange: {
19
- type: Function,
20
- default: void 0
21
- },
22
- /** 惰性档:只有激活的面板才渲染(切走即卸载),用于面板很重(图表 / 大表格)的场景 */
23
- lazy: {
24
- type: Boolean,
25
- default: false
26
- }
27
- },
28
- slots: Object,
29
- setup(props, {
30
- slots,
31
- attrs
32
- }) {
33
- const innerValue = ref(props.value ?? props.defaultValue ?? props.options[0]?.value);
34
- const current = computed(() => props.value ?? innerValue.value);
35
- const select = (value) => {
36
- const target = props.options.find((option) => option.value === value);
37
- if (target?.disabled) return;
38
- if (props.value === void 0) innerValue.value = value;
39
- props.onChange?.(value);
40
- };
41
- const panels = () => {
42
- const children = slots.default?.();
43
- const list = Array.isArray(children) ? children : children ? [children] : [];
44
- return list.map((child, index) => {
45
- const option = props.options[index];
46
- const active = option !== void 0 && option.value === current.value;
47
- if (props.lazy && !active) return null;
48
- return createVNode("div", {
49
- "class": "mh-tabset-panel",
50
- "hidden": !active
51
- }, [child]);
52
- });
53
- };
54
- return () => createVNode("div", {
55
- "class": ["mh-tabset", attrs.class].filter(Boolean).join(" "),
56
- "style": attrs.style
57
- }, [slots.selector?.({
58
- value: current.value,
59
- options: props.options,
60
- select
61
- }), createVNode("div", {
62
- "class": "mh-tabset-panels"
63
- }, [panels()])]);
64
- }
65
- });
66
- export {
67
- Tabset
68
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * tabs —— 单件令牌(**基础值**)。
3
- *
4
- * 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
5
- *
6
- * ## 抽出说明
7
- * 本文件从面文件里抽出(原先混写在 `tabs.css` 顶部):这些是**基础值**,锚在
8
- * `[data-manohub-ui]` —— 跨包唯一作用域锚,由入口层无条件写在应用容器上,因此**任何落在
9
- * 容器里的分件都取得到值**,不再依赖「声明在某个组件根类上」这条脆弱假设
10
- * (历史症状:跨件消费的 `--ui-*-group-*` 取不到值,组内间距变 0)。
11
- *
12
- * ⚠️ `.mh-<件>--<档>` 这类**档位改写**留在面文件的修饰符块里 —— 它们靠「同一元素上两个
13
- * 选择器改写同一个令牌」生效,搬到本文件会让档位失效。
14
- * ⚠️ 新增组件要登记两处:本文件 + `src/styles/index.css`(见其文件头「五处齐备」)。
15
- */
16
- [data-manohub-ui] {
17
- /* 单件令牌 */
18
- --ui-tabs-height: var(--ui-control-height-md); /* 标准控件高 32 */
19
- --ui-tabs-gap: 30px; /* 项间距(规范实测) */
20
- --ui-tabs-font-size: var(--ui-font-body);
21
- --ui-tabs-text: var(--ui-base-content); /* 规范未选档 #446a9f(偏蓝的正文色),本仓取正文色 */
22
- --ui-tabs-text-hover: var(--ui-primary-hover); /* 规范 #529dff */
23
- --ui-tabs-text-active: var(--ui-primary); /* 规范 #4e94ff */
24
- --ui-tabs-text-disabled: var(--ui-base-content-subtle); /* 规范 Te07 */
25
- --ui-tabs-indicator: var(--ui-primary);
26
- --ui-tabs-indicator-gap: 3px; /* 指示条与文字的留白 */
27
- --ui-tabs-indicator-height: 3px;
28
- --ui-tabs-indicator-radius: var(--ui-radius-full);
29
- --ui-tabs-card-padding-x: var(--ui-space-4);
30
- }
@@ -1,57 +0,0 @@
1
- /**
2
- * 操作层 · 面板切换(把「一组同名 radio + 对应面板」接起来;零 JS,**只给操作、不给面**)。
3
- *
4
- * 出处:`@aihub/theme` 的 `playground/components/tabset.css`。
5
- * 映射:`--mh-*` → `--ui-*`;类名加 `.mh-` 前缀。
6
- *
7
- * 与折叠 / 浮层同一路数:本层只做三件事 —— ① 根(条带 → 面板的呼吸位)② 面板钩子与默认收起
8
- * ③ 档位表(第 n 个开关 ↔ 第 n 个面板)。
9
- * 开关的隐身与焦点环**归皮肤族**(谁家的选择控件谁自己画:胶囊见 `styles/components/capsule.css`),
10
- * 本层不碰 —— 这样同一层能伺候任意选择控件(胶囊 / 分段按钮 / 单选卡片 / 向导步骤),换皮肤不必动本文件。
11
- *
12
- * **与皮肤零互指**(两层连接点全部走原生元素,谁都不引用对方的类):
13
- * · 皮肤键在 `input:checked + <自家项>`(原生路径)与 `[data-state='active']`(组件路径)上;
14
- * · 本层只认 `input` 与面板的**顺序**,不认任何皮肤类名。
15
- *
16
- * 结构契约(开关与项平级相邻、开关在前;面板组顺序与开关**一一对应**):
17
- * <div class="mh-tabset">
18
- * <div class="[皮肤:轨道/选择控件]">
19
- * <input type="radio" name="t1" id="t1a" checked>
20
- * <label class="[皮肤项]" for="t1a">全部</label>
21
- * <input type="radio" name="t1" id="t1b">
22
- * <label class="[皮肤项]" for="t1b">进行中</label>
23
- * </div>
24
- * <div class="mh-tabset-panels">
25
- * <section class="mh-tabset-panel [皮肤类]">…</section>
26
- * </div>
27
- * </div>
28
- *
29
- * 禁写(与折叠 / 浮层同款):底 / 边 / 圆角 / 内距 / 宽高 / 字号 / 阴影 —— 写了就顶掉皮肤族属性面。
30
- * 面板的面与几何由皮肤族给(卡片一类),本层只写「哪一个显形」与根上的呼吸位。
31
- */
32
-
33
- /* ===== 操作根:选择控件在上、面板在下 ===== */
34
- .mh-tabset {
35
- display: flex;
36
- flex-direction: column;
37
- gap: var(--ui-space-4); /* 控件 → 面板的呼吸位 12px */
38
- }
39
-
40
- /* ===== 面板显隐:档位表(上限 8 档) ===== */
41
- /* 第 n 个开关 ↔ 第 n 个面板。写不出通式:CSS 没有「按被勾选开关的序号去选同序面板」的选择器
42
- (树的缩进档位表同一路数)。超过 8 个请扩表,或改走组件路径由 JS 下发 hidden。
43
- 注:`input:nth-of-type(n)` 按「同一父级里的第 n 个 input」计数 —— 故开关须集中在同一个轨道容器内。 */
44
- .mh-tabset-panel {
45
- display: none;
46
- }
47
-
48
- .mh-tabset:has(input:nth-of-type(1):checked) .mh-tabset-panels > :nth-child(1),
49
- .mh-tabset:has(input:nth-of-type(2):checked) .mh-tabset-panels > :nth-child(2),
50
- .mh-tabset:has(input:nth-of-type(3):checked) .mh-tabset-panels > :nth-child(3),
51
- .mh-tabset:has(input:nth-of-type(4):checked) .mh-tabset-panels > :nth-child(4),
52
- .mh-tabset:has(input:nth-of-type(5):checked) .mh-tabset-panels > :nth-child(5),
53
- .mh-tabset:has(input:nth-of-type(6):checked) .mh-tabset-panels > :nth-child(6),
54
- .mh-tabset:has(input:nth-of-type(7):checked) .mh-tabset-panels > :nth-child(7),
55
- .mh-tabset:has(input:nth-of-type(8):checked) .mh-tabset-panels > :nth-child(8) {
56
- display: block;
57
- }