@xihan-ui/styles 1.0.0-alpha.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/CHANGELOG.md +44 -0
- package/LICENSE +21 -0
- package/README.md +27 -0
- package/css/accordion.css +108 -0
- package/css/affix.css +27 -0
- package/css/alert.css +108 -0
- package/css/anchor.css +137 -0
- package/css/avatar-group.css +82 -0
- package/css/avatar.css +55 -0
- package/css/back-top.css +61 -0
- package/css/badge.css +50 -0
- package/css/breadcrumb.css +127 -0
- package/css/button-group.css +131 -0
- package/css/button.css +98 -0
- package/css/calendar.css +219 -0
- package/css/card.css +116 -0
- package/css/carousel.css +193 -0
- package/css/cascader.css +397 -0
- package/css/checkbox-group.css +185 -0
- package/css/checkbox.css +91 -0
- package/css/clipboard.css +133 -0
- package/css/code-block.css +81 -0
- package/css/collapsible.css +63 -0
- package/css/color-picker.css +424 -0
- package/css/combobox.css +433 -0
- package/css/composer.css +127 -0
- package/css/context-menu.css +263 -0
- package/css/countdown.css +21 -0
- package/css/date-field.css +200 -0
- package/css/date-picker.css +231 -0
- package/css/descriptions.css +200 -0
- package/css/dialog.css +127 -0
- package/css/drawer.css +372 -0
- package/css/dynamic-input.css +157 -0
- package/css/editable.css +249 -0
- package/css/ellipsis.css +41 -0
- package/css/empty-state.css +78 -0
- package/css/field.css +65 -0
- package/css/file-upload.css +298 -0
- package/css/flex.css +95 -0
- package/css/float-button.css +121 -0
- package/css/form.css +185 -0
- package/css/gradient-text.css +62 -0
- package/css/grid.css +428 -0
- package/css/highlight.css +21 -0
- package/css/hover-card.css +146 -0
- package/css/icon-wrapper.css +64 -0
- package/css/icon.css +54 -0
- package/css/image.css +45 -0
- package/css/infinite-scroll.css +22 -0
- package/css/layers.css +2 -0
- package/css/layout.css +169 -0
- package/css/list.css +117 -0
- package/css/listbox.css +174 -0
- package/css/loading-bar.css +66 -0
- package/css/log.css +66 -0
- package/css/marquee.css +182 -0
- package/css/mention.css +222 -0
- package/css/menu.css +144 -0
- package/css/menubar.css +271 -0
- package/css/motion.css +58 -0
- package/css/navigation-menu.css +270 -0
- package/css/number-animation.css +32 -0
- package/css/number-field.css +219 -0
- package/css/page-header.css +85 -0
- package/css/pagination.css +148 -0
- package/css/pin-input.css +157 -0
- package/css/popconfirm.css +150 -0
- package/css/popover.css +150 -0
- package/css/popselect.css +207 -0
- package/css/progress.css +37 -0
- package/css/qr-code.css +50 -0
- package/css/radio-group.css +101 -0
- package/css/rating.css +141 -0
- package/css/reset.css +22 -0
- package/css/result.css +104 -0
- package/css/scroll-area.css +176 -0
- package/css/select.css +264 -0
- package/css/separator.css +17 -0
- package/css/skeleton.css +78 -0
- package/css/slider.css +197 -0
- package/css/spinner.css +74 -0
- package/css/splitter.css +127 -0
- package/css/statistic.css +67 -0
- package/css/steps.css +252 -0
- package/css/switch.css +61 -0
- package/css/table.css +404 -0
- package/css/tabs.css +157 -0
- package/css/tags-input.css +360 -0
- package/css/text-field.css +195 -0
- package/css/thread.css +107 -0
- package/css/time-field.css +200 -0
- package/css/time-picker.css +347 -0
- package/css/time.css +20 -0
- package/css/timeline.css +284 -0
- package/css/toast.css +195 -0
- package/css/toaster.css +69 -0
- package/css/toggle-group.css +160 -0
- package/css/toggle.css +103 -0
- package/css/tone.css +85 -0
- package/css/toolbar.css +114 -0
- package/css/tooltip.css +109 -0
- package/css/tour.css +305 -0
- package/css/transfer.css +318 -0
- package/css/tree-select.css +441 -0
- package/css/tree.css +204 -0
- package/css/typography.css +151 -0
- package/css/undefined.css +38 -0
- package/css/virtualizer.css +104 -0
- package/css/visually-hidden.css +13 -0
- package/css/watermark.css +48 -0
- package/index.css +113 -0
- package/index.unlayered.css +16164 -0
- package/package.json +163 -0
package/css/cascader.css
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 解剖里没有把「触发器 + 清空按钮」裹在一起的 control 部件,一行是靠 flex-wrap 分出来的:
|
|
3
|
+
标签占满整行把后面的挤到下一行,触发器与清空按钮就并排落在同一行上。
|
|
4
|
+
这样作者少写标签、少写清空按钮,剩下的部件也不会塌 */
|
|
5
|
+
[data-scope='cascader'][data-part='root'] {
|
|
6
|
+
/* 尺寸档只换这几个私有槽,触发框与列里的条目都从 root 继承它们,换档不必给每个部件各写一条选择器 */
|
|
7
|
+
--xh-_cascader-h: var(--xh-control-h-md);
|
|
8
|
+
--xh-_cascader-px: var(--xh-control-px-md);
|
|
9
|
+
--xh-_cascader-gap: var(--xh-control-gap-md);
|
|
10
|
+
--xh-_cascader-font-size: var(--xh-text-body-size);
|
|
11
|
+
--xh-_cascader-label-font-size: var(--xh-text-label-size);
|
|
12
|
+
|
|
13
|
+
/* 形态档只换触发框的描边与底色这三个槽,浮层与列不跟着变:
|
|
14
|
+
变的是「这是个输入位」的表达方式,不是弹出内容的表达方式 */
|
|
15
|
+
--xh-_cascader-border: var(--xh-border-default);
|
|
16
|
+
--xh-_cascader-border-hover: var(--xh-border-strong);
|
|
17
|
+
--xh-_cascader-bg: var(--xh-bg-canvas);
|
|
18
|
+
|
|
19
|
+
/* 选中条目的文字色随语气走,没写 data-tone 时退回品牌强调色 */
|
|
20
|
+
--xh-_cascader-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
|
|
21
|
+
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
flex-wrap: wrap;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: var(--xh-cascader-gap, var(--xh-space-1));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},作者手动收起时要自己还回去 */
|
|
29
|
+
[data-scope='cascader'][data-part='root'][hidden] {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* —— 形态 —— */
|
|
34
|
+
/* 形态只决定描边与底色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的中性配色 */
|
|
35
|
+
/* outline 就是缺省那一身:描边加画布底,写出来只为让三档并列可读 */
|
|
36
|
+
[data-scope='cascader'][data-part='root'][data-variant='outline'] {
|
|
37
|
+
--xh-_cascader-border: var(--xh-border-default);
|
|
38
|
+
--xh-_cascader-border-hover: var(--xh-border-strong);
|
|
39
|
+
--xh-_cascader-bg: var(--xh-bg-canvas);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* subtle 是填充式:底色接过「这里能点」的表达,描边随之让位 */
|
|
43
|
+
[data-scope='cascader'][data-part='root'][data-variant='subtle'] {
|
|
44
|
+
--xh-_cascader-border: transparent;
|
|
45
|
+
--xh-_cascader-border-hover: var(--xh-_tone-border, var(--xh-border-default));
|
|
46
|
+
--xh-_cascader-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ghost 无框无底,可见反馈只在聚焦时给;边框宽度仍占位,切换形态不引起布局抖动 */
|
|
50
|
+
[data-scope='cascader'][data-part='root'][data-variant='ghost'] {
|
|
51
|
+
--xh-_cascader-border: transparent;
|
|
52
|
+
--xh-_cascader-border-hover: transparent;
|
|
53
|
+
--xh-_cascader-bg: transparent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* —— 尺寸 —— */
|
|
57
|
+
/* 缺省档写在上面的基础规则里 */
|
|
58
|
+
[data-scope='cascader'][data-part='root'][data-size='sm'] {
|
|
59
|
+
--xh-_cascader-h: var(--xh-control-h-sm);
|
|
60
|
+
--xh-_cascader-px: var(--xh-control-px-sm);
|
|
61
|
+
--xh-_cascader-gap: var(--xh-control-gap-sm);
|
|
62
|
+
--xh-_cascader-font-size: var(--xh-font-size-sm);
|
|
63
|
+
--xh-_cascader-label-font-size: var(--xh-font-size-sm);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[data-scope='cascader'][data-part='root'][data-size='lg'] {
|
|
67
|
+
--xh-_cascader-h: var(--xh-control-h-lg);
|
|
68
|
+
--xh-_cascader-px: var(--xh-control-px-lg);
|
|
69
|
+
--xh-_cascader-gap: var(--xh-control-gap-lg);
|
|
70
|
+
--xh-_cascader-font-size: var(--xh-font-size-lg);
|
|
71
|
+
--xh-_cascader-label-font-size: var(--xh-font-size-lg);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
[data-scope='cascader'][data-part='label'] {
|
|
75
|
+
/* 占满整行,把触发器那一行挤下去 */
|
|
76
|
+
flex-basis: 100%;
|
|
77
|
+
color: var(--xh-cascader-label-fg, var(--xh-fg-muted));
|
|
78
|
+
font-size: var(--xh-cascader-label-font-size, var(--xh-_cascader-label-font-size));
|
|
79
|
+
font-weight: var(--xh-cascader-label-font-weight, var(--xh-text-label-weight));
|
|
80
|
+
line-height: var(--xh-leading-none);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* 整个控件禁用会把 data-disabled 一路打到 label / value-text / indicator 上,各处观感保持一致 */
|
|
84
|
+
[data-scope='cascader'][data-part='label'][data-disabled] {
|
|
85
|
+
color: var(--xh-fg-subtle);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* 画成一个框的就是 trigger 自己:整条路径的回显与展开箭头都长在它里面,
|
|
89
|
+
清空按钮贴在框外与它并排 */
|
|
90
|
+
[data-scope='cascader'][data-part='trigger'] {
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
flex: 1;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: space-between;
|
|
95
|
+
gap: var(--xh-cascader-trigger-gap, var(--xh-_cascader-gap));
|
|
96
|
+
min-inline-size: var(--xh-cascader-trigger-min-w, 14rem);
|
|
97
|
+
block-size: var(--xh-cascader-trigger-h, var(--xh-_cascader-h));
|
|
98
|
+
padding-inline: var(--xh-cascader-trigger-px, var(--xh-_cascader-px));
|
|
99
|
+
border: var(--xh-stroke-thin) solid var(--xh-cascader-trigger-border, var(--xh-_cascader-border));
|
|
100
|
+
border-radius: var(--xh-cascader-trigger-radius, var(--xh-shape-control));
|
|
101
|
+
background: var(--xh-cascader-trigger-bg, var(--xh-_cascader-bg));
|
|
102
|
+
color: var(--xh-cascader-trigger-fg, var(--xh-fg-default));
|
|
103
|
+
font-family: inherit;
|
|
104
|
+
font-size: var(--xh-cascader-trigger-font-size, var(--xh-_cascader-font-size));
|
|
105
|
+
line-height: var(--xh-leading-none);
|
|
106
|
+
text-align: start;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
[data-scope='cascader'][data-part='trigger'][hidden] {
|
|
112
|
+
display: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
|
|
116
|
+
[data-scope='cascader'][data-part='trigger']:hover:not(:disabled, [data-invalid]) {
|
|
117
|
+
border-color: var(--xh-cascader-trigger-border-hover, var(--xh-_cascader-border-hover));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* trigger 是整个控件唯一的 Tab 停靠点(展开后停靠点才移进列里),落焦必须看得见。
|
|
121
|
+
语气落在环上:没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色 */
|
|
122
|
+
[data-scope='cascader'][data-part='trigger']:focus-visible {
|
|
123
|
+
outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
|
|
124
|
+
outline-offset: var(--xh-ring-offset);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[data-scope='cascader'][data-part='trigger'][data-invalid] {
|
|
128
|
+
border-color: var(--xh-cascader-trigger-border-invalid, var(--xh-color-danger-500));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* 只读仍可聚焦、浮层仍展得开、列仍能浏览,所以不置灰,只把底色压下去表示「改不动」 */
|
|
132
|
+
[data-scope='cascader'][data-part='trigger'][data-readonly] {
|
|
133
|
+
background: var(--xh-cascader-trigger-bg-readonly, var(--xh-bg-subtle));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* trigger 是单体控件,用原生 disabled(列里的集合条目一律 aria-disabled,写 :disabled 永不命中) */
|
|
137
|
+
[data-scope='cascader'][data-part='trigger']:disabled {
|
|
138
|
+
background: var(--xh-cascader-trigger-bg-disabled, var(--xh-bg-subtle));
|
|
139
|
+
color: var(--xh-fg-disabled);
|
|
140
|
+
cursor: not-allowed;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* 路径连起来会很长,必须能截断;框宽由 trigger 定,这里得允许自己被压缩 */
|
|
144
|
+
[data-scope='cascader'][data-part='value-text'] {
|
|
145
|
+
flex: 1;
|
|
146
|
+
min-inline-size: 0;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
text-overflow: ellipsis;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* 无选中:显示的是 placeholder,画淡一档 */
|
|
153
|
+
[data-scope='cascader'][data-part='value-text'][data-placeholder] {
|
|
154
|
+
color: var(--xh-cascader-placeholder-fg, var(--xh-fg-subtle));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
[data-scope='cascader'][data-part='value-text'][data-disabled] {
|
|
158
|
+
color: var(--xh-fg-disabled);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
[data-scope='cascader'][data-part='indicator'] {
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
flex: none;
|
|
164
|
+
align-items: center;
|
|
165
|
+
justify-content: center;
|
|
166
|
+
color: var(--xh-cascader-indicator-fg, var(--xh-fg-muted));
|
|
167
|
+
transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
[data-scope='cascader'][data-part='indicator'][hidden] {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
[data-scope='cascader'][data-part='indicator'][data-state='open'] {
|
|
175
|
+
rotate: 180deg;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
[data-scope='cascader'][data-part='indicator'][data-disabled] {
|
|
179
|
+
color: var(--xh-fg-disabled);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* 贴在触发框旁边的小方钮,不撑高那一行 */
|
|
183
|
+
[data-scope='cascader'][data-part='clear-trigger'] {
|
|
184
|
+
display: inline-flex;
|
|
185
|
+
flex: none;
|
|
186
|
+
align-items: center;
|
|
187
|
+
justify-content: center;
|
|
188
|
+
inline-size: var(--xh-cascader-action-size, var(--xh-control-action-size));
|
|
189
|
+
block-size: var(--xh-cascader-action-size, var(--xh-control-action-size));
|
|
190
|
+
padding: 0;
|
|
191
|
+
border: 0;
|
|
192
|
+
border-radius: var(--xh-cascader-action-radius, var(--xh-shape-control));
|
|
193
|
+
background: var(--xh-cascader-action-bg, transparent);
|
|
194
|
+
color: var(--xh-cascader-action-fg, var(--xh-fg-muted));
|
|
195
|
+
font-family: inherit;
|
|
196
|
+
font-size: var(--xh-cascader-action-font-size, var(--xh-font-size-sm));
|
|
197
|
+
line-height: var(--xh-leading-none);
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
user-select: none;
|
|
200
|
+
transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
[data-scope='cascader'][data-part='clear-trigger'][hidden] {
|
|
204
|
+
display: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
[data-scope='cascader'][data-part='clear-trigger']:hover:not(:disabled) {
|
|
208
|
+
background: var(--xh-cascader-action-bg-hover, var(--xh-bg-subtle-hover));
|
|
209
|
+
color: var(--xh-cascader-action-fg-hover, var(--xh-fg-default));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
[data-scope='cascader'][data-part='clear-trigger']:active:not(:disabled) {
|
|
213
|
+
background: var(--xh-cascader-action-bg-active, var(--xh-bg-subtle-active));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* 清空按钮退出了 Tab 序列(tabindex=-1),正常操作走不到这里;
|
|
217
|
+
留着是给程序化聚焦兜底,落焦时得看得见 */
|
|
218
|
+
[data-scope='cascader'][data-part='clear-trigger']:focus-visible {
|
|
219
|
+
outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
|
|
220
|
+
outline-offset: var(--xh-ring-offset);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* 无选中、只读、整控件禁用三种情况下都按不动,用的是原生 disabled */
|
|
224
|
+
[data-scope='cascader'][data-part='clear-trigger']:disabled {
|
|
225
|
+
background: var(--xh-cascader-action-bg, transparent);
|
|
226
|
+
color: var(--xh-fg-disabled);
|
|
227
|
+
cursor: not-allowed;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
|
|
231
|
+
[data-scope='cascader'][data-part='positioner'] {
|
|
232
|
+
position: fixed;
|
|
233
|
+
z-index: var(--xh-layer-popover);
|
|
234
|
+
/* 空壳不吃指针,交互只发生在 content 里 */
|
|
235
|
+
pointer-events: none;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* 锚点被滚出可视区:整个浮层随之收起 */
|
|
239
|
+
[data-scope='cascader'][data-part='positioner'][data-hidden] {
|
|
240
|
+
visibility: hidden;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* 级联的骨架就在这一条上:列沿书写方向并排,一层一列。
|
|
244
|
+
横向随列数增减,因此不设固定宽度,只给每列自己的宽度 */
|
|
245
|
+
[data-scope='cascader'][data-part='content'] {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-direction: row;
|
|
248
|
+
align-items: stretch;
|
|
249
|
+
max-inline-size: var(--xh-cascader-content-max-w, 48rem);
|
|
250
|
+
border: var(--xh-stroke-thin) solid var(--xh-cascader-content-border, var(--xh-border-default));
|
|
251
|
+
border-radius: var(--xh-cascader-content-radius, var(--xh-shape-surface));
|
|
252
|
+
background: var(--xh-cascader-content-bg, var(--xh-bg-surface));
|
|
253
|
+
color: var(--xh-cascader-content-fg, var(--xh-fg-default));
|
|
254
|
+
box-shadow: var(--xh-cascader-content-shadow, var(--xh-elevation-2));
|
|
255
|
+
/* 列多到放不下时整体横向滚动;纵向溢出归每一列自己 */
|
|
256
|
+
overflow-x: auto;
|
|
257
|
+
pointer-events: auto;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* 收起态的唯一开关:display 盖掉了 UA 的 [hidden]{display:none},漏了这条浮层就收不起来 */
|
|
261
|
+
[data-scope='cascader'][data-part='content'][hidden] {
|
|
262
|
+
display: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* 容器只是焦点域的兜底落点,落焦不画环:高亮永远长在条目上 */
|
|
266
|
+
[data-scope='cascader'][data-part='content']:focus-visible {
|
|
267
|
+
outline: none;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
[data-scope='cascader'][data-part='content'][data-state='open'] {
|
|
271
|
+
animation: xh-cascader-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* 一列:自己定宽、自己滚。列与列之间用一条分隔线,比留白更能说明「这是下一级」 */
|
|
275
|
+
[data-scope='cascader'][data-part='column'] {
|
|
276
|
+
display: flex;
|
|
277
|
+
flex: none;
|
|
278
|
+
flex-direction: column;
|
|
279
|
+
inline-size: var(--xh-cascader-column-w, 11rem);
|
|
280
|
+
max-block-size: var(--xh-cascader-column-max-h, 16rem);
|
|
281
|
+
padding-block: var(--xh-cascader-column-py, var(--xh-space-1));
|
|
282
|
+
padding-inline: var(--xh-cascader-column-px, var(--xh-space-1));
|
|
283
|
+
overflow-y: auto;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* 展开路径砍短了这一列就收起来。display 盖掉了 UA 的 [hidden]{display:none},
|
|
287
|
+
漏了这条「选了靠左的一列就把右边的列砍掉」在视觉上根本不会发生 */
|
|
288
|
+
[data-scope='cascader'][data-part='column'][hidden] {
|
|
289
|
+
display: none;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* 分隔线画在列的起始缘,且第一列不画:这样列数增减时线永远只出现在列与列之间。
|
|
293
|
+
用逻辑属性,rtl 下自动跑到另一侧 */
|
|
294
|
+
[data-scope='cascader'][data-part='column'] + [data-scope='cascader'][data-part='column'] {
|
|
295
|
+
border-inline-start: var(--xh-stroke-thin) solid var(--xh-cascader-column-divider, var(--xh-border-subtle));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* 列不进 Tab 序列也不承载焦点,落焦不画环:高亮永远长在条目上 */
|
|
299
|
+
[data-scope='cascader'][data-part='column']:focus-visible {
|
|
300
|
+
outline: none;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
[data-scope='cascader'][data-part='item'] {
|
|
304
|
+
display: flex;
|
|
305
|
+
align-items: center;
|
|
306
|
+
gap: var(--xh-cascader-row-gap, var(--xh-_cascader-gap));
|
|
307
|
+
padding-block: var(--xh-cascader-row-py, var(--xh-space-1));
|
|
308
|
+
padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-sm));
|
|
309
|
+
border-radius: var(--xh-cascader-row-radius, var(--xh-shape-control));
|
|
310
|
+
color: var(--xh-cascader-row-fg, var(--xh-fg-default));
|
|
311
|
+
font-size: var(--xh-cascader-row-font-size, var(--xh-_cascader-font-size));
|
|
312
|
+
/* 行高留出文字的上下伸展空间,行内那层 overflow:hidden 才不会把字削掉 */
|
|
313
|
+
line-height: var(--xh-cascader-row-leading, var(--xh-leading-normal));
|
|
314
|
+
white-space: nowrap;
|
|
315
|
+
cursor: pointer;
|
|
316
|
+
user-select: none;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* 条目常挂不卸载:不属于当前这一列的那些靠 hidden 收起。
|
|
320
|
+
display 盖掉了 UA 的 [hidden]{display:none},漏了这条列换了内容旧条目还留在那儿 */
|
|
321
|
+
[data-scope='cascader'][data-part='item'][hidden] {
|
|
322
|
+
display: none;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* 指针悬停、键盘高亮与展开路径共用同一张底:三者都是「此刻停在这儿」,
|
|
326
|
+
data-highlighted 跟的是连接层记的焦点条目 */
|
|
327
|
+
[data-scope='cascader'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted], [data-active]) {
|
|
328
|
+
background: var(--xh-cascader-row-bg-highlight, var(--xh-bg-subtle-hover));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色整条通道留给悬停,
|
|
332
|
+
两者因此能同时看见 */
|
|
333
|
+
[data-scope='cascader'][data-part='item'][data-selected] {
|
|
334
|
+
color: var(--xh-cascader-row-fg-selected, var(--xh-_cascader-selected-fg));
|
|
335
|
+
font-weight: var(--xh-cascader-row-selected-font-weight, var(--xh-font-weight-medium));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* 条目自己就是 option,环直接画在它身上;往内收,行是撑满列宽的,环画在外沿会被裁掉 */
|
|
339
|
+
[data-scope='cascader'][data-part='item']:focus-visible {
|
|
340
|
+
outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
|
|
341
|
+
outline-offset: calc(-1 * var(--xh-ring-width));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* 禁用走 aria-disabled 而非原生 disabled:条目仍要可聚焦(它还得当方向键的起点),
|
|
345
|
+
所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
|
|
346
|
+
[data-scope='cascader'][data-part='item'][data-disabled] {
|
|
347
|
+
color: var(--xh-fg-disabled);
|
|
348
|
+
cursor: not-allowed;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
[data-scope='cascader'][data-part='item-text'] {
|
|
352
|
+
flex: 1;
|
|
353
|
+
min-inline-size: 0;
|
|
354
|
+
overflow: hidden;
|
|
355
|
+
white-space: nowrap;
|
|
356
|
+
text-overflow: ellipsis;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* 勾选标记只在选中项上出现;未选中时占位不塌,切换选中不引起行宽抖动 */
|
|
360
|
+
[data-scope='cascader'][data-part='item-indicator'] {
|
|
361
|
+
display: inline-flex;
|
|
362
|
+
flex: none;
|
|
363
|
+
align-items: center;
|
|
364
|
+
justify-content: center;
|
|
365
|
+
inline-size: var(--xh-cascader-indicator-size, var(--xh-control-indicator-size));
|
|
366
|
+
color: var(--xh-cascader-item-indicator-fg, var(--xh-_tone, var(--xh-bg-brand)));
|
|
367
|
+
visibility: hidden;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
[data-scope='cascader'][data-part='item-indicator'][hidden] {
|
|
371
|
+
display: none;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
[data-scope='cascader'][data-part='item-indicator'][data-selected] {
|
|
375
|
+
visibility: visible;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
[data-scope='cascader'][data-part='item-indicator'][data-disabled] {
|
|
379
|
+
color: var(--xh-fg-disabled);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@layer xihan.motion {
|
|
384
|
+
/* 浮层是横向长出来的:淡入之外再沿书写方向起始缘推一小段,观感上像列被「拉开」。
|
|
385
|
+
关键帧写在本文件里、名字带组件前缀,不动公共的那一份 */
|
|
386
|
+
@keyframes xh-cascader-in {
|
|
387
|
+
from {
|
|
388
|
+
opacity: 0;
|
|
389
|
+
translate: -0.25rem 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
to {
|
|
393
|
+
opacity: 1;
|
|
394
|
+
translate: 0 0;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 组容器:label、trigger、条目都是它的直接子节点,排布方式只能读 data-orientation——
|
|
3
|
+
连接层明说了 role=group 不接受 aria-orientation,那个属性它根本没输出 */
|
|
4
|
+
[data-scope='checkbox-group'][data-part='root'] {
|
|
5
|
+
display: flex;
|
|
6
|
+
gap: var(--xh-checkbox-group-gap, var(--xh-stack-gap-md));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* 两种取值各写一条:连接层缺省给的是 vertical,但受控写 horizontal 时不能靠默认值兜底 */
|
|
10
|
+
[data-scope='checkbox-group'][data-part='root'][data-orientation='vertical'] {
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
/* 条目按内容收宽。竖排下 flex 子项默认拉伸,点击区会一路延伸到文字右侧的空白处,
|
|
13
|
+
用户点在离文字很远的地方也能翻转选项 */
|
|
14
|
+
align-items: flex-start;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[data-scope='checkbox-group'][data-part='root'][data-orientation='horizontal'] {
|
|
18
|
+
flex-direction: row;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
align-items: center;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
[data-scope='checkbox-group'][data-part='label'] {
|
|
24
|
+
color: var(--xh-checkbox-group-label-fg, var(--xh-fg-muted));
|
|
25
|
+
font-size: var(--xh-checkbox-group-label-font-size, var(--xh-text-label-size));
|
|
26
|
+
font-weight: var(--xh-checkbox-group-label-font-weight, var(--xh-text-label-weight));
|
|
27
|
+
line-height: var(--xh-leading-none);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* label 自己不带任何状态属性,整组禁用只写在 root 上,只能从 root 往下够 */
|
|
31
|
+
[data-scope='checkbox-group'][data-part='root'][data-disabled]
|
|
32
|
+
[data-scope='checkbox-group'][data-part='label'] {
|
|
33
|
+
color: var(--xh-checkbox-group-label-fg-disabled, var(--xh-fg-subtle));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* position 是给条目内那份视觉隐藏的原生输入当定位基准:连接层给它写死了 position:absolute,
|
|
37
|
+
这里不立基准的话,原生校验气泡会飘到页面上离该条目很远的地方 */
|
|
38
|
+
[data-scope='checkbox-group'][data-part='item'] {
|
|
39
|
+
position: relative;
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
gap: var(--xh-checkbox-group-item-gap, var(--xh-control-gap-md));
|
|
43
|
+
border-radius: var(--xh-checkbox-group-item-radius, var(--xh-shape-control));
|
|
44
|
+
color: var(--xh-checkbox-group-item-fg, var(--xh-fg-default));
|
|
45
|
+
font-size: var(--xh-checkbox-group-item-font-size, var(--xh-text-label-size));
|
|
46
|
+
line-height: var(--xh-leading-none);
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
[data-scope='checkbox-group'][data-part='item']:focus-visible {
|
|
51
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
52
|
+
outline-offset: var(--xh-ring-offset);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* 条目禁用一律走 aria-disabled(原生 disabled 会让它从键盘用户眼里消失),
|
|
56
|
+
所以样式只能读 data-disabled,写 :disabled 永远不命中 */
|
|
57
|
+
[data-scope='checkbox-group'][data-part='item'][data-disabled] {
|
|
58
|
+
color: var(--xh-checkbox-group-item-fg-disabled, var(--xh-fg-disabled));
|
|
59
|
+
cursor: not-allowed;
|
|
60
|
+
opacity: var(--xh-state-disabled-opacity);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* 只读整组都改不动,但不是禁用:颜色照常,只把"可点"这个暗示收回来。
|
|
64
|
+
排掉禁用项是因为这条选择器权重高过上面那条,不排就会把 not-allowed 覆盖回 default */
|
|
65
|
+
[data-scope='checkbox-group'][data-part='root'][data-readonly]
|
|
66
|
+
[data-scope='checkbox-group'][data-part='item']:not([data-disabled]) {
|
|
67
|
+
cursor: default;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* 全选格与条目格共用同一套盒子,并成一条规则写:分开写迟早只改到一半,两个方框就此走形。
|
|
71
|
+
尺寸与选中态照 checkbox 的 root 搬,同一份视觉语言在单体与集合里必须一致。
|
|
72
|
+
trigger 那格没有对应的角色节点(anatomy 到 trigger 为止),只能由伪元素补出来 */
|
|
73
|
+
[data-scope='checkbox-group'][data-part='item-control'],
|
|
74
|
+
[data-scope='checkbox-group'][data-part='trigger']::before {
|
|
75
|
+
display: inline-flex;
|
|
76
|
+
flex: none;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
inline-size: var(--xh-checkbox-group-control-size, 16px);
|
|
80
|
+
block-size: var(--xh-checkbox-group-control-size, 16px);
|
|
81
|
+
border: var(--xh-stroke-thin) solid var(--xh-checkbox-group-control-border, var(--xh-border-default));
|
|
82
|
+
border-radius: var(--xh-checkbox-group-control-radius, var(--xh-radius-sm));
|
|
83
|
+
background: var(--xh-checkbox-group-control-bg, var(--xh-bg-canvas));
|
|
84
|
+
color: var(--xh-checkbox-group-control-fg, var(--xh-fg-on-brand));
|
|
85
|
+
font-size: var(--xh-checkbox-group-control-font-size, 12px);
|
|
86
|
+
line-height: var(--xh-leading-none);
|
|
87
|
+
transition:
|
|
88
|
+
background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
|
|
89
|
+
border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* content 只能给伪元素,绝不能并进上面那条:content 落在普通元素上会顶掉它的全部子节点,
|
|
93
|
+
item-control 里作者写的图标就此消失 */
|
|
94
|
+
[data-scope='checkbox-group'][data-part='trigger']::before {
|
|
95
|
+
content: '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* 悬停只加深空方框的描边。已选中的那一格必须排除:这条选择器的权重高过下面那条填色规则,
|
|
99
|
+
不排除就会在悬停时把 brand 描边换回灰色,方框看起来"缺了一圈" */
|
|
100
|
+
[data-scope='checkbox-group'][data-part='item']:not([data-disabled]):hover
|
|
101
|
+
[data-scope='checkbox-group'][data-part='item-control']:not([data-state='checked']) {
|
|
102
|
+
border-color: var(--xh-checkbox-group-control-border-hover, var(--xh-border-strong));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* 选中即填色:条目是二态,全选格三态里 all 与 some 都算"有值",共用同一副填色 */
|
|
106
|
+
[data-scope='checkbox-group'][data-part='item-control'][data-state='checked'],
|
|
107
|
+
[data-scope='checkbox-group'][data-part='trigger']:is([data-state='all'], [data-state='some'])::before {
|
|
108
|
+
border-color: var(--xh-checkbox-group-control-border-checked, var(--xh-bg-brand));
|
|
109
|
+
background: var(--xh-checkbox-group-control-bg-checked, var(--xh-bg-brand));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* 勾号由皮肤补,作者不必自己往 item-control 里塞字符 */
|
|
113
|
+
[data-scope='checkbox-group'][data-part='item-control'][data-state='checked']::before {
|
|
114
|
+
content: '✓';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* 全选格的三态:all 打勾、some 打横杠、none 留空。
|
|
118
|
+
some 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state */
|
|
119
|
+
[data-scope='checkbox-group'][data-part='trigger'][data-state='all']::before {
|
|
120
|
+
content: '✓';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
[data-scope='checkbox-group'][data-part='trigger'][data-state='some']::before {
|
|
124
|
+
content: '−';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* 校验失败标在每个方框上:root 上的 data-invalid 是唯一出处,条目自己不带这个属性 */
|
|
128
|
+
[data-scope='checkbox-group'][data-part='root'][data-invalid]
|
|
129
|
+
[data-scope='checkbox-group'][data-part='item-control'] {
|
|
130
|
+
border-color: var(--xh-checkbox-group-control-border-invalid, var(--xh-color-danger-500));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
[data-scope='checkbox-group'][data-part='item-text'] {
|
|
134
|
+
color: inherit;
|
|
135
|
+
user-select: none;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* 全选格与条目同形,但字重加一档,读起来才不像又一个普通选项。
|
|
139
|
+
它是普通元素而非原生控件(三态只有非原生控件表达得出),禁用态同样只能读 data-disabled */
|
|
140
|
+
[data-scope='checkbox-group'][data-part='trigger'] {
|
|
141
|
+
display: inline-flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
gap: var(--xh-checkbox-group-trigger-gap, var(--xh-control-gap-md));
|
|
144
|
+
border-radius: var(--xh-checkbox-group-trigger-radius, var(--xh-shape-control));
|
|
145
|
+
color: var(--xh-checkbox-group-trigger-fg, var(--xh-fg-default));
|
|
146
|
+
font-size: var(--xh-checkbox-group-trigger-font-size, var(--xh-text-label-size));
|
|
147
|
+
font-weight: var(--xh-checkbox-group-trigger-font-weight, var(--xh-font-weight-medium));
|
|
148
|
+
line-height: var(--xh-leading-none);
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
user-select: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
[data-scope='checkbox-group'][data-part='trigger']:focus-visible {
|
|
154
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
155
|
+
outline-offset: var(--xh-ring-offset);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[data-scope='checkbox-group'][data-part='trigger'][data-disabled] {
|
|
159
|
+
color: var(--xh-checkbox-group-trigger-fg-disabled, var(--xh-fg-disabled));
|
|
160
|
+
cursor: not-allowed;
|
|
161
|
+
opacity: var(--xh-state-disabled-opacity);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* 只读与禁用会同时出现在 trigger 上(连接层两个属性各写各的),
|
|
165
|
+
同权重下后写的赢,所以这里必须显式排掉禁用,否则禁用的手势指示被只读盖掉 */
|
|
166
|
+
[data-scope='checkbox-group'][data-part='trigger'][data-readonly]:not([data-disabled]) {
|
|
167
|
+
cursor: default;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* 表单出口:连接层已经把整套视觉隐藏写进内联 style(absolute + 1px + clip-path),
|
|
171
|
+
这里绝不能再补 display:none——那份输入必须留在布局里,原生校验提示要有处可贴。
|
|
172
|
+
只补一条不吃指针,免得它挡住条目的点击 */
|
|
173
|
+
[data-scope='checkbox-group'][data-part='item-hidden-input'] {
|
|
174
|
+
pointer-events: none;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* 上面凡是给了 display 的角色节点都要补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
|
|
178
|
+
不补的话作者给节点加 hidden 后它照样显示 */
|
|
179
|
+
[data-scope='checkbox-group'][data-part='root'][hidden],
|
|
180
|
+
[data-scope='checkbox-group'][data-part='item'][hidden],
|
|
181
|
+
[data-scope='checkbox-group'][data-part='item-control'][hidden],
|
|
182
|
+
[data-scope='checkbox-group'][data-part='trigger'][hidden] {
|
|
183
|
+
display: none;
|
|
184
|
+
}
|
|
185
|
+
}
|
package/css/checkbox.css
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
[data-scope='checkbox'][data-part='root'] {
|
|
3
|
+
/* 尺寸档只换方框边长这一个私有槽,勾的字号按边长的比例跟着走;
|
|
4
|
+
指示器从 root 继承这两个槽,换档不必给每个部件各写一条选择器 */
|
|
5
|
+
--xh-_checkbox-box: var(--xh-space-4);
|
|
6
|
+
--xh-_checkbox-glyph: calc(var(--xh-_checkbox-box) * 0.75);
|
|
7
|
+
|
|
8
|
+
/* 选中态的底与描边随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的品牌色 */
|
|
9
|
+
--xh-_checkbox-accent: var(--xh-_tone, var(--xh-bg-brand));
|
|
10
|
+
|
|
11
|
+
/* 实心底上的勾与横杠,同样没写 data-tone 时退回原来的品牌底前景色 */
|
|
12
|
+
--xh-_checkbox-on-accent: var(--xh-_tone-on, var(--xh-fg-on-brand));
|
|
13
|
+
|
|
14
|
+
position: relative;
|
|
15
|
+
display: inline-flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
inline-size: var(--xh-_checkbox-box);
|
|
19
|
+
block-size: var(--xh-_checkbox-box);
|
|
20
|
+
padding: 0;
|
|
21
|
+
border: 1px solid var(--xh-checkbox-border, var(--xh-border-default));
|
|
22
|
+
border-radius: var(--xh-radius-sm);
|
|
23
|
+
background: var(--xh-checkbox-bg, var(--xh-bg-canvas));
|
|
24
|
+
color: var(--xh-checkbox-fg, var(--xh-_checkbox-on-accent));
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
transition:
|
|
27
|
+
background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
|
|
28
|
+
border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* 半选与全选同样是「有值」,方框都得填上:
|
|
32
|
+
只填全选的话,半选那条横杠是实心底上的前景色(白),压在白画布上等于没画 */
|
|
33
|
+
[data-scope='checkbox'][data-part='root'][data-state='checked'],
|
|
34
|
+
[data-scope='checkbox'][data-part='root'][data-state='indeterminate'] {
|
|
35
|
+
border-color: var(--xh-checkbox-border-checked, var(--xh-_checkbox-accent));
|
|
36
|
+
background: var(--xh-checkbox-bg-checked, var(--xh-_checkbox-accent));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-scope='checkbox'][data-part='root'][data-disabled] {
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
opacity: var(--xh-state-disabled-opacity);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
[data-scope='checkbox'][data-part='root']:focus-visible {
|
|
45
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
46
|
+
outline-offset: var(--xh-ring-offset);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* —— 尺寸 —— */
|
|
50
|
+
/* 缺省档写在上面的基础规则里 */
|
|
51
|
+
[data-scope='checkbox'][data-part='root'][data-size='sm'] {
|
|
52
|
+
--xh-_checkbox-box: var(--xh-space-3);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[data-scope='checkbox'][data-part='root'][data-size='lg'] {
|
|
56
|
+
--xh-_checkbox-box: var(--xh-space-5);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[data-scope='checkbox'][data-part='indicator'] {
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
inline-size: 100%;
|
|
64
|
+
block-size: 100%;
|
|
65
|
+
line-height: var(--xh-leading-none);
|
|
66
|
+
font-size: var(--xh-_checkbox-glyph);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-scope='checkbox'][data-part='indicator']::before {
|
|
70
|
+
content: '✓';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[data-scope='checkbox'][data-part='indicator'][data-state='unchecked'] {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* 半选画一条横杠盖住勾:aria-checked=mixed 在视觉上也得与「全选」分得开 */
|
|
78
|
+
[data-scope='checkbox'][data-part='indicator'][data-state='indeterminate'] {
|
|
79
|
+
position: relative;
|
|
80
|
+
color: transparent;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
[data-scope='checkbox'][data-part='indicator'][data-state='indeterminate']::after {
|
|
84
|
+
position: absolute;
|
|
85
|
+
inline-size: 60%;
|
|
86
|
+
block-size: var(--xh-stroke-thick);
|
|
87
|
+
border-radius: var(--xh-radius-full);
|
|
88
|
+
background: var(--xh-checkbox-indicator-fg, var(--xh-_checkbox-on-accent));
|
|
89
|
+
content: '';
|
|
90
|
+
}
|
|
91
|
+
}
|