@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.
- package/README.md +141 -0
- package/dist/components/avatar/index.d.ts +283 -0
- package/dist/components/avatar/index.js +167 -0
- package/dist/components/badge/index.d.ts +132 -0
- package/dist/components/badge/index.js +99 -0
- package/dist/components/button/index.d.ts +578 -0
- package/dist/components/button/index.js +191 -0
- package/dist/components/capsule/index.d.ts +161 -0
- package/dist/components/capsule/index.js +101 -0
- package/dist/components/card/index.d.ts +456 -0
- package/dist/components/card/index.js +231 -0
- package/dist/components/checkbox/index.d.ts +331 -0
- package/dist/components/checkbox/index.js +165 -0
- package/dist/components/code/index.d.ts +134 -0
- package/dist/components/code/index.js +117 -0
- package/dist/components/code-editor/index.d.ts +163 -0
- package/dist/components/code-editor/index.js +98 -0
- package/dist/components/collapse/index.d.ts +125 -0
- package/dist/components/collapse/index.js +95 -0
- package/dist/components/control-size.d.ts +8 -0
- package/dist/components/dialog/index.d.ts +224 -0
- package/dist/components/dialog/index.js +194 -0
- package/dist/components/divider/index.d.ts +64 -0
- package/dist/components/divider/index.js +62 -0
- package/dist/components/drawer/index.d.ts +226 -0
- package/dist/components/drawer/index.js +190 -0
- package/dist/components/filter/index.d.ts +391 -0
- package/dist/components/filter/index.js +203 -0
- package/dist/components/form/index.d.ts +704 -0
- package/dist/components/form/index.js +329 -0
- package/dist/components/input/index.d.ts +980 -0
- package/dist/components/input/index.js +334 -0
- package/dist/components/layout/index.d.ts +162 -0
- package/dist/components/layout/index.js +100 -0
- package/dist/components/list-view/index.d.ts +563 -0
- package/dist/components/list-view/index.js +221 -0
- package/dist/components/loading/index.d.ts +77 -0
- package/dist/components/loading/index.js +40 -0
- package/dist/components/nav/index.d.ts +293 -0
- package/dist/components/nav/index.js +164 -0
- package/dist/components/notice/index.d.ts +137 -0
- package/dist/components/notice/index.js +101 -0
- package/dist/components/notification/index.d.ts +118 -0
- package/dist/components/notification/index.js +99 -0
- package/dist/components/page/index.d.ts +276 -0
- package/dist/components/page/index.js +351 -0
- package/dist/components/page/split-resize.d.ts +42 -0
- package/dist/components/page/split-resize.js +36 -0
- package/dist/components/pagination/index.d.ts +171 -0
- package/dist/components/pagination/index.js +226 -0
- package/dist/components/panel/index.d.ts +401 -0
- package/dist/components/panel/index.js +193 -0
- package/dist/components/part-padding.d.ts +27 -0
- package/dist/components/part-padding.js +23 -0
- package/dist/components/query-state/index.d.ts +207 -0
- package/dist/components/query-state/index.js +181 -0
- package/dist/components/radio/index.d.ts +473 -0
- package/dist/components/radio/index.js +250 -0
- package/dist/components/search/index.d.ts +167 -0
- package/dist/components/search/index.js +105 -0
- package/dist/components/select/index.d.ts +252 -0
- package/dist/components/select/index.js +281 -0
- package/dist/components/skeleton/index.d.ts +88 -0
- package/dist/components/skeleton/index.js +56 -0
- package/dist/components/steps/index.d.ts +199 -0
- package/dist/components/steps/index.js +117 -0
- package/dist/components/switch/index.d.ts +150 -0
- package/dist/components/switch/index.js +103 -0
- package/dist/components/table/index.d.ts +351 -0
- package/dist/components/table/index.js +286 -0
- package/dist/components/tabs/index.d.ts +179 -0
- package/dist/components/tabs/index.js +153 -0
- package/dist/components/tabset/index.d.ts +105 -0
- package/dist/components/tabset/index.js +68 -0
- package/dist/components/tag/index.d.ts +203 -0
- package/dist/components/tag/index.js +144 -0
- package/dist/components/toast/index.d.ts +271 -0
- package/dist/components/toast/index.js +116 -0
- package/dist/components/tooltip/index.d.ts +126 -0
- package/dist/components/tooltip/index.js +97 -0
- package/dist/components/tree/index.d.ts +317 -0
- package/dist/components/tree/index.js +251 -0
- package/dist/components/upload/index.d.ts +384 -0
- package/dist/components/upload/index.js +172 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +102 -0
- package/dist/services/base.d.ts +21 -0
- package/dist/services/base.js +42 -0
- package/dist/services/dialog.d.ts +41 -0
- package/dist/services/dialog.js +83 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/loading.d.ts +21 -0
- package/dist/services/loading.js +41 -0
- package/dist/services/toast.d.ts +40 -0
- package/dist/services/toast.js +74 -0
- package/dist/styles/components/avatar.css +128 -0
- package/dist/styles/components/avatar.tokens.css +24 -0
- package/dist/styles/components/badge.css +237 -0
- package/dist/styles/components/button.css +454 -0
- package/dist/styles/components/button.tokens.css +56 -0
- package/dist/styles/components/capsule.css +120 -0
- package/dist/styles/components/capsule.tokens.css +27 -0
- package/dist/styles/components/card.css +192 -0
- package/dist/styles/components/checkbox.css +145 -0
- package/dist/styles/components/checkbox.tokens.css +26 -0
- package/dist/styles/components/code-editor.css +91 -0
- package/dist/styles/components/code-editor.tokens.css +24 -0
- package/dist/styles/components/code.css +153 -0
- package/dist/styles/components/code.tokens.css +29 -0
- package/dist/styles/components/collapse.css +62 -0
- package/dist/styles/components/collapse.tokens.css +20 -0
- package/dist/styles/components/dialog.css +106 -0
- package/dist/styles/components/dialog.tokens.css +24 -0
- package/dist/styles/components/divider.css +71 -0
- package/dist/styles/components/divider.tokens.css +21 -0
- package/dist/styles/components/drawer.css +143 -0
- package/dist/styles/components/drawer.tokens.css +22 -0
- package/dist/styles/components/filter.css +41 -0
- package/dist/styles/components/filter.tokens.css +14 -0
- package/dist/styles/components/form.css +220 -0
- package/dist/styles/components/form.tokens.css +15 -0
- package/dist/styles/components/input.css +445 -0
- package/dist/styles/components/input.tokens.css +41 -0
- package/dist/styles/components/layout.css +198 -0
- package/dist/styles/components/list-view.css +244 -0
- package/dist/styles/components/loading.css +76 -0
- package/dist/styles/components/loading.tokens.css +23 -0
- package/dist/styles/components/nav.css +48 -0
- package/dist/styles/components/notice.css +153 -0
- package/dist/styles/components/notice.tokens.css +17 -0
- package/dist/styles/components/notification.css +159 -0
- package/dist/styles/components/notification.tokens.css +37 -0
- package/dist/styles/components/page.css +473 -0
- package/dist/styles/components/pagination.css +297 -0
- package/dist/styles/components/pagination.tokens.css +32 -0
- package/dist/styles/components/panel.css +77 -0
- package/dist/styles/components/query-state.css +88 -0
- package/dist/styles/components/radio.css +271 -0
- package/dist/styles/components/radio.tokens.css +26 -0
- package/dist/styles/components/search.css +30 -0
- package/dist/styles/components/select.css +242 -0
- package/dist/styles/components/select.tokens.css +33 -0
- package/dist/styles/components/skeleton.css +60 -0
- package/dist/styles/components/skeleton.tokens.css +27 -0
- package/dist/styles/components/steps.css +157 -0
- package/dist/styles/components/steps.tokens.css +42 -0
- package/dist/styles/components/switch.css +165 -0
- package/dist/styles/components/switch.tokens.css +26 -0
- package/dist/styles/components/table.css +439 -0
- package/dist/styles/components/table.tokens.css +41 -0
- package/dist/styles/components/tabs.css +234 -0
- package/dist/styles/components/tabs.tokens.css +30 -0
- package/dist/styles/components/tag.css +200 -0
- package/dist/styles/components/tag.tokens.css +30 -0
- package/dist/styles/components/toast.css +150 -0
- package/dist/styles/components/toast.tokens.css +26 -0
- package/dist/styles/components/tooltip.css +89 -0
- package/dist/styles/components/tooltip.tokens.css +25 -0
- package/dist/styles/components/tree.css +139 -0
- package/dist/styles/components/tree.tokens.css +20 -0
- package/dist/styles/components/upload.css +150 -0
- package/dist/styles/components/upload.tokens.css +27 -0
- package/dist/styles/index.css +149 -0
- package/dist/styles/operations/collapse.css +84 -0
- package/dist/styles/operations/popup.css +189 -0
- package/dist/styles/operations/tabset.css +57 -0
- package/dist/utils/state-illustration.d.ts +31 -0
- package/dist/utils/state-illustration.js +156 -0
- package/package.json +62 -0
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
* **类名与面文件名同根**:`.mh-search*`,一律 `mh-` 前缀。
|
|
14
|
+
*/
|
|
15
|
+
.mh-search {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: var(--ui-space-2);
|
|
19
|
+
width: 100%;
|
|
20
|
+
min-width: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.mh-search__input {
|
|
24
|
+
flex: 1 1 auto;
|
|
25
|
+
min-width: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.mh-search__btn {
|
|
29
|
+
flex: none;
|
|
30
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Select —— 选择器族(单选触发器 + 多选标签 + 选项面板 + 搜索行 + 日期格)。
|
|
3
|
+
*
|
|
4
|
+
* 出处:`@aihub/theme` 的 `playground/components/select.css` 与 `src/components/select.css`
|
|
5
|
+
* (触发器同输入框、选项行高 30、内距 8;面板内距 4 + 选项 30;多选标签复用标签族形态;
|
|
6
|
+
* 日期格 26 方形,选中主色实底、区间 Ne10)。
|
|
7
|
+
*
|
|
8
|
+
* **触发器的框不在本件**:触发器 = 输入框的「触发器形态」(TSX 里是 `<Input as="button">`),
|
|
9
|
+
* 框 / 内距 / 边 / 圆角 / 底 / 字 / hover / 聚焦 / 禁用 / 校验色与**清除位**、**右侧图标位**
|
|
10
|
+
* 全部归输入面与它的表壳(`.mh-input` + `.mh-input__wrap`)。本件只给选择器自己的排版
|
|
11
|
+
* (`display` / `gap` / `width` / `text-align` / `overflow` 与值 / 标签),另通过挂在**表壳**上的
|
|
12
|
+
* `.mh-select-host` 微调两处壳内节奏(间距回到 4px、箭头收敛回 12px)。
|
|
13
|
+
* **禁写:本件不得再画框**(画了就又开一份会与输入面漂移的规格 —— 这正是本次收敛掉的东西)。
|
|
14
|
+
*
|
|
15
|
+
* **面板开合与定位不在本件**:面板是操作层的组合 —— 消费方/组件在面板根并列挂
|
|
16
|
+
* `class="mh-popup mh-select__panel mh-popup--anchored"`(`data-side` / `data-align` 定位档、
|
|
17
|
+
* Esc、点外部关闭、顶层渲染全在 `styles/operations/popup.css`)。本件只给**面**
|
|
18
|
+
* (底 / 圆角 / 内距 / 阴影 / 选项行)。
|
|
19
|
+
*
|
|
20
|
+
* **面板宽度跟触发器走**:规范把触发器与面板都钉在 300px,本仓触发器是**流式宽度**
|
|
21
|
+
* (与 input 同一结论),故面板用 `anchor-size(width)` 取锚点宽。触发器进表壳后,
|
|
22
|
+
* `popovertarget` 的**隐式锚**只有壳内那个控件那么宽,故这里走**显式锚档**:
|
|
23
|
+
* 表壳挂 `.mh-popup-anchor`(`anchor-name`)、面板挂 `.mh-popup--anchored`(`position-anchor`),
|
|
24
|
+
* 锚点即整件;非锚定场景回落到 240px 兜底值。
|
|
25
|
+
*
|
|
26
|
+
* **一处有色差异**:规范的选中行是灰底(Ne10),本仓的「选中」统一走**主色浅底**
|
|
27
|
+
* `--ui-primary-subtle`(与列表 / 树的选中态同一语义槽位),否则悬停(Ne11)与选中(Ne10)两档灰
|
|
28
|
+
* 在本仓有限的灰阶里挤成同色、看不出选中。
|
|
29
|
+
*
|
|
30
|
+
* 选项选中态**三源等价**:原生 `:has(input:checked)`(零 JS 单选路径)/ 组件下发
|
|
31
|
+
* `[data-state='selected']` / 静态档 `.is-selected`。
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/* ===== 触发器:只留选择器自己的排版(框与状态全归输入面) ===== */
|
|
35
|
+
.mh-select {
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: var(--ui-space-1);
|
|
39
|
+
width: 100%;
|
|
40
|
+
text-align: left;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* 表壳上的本件修饰(TSX 把 `mh-select-host` 挂在**表壳**上:`class` 落壳是输入面的既有契约)。 */
|
|
46
|
+
/* ① 壳内间距:输入框的附加位节奏是 8px,选择器自己的是 4px(值 / 标签与清除位、箭头之间) */
|
|
47
|
+
.mh-select-host {
|
|
48
|
+
gap: var(--ui-space-1);
|
|
49
|
+
}
|
|
50
|
+
/* ② 箭头尺寸:`.mh-input__suffix > svg`(0-1-1)会把槽内图标统一成 16px,而本件箭头是 12px
|
|
51
|
+
—— 这里以 0-2-0 收敛回来。注意不能在 select.css 里直写 `.mh-input__suffix`:
|
|
52
|
+
面文件的类名必须与文件词根同根(机械护栏),故走自己的壳修饰类。 */
|
|
53
|
+
.mh-select-host .mh-select__caret {
|
|
54
|
+
width: var(--ui-select-icon-size);
|
|
55
|
+
height: var(--ui-select-icon-size);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* ===== 尺寸档:框的尺寸归输入面,本类只承载选择器自有部位的对档微调 ===== */
|
|
59
|
+
/* 框高 / 字号由 `<Input size>` 下发的 `mh-input--sm` / `--lg` 承担(含表壳的换高)。
|
|
60
|
+
两处口径要认(都是输入面既有事实,不是本件选择):
|
|
61
|
+
① **左右内距不随档位变**:带壳时内距归表壳(`--ui-input-padding-x` = 12px 恒定),
|
|
62
|
+
`--ui-input-padding-x-sm/-lg` 只对**裸控件**生效 —— 输入框自己的 sm / lg 实测也是 12px;
|
|
63
|
+
② `mh-select--*` 只跟「选择器自己的东西」有关 —— 当前只有标签:小号控件 24px 高,
|
|
64
|
+
24px 的标签会顶满整件、失去呼吸位,故收 4px。 */
|
|
65
|
+
.mh-select--sm .mh-select__chip {
|
|
66
|
+
height: calc(var(--ui-select-chip-height) - 4px);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* 无选中值时的提示文字(组件把 placeholder 渲染进 `__value` 并挂这个修饰类) */
|
|
70
|
+
.mh-select__value {
|
|
71
|
+
flex: 1;
|
|
72
|
+
min-width: 0;
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
text-overflow: ellipsis;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
}
|
|
77
|
+
.mh-select__value--placeholder {
|
|
78
|
+
color: var(--ui-base-content-subtle);
|
|
79
|
+
}
|
|
80
|
+
/* 下拉箭头:渲染在输入面的**右侧图标位**(`.mh-input__suffix`,表壳的子元素)里 ——
|
|
81
|
+
位置由表壳的 flex 排布给(控件 `flex: 1 1 auto` 自然把附加位挤到右端),故不再需要 `margin-left: auto`。
|
|
82
|
+
字形由 @manohub/icon 给;展开转向由 popup.css 的 `.mh-popup-caret` 承担(含触发器进表壳后的兄弟档);
|
|
83
|
+
尺寸的 12px 在下面 `mh-select-host` 一节按特异性收敛(槽内 svg 会被输入面统一成 16px)。 */
|
|
84
|
+
.mh-select__caret {
|
|
85
|
+
flex: none;
|
|
86
|
+
color: var(--ui-base-content-muted); /* Te07 */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ===== 多选:标签 + 收纳(单行不换行,超出由组件算「其他 n 项」) =====
|
|
90
|
+
清除位不在本件:它是输入面的内建件(`.mh-input__clear`,圆点实底 + 反白叉号),
|
|
91
|
+
由 `<Input clearable>` 渲染在**表壳**里 —— 与值 / 标签同一行的右端。 */
|
|
92
|
+
.mh-select--multiple {
|
|
93
|
+
flex-wrap: nowrap;
|
|
94
|
+
}
|
|
95
|
+
.mh-select__chip {
|
|
96
|
+
display: inline-flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
flex: none;
|
|
99
|
+
height: var(--ui-select-chip-height);
|
|
100
|
+
padding: 0 var(--ui-space-2);
|
|
101
|
+
border-radius: var(--ui-radius-full);
|
|
102
|
+
background: var(--ui-base-200); /* Ne11 轻量片底 */
|
|
103
|
+
font-size: var(--ui-select-font-size);
|
|
104
|
+
color: var(--ui-base-content);
|
|
105
|
+
}
|
|
106
|
+
.mh-select__chip--fold {
|
|
107
|
+
background: var(--ui-base-200);
|
|
108
|
+
color: var(--ui-base-content-muted);
|
|
109
|
+
}
|
|
110
|
+
/* ===== 面板皮肤(与操作层并列组合:`class="mh-popup mh-select__panel mh-popup--anchored"`) ===== */
|
|
111
|
+
.mh-select__panel {
|
|
112
|
+
/* 锚 = `.mh-popup-anchor`(挂在表壳上)→ 面板与**整件**同宽;非锚定场景回落 240 */
|
|
113
|
+
width: anchor-size(width, 240px);
|
|
114
|
+
padding: var(--ui-space-1) 0;
|
|
115
|
+
border-radius: var(--ui-select-radius);
|
|
116
|
+
background: var(--ui-base-100);
|
|
117
|
+
/* 锚定浮层的投影走 `--ui-shadow-popover`(**不是** elevated):两枚令牌按「锚定浮层 vs 居中浮层」
|
|
118
|
+
分工,default 主题给前者填的是设计实测值(`0:4025` 的 `0 4px 20px rgba(0,14,51,.10)`),
|
|
119
|
+
farris 主题给的是规范的 `--mh-shadow-lg:14dp 下拉/弹出层` —— 语义与两套来源都对得上。 */
|
|
120
|
+
box-shadow: var(--ui-shadow-popover);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* 选项行:滑过 / 选中 / 禁用 / 提示 / 空态 */
|
|
124
|
+
.mh-select__option {
|
|
125
|
+
position: relative;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
/* **必须显式给宽**:选项是 `<button>`,而按钮的 `width: auto` 解析成「包裹内容宽」
|
|
129
|
+
(表单控件不参与块级拉伸),不给就会缩成文字那么宽 ——
|
|
130
|
+
滑过 / 选中的底色只剩一小条,聚焦环也贴着文字。`.mh-select__add` 同理。 */
|
|
131
|
+
width: 100%;
|
|
132
|
+
height: var(--ui-select-option-height);
|
|
133
|
+
padding: 0 var(--ui-select-padding-x);
|
|
134
|
+
font-size: var(--ui-select-font-size);
|
|
135
|
+
color: var(--ui-base-content);
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
}
|
|
138
|
+
/* 零 JS 单选路径的隐身开关(真实 radio 负责键盘与可访问性,高亮画在行上) */
|
|
139
|
+
.mh-select__option > input {
|
|
140
|
+
position: absolute;
|
|
141
|
+
width: 1px;
|
|
142
|
+
height: 1px;
|
|
143
|
+
margin: -1px;
|
|
144
|
+
padding: 0;
|
|
145
|
+
border: 0;
|
|
146
|
+
overflow: hidden;
|
|
147
|
+
white-space: nowrap;
|
|
148
|
+
clip-path: inset(50%);
|
|
149
|
+
appearance: none;
|
|
150
|
+
pointer-events: none;
|
|
151
|
+
}
|
|
152
|
+
.mh-select__option:hover,
|
|
153
|
+
.mh-select__option.is-hover {
|
|
154
|
+
background: var(--ui-select-option-hover);
|
|
155
|
+
}
|
|
156
|
+
.mh-select__option:has(input:focus-visible) {
|
|
157
|
+
outline: 2px solid var(--ui-primary);
|
|
158
|
+
outline-offset: -2px;
|
|
159
|
+
}
|
|
160
|
+
/* 选中:三源等价(原生 / 组件 / 静态档) */
|
|
161
|
+
.mh-select__option.is-selected,
|
|
162
|
+
.mh-select__option[data-state='selected'],
|
|
163
|
+
.mh-select__option:has(input:checked) {
|
|
164
|
+
background: var(--ui-select-option-selected);
|
|
165
|
+
color: var(--ui-primary);
|
|
166
|
+
}
|
|
167
|
+
.mh-select__option.is-disabled,
|
|
168
|
+
.mh-select__option[data-disabled='true'],
|
|
169
|
+
.mh-select__option:has(input:disabled) {
|
|
170
|
+
color: var(--ui-base-content-subtle);
|
|
171
|
+
cursor: not-allowed;
|
|
172
|
+
}
|
|
173
|
+
.mh-select__option--hint {
|
|
174
|
+
color: var(--ui-base-content-muted);
|
|
175
|
+
}
|
|
176
|
+
.mh-select__option--empty {
|
|
177
|
+
color: var(--ui-base-content-muted);
|
|
178
|
+
}
|
|
179
|
+
/* 「创建 xxx」行:搜索词无命中时出现,语义与选项行一致但用主色标出 */
|
|
180
|
+
.mh-select__add {
|
|
181
|
+
width: 100%;
|
|
182
|
+
border: none;
|
|
183
|
+
background: transparent;
|
|
184
|
+
color: var(--ui-primary);
|
|
185
|
+
font-family: inherit;
|
|
186
|
+
text-align: left;
|
|
187
|
+
}
|
|
188
|
+
.mh-select__add:hover,
|
|
189
|
+
.mh-select__add.is-hover {
|
|
190
|
+
background: var(--ui-select-option-hover);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* ===== 选项分组(组标题不可点,只做分区;组间距靠分隔线给) ===== */
|
|
194
|
+
.mh-select__group + .mh-select__group,
|
|
195
|
+
.mh-select__group + .mh-select__option {
|
|
196
|
+
border-top: 1px solid var(--ui-base-200);
|
|
197
|
+
}
|
|
198
|
+
.mh-select__group-label {
|
|
199
|
+
display: block;
|
|
200
|
+
padding: var(--ui-space-1) var(--ui-select-padding-x);
|
|
201
|
+
font-size: var(--ui-select-font-size);
|
|
202
|
+
color: var(--ui-base-content-muted);
|
|
203
|
+
cursor: default;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* 搜索行(选项多于 8 条时由组件渲染) */
|
|
207
|
+
.mh-select__search {
|
|
208
|
+
padding: var(--ui-space-2) var(--ui-space-2) var(--ui-space-1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* ===== 日期格(DatePicker 复用本族面板;选中主色实底、区间浅底) ===== */
|
|
212
|
+
.mh-select__date {
|
|
213
|
+
display: inline-flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
justify-content: center;
|
|
216
|
+
width: var(--ui-select-height);
|
|
217
|
+
height: var(--ui-select-height);
|
|
218
|
+
border: none;
|
|
219
|
+
border-radius: var(--ui-radius-control);
|
|
220
|
+
background: transparent;
|
|
221
|
+
font-family: inherit;
|
|
222
|
+
font-size: var(--ui-select-font-size);
|
|
223
|
+
color: var(--ui-base-content);
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
}
|
|
226
|
+
.mh-select__date:hover,
|
|
227
|
+
.mh-select__date.is-hover {
|
|
228
|
+
background: var(--ui-select-option-hover);
|
|
229
|
+
}
|
|
230
|
+
.mh-select__date.is-selected,
|
|
231
|
+
.mh-select__date[data-state='selected'] {
|
|
232
|
+
background: var(--ui-primary);
|
|
233
|
+
color: var(--ui-primary-content);
|
|
234
|
+
}
|
|
235
|
+
.mh-select__date.is-range {
|
|
236
|
+
background: var(--ui-primary-weak);
|
|
237
|
+
}
|
|
238
|
+
.mh-select__date.is-disabled,
|
|
239
|
+
.mh-select__date:disabled {
|
|
240
|
+
color: var(--ui-base-content-subtle);
|
|
241
|
+
cursor: not-allowed;
|
|
242
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* select —— 单件令牌(**基础值**)。
|
|
3
|
+
*
|
|
4
|
+
* 本件自己的几何 / 尺寸 / 色彩槽位;只服务本件,故不随主题进 `@manohub/theme`。
|
|
5
|
+
*
|
|
6
|
+
* ## 抽出说明
|
|
7
|
+
* 本文件从面文件里抽出(原先混写在 `select.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
|
+
- 表壳 `.mh-select-host`:箭头槽(`.mh-input__suffix`)挂在壳里、**不在控件子树里** ——
|
|
19
|
+
少了这一条,箭头的 `width: var(--ui-select-icon-size)` 整条作废、会被输入面的槽规则顶成 16px
|
|
20
|
+
(实测:chrome 里量到 16px 才发现的);
|
|
21
|
+
- 面板 `.mh-select__panel`:挂在 `.mh-popup-host` 下、与触发器**兄弟**(不在 `.mh-select`
|
|
22
|
+
子树里)—— 否则圆角、行高、字号、选中底全失效。 */
|
|
23
|
+
/* 单件令牌 */
|
|
24
|
+
--ui-select-height: var(--ui-control-height-md); /* 标准档 32(日期格与面板内部用;触发器的框高归输入面) */
|
|
25
|
+
--ui-select-padding-x: var(--ui-space-3); /* 12 */
|
|
26
|
+
--ui-select-radius: var(--ui-radius-md); /* 8:设计 `0:4025` 下拉面板 r8(原注释写 8 但取的是控件档 6) */
|
|
27
|
+
--ui-select-font-size: var(--ui-font-body); /* 14 */
|
|
28
|
+
--ui-select-option-height: 36px; /* 设计 `0:4024`:选项行 144×36(原为 34) */
|
|
29
|
+
--ui-select-option-hover: var(--ui-base-200); /* 设计滑过底 #f2f2f2 */
|
|
30
|
+
--ui-select-option-selected: var(--ui-primary-subtle); /* 见头部「有色差异」 */
|
|
31
|
+
--ui-select-chip-height: 24px; /* 多选标签(规范复用标签族 24 档) */
|
|
32
|
+
--ui-select-icon-size: var(--ui-font-icon); /* 下拉箭头:常规图标档 */
|
|
33
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skeleton —— 骨架屏(骨架行 / 列表骨架 / 块状骨架)。
|
|
3
|
+
*
|
|
4
|
+
* 出处:`@aihub/theme` 的 `playground/components/skeleton.css` 与 `src/components/skeleton.css`
|
|
5
|
+
* (行高 30 与表格行高一致、圆角 6、行间距 10、shimmer 微光 1.6s ease-in-out)。
|
|
6
|
+
*
|
|
7
|
+
* **微光动画与色值在本包只有这一处定义**(`--ui-skeleton-*` + `@keyframes mh-skeleton-shimmer`):
|
|
8
|
+
* `query-state.css` 的加载态骨架复用这里的令牌与动画名,不再自带一份 —— 两处各写一份必然漂
|
|
9
|
+
* (时长/色值改一处漏一处,同一屏出现两种呼吸节奏)。
|
|
10
|
+
*
|
|
11
|
+
* 动画降级:`prefers-reduced-motion` 下应压平(本件只声明动画,压平由消费方或后续统一的降级策略负责,
|
|
12
|
+
* 与 theme 包 `base/motion.css` 的分工一致)。
|
|
13
|
+
*/
|
|
14
|
+
.mh-skeleton {
|
|
15
|
+
height: var(--ui-skeleton-height);
|
|
16
|
+
border-radius: var(--ui-skeleton-radius);
|
|
17
|
+
background: var(--ui-skeleton-bg);
|
|
18
|
+
animation: var(--ui-skeleton-animation);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* 行与行之间(纵向列表的默认节奏) */
|
|
22
|
+
.mh-skeleton + .mh-skeleton {
|
|
23
|
+
margin-top: var(--ui-skeleton-gap);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* 骨架列表容器:只做纵向排布,不写任何面(行自己的样子由 `.mh-skeleton` 给) */
|
|
27
|
+
.mh-skeleton-list {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* 块状骨架:给一段区间的占位(如卡片体 / 详情页),不参与「行间距」节奏 */
|
|
33
|
+
.mh-skeleton--block {
|
|
34
|
+
height: auto;
|
|
35
|
+
min-height: var(--ui-skeleton-height);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 微光动画(唯一来源;名字带 mh- 前缀防撞) */
|
|
39
|
+
@keyframes mh-skeleton-shimmer {
|
|
40
|
+
0% {
|
|
41
|
+
background-color: var(--ui-skeleton-bg);
|
|
42
|
+
}
|
|
43
|
+
50% {
|
|
44
|
+
background-color: var(--ui-skeleton-highlight);
|
|
45
|
+
}
|
|
46
|
+
100% {
|
|
47
|
+
background-color: var(--ui-skeleton-bg);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ===== 胶囊档(标签 / 头像 / 次按钮的占位) ===== */
|
|
52
|
+
.mh-skeleton--round {
|
|
53
|
+
border-radius: var(--ui-radius-full);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ===== 静态档:关掉微光 =====
|
|
57
|
+
* 静态摆样、截图与打印时用 —— 动着的占位会让截图前后不一致。 */
|
|
58
|
+
.mh-skeleton-list--static .mh-skeleton {
|
|
59
|
+
animation: none;
|
|
60
|
+
}
|