@manohub/ui 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 (169) hide show
  1. package/README.md +141 -0
  2. package/dist/components/avatar/index.d.ts +283 -0
  3. package/dist/components/avatar/index.js +167 -0
  4. package/dist/components/badge/index.d.ts +132 -0
  5. package/dist/components/badge/index.js +99 -0
  6. package/dist/components/button/index.d.ts +578 -0
  7. package/dist/components/button/index.js +191 -0
  8. package/dist/components/capsule/index.d.ts +161 -0
  9. package/dist/components/capsule/index.js +101 -0
  10. package/dist/components/card/index.d.ts +456 -0
  11. package/dist/components/card/index.js +231 -0
  12. package/dist/components/checkbox/index.d.ts +331 -0
  13. package/dist/components/checkbox/index.js +165 -0
  14. package/dist/components/code/index.d.ts +134 -0
  15. package/dist/components/code/index.js +117 -0
  16. package/dist/components/code-editor/index.d.ts +163 -0
  17. package/dist/components/code-editor/index.js +98 -0
  18. package/dist/components/collapse/index.d.ts +125 -0
  19. package/dist/components/collapse/index.js +95 -0
  20. package/dist/components/control-size.d.ts +8 -0
  21. package/dist/components/dialog/index.d.ts +224 -0
  22. package/dist/components/dialog/index.js +194 -0
  23. package/dist/components/divider/index.d.ts +64 -0
  24. package/dist/components/divider/index.js +62 -0
  25. package/dist/components/drawer/index.d.ts +226 -0
  26. package/dist/components/drawer/index.js +190 -0
  27. package/dist/components/filter/index.d.ts +391 -0
  28. package/dist/components/filter/index.js +203 -0
  29. package/dist/components/form/index.d.ts +704 -0
  30. package/dist/components/form/index.js +329 -0
  31. package/dist/components/input/index.d.ts +980 -0
  32. package/dist/components/input/index.js +334 -0
  33. package/dist/components/layout/index.d.ts +162 -0
  34. package/dist/components/layout/index.js +100 -0
  35. package/dist/components/list-view/index.d.ts +563 -0
  36. package/dist/components/list-view/index.js +221 -0
  37. package/dist/components/loading/index.d.ts +77 -0
  38. package/dist/components/loading/index.js +40 -0
  39. package/dist/components/nav/index.d.ts +293 -0
  40. package/dist/components/nav/index.js +164 -0
  41. package/dist/components/notice/index.d.ts +137 -0
  42. package/dist/components/notice/index.js +101 -0
  43. package/dist/components/notification/index.d.ts +118 -0
  44. package/dist/components/notification/index.js +99 -0
  45. package/dist/components/page/index.d.ts +276 -0
  46. package/dist/components/page/index.js +351 -0
  47. package/dist/components/page/split-resize.d.ts +42 -0
  48. package/dist/components/page/split-resize.js +36 -0
  49. package/dist/components/pagination/index.d.ts +171 -0
  50. package/dist/components/pagination/index.js +226 -0
  51. package/dist/components/panel/index.d.ts +401 -0
  52. package/dist/components/panel/index.js +193 -0
  53. package/dist/components/part-padding.d.ts +27 -0
  54. package/dist/components/part-padding.js +23 -0
  55. package/dist/components/query-state/index.d.ts +207 -0
  56. package/dist/components/query-state/index.js +181 -0
  57. package/dist/components/radio/index.d.ts +473 -0
  58. package/dist/components/radio/index.js +250 -0
  59. package/dist/components/search/index.d.ts +167 -0
  60. package/dist/components/search/index.js +105 -0
  61. package/dist/components/select/index.d.ts +252 -0
  62. package/dist/components/select/index.js +281 -0
  63. package/dist/components/skeleton/index.d.ts +88 -0
  64. package/dist/components/skeleton/index.js +56 -0
  65. package/dist/components/steps/index.d.ts +199 -0
  66. package/dist/components/steps/index.js +117 -0
  67. package/dist/components/switch/index.d.ts +150 -0
  68. package/dist/components/switch/index.js +103 -0
  69. package/dist/components/table/index.d.ts +351 -0
  70. package/dist/components/table/index.js +286 -0
  71. package/dist/components/tabs/index.d.ts +179 -0
  72. package/dist/components/tabs/index.js +153 -0
  73. package/dist/components/tabset/index.d.ts +105 -0
  74. package/dist/components/tabset/index.js +68 -0
  75. package/dist/components/tag/index.d.ts +203 -0
  76. package/dist/components/tag/index.js +144 -0
  77. package/dist/components/toast/index.d.ts +271 -0
  78. package/dist/components/toast/index.js +116 -0
  79. package/dist/components/tooltip/index.d.ts +126 -0
  80. package/dist/components/tooltip/index.js +97 -0
  81. package/dist/components/tree/index.d.ts +317 -0
  82. package/dist/components/tree/index.js +251 -0
  83. package/dist/components/upload/index.d.ts +384 -0
  84. package/dist/components/upload/index.js +172 -0
  85. package/dist/index.d.ts +63 -0
  86. package/dist/index.js +102 -0
  87. package/dist/services/base.d.ts +21 -0
  88. package/dist/services/base.js +42 -0
  89. package/dist/services/dialog.d.ts +41 -0
  90. package/dist/services/dialog.js +83 -0
  91. package/dist/services/index.d.ts +12 -0
  92. package/dist/services/loading.d.ts +21 -0
  93. package/dist/services/loading.js +41 -0
  94. package/dist/services/toast.d.ts +40 -0
  95. package/dist/services/toast.js +74 -0
  96. package/dist/styles/components/avatar.css +128 -0
  97. package/dist/styles/components/avatar.tokens.css +24 -0
  98. package/dist/styles/components/badge.css +237 -0
  99. package/dist/styles/components/button.css +454 -0
  100. package/dist/styles/components/button.tokens.css +56 -0
  101. package/dist/styles/components/capsule.css +120 -0
  102. package/dist/styles/components/capsule.tokens.css +27 -0
  103. package/dist/styles/components/card.css +192 -0
  104. package/dist/styles/components/checkbox.css +145 -0
  105. package/dist/styles/components/checkbox.tokens.css +26 -0
  106. package/dist/styles/components/code-editor.css +91 -0
  107. package/dist/styles/components/code-editor.tokens.css +24 -0
  108. package/dist/styles/components/code.css +153 -0
  109. package/dist/styles/components/code.tokens.css +29 -0
  110. package/dist/styles/components/collapse.css +62 -0
  111. package/dist/styles/components/collapse.tokens.css +20 -0
  112. package/dist/styles/components/dialog.css +106 -0
  113. package/dist/styles/components/dialog.tokens.css +24 -0
  114. package/dist/styles/components/divider.css +71 -0
  115. package/dist/styles/components/divider.tokens.css +21 -0
  116. package/dist/styles/components/drawer.css +143 -0
  117. package/dist/styles/components/drawer.tokens.css +22 -0
  118. package/dist/styles/components/filter.css +41 -0
  119. package/dist/styles/components/filter.tokens.css +14 -0
  120. package/dist/styles/components/form.css +220 -0
  121. package/dist/styles/components/form.tokens.css +15 -0
  122. package/dist/styles/components/input.css +445 -0
  123. package/dist/styles/components/input.tokens.css +41 -0
  124. package/dist/styles/components/layout.css +198 -0
  125. package/dist/styles/components/list-view.css +244 -0
  126. package/dist/styles/components/loading.css +76 -0
  127. package/dist/styles/components/loading.tokens.css +23 -0
  128. package/dist/styles/components/nav.css +48 -0
  129. package/dist/styles/components/notice.css +153 -0
  130. package/dist/styles/components/notice.tokens.css +17 -0
  131. package/dist/styles/components/notification.css +159 -0
  132. package/dist/styles/components/notification.tokens.css +37 -0
  133. package/dist/styles/components/page.css +473 -0
  134. package/dist/styles/components/pagination.css +297 -0
  135. package/dist/styles/components/pagination.tokens.css +32 -0
  136. package/dist/styles/components/panel.css +77 -0
  137. package/dist/styles/components/query-state.css +88 -0
  138. package/dist/styles/components/radio.css +271 -0
  139. package/dist/styles/components/radio.tokens.css +26 -0
  140. package/dist/styles/components/search.css +30 -0
  141. package/dist/styles/components/select.css +242 -0
  142. package/dist/styles/components/select.tokens.css +33 -0
  143. package/dist/styles/components/skeleton.css +60 -0
  144. package/dist/styles/components/skeleton.tokens.css +27 -0
  145. package/dist/styles/components/steps.css +157 -0
  146. package/dist/styles/components/steps.tokens.css +42 -0
  147. package/dist/styles/components/switch.css +165 -0
  148. package/dist/styles/components/switch.tokens.css +26 -0
  149. package/dist/styles/components/table.css +439 -0
  150. package/dist/styles/components/table.tokens.css +41 -0
  151. package/dist/styles/components/tabs.css +234 -0
  152. package/dist/styles/components/tabs.tokens.css +30 -0
  153. package/dist/styles/components/tag.css +200 -0
  154. package/dist/styles/components/tag.tokens.css +30 -0
  155. package/dist/styles/components/toast.css +150 -0
  156. package/dist/styles/components/toast.tokens.css +26 -0
  157. package/dist/styles/components/tooltip.css +89 -0
  158. package/dist/styles/components/tooltip.tokens.css +25 -0
  159. package/dist/styles/components/tree.css +139 -0
  160. package/dist/styles/components/tree.tokens.css +20 -0
  161. package/dist/styles/components/upload.css +150 -0
  162. package/dist/styles/components/upload.tokens.css +27 -0
  163. package/dist/styles/index.css +149 -0
  164. package/dist/styles/operations/collapse.css +84 -0
  165. package/dist/styles/operations/popup.css +189 -0
  166. package/dist/styles/operations/tabset.css +57 -0
  167. package/dist/utils/state-illustration.d.ts +31 -0
  168. package/dist/utils/state-illustration.js +156 -0
  169. package/package.json +62 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Button —— 自绘按钮族(六型 + 三档真实尺寸 + 外形 / 危险色 / 整宽修饰 + 加载 + 图标/文本/菜单形态 + 组容器 + 菜单皮肤)。
3
+ *
4
+ * 出处(几何以设计稿《MH后台-0911》品牌页为准,规范同值处不再复述):
5
+ * - 控件高 **32** / 内距 **12** / 图文距 **4** / 圆角 **6** / 字号 **14/18 w400** / 组间距 8;
6
+ * - 主要 = 主色实底 **无投影**(`0:3897`);次要 = 白底 + `#e6e6e6` 描边 + **中性字色**
7
+ * (`0:3892`,文本 `#1a1a1a`);禁用 = `#f2f2f2` 底 + `#888888` 字(`次要按钮备份`);
8
+ * - 小号 24、大号 40(设计未覆盖,沿用);图标槽 = 全局图标档(见 `--ui-button-icon-size`);加载环 14 · 0.8s linear;
9
+ * 虚线 = 区域内添加,文本 = 行内操作,图标 = 方形热区;菜单按钮 = 文本区 ‖ 分割线 ‖ 箭头区。
10
+ *
11
+ * **色彩槽位走局部变量**(`--ui-button-accent*`):六型只描述「底 / 边 / 字的取用位置」,
12
+ * 具体颜色由槽位变量给。危险色只是把槽位换成错误色,故 `danger` 与任意型**天然正交**,
13
+ * hover / active / 加载态一并跟随,无需为每个型再写一遍危险态(这是本文件的核心结构)。
14
+ *
15
+ * **高度三档全部吃主题令牌**(`--ui-control-height-sm` / `-md` / `-lg`,default 24 / 32 / 40)——
16
+ * 换主题即换控件尺寸,这正是 theme 层的职责。md 与 lg **不同高**:同高会让 `size`
17
+ * 沦为无视觉差别的语义标签,调用方无从选择。
18
+ *
19
+ * **类名一律 `mh-` 前缀**:本包独立发布,不迁就任何下游的既有类名;同一词根在本包内只有一套类(见 AGENTS)。
20
+ * 自绘件服务「不装 farris」的场景:静态页 / 其他框架 / 微前端里不带 farris 的子应用。
21
+ *
22
+ * **投影**:主要与次要两型**不再带投影**(设计稿的按钮是平的,节点上无 effects)。
23
+ * 图标型的 hover 光晕仍引用 `--ui-shadow-card-hover` —— 那是 hover 反馈,不是静止装饰,
24
+ * 且投影一律走令牌、不新造字面量(与 shadows.css「拟物重投影一律收敛到令牌」的口径一致)。
25
+ *
26
+ * 边界(有意不做):规范的 `.btn-seg`(分段按钮,原生同名 radio 驱动)**不在这里实现** ——
27
+ * 它的用途(一组互斥选项的轻量选择器)由 `capsule` 族承担,重复实现会出现两套分段控件。
28
+ */
29
+
30
+ /* 几何只挂在按钮本体上:令牌在同名 `.tokens.css`(锚 `[data-manohub-ui]`),几何若跟着挂会把容器也画成按钮 */
31
+ .mh-button {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ gap: var(--ui-button-gap);
36
+ height: var(--ui-button-height);
37
+ padding: 0 var(--ui-button-padding-x);
38
+ border: none;
39
+ border-radius: var(--ui-button-radius);
40
+ font-family: inherit;
41
+ font-size: var(--ui-button-font-size);
42
+ line-height: var(--ui-line-body);
43
+ cursor: pointer;
44
+ white-space: nowrap;
45
+ /* 三态补间(底 / 边 / 字 / 影) */
46
+ transition-property: background-color, border-color, color, box-shadow;
47
+ transition-duration: 0.15s;
48
+ transition-timing-function: ease;
49
+ }
50
+
51
+ /* 危险色修饰:换槽位即可,六型与各自 hover / active 一并跟随 */
52
+ .mh-button--danger {
53
+ --ui-button-accent: var(--ui-error);
54
+ --ui-button-accent-hover: color-mix(in srgb, var(--ui-error) 88%, black);
55
+ --ui-button-accent-content: var(--ui-error-content);
56
+ --ui-button-accent-soft: var(--ui-error-weak);
57
+ }
58
+
59
+ /* 键盘焦点环:画在按钮自身(与 radio / tag 同一句) */
60
+ .mh-button:focus-visible {
61
+ outline: 2px solid var(--ui-primary);
62
+ outline-offset: -2px;
63
+ }
64
+
65
+ .mh-button__icon {
66
+ flex: none;
67
+ width: var(--ui-button-icon-size);
68
+ height: var(--ui-button-icon-size);
69
+ }
70
+
71
+ /* ===== 尺寸档 ===== */
72
+ .mh-button--sm {
73
+ height: var(--ui-button-height-sm);
74
+ padding: 0 var(--ui-button-padding-x-sm);
75
+ font-size: var(--ui-button-font-size-sm);
76
+ }
77
+ .mh-button--sm .mh-button__icon,
78
+ .mh-button--sm .mh-button__caret {
79
+ width: var(--ui-button-icon-size-sm);
80
+ height: var(--ui-button-icon-size-sm);
81
+ }
82
+ .mh-button--lg {
83
+ height: var(--ui-button-height-lg);
84
+ padding: 0 var(--ui-button-padding-x-lg);
85
+ font-size: var(--ui-button-font-size-lg);
86
+ }
87
+ .mh-button--lg .mh-button__icon,
88
+ .mh-button--lg .mh-button__caret {
89
+ width: var(--ui-button-icon-size-lg);
90
+ height: var(--ui-button-icon-size-lg);
91
+ }
92
+ /* 尺寸档的菜单结构:文字区内距与分割线高度必须跟着档位走 */
93
+ .mh-button--sm.mh-button--menu .mh-button__label {
94
+ padding: 0 var(--ui-button-padding-x-sm);
95
+ }
96
+ .mh-button--lg.mh-button--menu .mh-button__label {
97
+ padding: 0 var(--ui-button-padding-x-lg);
98
+ }
99
+ .mh-button--sm .mh-button__divider {
100
+ height: var(--ui-button-height-sm);
101
+ }
102
+ .mh-button--lg .mh-button__divider {
103
+ height: var(--ui-button-height-lg);
104
+ }
105
+
106
+ /* ===== 外形修饰(与型正交) ===== */
107
+ .mh-button--round {
108
+ border-radius: var(--ui-radius-full);
109
+ }
110
+ .mh-button--circle {
111
+ width: var(--ui-button-height);
112
+ height: var(--ui-button-height);
113
+ padding: 0;
114
+ border-radius: var(--ui-radius-full);
115
+ }
116
+ .mh-button--sm.mh-button--circle {
117
+ width: var(--ui-button-height-sm);
118
+ height: var(--ui-button-height-sm);
119
+ }
120
+ .mh-button--lg.mh-button--circle {
121
+ width: var(--ui-button-height-lg);
122
+ height: var(--ui-button-height-lg);
123
+ }
124
+ /* 整宽:表单底栏 / 移动端主操作;用 flex 而非 width 单给,保证菜单结构的内部分布不变 */
125
+ .mh-button--block {
126
+ display: flex;
127
+ width: 100%;
128
+ }
129
+
130
+ /* ===== 主要:主色实底(**无投影**) =====
131
+ 设计实证:`0:3897` 是纯 `#2660ff` 实底 + r6,节点上没有任何 effects。
132
+ 改前挂的 `--ui-shadow-card-hover` 会让按钮在设计里「浮起来」,属多余装饰。 */
133
+ .mh-button--primary {
134
+ background: var(--ui-button-accent);
135
+ color: var(--ui-button-accent-content);
136
+ }
137
+ .mh-button--primary:hover,
138
+ .mh-button--primary.is-hover {
139
+ background: var(--ui-button-accent-hover);
140
+ }
141
+ .mh-button--primary:active,
142
+ .mh-button--primary.is-active {
143
+ background: color-mix(in srgb, var(--ui-button-accent) 88%, black); /* 规范按下档比滑过更沉 */
144
+ }
145
+
146
+ /* ===== 次要:白底描边 + **中性字色**(无投影) =====
147
+ 设计实证:`0:3892` = 白底 + `#e6e6e6` 描边 + r6 + 文本 `#1a1a1a`(**中性**,不是主色蓝)。
148
+ 改前用 `--ui-button-accent`(主色蓝)+ `--ui-shadow-card`,页头上会出现「蓝字带投影」的次要按钮,
149
+ 与设计的「黑字平贴」观感不同。白底按钮在浅色页面上本就靠描边成形,**不需要投影**。 */
150
+ .mh-button--secondary {
151
+ background: var(--ui-base-100);
152
+ border: 1px solid var(--ui-base-300);
153
+ color: var(--ui-base-content);
154
+ }
155
+ .mh-button--secondary:hover,
156
+ .mh-button--secondary.is-hover {
157
+ border-color: var(--ui-button-accent-hover);
158
+ color: var(--ui-button-accent-hover);
159
+ }
160
+ .mh-button--secondary:active,
161
+ .mh-button--secondary.is-active {
162
+ border-color: var(--ui-button-accent);
163
+ color: var(--ui-button-accent);
164
+ }
165
+
166
+ /* ===== 虚线:区域内添加内容 ===== */
167
+ .mh-button--dashed {
168
+ background: var(--ui-base-100);
169
+ border: 1px dashed var(--ui-base-400);
170
+ color: var(--ui-button-accent);
171
+ }
172
+ .mh-button--dashed:hover,
173
+ .mh-button--dashed.is-hover {
174
+ border-color: var(--ui-button-accent-hover);
175
+ color: var(--ui-button-accent-hover);
176
+ }
177
+ .mh-button--dashed:active,
178
+ .mh-button--dashed.is-active {
179
+ border-color: var(--ui-button-accent);
180
+ color: var(--ui-button-accent);
181
+ }
182
+
183
+ /* ===== 文本按钮(**只用于行内 / 批量操作**:表格操作列、批量条、列表行内操作;
184
+ * 页头与区块的操作区一律用 primary + secondary —— 与规范 README 同口径) ===== */
185
+ .mh-button--text {
186
+ padding: 0 var(--ui-space-1);
187
+ background: transparent;
188
+ color: var(--ui-button-accent);
189
+ }
190
+ .mh-button--text:hover,
191
+ .mh-button--text.is-hover {
192
+ color: var(--ui-button-accent-hover);
193
+ }
194
+ .mh-button--text:active,
195
+ .mh-button--text.is-active {
196
+ color: color-mix(in srgb, var(--ui-button-accent) 80%, black);
197
+ }
198
+
199
+ /* ===== 链接按钮(跳转语义:带下划线,与「行内文本操作」的 text 档区分开) ===== */
200
+ .mh-button--link {
201
+ padding: 0;
202
+ background: transparent;
203
+ color: var(--ui-button-accent);
204
+ text-decoration: underline;
205
+ text-underline-offset: 3px;
206
+ }
207
+ .mh-button--link:hover,
208
+ .mh-button--link.is-hover {
209
+ color: var(--ui-button-accent-hover);
210
+ }
211
+ .mh-button--link:active,
212
+ .mh-button--link.is-active {
213
+ color: color-mix(in srgb, var(--ui-button-accent) 80%, black);
214
+ }
215
+
216
+ /* ===== 图标按钮(方形热区 + 16 字形;滑过/点击带主色光晕) ===== */
217
+ .mh-button--icon {
218
+ width: var(--ui-button-height);
219
+ height: var(--ui-button-height);
220
+ padding: 0; /* 显式清 UA 给 <button> 的内距,否则 border-box 下字形被挤扁 */
221
+ background: transparent;
222
+ color: var(--ui-base-content);
223
+ }
224
+ .mh-button--sm.mh-button--icon {
225
+ width: var(--ui-button-height-sm);
226
+ height: var(--ui-button-height-sm);
227
+ }
228
+ .mh-button--lg.mh-button--icon {
229
+ width: var(--ui-button-height-lg);
230
+ height: var(--ui-button-height-lg);
231
+ }
232
+ .mh-button--icon:hover,
233
+ .mh-button--icon.is-hover {
234
+ color: var(--ui-button-accent-hover);
235
+ box-shadow: var(--ui-shadow-card-hover);
236
+ }
237
+ .mh-button--icon:active,
238
+ .mh-button--icon.is-active {
239
+ color: var(--ui-button-accent);
240
+ }
241
+ /* 危险色 + 图标 / 文本 / 链接:这三型的字色不走 accent 槽(分别是中性 / 主色语义),单列一条 */
242
+ .mh-button--danger.mh-button--icon,
243
+ .mh-button--danger.mh-button--text,
244
+ .mh-button--danger.mh-button--link {
245
+ color: var(--ui-error);
246
+ }
247
+ .mh-button--danger.mh-button--icon:hover,
248
+ .mh-button--danger.mh-button--text:hover,
249
+ .mh-button--danger.mh-button--link:hover {
250
+ color: color-mix(in srgb, var(--ui-error) 88%, black);
251
+ }
252
+
253
+ /* ===== 禁用(各类通用;用专用令牌而非 opacity,避免禁用态被底色影响)
254
+ *
255
+ * 描边走 **inset 阴影而不是 `border`**:`border: 1px` 会把「无边框」的常态按钮撑宽 2px,
256
+ * 按钮一进禁用就在底栏里抖一下 —— inset 阴影画的还是同一圈 1px、位置也一致,但元素尺寸不变。
257
+ *
258
+ * **加载态排除在外**(`:not()`):`loading` 虽然也置原生 disabled(吞点击),但它**外观保持本型**
259
+ * —— 点击前后只有「文字 → 环」这一处变化,不换底 / 不换边 / 不换字。不排除的话,禁用档
260
+ * (2 个类)会压过 `.mh-button--loading`(1 个类),全屏最显眼的主操作会在点下去的一瞬间
261
+ * 整块变成禁用灰,观感突兀(浏览器实测过:底 `rgb(241,242,245)` + 灰字 + 灰边)。 */
262
+ .mh-button:disabled:not(.mh-button--loading),
263
+ .mh-button.is-disabled:not(.mh-button--loading),
264
+ .mh-button[aria-disabled='true']:not(.mh-button--loading) {
265
+ background: var(--ui-button-bg-disabled);
266
+ box-shadow: inset 0 0 0 1px var(--ui-button-border-disabled);
267
+ color: var(--ui-button-text-disabled);
268
+ cursor: not-allowed;
269
+ }
270
+ /* 文本 / 链接 / 图标三型没有底与边,禁用只换字色 */
271
+ .mh-button--text:disabled:not(.mh-button--loading),
272
+ .mh-button--text.is-disabled:not(.mh-button--loading),
273
+ .mh-button--text[aria-disabled='true']:not(.mh-button--loading),
274
+ .mh-button--link:disabled:not(.mh-button--loading),
275
+ .mh-button--link.is-disabled:not(.mh-button--loading),
276
+ .mh-button--link[aria-disabled='true']:not(.mh-button--loading),
277
+ .mh-button--icon:disabled:not(.mh-button--loading),
278
+ .mh-button--icon.is-disabled:not(.mh-button--loading),
279
+ .mh-button--icon[aria-disabled='true']:not(.mh-button--loading) {
280
+ background: transparent;
281
+ border: none;
282
+ color: var(--ui-button-text-disabled);
283
+ box-shadow: none;
284
+ text-decoration: none;
285
+ }
286
+
287
+ /* ===== 加载(**本型外观 + 主色降透明 + 环**) =====
288
+ *
289
+ * 加载态不改色彩角色:`primary` 还是主色、`danger` 还是错误色、`secondary` 还是白底黑字 ——
290
+ * 只是实底型的**主色底**按 `--ui-button-loading-mix` 与面板色显式合成一档更淡的同色。
291
+ * 忙碌时的按钮该是「同一个按钮淡了一点点、在转圈」,而不是换一副面孔(整块变灰或换档色都太突兀)。
292
+ *
293
+ * **为什么是显式合成而不是 `opacity`**:`opacity` 压的是整块,连文案与加载环一起淡 ——
294
+ * 忙碌时的文案恰恰要读得清;写成 `color-mix(主色 × mix, 面板色)` 只让**底**淡一档。
295
+ * (也别用覆盖层:主色实底上再盖一层同色半透明层等于什么都没做 —— 那是条死路。)
296
+ *
297
+ * 其余五型(`secondary` / `dashed` / `text` / `link` / `icon`)的「主色」在描边或字上,
298
+ * 底本来就是白的或透明的 —— 再降一档只会把边与字读淡,故它们加载时**外观完全不变**,只多一个环。
299
+ * 环取 **`currentColor`**:一条规则自动跟上六型与 `danger`(实底型白环、浅底与图标型本型字色环、
300
+ * 透明底型主色环),既不必逐型特判,也不额外引令牌。 */
301
+ .mh-button--loading {
302
+ cursor: not-allowed; /* 禁用档被排除了,`:disabled` 那条已不匹配它 */
303
+ }
304
+ /* 实底型的加载底:主色与面板色按令牌比例显式混出。
305
+ 写在 hover / active 之后:同特异性(0.2.0)下后者胜出,故加载中滑过、按下都不会回到满主色 */
306
+ .mh-button--loading.mh-button--primary {
307
+ background: color-mix(
308
+ in srgb,
309
+ var(--ui-button-accent) var(--ui-button-loading-mix),
310
+ var(--ui-base-100)
311
+ );
312
+ }
313
+ .mh-button__spinner {
314
+ flex: none;
315
+ width: var(--ui-button-spinner-size);
316
+ height: var(--ui-button-spinner-size);
317
+ border: 1.5px solid currentColor; /* 跟随按钮的字色,六型通用 */
318
+ border-top-color: transparent;
319
+ border-radius: var(--ui-radius-full);
320
+ animation: mh-button-spin 0.8s linear infinite; /* 规范 0.8s linear */
321
+ }
322
+ @keyframes mh-button-spin {
323
+ to {
324
+ transform: rotate(360deg);
325
+ }
326
+ }
327
+
328
+ /* ===== 下拉箭头槽 =====
329
+ * **只给槽位尺寸,不给字形**:字形由 `@manohub/icon` 的 `<Icon name="chevron-down">` 画,
330
+ * 展开时的转向由操作层 `popup.css` 的 `.mh-popup-caret` 承担(本件不定义第二份 mask / 第二处转向)。
331
+ * 故组件把两个类同时挂在图标上:`class="mh-button__caret mh-popup-caret"`。 */
332
+ .mh-button__caret {
333
+ flex: none;
334
+ width: var(--ui-button-icon-size);
335
+ height: var(--ui-button-icon-size);
336
+ }
337
+
338
+ /* ===== 菜单按钮(文本区 ‖ 分割线 ‖ 箭头区;只管结构,色调随修饰符) ===== */
339
+ .mh-button--menu {
340
+ padding: 0;
341
+ gap: 0;
342
+ }
343
+ .mh-button__label {
344
+ padding: 0 var(--ui-button-padding-x);
345
+ }
346
+ .mh-button--menu .mh-button__caret {
347
+ margin: 0 var(--ui-button-gap);
348
+ }
349
+
350
+ /* 竖分割线(1px,跟按钮同高) */
351
+ .mh-button__divider {
352
+ flex: none;
353
+ width: 1px;
354
+ height: var(--ui-button-height);
355
+ background: var(--ui-base-300);
356
+ }
357
+
358
+ /* ===== 组容器(组件层结构,不是排版行):组内间距恒 8 ===== */
359
+ .mh-button__group {
360
+ display: inline-flex;
361
+ align-items: center;
362
+ gap: var(--ui-button-group-gap);
363
+ }
364
+ /* 组内文本按钮把水平内距交还容器 —— 间距只由 gap 单一拥有(否则 4+8+4=16) */
365
+ .mh-button__group > .mh-button--text {
366
+ padding-inline: 0;
367
+ }
368
+ /* 连体档:相邻按钮边重合、中间圆角归零(工具条形态;首末保留圆角) */
369
+ .mh-button__group--compact {
370
+ gap: 0;
371
+ }
372
+ .mh-button__group--compact > .mh-button {
373
+ border-radius: 0;
374
+ }
375
+ .mh-button__group--compact > .mh-button:first-child {
376
+ border-radius: var(--ui-button-radius) 0 0 var(--ui-button-radius);
377
+ }
378
+ .mh-button__group--compact > .mh-button:last-child {
379
+ border-radius: 0 var(--ui-button-radius) var(--ui-button-radius) 0;
380
+ }
381
+ .mh-button__group--compact > .mh-button + .mh-button {
382
+ margin-left: -1px; /* 相邻描边重合,避免连体处出现 2px 双线 */
383
+ }
384
+
385
+ /* ===== 连体切换(选中半区 + 未选半区连体;状态由组件或静态档给) ===== */
386
+ .mh-button__switch {
387
+ display: inline-flex;
388
+ border-radius: var(--ui-button-radius);
389
+ }
390
+ .mh-button__switch > .mh-button {
391
+ border-radius: 0;
392
+ }
393
+ .mh-button__switch > .mh-button:first-child {
394
+ border-radius: var(--ui-button-radius) 0 0 var(--ui-button-radius);
395
+ }
396
+ .mh-button__switch > .mh-button:last-child {
397
+ border-radius: 0 var(--ui-button-radius) var(--ui-button-radius) 0;
398
+ }
399
+ .mh-button--off {
400
+ background: var(--ui-base-100);
401
+ border: 1px solid var(--ui-base-300);
402
+ color: var(--ui-base-content);
403
+ box-shadow: var(--ui-shadow-card);
404
+ }
405
+ .mh-button--off:hover,
406
+ .mh-button--off.is-hover {
407
+ border-color: var(--ui-button-accent-hover);
408
+ color: var(--ui-button-accent-hover);
409
+ }
410
+
411
+ /* ===== 按钮当「文件选择器」触发器(upload 族复用:点按钮即唤起系统选择,零 JS) ===== */
412
+ .mh-button > input[type='file'] {
413
+ position: absolute;
414
+ width: 1px;
415
+ height: 1px;
416
+ margin: -1px;
417
+ padding: 0;
418
+ border: 0;
419
+ overflow: hidden;
420
+ white-space: nowrap;
421
+ clip-path: inset(50%);
422
+ appearance: none;
423
+ pointer-events: none;
424
+ }
425
+ /* 焦点环画在按钮上(隐身的 file input 没有可见焦点) */
426
+ .mh-button:has(> input[type='file']:focus-visible) {
427
+ outline: 2px solid var(--ui-primary);
428
+ outline-offset: -2px;
429
+ }
430
+
431
+ /* ===== 子菜单浮层皮肤(与操作层并列组合:`class="mh-popup mh-button__menu"`) =====
432
+ * 只给面(底 / 圆角 / 内距 / 阴影 / 选项行),开合、Esc、点外部关闭、顶层渲染、定位档全在 popup.css。 */
433
+ .mh-button__menu {
434
+ width: 130px;
435
+ padding: var(--ui-space-1) 6px;
436
+ /* 圆角取容器档(原为硬编码 10px —— 与令牌里的容器档同义却写死,改版时不会跟随);
437
+ 投影取锚定浮层档(`--ui-shadow-popover`),不是居中浮层档。 */
438
+ border-radius: var(--ui-radius-md);
439
+ background: var(--ui-base-100);
440
+ box-shadow: var(--ui-shadow-popover);
441
+ }
442
+ .mh-button__menu-item {
443
+ height: 30px;
444
+ padding: 0 var(--ui-space-2);
445
+ border-radius: var(--ui-button-radius);
446
+ font-size: var(--ui-button-font-size);
447
+ line-height: 30px;
448
+ color: var(--ui-base-content);
449
+ cursor: pointer;
450
+ }
451
+ .mh-button__menu-item:hover,
452
+ .mh-button__menu-item.is-hover {
453
+ background: var(--ui-base-200);
454
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 单件令牌(只服务本件,故只随本包走,不进 `@manohub/theme`)。
3
+ *
4
+ * **本件有一批令牌是「跨分件消费」的**:`--ui-button-group-gap` 归组容器 `.mh-button__group`、
5
+ * 组内分割线高度与菜单项圆角归 `.mh-button__menu`(popover 面板,与按钮**兄弟**、
6
+ * 不在它的子树里)—— 自定义属性只向下继承,声明在 `.mh-button` 上这类分件取不到值
7
+ * (声明在计算值阶段作废,且不报任何错)。
8
+ *
9
+ * 改前靠「把令牌同时声明在 4 个外层类上」的 workaround 兜(历史症状:组内间距变 0、
10
+ * 组内分割线高度 0、连体切换与菜单项圆角 0);锚到容器后,**容器是每个分件的祖先**,
11
+ * 这类 workaround 整块撤掉 —— 这正是本文件从面文件里抽出来的直接原因。
12
+ *
13
+ * ## 抽出说明
14
+ * 本文件从面文件里抽出:这些是**基础值**,锚在 `[data-manohub-ui]`(跨包唯一作用域锚,
15
+ * 由入口层无条件写在应用容器上)—— 任何落在容器里的分件都取得到值,不再依赖
16
+ * 「声明在某个组件根类上」这条脆弱假设。
17
+ * ⚠️ `.mh-<件>--<档>` 这类**档位改写**留在面文件的修饰符块里(拆开会让档位失效)。
18
+ */
19
+ [data-manohub-ui] {
20
+ /* 单件令牌(只服务本件,故不随主题进 `@manohub/theme`) */
21
+ --ui-button-height: var(--ui-control-height-md); /* 标准档 32 */
22
+ --ui-button-height-sm: var(--ui-control-height-sm); /* 小号 24 */
23
+ --ui-button-height-lg: var(--ui-control-height-lg); /* 大号 40 */
24
+ /* 左右内距 12:设计实测反推 —— 次要按钮「删除」52 宽 = 12 + 文本 28 + 12;
25
+ 主要按钮「新增」70 宽 = 12 + 28 + 4(图文距) + 14(图标) + 12。改前为 15(两字按钮会宽出 6px)。 */
26
+ --ui-button-padding-x: 12px;
27
+ --ui-button-padding-x-sm: 8px;
28
+ --ui-button-padding-x-lg: 20px;
29
+ --ui-button-gap: var(--ui-space-1); /* 图文/箭头间距 4 */
30
+ --ui-button-radius: var(--ui-radius-control); /* 6 */
31
+ /* 图标槽:**常规图标一律取全局图标档**(`--ui-font-icon` = 14)。
32
+ 与设计反推自洽:主要按钮「新增」70 宽 = 12 + 文本 28 + 4(图文距) + **14(图标)** + 12。
33
+ 档距沿用原表的 ±2(小号 −2 / 大号 +2),改全局图标档时三档同步缩放。
34
+ ⚠️ 与规范登记的偏差:规范「图标按钮字形」实测 **16**;本轮按「常规图标统一取全局图标档」取 14 ——
35
+ 图标按钮与文本按钮共用同一图标槽(同一类 `mh-button__icon`),不为此分叉。 */
36
+ --ui-button-icon-size: var(--ui-font-icon);
37
+ --ui-button-icon-size-sm: calc(var(--ui-font-icon) - 2px);
38
+ --ui-button-icon-size-lg: calc(var(--ui-font-icon) + 2px);
39
+ --ui-button-spinner-size: 14px; /* 加载环(与正文档图标同径) */
40
+ --ui-button-font-size: var(--ui-font-body); /* 14:控件内容走正文档 */
41
+ --ui-button-font-size-sm: var(--ui-font-caption); /* 13:小号回归说明文档 */
42
+ --ui-button-font-size-lg: var(--ui-font-heading); /* 16:大号升到标题档 */
43
+ --ui-button-group-gap: var(--ui-space-2); /* 同组按钮恒 8 */
44
+ --ui-button-bg-disabled: var(--ui-base-200); /* 设计「次要按钮备份」底 #f2f2f2 */
45
+ --ui-button-border-disabled: var(--ui-base-300);
46
+ --ui-button-text-disabled: var(--ui-base-content-subtle); /* 设计禁用字 #888888 → 并入 subtle 档 */
47
+ /* 加载态「主色降透明」的混合比例(规范 0.65):实底型的底 = 主色 × 本值 + 面板色 × (1 − 本值)。
48
+ 等效「主色 65% 透明叠在页面上」,但**只作用于底** —— 字与环保持纯色(见「加载」节)。
49
+ 嫌淡嫌深都改这一处,不必去动任何一条色彩规则。 */
50
+ --ui-button-loading-mix: 65%;
51
+ /* 色彩槽位:危险色只换这四个变量(设计见文件头) */
52
+ --ui-button-accent: var(--ui-primary);
53
+ --ui-button-accent-hover: var(--ui-primary-hover);
54
+ --ui-button-accent-content: var(--ui-primary-content);
55
+ --ui-button-accent-soft: var(--ui-primary-subtle); /* 危险的浅底(次级实心档) */
56
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Capsule —— 胶囊选择器(一组互斥选项,选中项白底胶囊浮在轨道上)。
3
+ *
4
+ * 出处:`@aihub/theme` 的 `playground/components/capsule.css` 与 `src/components/capsule.css`
5
+ * (轨道 32 高 / 内距 2 / 项 28 高 / 项内距 14 / 字号 14 / 圆角全;选中 = 白底 + 主色字 + medium +
6
+ * 1px 4px 主色投影;未选字 Te05、滑过转主色、禁用 Te07;轨道底 Au04)。
7
+ *
8
+ * **外形档**(`shape`):规范只有「圆角全」的胶囊形态;`.mh-capsule--square` 是**本仓新增**的圆角矩形档
9
+ * (与方角控件并排排版时用),圆角取**复选框档**令牌 `--ui-radius-sm`(比控件档更方,具体值随主题变)。
10
+ * 两档只差圆角令牌一处,其余几何与颜色一律不变。
11
+ *
12
+ * **操作是原生的**:一组同名 radio —— 开关与项**平级相邻、开关在前**,开关由本族隐身但保持可聚焦
13
+ * (Tab 进组、方向键换项、空格选中)。焦点环画在可见项上。
14
+ *
15
+ * 状态三源等价:原生 `input:checked` / 组件下发 `[data-state='active']` / 静态档 `.is-selected`。
16
+ *
17
+ * **与面板组合**:要「选中即切面板」,外面套 `styles/operations/tabset.css` 的 `.mh-tabset` ——
18
+ * 本族不认识它、它也不认识本族(两层零互指),壳层挂类即可。
19
+ *
20
+ * **与 `Tabset` 的判据**:`Tabset` 是操作层(只给行为与档位表、不带面),面可由本件或按钮族的分段形态担任;
21
+ * 本件是**带自己轨道与选中胶囊的轻量选择控件**。
22
+ */
23
+ .mh-capsule {
24
+ display: inline-flex;
25
+ align-items: center;
26
+ gap: 0; /* 胶囊相邻无间隙 */
27
+ min-height: var(--ui-capsule-height);
28
+ padding: var(--ui-capsule-inset);
29
+ border-radius: var(--ui-capsule-radius);
30
+ background: var(--ui-capsule-track-bg);
31
+ }
32
+
33
+ /* 隐身开关:视觉隐藏但保持可聚焦(1px 盒 + clip-path,同 checkbox / radio 配方) */
34
+ .mh-capsule__input {
35
+ position: absolute;
36
+ width: 1px;
37
+ height: 1px;
38
+ margin: -1px;
39
+ padding: 0;
40
+ border: 0;
41
+ overflow: hidden;
42
+ white-space: nowrap;
43
+ clip-path: inset(50%);
44
+ appearance: none;
45
+ pointer-events: none; /* 别让这 1px 盒抢走轨道上的点击 */
46
+ }
47
+
48
+ .mh-capsule__item {
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ height: var(--ui-capsule-item-height);
53
+ padding: 0 var(--ui-capsule-item-padding-x);
54
+ border: none;
55
+ border-radius: var(--ui-capsule-radius);
56
+ background: transparent;
57
+ font-family: inherit;
58
+ font-size: var(--ui-capsule-font-size);
59
+ line-height: var(--ui-line-body);
60
+ color: var(--ui-capsule-text);
61
+ cursor: pointer;
62
+ user-select: none;
63
+ }
64
+
65
+ /* 滑过:未选项文字转主色滑过档(白底项保持自己的字色) */
66
+ .mh-capsule__item:hover,
67
+ .mh-capsule__item.is-hover {
68
+ color: var(--ui-primary-hover);
69
+ }
70
+
71
+ /* 键盘焦点环画在可见项上(隐身开关没有可见焦点;环随项自身圆角 = 胶囊形) */
72
+ .mh-capsule__input:focus-visible + .mh-capsule__item {
73
+ outline: 2px solid var(--ui-primary);
74
+ outline-offset: -2px;
75
+ }
76
+
77
+ /* 禁用:原生 disabled 与静态档同款(方向键会自动跳过禁用项,这是原生 radio 组的行为) */
78
+ .mh-capsule__item.is-disabled,
79
+ .mh-capsule__input:disabled + .mh-capsule__item {
80
+ color: var(--ui-base-content-subtle); /* Te07 */
81
+ cursor: not-allowed;
82
+ }
83
+
84
+ /* 选中:白底胶囊 + 主色字 + 投影(三源等价;下划线只属已退役的线性档,本族不画) */
85
+ .mh-capsule__item.is-selected,
86
+ .mh-capsule__item[data-state='active'],
87
+ .mh-capsule__input:checked + .mh-capsule__item {
88
+ background: var(--ui-capsule-item-bg);
89
+ color: var(--ui-primary);
90
+ font-weight: var(--ui-weight-medium);
91
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--ui-primary) 30%, transparent);
92
+ }
93
+
94
+ /* ===== 尺寸档(只覆盖令牌,几何规则只有一份) ===== */
95
+ .mh-capsule--sm {
96
+ --ui-capsule-height: var(--ui-control-height-sm);
97
+ --ui-capsule-item-height: calc(var(--ui-control-height-sm) - 4px);
98
+ --ui-capsule-font-size: var(--ui-font-caption);
99
+ }
100
+ .mh-capsule--lg {
101
+ --ui-capsule-height: var(--ui-control-height-lg);
102
+ --ui-capsule-item-height: calc(var(--ui-control-height-lg) - 4px);
103
+ --ui-capsule-font-size: var(--ui-font-body);
104
+ }
105
+
106
+ /* ===== 外形档(只覆盖圆角令牌,几何与颜色规则只有一份) ===== */
107
+ .mh-capsule--square {
108
+ --ui-capsule-radius: var(--ui-radius-sm); /* 复选框档:比控件档更方(值随主题变) */
109
+ }
110
+
111
+ /* ===== 整宽档:每项等分(移动端 / 表单里占满一行) ===== */
112
+ .mh-capsule--block {
113
+ display: flex;
114
+ width: 100%;
115
+ }
116
+ .mh-capsule--block > .mh-capsule__item {
117
+ flex: 1;
118
+ min-width: 0;
119
+ justify-content: center;
120
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * capsule —— 单件令牌(**基础值**)。
3
+ *
4
+ * 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
5
+ *
6
+ * ## 抽出说明
7
+ * 本文件从面文件里抽出(原先混写在 `capsule.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
+ /* 单件令牌(项高 28 + 内距 2×2 = 轨道 32,与规范实测一致) */
18
+ --ui-capsule-height: 32px;
19
+ --ui-capsule-item-height: 28px;
20
+ --ui-capsule-inset: 2px; /* 规范实测 2(本仓间距刻度从 4 起,取 4 会让轨道变 36,故按实测值给) */
21
+ --ui-capsule-item-padding-x: 14px; /* 规范实测(项宽 84 = 14 + 文字 56 + 14) */
22
+ --ui-capsule-font-size: var(--ui-font-body); /* 规范字号档 md(14)对位 */
23
+ --ui-capsule-track-bg: var(--ui-primary-weak); /* 规范 Au04 轨道底 */
24
+ --ui-capsule-item-bg: var(--ui-base-100); /* 选中 = 白底 */
25
+ --ui-capsule-text: var(--ui-base-content-muted); /* 未选 Te05 */
26
+ --ui-capsule-radius: var(--ui-radius-full); /* 缺省胶囊形;方形档覆盖为复选框档(见「外形档」) */
27
+ }