@xihan-ui/styles 1.0.0-alpha.2 → 1.0.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 +2177 -0
- package/README.md +1 -1
- package/css/accordion.css +80 -6
- package/css/alert.css +43 -14
- package/css/anchor.css +8 -8
- package/css/avatar-group.css +7 -3
- package/css/avatar.css +9 -3
- package/css/back-top.css +22 -1
- package/css/badge.css +104 -32
- package/css/breadcrumb.css +25 -5
- package/css/button-group.css +18 -13
- package/css/button.css +48 -11
- package/css/calendar.css +150 -7
- package/css/card.css +20 -11
- package/css/carousel.css +36 -5
- package/css/cascader.css +211 -124
- package/css/checkbox-group.css +72 -22
- package/css/checkbox.css +70 -13
- package/css/clipboard.css +2 -1
- package/css/code-block.css +12 -7
- package/css/collapsible.css +49 -3
- package/css/color-picker.css +132 -46
- package/css/combobox.css +132 -60
- package/css/composer.css +5 -3
- package/css/context-menu.css +113 -74
- package/css/date-field.css +93 -16
- package/css/date-picker.css +293 -72
- package/css/descriptions.css +11 -5
- package/css/dialog.css +47 -14
- package/css/download-trigger.css +76 -0
- package/css/drawer.css +57 -16
- package/css/dynamic-input.css +75 -17
- package/css/editable.css +12 -10
- package/css/ellipsis.css +7 -1
- package/css/empty-state.css +22 -12
- package/css/field.css +16 -6
- package/css/fieldset.css +69 -0
- package/css/file-upload.css +46 -8
- package/css/flex.css +13 -7
- package/css/float-button.css +23 -1
- package/css/floating-panel.css +316 -0
- package/css/form.css +4 -4
- package/css/grid.css +11 -5
- package/css/heatmap.css +411 -0
- package/css/highlight.css +2 -2
- package/css/hotkeys.css +90 -0
- package/css/hover-card.css +43 -45
- package/css/image-cropper.css +233 -0
- package/css/image-viewer.css +155 -17
- package/css/image.css +2 -2
- package/css/infinite-scroll.css +1 -1
- package/css/json-viewer.css +274 -0
- package/css/layout.css +19 -15
- package/css/list.css +22 -13
- package/css/listbox.css +24 -6
- package/css/loading-bar.css +12 -5
- package/css/log.css +7 -3
- package/css/marquee.css +9 -0
- package/css/masonry.css +63 -0
- package/css/mention.css +100 -36
- package/css/menu.css +127 -50
- package/css/menubar.css +155 -61
- package/css/navigation-menu.css +56 -31
- package/css/notification.css +377 -0
- package/css/number-animation.css +3 -3
- package/css/number-field.css +182 -19
- package/css/overlay-arrow.css +51 -0
- package/css/page-header.css +12 -5
- package/css/pagination.css +171 -14
- package/css/password-input.css +356 -0
- package/css/pin-input.css +15 -12
- package/css/popconfirm.css +55 -12
- package/css/popover.css +73 -45
- package/css/popselect.css +207 -57
- package/css/progress.css +54 -8
- package/css/qr-code.css +1 -1
- package/css/radio-group.css +27 -10
- package/css/rating.css +4 -4
- package/css/reset.css +17 -0
- package/css/result.css +21 -11
- package/css/scroll-area.css +61 -89
- package/css/scrollbar.css +170 -0
- package/css/segmented.css +215 -0
- package/css/select.css +298 -131
- package/css/separator.css +2 -2
- package/css/side-nav.css +127 -24
- package/css/signature-pad.css +144 -0
- package/css/skeleton.css +7 -1
- package/css/slider.css +14 -12
- package/css/space.css +117 -0
- package/css/spinner.css +22 -10
- package/css/statistic.css +9 -9
- package/css/steps.css +29 -12
- package/css/switch.css +57 -8
- package/css/table.css +146 -44
- package/css/tabs.css +13 -5
- package/css/tag.css +179 -0
- package/css/tags-input.css +80 -42
- package/css/text-field.css +151 -38
- package/css/thread.css +11 -3
- package/css/time-field.css +99 -18
- package/css/time-picker.css +261 -71
- package/css/timeline.css +15 -15
- package/css/timer.css +119 -0
- package/css/toast.css +129 -55
- package/css/toggle-group.css +30 -4
- package/css/toggle.css +12 -6
- package/css/tone.css +57 -22
- package/css/toolbar.css +1 -1
- package/css/tooltip.css +40 -31
- package/css/tour.css +112 -61
- package/css/transfer.css +98 -21
- package/css/tree-select.css +215 -89
- package/css/tree.css +131 -5
- package/css/typography.css +5 -5
- package/css/undefined.css +12 -1
- package/css/virtualizer.css +3 -1
- package/css/watermark.css +1 -2
- package/index.css +18 -1
- package/index.unlayered.css +10356 -3255
- package/package.json +20 -4
- package/css/toaster.css +0 -74
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
|
|
3
|
+
[data-scope='scrollbar'] {
|
|
4
|
+
--xh-scrollbar-skin: 1;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* 挂了自绘滚动条的容器:原生滚动条只藏外观,滚动能力一点不动。
|
|
8
|
+
标记由机器挂监听时打上,最后一条滚动条拆走才撤。下面那条 ::-webkit-scrollbar 兜住还没实现 scrollbar-width 的引擎 */
|
|
9
|
+
[data-xh-scrollbar] {
|
|
10
|
+
scrollbar-width: none;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
[data-xh-scrollbar]::-webkit-scrollbar {
|
|
14
|
+
display: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* 定位分工:滑块在**主轴**上的起点与长度由连接层每帧写进内联样式——
|
|
18
|
+
竖向是 inset-block-start / block-size,横向是 inset-inline-start / inline-size。
|
|
19
|
+
这份皮肤一个都不碰:内联优先级高于样式表,写了不但是死声明,
|
|
20
|
+
换轴的那一帧还会跟连接层清空另一轴的动作抢位置,把滑块钉在两轴都被约束的地方。
|
|
21
|
+
皮肤只管另一条轴(交叉轴)的尺寸、颜色、圆角与状态表现。
|
|
22
|
+
|
|
23
|
+
根用绝对定位、贴容器的对应边:滚动容器归作者,本组件只要求它自己的定位祖先建了上下文。
|
|
24
|
+
作者要把它放在别处(比如浮在内容之上、或摆到框外),改这一条即可。 */
|
|
25
|
+
[data-scope='scrollbar'][data-part='root'] {
|
|
26
|
+
/* 厚度只算一次:尺寸档换的就是它,交叉口的让位与补丁都按同一个数 */
|
|
27
|
+
--xh-_scrollbar-thickness: var(--xh-scrollbar-thickness-md);
|
|
28
|
+
|
|
29
|
+
position: absolute;
|
|
30
|
+
/* 浮层的 positioner 一律 pointer-events: none,条子作为它的子节点会继承到,拖不动也点不着;
|
|
31
|
+
收起态那条规则优先级更高,仍旧穿透 */
|
|
32
|
+
pointer-events: auto;
|
|
33
|
+
/* touch-action 关掉浏览器自己的手势:不关的话手指一按滑块页面就跟着滚,
|
|
34
|
+
指针随即被系统收走(pointercancel),拖到一半的滑块停在原地。
|
|
35
|
+
user-select 同理——拖动时选中页面文字会让滑块"粘"住。 */
|
|
36
|
+
touch-action: none;
|
|
37
|
+
user-select: none;
|
|
38
|
+
/* 露出与收起都淡变;收起态连 visibility 一起收,退场播完才真正摸不到、也进不了 Tab 序 */
|
|
39
|
+
transition:
|
|
40
|
+
opacity var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
|
|
41
|
+
visibility 0s linear 0s;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
[data-scope='scrollbar'][data-part='root'][data-size='sm'] {
|
|
45
|
+
--xh-_scrollbar-thickness: var(--xh-scrollbar-thickness-sm);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[data-scope='scrollbar'][data-part='root'][data-size='lg'] {
|
|
49
|
+
--xh-_scrollbar-thickness: var(--xh-scrollbar-thickness-lg);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
[data-scope='scrollbar'][data-part='root'][data-orientation='vertical'] {
|
|
53
|
+
inset-block: 0;
|
|
54
|
+
inset-inline-end: 0;
|
|
55
|
+
inline-size: var(--xh-_scrollbar-thickness);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-scope='scrollbar'][data-part='root'][data-orientation='horizontal'] {
|
|
59
|
+
inset-inline: 0;
|
|
60
|
+
inset-block-end: 0;
|
|
61
|
+
block-size: var(--xh-_scrollbar-thickness);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* 横竖两条同时摆着:各自在末端让出交叉口那一格,交叉口由 corner 补 */
|
|
65
|
+
[data-scope='scrollbar'][data-part='root'][data-orientation='vertical'][data-gutter] {
|
|
66
|
+
inset-block-end: var(--xh-_scrollbar-thickness);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-scope='scrollbar'][data-part='root'][data-orientation='horizontal'][data-gutter] {
|
|
70
|
+
inset-inline-end: var(--xh-_scrollbar-thickness);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[data-scope='scrollbar'][data-part='root'][data-state='hidden'] {
|
|
74
|
+
visibility: hidden;
|
|
75
|
+
opacity: 0;
|
|
76
|
+
pointer-events: none;
|
|
77
|
+
transition:
|
|
78
|
+
opacity var(--xh-motion-duration-exit) var(--xh-motion-ease-exit),
|
|
79
|
+
visibility 0s linear var(--xh-motion-duration-exit);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* 触屏上交给原生滚动:整条不占位也不画 */
|
|
83
|
+
[data-scope='scrollbar'][data-part='root'][data-native] {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* 轨道铺满根,滑块的行程按它量。内边距把滑块从两侧收进来一点,
|
|
88
|
+
与 scroll-area 那份共用同一个间隙令牌 */
|
|
89
|
+
[data-scope='scrollbar'][data-part='track'] {
|
|
90
|
+
position: relative;
|
|
91
|
+
inline-size: 100%;
|
|
92
|
+
block-size: 100%;
|
|
93
|
+
padding: var(--xh-scrollbar-gutter);
|
|
94
|
+
background: var(--xh-scrollbar-track-bg, var(--xh-bg-scrollbar-track));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* 滑块。主轴(起点 + 长度)来自内联样式,这里只给定位模式、交叉轴与配色。
|
|
98
|
+
绝不给 inset / size 加过渡:滚动时这两个值每帧都在变,一加过渡滑块就永远追在内容后面。
|
|
99
|
+
也刻意不写 min-block-size / min-inline-size:滑块的最短长度由几何层折进内联尺寸里,
|
|
100
|
+
样式表再给一个下限就成了两个事实源,两者一旦不一致,滑块的实际长度与它能走的距离就对不上。 */
|
|
101
|
+
[data-scope='scrollbar'][data-part='thumb'] {
|
|
102
|
+
position: absolute;
|
|
103
|
+
border-radius: var(--xh-scrollbar-thumb-radius, var(--xh-shape-pill));
|
|
104
|
+
background: var(--xh-scrollbar-thumb-bg, var(--xh-fg-scrollbar-thumb));
|
|
105
|
+
cursor: default;
|
|
106
|
+
transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* 交叉轴在轨道内两侧各收进一个间隙,与轨道那条 padding 共用同一个旋钮。
|
|
110
|
+
这一侧的 inset 连接层每帧写成空串(即不设),样式表接手才有确定值;
|
|
111
|
+
不写的话绝对定位会退回"静态位置"。
|
|
112
|
+
主轴那一侧一律不写:几何层量的轨道是 padding box,滑块长度也解析在同一个盒子上。 */
|
|
113
|
+
[data-scope='scrollbar'][data-part='thumb'][data-orientation='vertical'] {
|
|
114
|
+
inset-inline: var(--xh-scrollbar-gutter);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
[data-scope='scrollbar'][data-part='thumb'][data-orientation='horizontal'] {
|
|
118
|
+
inset-block: var(--xh-scrollbar-gutter);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[data-scope='scrollbar'][data-part='thumb']:hover {
|
|
122
|
+
background: var(--xh-scrollbar-thumb-bg-hover, var(--xh-fg-scrollbar-thumb-hover));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
[data-scope='scrollbar'][data-part='thumb'][data-dragging] {
|
|
126
|
+
background: var(--xh-scrollbar-thumb-bg-active, var(--xh-fg-scrollbar-thumb-active));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* 只有开了 focusable 的滑块进得了 Tab 序,环也就只画在它身上。
|
|
130
|
+
偏移取负:环画在轨道内侧,否则会被滚动容器的溢出边界裁掉半圈 */
|
|
131
|
+
[data-scope='scrollbar'][data-part='thumb']:focus-visible {
|
|
132
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
133
|
+
outline-offset: calc(-1 * var(--xh-ring-width));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* 根与轨道都是纯容器,不承载焦点;作者若给它们加了 tabindex,也不该在这儿多画一圈 */
|
|
137
|
+
[data-scope='scrollbar'][data-part='root']:focus-visible,
|
|
138
|
+
[data-scope='scrollbar'][data-part='track']:focus-visible {
|
|
139
|
+
outline: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* 禁用:整条不显形,这里只兜住作者硬把它显出来的那一路 */
|
|
143
|
+
[data-scope='scrollbar'][data-part='thumb'][data-disabled] {
|
|
144
|
+
background: var(--xh-scrollbar-thumb-bg-disabled, var(--xh-border-subtle));
|
|
145
|
+
cursor: not-allowed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* 交叉口补丁:贴在本条末端之外的那一格,与轨道同色,跟着本条淡入淡出 */
|
|
149
|
+
[data-scope='scrollbar'][data-part='corner'] {
|
|
150
|
+
position: absolute;
|
|
151
|
+
inline-size: var(--xh-_scrollbar-thickness);
|
|
152
|
+
block-size: var(--xh-_scrollbar-thickness);
|
|
153
|
+
background: var(--xh-scrollbar-corner-bg, var(--xh-scrollbar-track-bg, var(--xh-bg-scrollbar-track)));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
[data-scope='scrollbar'][data-part='corner'][data-orientation='vertical'] {
|
|
157
|
+
inset-inline-start: 0;
|
|
158
|
+
inset-block-end: calc(-1 * var(--xh-_scrollbar-thickness));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
[data-scope='scrollbar'][data-part='corner'][data-orientation='horizontal'] {
|
|
162
|
+
inset-block-start: 0;
|
|
163
|
+
inset-inline-end: calc(-1 * var(--xh-_scrollbar-thickness));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
[data-scope='scrollbar'][data-part='root'][hidden],
|
|
167
|
+
[data-scope='scrollbar'][data-part='corner'][hidden] {
|
|
168
|
+
display: none;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
@layer xihan.components {
|
|
2
|
+
/* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
|
|
3
|
+
[data-scope='segmented'] {
|
|
4
|
+
--xh-segmented-skin: 1;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* 一条轨道装着若干段,指示器在轨道里滑。指示器是绝对定位的,
|
|
8
|
+
root 必须是它的定位参照系;段与段之间不留缝,所以不设 gap */
|
|
9
|
+
[data-scope='segmented'][data-part='root'] {
|
|
10
|
+
/* 尺寸档只换这四个私有槽,段与文字从 root 继承它们,换档不必给每个部件各写一条选择器 */
|
|
11
|
+
--xh-_segmented-h: var(--xh-control-h-md);
|
|
12
|
+
--xh-_segmented-px: var(--xh-control-px-md);
|
|
13
|
+
--xh-_segmented-gap: var(--xh-control-gap-md);
|
|
14
|
+
--xh-_segmented-font-size: var(--xh-control-font-md);
|
|
15
|
+
/* 指示器底色与选中段的文字色;没写 data-tone 时就是这里的取值 */
|
|
16
|
+
--xh-_segmented-indicator-bg: var(--xh-bg-surface);
|
|
17
|
+
--xh-_segmented-fg-selected: var(--xh-fg-default);
|
|
18
|
+
|
|
19
|
+
position: relative;
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: stretch;
|
|
22
|
+
padding: var(--xh-segmented-track-padding, var(--xh-space-0_5));
|
|
23
|
+
border: var(--xh-stroke-thin) solid var(--xh-segmented-border, var(--xh-border-subtle));
|
|
24
|
+
border-radius: var(--xh-segmented-radius, var(--xh-shape-control));
|
|
25
|
+
background: var(--xh-segmented-bg, var(--xh-bg-subtle));
|
|
26
|
+
font-size: var(--xh-segmented-font-size, var(--xh-_segmented-font-size));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* 横排时外盒整体就是一档控件高:段被 align-items: stretch 撑满轨道内侧,与同行控件齐平 */
|
|
30
|
+
[data-scope='segmented'][data-part='root'][data-orientation='horizontal'] {
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
block-size: var(--xh-segmented-h, var(--xh-_segmented-h));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[data-scope='segmented'][data-part='root'][data-orientation='horizontal'] [data-scope='segmented'][data-part='item'] {
|
|
36
|
+
block-size: auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-scope='segmented'][data-part='root'][data-orientation='vertical'] {
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* 撑满行宽:各段等分剩余空间,长短不一的文字也排得齐 */
|
|
44
|
+
[data-scope='segmented'][data-part='root'][data-block] {
|
|
45
|
+
display: flex;
|
|
46
|
+
inline-size: 100%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* 等分只在横排成立:竖排的主轴是块轴,flex-basis: 0 会顶掉段自己的高度档,
|
|
50
|
+
段高改由「等分容器高度」决定,三档控件高度从此对它没有作用。
|
|
51
|
+
竖排下段本来就靠上面那条 inline-size: 100% 与 align-items: stretch 撑满宽度 */
|
|
52
|
+
[data-scope='segmented'][data-part='root'][data-block][data-orientation='horizontal']
|
|
53
|
+
> [data-scope='segmented'][data-part='item'] {
|
|
54
|
+
flex: 1 1 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* root 会短暂拿到 tabindex=0,但它的 onFocus 立刻把焦点转投给段,
|
|
58
|
+
在它身上画环只会闪一下就跳走,高亮要长在段上 */
|
|
59
|
+
[data-scope='segmented'][data-part='root']:focus-visible {
|
|
60
|
+
outline: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
[data-scope='segmented'][data-part='root'][data-invalid] {
|
|
64
|
+
border-color: var(--xh-segmented-border-invalid, var(--xh-border-invalid));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[data-scope='segmented'][data-part='root'][data-disabled] {
|
|
68
|
+
background: var(--xh-segmented-bg-disabled, var(--xh-bg-muted));
|
|
69
|
+
cursor: not-allowed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* 整组禁用时指示器落回轨道平面(不再浮起),但底色一点不兑淡:
|
|
73
|
+
它上面压着选中段的文字,往 muted 兑哪怕一成,brand 的对比度就从 5.08 掉到 4.24 */
|
|
74
|
+
[data-scope='segmented'][data-part='root'][data-disabled]
|
|
75
|
+
[data-scope='segmented'][data-part='indicator'] {
|
|
76
|
+
box-shadow: var(--xh-segmented-indicator-shadow-disabled, none);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* —— 语气 —— */
|
|
80
|
+
/* 选择器带 [data-tone] 限定:不限定的话,放在语气容器里的分段控件会跟着改色 */
|
|
81
|
+
[data-scope='segmented'][data-part='root'][data-tone] {
|
|
82
|
+
--xh-_segmented-indicator-bg: var(--xh-_tone, var(--xh-bg-surface));
|
|
83
|
+
--xh-_segmented-fg-selected: var(--xh-_tone-on, var(--xh-fg-default));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* —— 尺寸 —— */
|
|
87
|
+
/* 缺省的 md 档写在上面的基础规则里 */
|
|
88
|
+
[data-scope='segmented'][data-part='root'][data-size='sm'] {
|
|
89
|
+
--xh-_segmented-h: var(--xh-control-h-sm);
|
|
90
|
+
--xh-_segmented-px: var(--xh-control-px-sm);
|
|
91
|
+
--xh-_segmented-gap: var(--xh-control-gap-sm);
|
|
92
|
+
--xh-_segmented-font-size: var(--xh-control-font-sm);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
[data-scope='segmented'][data-part='root'][data-size='lg'] {
|
|
96
|
+
--xh-_segmented-h: var(--xh-control-h-lg);
|
|
97
|
+
--xh-_segmented-px: var(--xh-control-px-lg);
|
|
98
|
+
--xh-_segmented-gap: var(--xh-control-gap-lg);
|
|
99
|
+
--xh-_segmented-font-size: var(--xh-control-font-lg);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* 段自己也定位,于是与绝对定位的指示器按文档序比高低:
|
|
103
|
+
指示器写在段之前,段与它的焦点环便压在指示器上面,不必动层号 */
|
|
104
|
+
[data-scope='segmented'][data-part='item'] {
|
|
105
|
+
position: relative;
|
|
106
|
+
display: inline-flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
gap: var(--xh-segmented-item-gap, var(--xh-_segmented-gap));
|
|
110
|
+
block-size: var(--xh-segmented-item-h, var(--xh-_segmented-h));
|
|
111
|
+
padding-inline: var(--xh-segmented-item-px, var(--xh-_segmented-px));
|
|
112
|
+
border: 0;
|
|
113
|
+
border-radius: var(--xh-segmented-item-radius, var(--xh-shape-inset));
|
|
114
|
+
background: transparent;
|
|
115
|
+
color: var(--xh-segmented-item-fg, var(--xh-fg-muted));
|
|
116
|
+
/* 按钮不继承宿主字体,尺寸档在 root 上,两者都要显式接过来 */
|
|
117
|
+
font-family: inherit;
|
|
118
|
+
font-size: inherit;
|
|
119
|
+
font-weight: var(--xh-segmented-item-font-weight, var(--xh-text-label-weight));
|
|
120
|
+
line-height: var(--xh-leading-none);
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
user-select: none;
|
|
124
|
+
transition:
|
|
125
|
+
color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
|
|
126
|
+
background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
|
|
127
|
+
scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* 选中态:单选是 role=radio + aria-checked,样式一律读 data-state,不读 ARIA。
|
|
131
|
+
文字色也要跟着变——指示器是可选部件,作者不渲染它时"当前是哪一段"仍然要看得出来 */
|
|
132
|
+
[data-scope='segmented'][data-part='item'][data-state='checked'] {
|
|
133
|
+
color: var(--xh-segmented-item-fg-checked, var(--xh-_segmented-fg-selected));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* 悬停只提亮未选中的那几段:选中段的底下压着指示器,再变色就成了两套强调。
|
|
137
|
+
底色用中性的悬停档——它是「指哪一段」的轻反馈,不表达选中 */
|
|
138
|
+
[data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-state='checked']):hover {
|
|
139
|
+
background-color: var(--xh-segmented-item-bg-hover, var(--xh-bg-subtle-hover));
|
|
140
|
+
color: var(--xh-segmented-item-fg-hover, var(--xh-fg-default));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* 按下去要有回应:整段轻微下压,松手即弹回。选中段也压——按在已选段上同样是一次点击。
|
|
144
|
+
只读段不压:它本来就不接受改值,压下去等于骗人 */
|
|
145
|
+
[data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-readonly]):active {
|
|
146
|
+
scale: var(--xh-segmented-item-press-scale, var(--xh-motion-scale-press));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* 只读:值改不动,但对比度不降,光标也不摆出"禁止"的样子 */
|
|
150
|
+
[data-scope='segmented'][data-part='item'][data-readonly] {
|
|
151
|
+
cursor: default;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* 集合条目一律 aria-disabled 而非原生 disabled(禁用段仍要能当方向键的起点),
|
|
155
|
+
所以这里读 data-disabled,写 :disabled 永远不命中。
|
|
156
|
+
用了 fg-disabled 就不再叠 opacity:半透明会把底下的指示器透出来 */
|
|
157
|
+
[data-scope='segmented'][data-part='item'][data-disabled] {
|
|
158
|
+
color: var(--xh-fg-disabled);
|
|
159
|
+
cursor: not-allowed;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* 禁用且选中的那一段不换文字色:它压着的是指示器的实心底,换成 fg-disabled 后
|
|
163
|
+
六族语气实测只剩 1.04–3.01 的对比度,「当前选的是哪一段」当场看不见。
|
|
164
|
+
禁用由轨道底色、未选中段的文字色与光标表达,选中段保持可读 */
|
|
165
|
+
[data-scope='segmented'][data-part='item'][data-disabled][data-state='checked'] {
|
|
166
|
+
color: var(--xh-segmented-item-fg-checked-disabled, var(--xh-_segmented-fg-selected));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* 焦点环往内收一格:段贴着轨道内缘,往外画会被 root 的描边切掉一半 */
|
|
170
|
+
[data-scope='segmented'][data-part='item']:focus-visible {
|
|
171
|
+
outline: var(--xh-ring-width) solid var(--xh-ring-focus);
|
|
172
|
+
outline-offset: calc(-1 * var(--xh-ring-offset));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
[data-scope='segmented'][data-part='item-text'] {
|
|
176
|
+
color: inherit;
|
|
177
|
+
user-select: none;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
[data-scope='segmented'][data-part='indicator'] {
|
|
181
|
+
/* 位置与尺寸由连接层量好写成内联样式(它量得到,样式表量不到);
|
|
182
|
+
这四个是还没量到时的落点,量到即被内联样式盖过 */
|
|
183
|
+
--xh-_segmented-indicator-x: 0;
|
|
184
|
+
--xh-_segmented-indicator-y: 0;
|
|
185
|
+
--xh-_segmented-indicator-w: 0;
|
|
186
|
+
--xh-_segmented-indicator-h: 0;
|
|
187
|
+
|
|
188
|
+
position: absolute;
|
|
189
|
+
display: block;
|
|
190
|
+
inset-inline-start: var(--xh-_segmented-indicator-x);
|
|
191
|
+
inset-block-start: var(--xh-_segmented-indicator-y);
|
|
192
|
+
inline-size: var(--xh-_segmented-indicator-w);
|
|
193
|
+
block-size: var(--xh-_segmented-indicator-h);
|
|
194
|
+
border-radius: var(--xh-segmented-indicator-radius, var(--xh-shape-inset));
|
|
195
|
+
background: var(--xh-segmented-indicator-bg, var(--xh-_segmented-indicator-bg));
|
|
196
|
+
box-shadow: var(--xh-segmented-indicator-shadow, var(--xh-elevation-raised));
|
|
197
|
+
/* 段压在它上面,点击一律交给段;作者把它写在段之后时也不至于吞掉点击 */
|
|
198
|
+
pointer-events: none;
|
|
199
|
+
/* 用标准曲线而不是进场那条:滑块是被推过去的,起步就该有速度,
|
|
200
|
+
纯减速曲线看着像自己飘过去。四个几何量同时走,段宽不等时才不会先变形再挪位 */
|
|
201
|
+
transition:
|
|
202
|
+
inset-inline-start var(--xh-motion-duration-enter) var(--xh-ease-standard),
|
|
203
|
+
inset-block-start var(--xh-motion-duration-enter) var(--xh-ease-standard),
|
|
204
|
+
inline-size var(--xh-motion-duration-enter) var(--xh-ease-standard),
|
|
205
|
+
block-size var(--xh-motion-duration-enter) var(--xh-ease-standard);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
|
|
209
|
+
不补的话作者给节点加 hidden 后它照样显示 */
|
|
210
|
+
[data-scope='segmented'][data-part='root'][hidden],
|
|
211
|
+
[data-scope='segmented'][data-part='item'][hidden],
|
|
212
|
+
[data-scope='segmented'][data-part='indicator'][hidden] {
|
|
213
|
+
display: none;
|
|
214
|
+
}
|
|
215
|
+
}
|