@manohub/ui 0.10.5 → 1.0.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.
- package/README.md +155 -155
- package/dist/components/form/index.js +8 -1
- package/dist/components/input/bordered.d.ts +15 -0
- package/dist/components/input/bordered.js +8 -0
- package/dist/components/input/index.d.ts +82 -31
- package/dist/components/input/index.js +16 -6
- package/dist/components/input/number-input.d.ts +239 -0
- package/dist/components/input/number-input.js +240 -0
- package/dist/components/select/index.d.ts +19 -0
- package/dist/components/select/index.js +10 -0
- package/dist/components/select/select-tree.d.ts +11 -0
- package/dist/components/select/select-tree.js +6 -0
- package/dist/components/select/select-trigger.d.ts +17 -0
- package/dist/components/select/select-trigger.js +9 -0
- package/dist/components/table/index.d.ts +85 -10
- package/dist/components/table/index.js +38 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -0
- package/dist/styles/components/avatar.css +131 -131
- package/dist/styles/components/avatar.tokens.css +24 -24
- package/dist/styles/components/badge.css +266 -266
- package/dist/styles/components/badge.tokens.css +24 -24
- package/dist/styles/components/button.css +460 -460
- package/dist/styles/components/capsule.css +128 -128
- package/dist/styles/components/capsule.tokens.css +27 -27
- package/dist/styles/components/card.css +198 -198
- package/dist/styles/components/checkbox.css +145 -145
- package/dist/styles/components/checkbox.tokens.css +26 -26
- package/dist/styles/components/code-block.css +216 -216
- package/dist/styles/components/code-block.tokens.css +40 -40
- package/dist/styles/components/collapse.css +62 -62
- package/dist/styles/components/collapse.tokens.css +20 -20
- package/dist/styles/components/dialog.css +158 -158
- package/dist/styles/components/dialog.tokens.css +24 -24
- package/dist/styles/components/divider.css +75 -75
- package/dist/styles/components/divider.tokens.css +22 -22
- package/dist/styles/components/drawer.css +143 -143
- package/dist/styles/components/drawer.tokens.css +22 -22
- package/dist/styles/components/filter.css +29 -29
- package/dist/styles/components/form.css +456 -425
- package/dist/styles/components/form.tokens.css +19 -15
- package/dist/styles/components/input.css +659 -538
- package/dist/styles/components/input.tokens.css +43 -43
- package/dist/styles/components/layout.css +200 -200
- package/dist/styles/components/list-view.css +244 -244
- package/dist/styles/components/loading.css +76 -76
- package/dist/styles/components/loading.tokens.css +23 -23
- package/dist/styles/components/nav.css +48 -48
- package/dist/styles/components/notice.css +153 -153
- package/dist/styles/components/notice.tokens.css +17 -17
- package/dist/styles/components/notification.css +159 -159
- package/dist/styles/components/notification.tokens.css +37 -37
- package/dist/styles/components/page.css +473 -473
- package/dist/styles/components/pagination.css +303 -303
- package/dist/styles/components/pagination.tokens.css +32 -32
- package/dist/styles/components/panel.css +77 -77
- package/dist/styles/components/query-state.css +88 -88
- package/dist/styles/components/radio.css +271 -271
- package/dist/styles/components/radio.tokens.css +26 -26
- package/dist/styles/components/search.css +34 -34
- package/dist/styles/components/select.css +326 -326
- package/dist/styles/components/select.tokens.css +44 -44
- package/dist/styles/components/skeleton.css +60 -60
- package/dist/styles/components/skeleton.tokens.css +27 -27
- package/dist/styles/components/steps.css +205 -205
- package/dist/styles/components/steps.tokens.css +44 -44
- package/dist/styles/components/switch.css +165 -165
- package/dist/styles/components/switch.tokens.css +26 -26
- package/dist/styles/components/tabbar.css +235 -235
- package/dist/styles/components/tabbar.tokens.css +30 -30
- package/dist/styles/components/table.css +510 -504
- package/dist/styles/components/table.tokens.css +44 -44
- package/dist/styles/components/tag.css +127 -127
- package/dist/styles/components/tag.tokens.css +24 -24
- package/dist/styles/components/toast.css +185 -185
- package/dist/styles/components/toast.tokens.css +26 -26
- package/dist/styles/components/tooltip.css +89 -89
- package/dist/styles/components/tooltip.tokens.css +25 -25
- package/dist/styles/components/tree.css +173 -173
- package/dist/styles/components/upload.css +151 -151
- package/dist/styles/components/upload.tokens.css +27 -27
- package/dist/styles/index.css +153 -153
- package/dist/styles/operations/collapse.css +84 -84
- package/dist/styles/operations/popup.css +193 -193
- package/dist/styles/operations/tabs.css +82 -82
- package/package.json +62 -62
|
@@ -1,271 +1,271 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Radio —— 单选族的面:普通单选组(`Radio.Group`)+ 卡片式单选组(`Radio.Card`),两形态共用一个文件。
|
|
3
|
-
*
|
|
4
|
-
* - `Radio` / `Radio.Group`:一行一个选项 + 组容器,类根 `.mh-radio*`
|
|
5
|
-
* - `Radio.Card`:一个选项一张卡、整卡可点,类根 `.mh-radio-card*`
|
|
6
|
-
*
|
|
7
|
-
* **为什么同面**:两者是**同一个件的两种组形态**,共用同一套状态协议(选中 / 禁用 / 键盘焦点)
|
|
8
|
-
* 与同一套「框体 + 圆点」几何,差别只在承载形态;拆成两份必然让同一族的选中 / 禁用语义各自漂。
|
|
9
|
-
* 合一后圆点配方只有一处(面二自绘,与面一的框体同色同档),且 `radio.css` 与
|
|
10
|
-
* `components/radio/` 仍是标准的「一组件一面」(护栏 `contract-class-surface.spec.ts`)。
|
|
11
|
-
*
|
|
12
|
-
* ===== 面一:`Radio`(普通单选组)=====
|
|
13
|
-
*
|
|
14
|
-
* 出处:`@aihub/theme` 的 `playground/components/radio.css` 与其令牌 `src/components/checkbox.css`
|
|
15
|
-
* (框体实测、单选为胶囊、未选边框 Ne04、滑过 Th05、选中主色圆点、禁用 Ne05 + Te07、选项间距 16 / 10)。
|
|
16
|
-
*
|
|
17
|
-
* **与 `Radio.Card` 的判据**:选项只有一行文字(或极短说明)→ 面一;
|
|
18
|
-
* 选项需要标题 + 描述 + 整卡可点(卡片式选择)→ 面二。
|
|
19
|
-
* **与 `Capsule` 的判据**:要「按钮形态的分组」→ `Capsule`(本面不实现按钮档,避免两套平铺控件)。
|
|
20
|
-
*
|
|
21
|
-
* **与复选框同族**:圆点由 `border` 从 1px 补间到圆点档画成(盒定尺,无布局位移),
|
|
22
|
-
* 不走字形 mask —— 这是规范的做法(勾/横杠才需要 mask)。
|
|
23
|
-
*
|
|
24
|
-
* **尺寸三档只覆盖令牌**(`--ui-radio-size*` / `--ui-radio-dot*`),几何规则只有一份。
|
|
25
|
-
*
|
|
26
|
-
* **状态三源等价**(本仓通例):原生 `input:checked` / 组件下发 `[data-state]` / 静态档 `.is-*`
|
|
27
|
-
* 指向同一份声明,不写第二份面。
|
|
28
|
-
*
|
|
29
|
-
* 边界(有意不做):规范 `radio.css` 里的 `.cell-check`(表格选择列)**不在这里实现** ——
|
|
30
|
-
* 表格选择列归表格族,本面不重复实现(否则会出现两套表格选择列外观)。
|
|
31
|
-
*/
|
|
32
|
-
.mh-radio {
|
|
33
|
-
display: inline-flex;
|
|
34
|
-
align-items: center;
|
|
35
|
-
gap: var(--ui-radio-label-gap);
|
|
36
|
-
font-size: var(--ui-font-body);
|
|
37
|
-
line-height: var(--ui-line-body);
|
|
38
|
-
color: var(--ui-base-content);
|
|
39
|
-
cursor: pointer;
|
|
40
|
-
user-select: none;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* 组容器:横向 16 / 纵向 12 */
|
|
44
|
-
.mh-radio-group {
|
|
45
|
-
display: flex;
|
|
46
|
-
flex-wrap: wrap;
|
|
47
|
-
gap: var(--ui-space-4);
|
|
48
|
-
}
|
|
49
|
-
.mh-radio-group--vertical {
|
|
50
|
-
flex-direction: column;
|
|
51
|
-
gap: var(--ui-space-3);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/* 隐身开关:真实 radio 负责可访问性与键盘,可见框体自绘(同 Checkbox 配方) */
|
|
55
|
-
.mh-radio__input {
|
|
56
|
-
position: absolute;
|
|
57
|
-
width: 1px;
|
|
58
|
-
height: 1px;
|
|
59
|
-
margin: -1px;
|
|
60
|
-
padding: 0;
|
|
61
|
-
border: 0;
|
|
62
|
-
overflow: hidden;
|
|
63
|
-
white-space: nowrap;
|
|
64
|
-
clip-path: inset(50%);
|
|
65
|
-
appearance: none;
|
|
66
|
-
pointer-events: none;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/* 框体 */
|
|
70
|
-
.mh-radio__box {
|
|
71
|
-
display: inline-flex;
|
|
72
|
-
align-items: center;
|
|
73
|
-
justify-content: center;
|
|
74
|
-
flex: none;
|
|
75
|
-
width: var(--ui-radio-size);
|
|
76
|
-
height: var(--ui-radio-size);
|
|
77
|
-
border: 1px solid var(--ui-base-400); /* Ne04 未选默认 */
|
|
78
|
-
border-radius: var(--ui-radius-full); /* 单选为胶囊 */
|
|
79
|
-
background: var(--ui-base-100);
|
|
80
|
-
transition-property: border-width, border-color, background-color;
|
|
81
|
-
transition-duration: 0.15s;
|
|
82
|
-
transition-timing-function: ease;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/* ===== 尺寸档(只覆盖令牌) ===== */
|
|
86
|
-
.mh-radio--sm {
|
|
87
|
-
--ui-radio-size: var(--ui-radio-size-sm);
|
|
88
|
-
--ui-radio-dot: var(--ui-radio-dot-sm);
|
|
89
|
-
font-size: var(--ui-font-caption);
|
|
90
|
-
}
|
|
91
|
-
.mh-radio--lg {
|
|
92
|
-
--ui-radio-size: var(--ui-radio-size-lg);
|
|
93
|
-
--ui-radio-dot: var(--ui-radio-dot-lg);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* 禁用整行:不可点(原生 disabled 与静态档同款) */
|
|
97
|
-
.mh-radio.is-disabled,
|
|
98
|
-
.mh-radio:has(> .mh-radio__input:disabled) {
|
|
99
|
-
cursor: not-allowed;
|
|
100
|
-
color: var(--ui-base-content-subtle);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* 滑过:未选边框转主色滑过档(Th05) */
|
|
104
|
-
.mh-radio.is-hover .mh-radio__box,
|
|
105
|
-
.mh-radio:hover > .mh-radio__box {
|
|
106
|
-
border-color: var(--ui-primary-hover);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/* 选中:圆点(主色,随选择控件色);三源等价 */
|
|
110
|
-
.mh-radio.is-checked .mh-radio__box,
|
|
111
|
-
.mh-radio__box[data-state='checked'],
|
|
112
|
-
.mh-radio > .mh-radio__input:checked + .mh-radio__box {
|
|
113
|
-
border: var(--ui-radio-dot) solid var(--ui-primary);
|
|
114
|
-
}
|
|
115
|
-
/* 选中后滑过不再改边色(已经是满色圆点,改色只会闪) */
|
|
116
|
-
.mh-radio.is-checked:hover > .mh-radio__box,
|
|
117
|
-
.mh-radio > .mh-radio__input:checked:hover + .mh-radio__box {
|
|
118
|
-
border-color: var(--ui-primary);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* 禁用边框(Ne05) */
|
|
122
|
-
.mh-radio.is-disabled .mh-radio__box,
|
|
123
|
-
.mh-radio > .mh-radio__input:disabled + .mh-radio__box {
|
|
124
|
-
border-color: var(--ui-base-300);
|
|
125
|
-
background: var(--ui-base-200);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/* 禁用且选中:圆点转 Te07 */
|
|
129
|
-
.mh-radio.is-disabled.is-checked .mh-radio__box,
|
|
130
|
-
.mh-radio > .mh-radio__input:disabled:checked + .mh-radio__box {
|
|
131
|
-
border-color: var(--ui-base-content-subtle);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/* 键盘焦点环画在可见框体上(隐身开关没有可见焦点) */
|
|
135
|
-
.mh-radio > .mh-radio__input:focus-visible + .mh-radio__box {
|
|
136
|
-
outline: 2px solid var(--ui-primary-weak);
|
|
137
|
-
outline-offset: 2px;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.mh-radio__label {
|
|
141
|
-
min-width: 0;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/* ===== 面二:`Radio.Card`(卡片式单选组,自建)=====
|
|
145
|
-
一个选项一张卡、整卡可点;选中态由描边 + 浅底 + 圆点三件一起表达(只靠颜色会看不出可点)。
|
|
146
|
-
真实 input 只保留可访问性与键盘(同 name 成组 ⇒ 方向键即换选),视觉全在卡片上。
|
|
147
|
-
卡片宽度取 flex 基准 240、上限 360:窄容器自动一列,宽容器两列并排且不无限拉伸。
|
|
148
|
-
圆点配方与面一同源(16px 框体 + 3px 上边距对齐 22px 行高的首行),色档亦同(主色 / 主色内容)。 */
|
|
149
|
-
|
|
150
|
-
.mh-radio-card {
|
|
151
|
-
display: flex;
|
|
152
|
-
flex-wrap: wrap;
|
|
153
|
-
gap: var(--ui-space-3);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.mh-radio-card__item {
|
|
157
|
-
position: relative;
|
|
158
|
-
flex: 1 1 240px;
|
|
159
|
-
max-width: 360px;
|
|
160
|
-
box-sizing: border-box;
|
|
161
|
-
display: flex;
|
|
162
|
-
align-items: flex-start;
|
|
163
|
-
gap: var(--ui-space-2);
|
|
164
|
-
padding: var(--ui-space-3) var(--ui-space-4);
|
|
165
|
-
border: 1px solid var(--ui-base-300);
|
|
166
|
-
border-radius: var(--ui-radius-md);
|
|
167
|
-
background: var(--ui-base-100);
|
|
168
|
-
cursor: pointer;
|
|
169
|
-
transition: border-color 0.15s, background-color 0.15s;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.mh-radio-card__item:hover {
|
|
173
|
-
border-color: var(--ui-primary);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.mh-radio-card__item[data-state='checked'] {
|
|
177
|
-
border-color: var(--ui-primary);
|
|
178
|
-
background: var(--ui-primary-subtle);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.mh-radio-card__item:focus-within {
|
|
182
|
-
outline: 2px solid var(--ui-primary-weak);
|
|
183
|
-
outline-offset: 1px;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.mh-radio-card__item[data-disabled='true'] {
|
|
187
|
-
cursor: not-allowed;
|
|
188
|
-
border-color: var(--ui-base-300);
|
|
189
|
-
background: var(--ui-base-200);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.mh-radio-card__item[data-disabled='true']:hover {
|
|
193
|
-
border-color: var(--ui-base-300);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/* 原生 radio:视觉由卡片承担(隐藏方式与 Checkbox 同款) */
|
|
197
|
-
|
|
198
|
-
.mh-radio-card__input {
|
|
199
|
-
position: absolute;
|
|
200
|
-
width: 1px;
|
|
201
|
-
height: 1px;
|
|
202
|
-
margin: 0;
|
|
203
|
-
padding: 0;
|
|
204
|
-
opacity: 0;
|
|
205
|
-
pointer-events: none;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.mh-radio-card__radio {
|
|
209
|
-
position: relative;
|
|
210
|
-
flex: 0 0 auto;
|
|
211
|
-
width: 16px;
|
|
212
|
-
height: 16px;
|
|
213
|
-
box-sizing: border-box;
|
|
214
|
-
/* 与标题首行(14px 字 / 22px 行高)视觉居中 */
|
|
215
|
-
margin-top: 3px;
|
|
216
|
-
border: 1px solid var(--ui-base-400);
|
|
217
|
-
border-radius: var(--ui-radius-full);
|
|
218
|
-
background: var(--ui-base-100);
|
|
219
|
-
transition: background-color 0.15s, border-color 0.15s;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.mh-radio-card__item[data-state='checked'] .mh-radio-card__radio {
|
|
223
|
-
border-color: var(--ui-primary);
|
|
224
|
-
background: var(--ui-primary);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.mh-radio-card__item[data-state='checked'] .mh-radio-card__radio::after {
|
|
228
|
-
content: '';
|
|
229
|
-
position: absolute;
|
|
230
|
-
inset: 0;
|
|
231
|
-
margin: auto;
|
|
232
|
-
width: 6px;
|
|
233
|
-
height: 6px;
|
|
234
|
-
border-radius: var(--ui-radius-full);
|
|
235
|
-
background: var(--ui-primary-content);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__radio {
|
|
239
|
-
border-color: var(--ui-base-400);
|
|
240
|
-
background: var(--ui-base-200);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.mh-radio-card__body {
|
|
244
|
-
display: flex;
|
|
245
|
-
flex-direction: column;
|
|
246
|
-
gap: 2px;
|
|
247
|
-
min-width: 0;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.mh-radio-card__label {
|
|
251
|
-
font-size: var(--ui-font-body);
|
|
252
|
-
font-weight: var(--ui-weight-medium);
|
|
253
|
-
color: var(--ui-base-content);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.mh-radio-card__desc {
|
|
257
|
-
font-size: var(--ui-font-caption);
|
|
258
|
-
line-height: var(--ui-line-caption);
|
|
259
|
-
color: var(--ui-base-content-subtle);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__label,
|
|
263
|
-
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__desc {
|
|
264
|
-
color: var(--ui-base-content-subtle);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/* ===== 网格档(`columns > 1`):等宽网格,列数由组件下发 ===== */
|
|
268
|
-
.mh-radio-card--grid {
|
|
269
|
-
display: grid;
|
|
270
|
-
grid-template-columns: repeat(var(--ui-radio-card-columns), minmax(0, 1fr));
|
|
271
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Radio —— 单选族的面:普通单选组(`Radio.Group`)+ 卡片式单选组(`Radio.Card`),两形态共用一个文件。
|
|
3
|
+
*
|
|
4
|
+
* - `Radio` / `Radio.Group`:一行一个选项 + 组容器,类根 `.mh-radio*`
|
|
5
|
+
* - `Radio.Card`:一个选项一张卡、整卡可点,类根 `.mh-radio-card*`
|
|
6
|
+
*
|
|
7
|
+
* **为什么同面**:两者是**同一个件的两种组形态**,共用同一套状态协议(选中 / 禁用 / 键盘焦点)
|
|
8
|
+
* 与同一套「框体 + 圆点」几何,差别只在承载形态;拆成两份必然让同一族的选中 / 禁用语义各自漂。
|
|
9
|
+
* 合一后圆点配方只有一处(面二自绘,与面一的框体同色同档),且 `radio.css` 与
|
|
10
|
+
* `components/radio/` 仍是标准的「一组件一面」(护栏 `contract-class-surface.spec.ts`)。
|
|
11
|
+
*
|
|
12
|
+
* ===== 面一:`Radio`(普通单选组)=====
|
|
13
|
+
*
|
|
14
|
+
* 出处:`@aihub/theme` 的 `playground/components/radio.css` 与其令牌 `src/components/checkbox.css`
|
|
15
|
+
* (框体实测、单选为胶囊、未选边框 Ne04、滑过 Th05、选中主色圆点、禁用 Ne05 + Te07、选项间距 16 / 10)。
|
|
16
|
+
*
|
|
17
|
+
* **与 `Radio.Card` 的判据**:选项只有一行文字(或极短说明)→ 面一;
|
|
18
|
+
* 选项需要标题 + 描述 + 整卡可点(卡片式选择)→ 面二。
|
|
19
|
+
* **与 `Capsule` 的判据**:要「按钮形态的分组」→ `Capsule`(本面不实现按钮档,避免两套平铺控件)。
|
|
20
|
+
*
|
|
21
|
+
* **与复选框同族**:圆点由 `border` 从 1px 补间到圆点档画成(盒定尺,无布局位移),
|
|
22
|
+
* 不走字形 mask —— 这是规范的做法(勾/横杠才需要 mask)。
|
|
23
|
+
*
|
|
24
|
+
* **尺寸三档只覆盖令牌**(`--ui-radio-size*` / `--ui-radio-dot*`),几何规则只有一份。
|
|
25
|
+
*
|
|
26
|
+
* **状态三源等价**(本仓通例):原生 `input:checked` / 组件下发 `[data-state]` / 静态档 `.is-*`
|
|
27
|
+
* 指向同一份声明,不写第二份面。
|
|
28
|
+
*
|
|
29
|
+
* 边界(有意不做):规范 `radio.css` 里的 `.cell-check`(表格选择列)**不在这里实现** ——
|
|
30
|
+
* 表格选择列归表格族,本面不重复实现(否则会出现两套表格选择列外观)。
|
|
31
|
+
*/
|
|
32
|
+
.mh-radio {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: var(--ui-radio-label-gap);
|
|
36
|
+
font-size: var(--ui-font-body);
|
|
37
|
+
line-height: var(--ui-line-body);
|
|
38
|
+
color: var(--ui-base-content);
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
user-select: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* 组容器:横向 16 / 纵向 12 */
|
|
44
|
+
.mh-radio-group {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-wrap: wrap;
|
|
47
|
+
gap: var(--ui-space-4);
|
|
48
|
+
}
|
|
49
|
+
.mh-radio-group--vertical {
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: var(--ui-space-3);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* 隐身开关:真实 radio 负责可访问性与键盘,可见框体自绘(同 Checkbox 配方) */
|
|
55
|
+
.mh-radio__input {
|
|
56
|
+
position: absolute;
|
|
57
|
+
width: 1px;
|
|
58
|
+
height: 1px;
|
|
59
|
+
margin: -1px;
|
|
60
|
+
padding: 0;
|
|
61
|
+
border: 0;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
clip-path: inset(50%);
|
|
65
|
+
appearance: none;
|
|
66
|
+
pointer-events: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* 框体 */
|
|
70
|
+
.mh-radio__box {
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: center;
|
|
74
|
+
flex: none;
|
|
75
|
+
width: var(--ui-radio-size);
|
|
76
|
+
height: var(--ui-radio-size);
|
|
77
|
+
border: 1px solid var(--ui-base-400); /* Ne04 未选默认 */
|
|
78
|
+
border-radius: var(--ui-radius-full); /* 单选为胶囊 */
|
|
79
|
+
background: var(--ui-base-100);
|
|
80
|
+
transition-property: border-width, border-color, background-color;
|
|
81
|
+
transition-duration: 0.15s;
|
|
82
|
+
transition-timing-function: ease;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* ===== 尺寸档(只覆盖令牌) ===== */
|
|
86
|
+
.mh-radio--sm {
|
|
87
|
+
--ui-radio-size: var(--ui-radio-size-sm);
|
|
88
|
+
--ui-radio-dot: var(--ui-radio-dot-sm);
|
|
89
|
+
font-size: var(--ui-font-caption);
|
|
90
|
+
}
|
|
91
|
+
.mh-radio--lg {
|
|
92
|
+
--ui-radio-size: var(--ui-radio-size-lg);
|
|
93
|
+
--ui-radio-dot: var(--ui-radio-dot-lg);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* 禁用整行:不可点(原生 disabled 与静态档同款) */
|
|
97
|
+
.mh-radio.is-disabled,
|
|
98
|
+
.mh-radio:has(> .mh-radio__input:disabled) {
|
|
99
|
+
cursor: not-allowed;
|
|
100
|
+
color: var(--ui-base-content-subtle);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* 滑过:未选边框转主色滑过档(Th05) */
|
|
104
|
+
.mh-radio.is-hover .mh-radio__box,
|
|
105
|
+
.mh-radio:hover > .mh-radio__box {
|
|
106
|
+
border-color: var(--ui-primary-hover);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* 选中:圆点(主色,随选择控件色);三源等价 */
|
|
110
|
+
.mh-radio.is-checked .mh-radio__box,
|
|
111
|
+
.mh-radio__box[data-state='checked'],
|
|
112
|
+
.mh-radio > .mh-radio__input:checked + .mh-radio__box {
|
|
113
|
+
border: var(--ui-radio-dot) solid var(--ui-primary);
|
|
114
|
+
}
|
|
115
|
+
/* 选中后滑过不再改边色(已经是满色圆点,改色只会闪) */
|
|
116
|
+
.mh-radio.is-checked:hover > .mh-radio__box,
|
|
117
|
+
.mh-radio > .mh-radio__input:checked:hover + .mh-radio__box {
|
|
118
|
+
border-color: var(--ui-primary);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* 禁用边框(Ne05) */
|
|
122
|
+
.mh-radio.is-disabled .mh-radio__box,
|
|
123
|
+
.mh-radio > .mh-radio__input:disabled + .mh-radio__box {
|
|
124
|
+
border-color: var(--ui-base-300);
|
|
125
|
+
background: var(--ui-base-200);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* 禁用且选中:圆点转 Te07 */
|
|
129
|
+
.mh-radio.is-disabled.is-checked .mh-radio__box,
|
|
130
|
+
.mh-radio > .mh-radio__input:disabled:checked + .mh-radio__box {
|
|
131
|
+
border-color: var(--ui-base-content-subtle);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* 键盘焦点环画在可见框体上(隐身开关没有可见焦点) */
|
|
135
|
+
.mh-radio > .mh-radio__input:focus-visible + .mh-radio__box {
|
|
136
|
+
outline: 2px solid var(--ui-primary-weak);
|
|
137
|
+
outline-offset: 2px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.mh-radio__label {
|
|
141
|
+
min-width: 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* ===== 面二:`Radio.Card`(卡片式单选组,自建)=====
|
|
145
|
+
一个选项一张卡、整卡可点;选中态由描边 + 浅底 + 圆点三件一起表达(只靠颜色会看不出可点)。
|
|
146
|
+
真实 input 只保留可访问性与键盘(同 name 成组 ⇒ 方向键即换选),视觉全在卡片上。
|
|
147
|
+
卡片宽度取 flex 基准 240、上限 360:窄容器自动一列,宽容器两列并排且不无限拉伸。
|
|
148
|
+
圆点配方与面一同源(16px 框体 + 3px 上边距对齐 22px 行高的首行),色档亦同(主色 / 主色内容)。 */
|
|
149
|
+
|
|
150
|
+
.mh-radio-card {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-wrap: wrap;
|
|
153
|
+
gap: var(--ui-space-3);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.mh-radio-card__item {
|
|
157
|
+
position: relative;
|
|
158
|
+
flex: 1 1 240px;
|
|
159
|
+
max-width: 360px;
|
|
160
|
+
box-sizing: border-box;
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: flex-start;
|
|
163
|
+
gap: var(--ui-space-2);
|
|
164
|
+
padding: var(--ui-space-3) var(--ui-space-4);
|
|
165
|
+
border: 1px solid var(--ui-base-300);
|
|
166
|
+
border-radius: var(--ui-radius-md);
|
|
167
|
+
background: var(--ui-base-100);
|
|
168
|
+
cursor: pointer;
|
|
169
|
+
transition: border-color 0.15s, background-color 0.15s;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.mh-radio-card__item:hover {
|
|
173
|
+
border-color: var(--ui-primary);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.mh-radio-card__item[data-state='checked'] {
|
|
177
|
+
border-color: var(--ui-primary);
|
|
178
|
+
background: var(--ui-primary-subtle);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.mh-radio-card__item:focus-within {
|
|
182
|
+
outline: 2px solid var(--ui-primary-weak);
|
|
183
|
+
outline-offset: 1px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.mh-radio-card__item[data-disabled='true'] {
|
|
187
|
+
cursor: not-allowed;
|
|
188
|
+
border-color: var(--ui-base-300);
|
|
189
|
+
background: var(--ui-base-200);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.mh-radio-card__item[data-disabled='true']:hover {
|
|
193
|
+
border-color: var(--ui-base-300);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* 原生 radio:视觉由卡片承担(隐藏方式与 Checkbox 同款) */
|
|
197
|
+
|
|
198
|
+
.mh-radio-card__input {
|
|
199
|
+
position: absolute;
|
|
200
|
+
width: 1px;
|
|
201
|
+
height: 1px;
|
|
202
|
+
margin: 0;
|
|
203
|
+
padding: 0;
|
|
204
|
+
opacity: 0;
|
|
205
|
+
pointer-events: none;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.mh-radio-card__radio {
|
|
209
|
+
position: relative;
|
|
210
|
+
flex: 0 0 auto;
|
|
211
|
+
width: 16px;
|
|
212
|
+
height: 16px;
|
|
213
|
+
box-sizing: border-box;
|
|
214
|
+
/* 与标题首行(14px 字 / 22px 行高)视觉居中 */
|
|
215
|
+
margin-top: 3px;
|
|
216
|
+
border: 1px solid var(--ui-base-400);
|
|
217
|
+
border-radius: var(--ui-radius-full);
|
|
218
|
+
background: var(--ui-base-100);
|
|
219
|
+
transition: background-color 0.15s, border-color 0.15s;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.mh-radio-card__item[data-state='checked'] .mh-radio-card__radio {
|
|
223
|
+
border-color: var(--ui-primary);
|
|
224
|
+
background: var(--ui-primary);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.mh-radio-card__item[data-state='checked'] .mh-radio-card__radio::after {
|
|
228
|
+
content: '';
|
|
229
|
+
position: absolute;
|
|
230
|
+
inset: 0;
|
|
231
|
+
margin: auto;
|
|
232
|
+
width: 6px;
|
|
233
|
+
height: 6px;
|
|
234
|
+
border-radius: var(--ui-radius-full);
|
|
235
|
+
background: var(--ui-primary-content);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__radio {
|
|
239
|
+
border-color: var(--ui-base-400);
|
|
240
|
+
background: var(--ui-base-200);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.mh-radio-card__body {
|
|
244
|
+
display: flex;
|
|
245
|
+
flex-direction: column;
|
|
246
|
+
gap: 2px;
|
|
247
|
+
min-width: 0;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.mh-radio-card__label {
|
|
251
|
+
font-size: var(--ui-font-body);
|
|
252
|
+
font-weight: var(--ui-weight-medium);
|
|
253
|
+
color: var(--ui-base-content);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.mh-radio-card__desc {
|
|
257
|
+
font-size: var(--ui-font-caption);
|
|
258
|
+
line-height: var(--ui-line-caption);
|
|
259
|
+
color: var(--ui-base-content-subtle);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__label,
|
|
263
|
+
.mh-radio-card__item[data-disabled='true'] .mh-radio-card__desc {
|
|
264
|
+
color: var(--ui-base-content-subtle);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* ===== 网格档(`columns > 1`):等宽网格,列数由组件下发 ===== */
|
|
268
|
+
.mh-radio-card--grid {
|
|
269
|
+
display: grid;
|
|
270
|
+
grid-template-columns: repeat(var(--ui-radio-card-columns), minmax(0, 1fr));
|
|
271
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* radio —— 单件令牌(**基础值**)。
|
|
3
|
-
*
|
|
4
|
-
* 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
|
|
5
|
-
*
|
|
6
|
-
* ## 抽出说明
|
|
7
|
-
* 本文件从面文件里抽出(原先混写在 `radio.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-radio-size: 16px;
|
|
19
|
-
--ui-radio-size-sm: 14px;
|
|
20
|
-
--ui-radio-size-lg: 20px;
|
|
21
|
-
--ui-radio-dot: 5px; /* 选中圆点(border-width 档:盒定尺、无位移) */
|
|
22
|
-
--ui-radio-dot-sm: 4px;
|
|
23
|
-
--ui-radio-dot-lg: 6px;
|
|
24
|
-
--ui-radio-label-gap: var(--ui-space-2); /* 框体与文字间距 8 */
|
|
25
|
-
--ui-radio-card-columns: 1;
|
|
26
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* radio —— 单件令牌(**基础值**)。
|
|
3
|
+
*
|
|
4
|
+
* 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
|
|
5
|
+
*
|
|
6
|
+
* ## 抽出说明
|
|
7
|
+
* 本文件从面文件里抽出(原先混写在 `radio.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-radio-size: 16px;
|
|
19
|
+
--ui-radio-size-sm: 14px;
|
|
20
|
+
--ui-radio-size-lg: 20px;
|
|
21
|
+
--ui-radio-dot: 5px; /* 选中圆点(border-width 档:盒定尺、无位移) */
|
|
22
|
+
--ui-radio-dot-sm: 4px;
|
|
23
|
+
--ui-radio-dot-lg: 6px;
|
|
24
|
+
--ui-radio-label-gap: var(--ui-space-2); /* 框体与文字间距 8 */
|
|
25
|
+
--ui-radio-card-columns: 1;
|
|
26
|
+
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search —— 搜索框(输入框 + 可选搜索按钮的**组合件面**)。
|
|
3
|
-
*
|
|
4
|
-
* 本面**只声明「一行里怎么摆」**:输入框那一段的面归 `input.css`(框 / 内距 / 清除位 /
|
|
5
|
-
* 聚焦态 / 禁用态全套复用),搜索按钮的面归 `button.css`。本件因此没有自己的几何令牌,
|
|
6
|
-
* 也不重画任何控件的框 —— 两份输入框几何必然在改令牌时漂开。
|
|
7
|
-
*
|
|
8
|
-
* 两条摆法:
|
|
9
|
-
* - 输入框 `flex: 1 1 auto` + `min-width: 0`:输入框自带 `width: 100%`,在 flex 行里
|
|
10
|
-
* 必须允许收缩,否则会把同行的搜索按钮挤出容器(窄栏里尤其明显);
|
|
11
|
-
* - 搜索按钮 `flex: none`:它永远是「那么大」,宽度让给输入框。
|
|
12
|
-
*
|
|
13
|
-
* **按钮是可选的**:不传 `searchText` 时本件只渲染输入框(框内的放大镜已占住「搜索」语义,
|
|
14
|
-
* 再出一个同字形的图标按钮就是同一个意思画两遍)。此时 `__btn` 那条摆法规则无对象,
|
|
15
|
-
* 输入框自然占满整行——摆法不用改,缺了按钮也不留空档。
|
|
16
|
-
*
|
|
17
|
-
* **类名与面文件名同根**:`.mh-search*`,一律 `mh-` 前缀。
|
|
18
|
-
*/
|
|
19
|
-
.mh-search {
|
|
20
|
-
display: flex;
|
|
21
|
-
align-items: center;
|
|
22
|
-
gap: var(--ui-space-2);
|
|
23
|
-
width: 100%;
|
|
24
|
-
min-width: 0;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.mh-search__input {
|
|
28
|
-
flex: 1 1 auto;
|
|
29
|
-
min-width: 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.mh-search__btn {
|
|
33
|
-
flex: none;
|
|
34
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Search —— 搜索框(输入框 + 可选搜索按钮的**组合件面**)。
|
|
3
|
+
*
|
|
4
|
+
* 本面**只声明「一行里怎么摆」**:输入框那一段的面归 `input.css`(框 / 内距 / 清除位 /
|
|
5
|
+
* 聚焦态 / 禁用态全套复用),搜索按钮的面归 `button.css`。本件因此没有自己的几何令牌,
|
|
6
|
+
* 也不重画任何控件的框 —— 两份输入框几何必然在改令牌时漂开。
|
|
7
|
+
*
|
|
8
|
+
* 两条摆法:
|
|
9
|
+
* - 输入框 `flex: 1 1 auto` + `min-width: 0`:输入框自带 `width: 100%`,在 flex 行里
|
|
10
|
+
* 必须允许收缩,否则会把同行的搜索按钮挤出容器(窄栏里尤其明显);
|
|
11
|
+
* - 搜索按钮 `flex: none`:它永远是「那么大」,宽度让给输入框。
|
|
12
|
+
*
|
|
13
|
+
* **按钮是可选的**:不传 `searchText` 时本件只渲染输入框(框内的放大镜已占住「搜索」语义,
|
|
14
|
+
* 再出一个同字形的图标按钮就是同一个意思画两遍)。此时 `__btn` 那条摆法规则无对象,
|
|
15
|
+
* 输入框自然占满整行——摆法不用改,缺了按钮也不留空档。
|
|
16
|
+
*
|
|
17
|
+
* **类名与面文件名同根**:`.mh-search*`,一律 `mh-` 前缀。
|
|
18
|
+
*/
|
|
19
|
+
.mh-search {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: var(--ui-space-2);
|
|
23
|
+
width: 100%;
|
|
24
|
+
min-width: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.mh-search__input {
|
|
28
|
+
flex: 1 1 auto;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.mh-search__btn {
|
|
33
|
+
flex: none;
|
|
34
|
+
}
|