@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.
Files changed (114) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +27 -0
  4. package/css/accordion.css +108 -0
  5. package/css/affix.css +27 -0
  6. package/css/alert.css +108 -0
  7. package/css/anchor.css +137 -0
  8. package/css/avatar-group.css +82 -0
  9. package/css/avatar.css +55 -0
  10. package/css/back-top.css +61 -0
  11. package/css/badge.css +50 -0
  12. package/css/breadcrumb.css +127 -0
  13. package/css/button-group.css +131 -0
  14. package/css/button.css +98 -0
  15. package/css/calendar.css +219 -0
  16. package/css/card.css +116 -0
  17. package/css/carousel.css +193 -0
  18. package/css/cascader.css +397 -0
  19. package/css/checkbox-group.css +185 -0
  20. package/css/checkbox.css +91 -0
  21. package/css/clipboard.css +133 -0
  22. package/css/code-block.css +81 -0
  23. package/css/collapsible.css +63 -0
  24. package/css/color-picker.css +424 -0
  25. package/css/combobox.css +433 -0
  26. package/css/composer.css +127 -0
  27. package/css/context-menu.css +263 -0
  28. package/css/countdown.css +21 -0
  29. package/css/date-field.css +200 -0
  30. package/css/date-picker.css +231 -0
  31. package/css/descriptions.css +200 -0
  32. package/css/dialog.css +127 -0
  33. package/css/drawer.css +372 -0
  34. package/css/dynamic-input.css +157 -0
  35. package/css/editable.css +249 -0
  36. package/css/ellipsis.css +41 -0
  37. package/css/empty-state.css +78 -0
  38. package/css/field.css +65 -0
  39. package/css/file-upload.css +298 -0
  40. package/css/flex.css +95 -0
  41. package/css/float-button.css +121 -0
  42. package/css/form.css +185 -0
  43. package/css/gradient-text.css +62 -0
  44. package/css/grid.css +428 -0
  45. package/css/highlight.css +21 -0
  46. package/css/hover-card.css +146 -0
  47. package/css/icon-wrapper.css +64 -0
  48. package/css/icon.css +54 -0
  49. package/css/image.css +45 -0
  50. package/css/infinite-scroll.css +22 -0
  51. package/css/layers.css +2 -0
  52. package/css/layout.css +169 -0
  53. package/css/list.css +117 -0
  54. package/css/listbox.css +174 -0
  55. package/css/loading-bar.css +66 -0
  56. package/css/log.css +66 -0
  57. package/css/marquee.css +182 -0
  58. package/css/mention.css +222 -0
  59. package/css/menu.css +144 -0
  60. package/css/menubar.css +271 -0
  61. package/css/motion.css +58 -0
  62. package/css/navigation-menu.css +270 -0
  63. package/css/number-animation.css +32 -0
  64. package/css/number-field.css +219 -0
  65. package/css/page-header.css +85 -0
  66. package/css/pagination.css +148 -0
  67. package/css/pin-input.css +157 -0
  68. package/css/popconfirm.css +150 -0
  69. package/css/popover.css +150 -0
  70. package/css/popselect.css +207 -0
  71. package/css/progress.css +37 -0
  72. package/css/qr-code.css +50 -0
  73. package/css/radio-group.css +101 -0
  74. package/css/rating.css +141 -0
  75. package/css/reset.css +22 -0
  76. package/css/result.css +104 -0
  77. package/css/scroll-area.css +176 -0
  78. package/css/select.css +264 -0
  79. package/css/separator.css +17 -0
  80. package/css/skeleton.css +78 -0
  81. package/css/slider.css +197 -0
  82. package/css/spinner.css +74 -0
  83. package/css/splitter.css +127 -0
  84. package/css/statistic.css +67 -0
  85. package/css/steps.css +252 -0
  86. package/css/switch.css +61 -0
  87. package/css/table.css +404 -0
  88. package/css/tabs.css +157 -0
  89. package/css/tags-input.css +360 -0
  90. package/css/text-field.css +195 -0
  91. package/css/thread.css +107 -0
  92. package/css/time-field.css +200 -0
  93. package/css/time-picker.css +347 -0
  94. package/css/time.css +20 -0
  95. package/css/timeline.css +284 -0
  96. package/css/toast.css +195 -0
  97. package/css/toaster.css +69 -0
  98. package/css/toggle-group.css +160 -0
  99. package/css/toggle.css +103 -0
  100. package/css/tone.css +85 -0
  101. package/css/toolbar.css +114 -0
  102. package/css/tooltip.css +109 -0
  103. package/css/tour.css +305 -0
  104. package/css/transfer.css +318 -0
  105. package/css/tree-select.css +441 -0
  106. package/css/tree.css +204 -0
  107. package/css/typography.css +151 -0
  108. package/css/undefined.css +38 -0
  109. package/css/virtualizer.css +104 -0
  110. package/css/visually-hidden.css +13 -0
  111. package/css/watermark.css +48 -0
  112. package/index.css +113 -0
  113. package/index.unlayered.css +16164 -0
  114. package/package.json +163 -0
package/css/slider.css ADDED
@@ -0,0 +1,197 @@
1
+ @layer xihan.components {
2
+ /* 定位分工:已选区间与拇指在**主轴**上的起点与长度,由连接层每帧写进内联样式——
3
+ 水平是 inset-inline-start / inline-size,竖直是 inset-block-end / block-size。
4
+ 这份皮肤一个都不碰:内联优先级高于样式表,写了不但是死声明,
5
+ 切换 orientation 的那一帧还会跟连接层清空另一轴的动作抢位置,把拇指钉在两轴都被约束的地方。
6
+ 皮肤只管另一条轴(交叉轴)的尺寸、颜色、圆角与状态表现。 */
7
+
8
+ /* 私有槽位:组件令牌 → 中档字面量两级回退。轨道厚度与拇指直径同时被 control / track / thumb
9
+ 三个角色节点用到,收成两个槽位挂在 root 上,尺寸档只改这两处,靠继承发到子部件。 */
10
+ [data-scope='slider'][data-part='root'] {
11
+ --xh-_thumb-size: var(--xh-slider-thumb-size, 18px);
12
+ --xh-_track-thickness: var(--xh-slider-track-thickness, 6px);
13
+
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: var(--xh-slider-gap, var(--xh-stack-gap-md));
17
+ }
18
+
19
+ /* 竖排时整条控件收成一块,不再撑满一行:宽度由拇指直径决定 */
20
+ [data-scope='slider'][data-part='root'][data-orientation='vertical'] {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ }
24
+
25
+ /* 禁用的整体压暗只做一次,落在最外层:track / range / thumb 各自再叠一层 opacity 会越叠越黑 */
26
+ [data-scope='slider'][data-part='root'][data-disabled] {
27
+ cursor: not-allowed;
28
+ opacity: var(--xh-state-disabled-opacity);
29
+ }
30
+
31
+ [data-scope='slider'][data-part='label'] {
32
+ color: var(--xh-slider-label-fg, var(--xh-fg-muted));
33
+ font-size: var(--xh-slider-label-font-size, var(--xh-text-label-size));
34
+ font-weight: var(--xh-slider-label-font-weight, var(--xh-text-label-weight));
35
+ line-height: var(--xh-leading-none);
36
+ }
37
+
38
+ [data-scope='slider'][data-part='label'][data-disabled] {
39
+ color: var(--xh-fg-subtle);
40
+ }
41
+
42
+ /* 拇指以它为定位上下文(拇指常常浮出轨道,挂在 track 上会被轨道的盒子束住)。
43
+ 厚度取拇指直径:轨道只有几个像素,控件若按轨道高,浮出来的拇指会顶到上下相邻的元素。
44
+ touch-action 由连接层内联给(拖动要接管手势),这里不写。 */
45
+ [data-scope='slider'][data-part='control'] {
46
+ position: relative;
47
+ display: flex;
48
+ align-items: center;
49
+ block-size: var(--xh-_thumb-size);
50
+ cursor: pointer;
51
+ }
52
+
53
+ [data-scope='slider'][data-part='control'][data-orientation='vertical'] {
54
+ flex-direction: column;
55
+ justify-content: center;
56
+ inline-size: var(--xh-_thumb-size);
57
+ block-size: var(--xh-slider-vertical-length, 10rem);
58
+ }
59
+
60
+ /* 按下轨道即跳,拖动中光标换成"抓着"的样子,手感与拇指一致 */
61
+ [data-scope='slider'][data-part='control'][data-dragging] {
62
+ cursor: grabbing;
63
+ }
64
+
65
+ [data-scope='slider'][data-part='control'][data-readonly] {
66
+ cursor: default;
67
+ }
68
+
69
+ [data-scope='slider'][data-part='control'][data-disabled] {
70
+ cursor: not-allowed;
71
+ }
72
+
73
+ /* 已选区间以它为定位上下文。不写 overflow: hidden:作者把拇指写进轨道里也是合法结构,
74
+ 一裁就把拇指切掉半个;区间的圆角由它自己那条 border-radius 兜住,本就不靠轨道来裁。 */
75
+ [data-scope='slider'][data-part='track'] {
76
+ position: relative;
77
+ border-radius: var(--xh-slider-track-radius, var(--xh-shape-pill));
78
+ background: var(--xh-slider-track-bg, var(--xh-bg-subtle-active));
79
+ }
80
+
81
+ [data-scope='slider'][data-part='track'][data-orientation='horizontal'] {
82
+ inline-size: 100%;
83
+ block-size: var(--xh-_track-thickness);
84
+ }
85
+
86
+ [data-scope='slider'][data-part='track'][data-orientation='vertical'] {
87
+ block-size: 100%;
88
+ inline-size: var(--xh-_track-thickness);
89
+ }
90
+
91
+ /* 主轴(起点 + 长度)来自内联样式,这里只给定位模式与配色。
92
+ 绝不给 inset / size 加过渡:拖拽时这两个值每帧都在变,一加过渡区间就永远追在指针后面。
93
+ 语气槽由 root 上的 data-tone 声明、经继承发下来;没写 data-tone 时退回原来的品牌色。
94
+ 轨道不跟着换族:区间与拇指换色即可读出语气,底槽保持中性才不会盖掉"已选/未选"的对比。 */
95
+ [data-scope='slider'][data-part='range'] {
96
+ position: absolute;
97
+ border-radius: var(--xh-slider-range-radius, var(--xh-shape-pill));
98
+ background: var(--xh-slider-range-bg, var(--xh-_tone, var(--xh-bg-brand)));
99
+ }
100
+
101
+ /* 交叉轴铺满轨道。这一侧的 inset 连接层每帧写成空串(即不设),样式表接手才有确定值;
102
+ 不写的话绝对定位会退回"静态位置",作者一给轨道加内边距就对不齐了。 */
103
+ [data-scope='slider'][data-part='range'][data-orientation='horizontal'] {
104
+ inset-block-start: 0;
105
+ block-size: 100%;
106
+ }
107
+
108
+ [data-scope='slider'][data-part='range'][data-orientation='vertical'] {
109
+ inset-inline-start: 0;
110
+ inline-size: 100%;
111
+ }
112
+
113
+ [data-scope='slider'][data-part='range'][data-invalid] {
114
+ background: var(--xh-slider-range-bg-invalid, var(--xh-color-danger-500));
115
+ }
116
+
117
+ /* 圆点浮在轨道之上:轨道是流内的,拇指是绝对定位的,天然后来居上,不必再堆 z-index。
118
+ box-sizing 必须显式写:描边要吃进直径里,否则实际盒子比 --xh-_thumb-size 宽两条边,
119
+ 下面按半个直径回拉的负外边距就对不上圆心。 */
120
+ [data-scope='slider'][data-part='thumb'] {
121
+ position: absolute;
122
+ box-sizing: border-box;
123
+ inline-size: var(--xh-_thumb-size);
124
+ block-size: var(--xh-_thumb-size);
125
+ border: var(--xh-stroke-thick) solid var(--xh-slider-thumb-border, var(--xh-bg-surface));
126
+ border-radius: var(--xh-slider-thumb-radius, var(--xh-shape-pill));
127
+ background: var(--xh-slider-thumb-bg, var(--xh-_tone, var(--xh-bg-brand)));
128
+ box-shadow: var(--xh-slider-thumb-shadow, var(--xh-elevation-1));
129
+ cursor: grab;
130
+ transition: scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
131
+ }
132
+
133
+ /* 内联样式把 inset-inline-start 定在值所在的比例上,那是拇指的**起始边**不是圆心;
134
+ 用负的逻辑外边距回拉半个直径,圆心才落在比例点上。
135
+ 这里刻意不用 translate(-50%):rtl 下 inset-inline-start 映射到 right,
136
+ 位移量是物理方向的,会把拇指推向错误的一侧;负的逻辑外边距自己就跟着换向。
137
+ 交叉轴同理:inset-block-start 是连接层不写的那条轴,样式表接管即可。 */
138
+ [data-scope='slider'][data-part='thumb'][data-orientation='horizontal'] {
139
+ inset-block-start: 50%;
140
+ margin-block-start: calc(var(--xh-_thumb-size) / -2);
141
+ margin-inline-start: calc(var(--xh-_thumb-size) / -2);
142
+ }
143
+
144
+ /* 竖排的主轴是 inset-block-end(值向上增大),回拉也就换到 block-end 那侧 */
145
+ [data-scope='slider'][data-part='thumb'][data-orientation='vertical'] {
146
+ inset-inline-start: 50%;
147
+ margin-inline-start: calc(var(--xh-_thumb-size) / -2);
148
+ margin-block-end: calc(var(--xh-_thumb-size) / -2);
149
+ }
150
+
151
+ [data-scope='slider'][data-part='thumb']:focus-visible {
152
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
153
+ outline-offset: var(--xh-ring-offset);
154
+ }
155
+
156
+ /* 多拇指时只有手真正推着的那一个带 data-dragging,放大与光标因此不会全组一起变。
157
+ 放大用 scale 而不是改尺寸:变换绕自身中心发生,圆心不动,负外边距的算式也不用跟着改。 */
158
+ [data-scope='slider'][data-part='thumb'][data-dragging] {
159
+ scale: var(--xh-slider-thumb-scale-dragging, 1.12);
160
+ cursor: grabbing;
161
+ box-shadow: var(--xh-slider-thumb-shadow-dragging, var(--xh-elevation-2));
162
+ }
163
+
164
+ [data-scope='slider'][data-part='thumb'][data-invalid] {
165
+ background: var(--xh-slider-thumb-bg-invalid, var(--xh-color-danger-500));
166
+ }
167
+
168
+ [data-scope='slider'][data-part='thumb'][data-readonly] {
169
+ cursor: default;
170
+ }
171
+
172
+ [data-scope='slider'][data-part='thumb'][data-disabled] {
173
+ cursor: not-allowed;
174
+ }
175
+
176
+ /* —— 尺寸 —— */
177
+ /* 尺寸只改 root 上那两个槽位,control / track / thumb 跟着一起走;中间档不写规则,缺省即中档。
178
+ 两档都保持"拇指是轨道的三倍厚"这个比例,换档时圆点与底槽的关系看着不变。 */
179
+ [data-scope='slider'][data-part='root'][data-size='sm'] {
180
+ --xh-_thumb-size: var(--xh-slider-thumb-size, var(--xh-space-3));
181
+ --xh-_track-thickness: var(--xh-slider-track-thickness, var(--xh-space-1));
182
+ }
183
+
184
+ [data-scope='slider'][data-part='root'][data-size='lg'] {
185
+ --xh-_thumb-size: var(--xh-slider-thumb-size, var(--xh-space-6));
186
+ --xh-_track-thickness: var(--xh-slider-track-thickness, var(--xh-space-2));
187
+ }
188
+
189
+ /* display 会盖掉 UA 的 [hidden]{display:none},凡是被赋了 display 的角色节点都要显式让位 */
190
+ [data-scope='slider'][data-part='root'][hidden],
191
+ [data-scope='slider'][data-part='control'][hidden] {
192
+ display: none;
193
+ }
194
+
195
+ /* hidden-input 是 type=hidden 的原生输入,浏览器本就不渲染它,
196
+ 这里一条声明都不给:给了 display / 尺寸反而会把它拽回布局里,在拇指内部撑出一块空白。 */
197
+ }
@@ -0,0 +1,74 @@
1
+ @layer xihan.components {
2
+ /* 转圈的关键帧定义在本文件里。皮肤可以按需单独引入,
3
+ 引用别处文件里的动画名时那份文件不一定在场,动画会静默地整个不跑 */
4
+ @keyframes xh-spinner-rotate {
5
+ to {
6
+ transform: rotate(1turn);
7
+ }
8
+ }
9
+
10
+ /* 圆环画在伪元素上,root 自身不转:转的只是图形,同一行里的文案要留在原地读得动 */
11
+ [data-scope='spinner'][data-part='root'] {
12
+ display: inline-flex;
13
+ align-items: center;
14
+ gap: var(--xh-spinner-gap, var(--xh-control-gap-md));
15
+ line-height: var(--xh-leading-none);
16
+ vertical-align: middle;
17
+ }
18
+
19
+ [data-scope='spinner'][data-part='root']::before {
20
+ content: '';
21
+
22
+ /* 边框算进直径,换厚度不会把圆环撑大 */
23
+ box-sizing: border-box;
24
+ flex: none;
25
+ inline-size: var(--xh-spinner-size, var(--xh-control-action-size));
26
+ block-size: var(--xh-spinner-size, var(--xh-control-action-size));
27
+ border: var(--xh-spinner-thickness, var(--xh-stroke-thick)) solid var(--xh-spinner-track, var(--xh-border-default));
28
+
29
+ /* 一整圈是轨道色,只有起始边换成前景色,转起来才看得出方向 */
30
+ border-block-start-color: var(--xh-spinner-fg, var(--xh-bg-brand));
31
+ border-radius: var(--xh-spinner-radius, var(--xh-shape-pill));
32
+ animation: xh-spinner-rotate var(--xh-spinner-duration, calc(var(--xh-duration-slow) * 2)) linear infinite;
33
+ }
34
+
35
+ /* 三档直径对齐控件档位,缺省档写在上面的基础规则里 */
36
+ [data-scope='spinner'][data-part='root'][data-size='sm']::before {
37
+ inline-size: var(--xh-control-indicator-size);
38
+ block-size: var(--xh-control-indicator-size);
39
+ }
40
+
41
+ [data-scope='spinner'][data-part='root'][data-size='lg']::before {
42
+ inline-size: var(--xh-control-h-md);
43
+ block-size: var(--xh-control-h-md);
44
+ }
45
+
46
+ /* 语气只换起始边那一段,轨道留在中性描边上:轨道与起始边的反差就是转向的读法,
47
+ 两者同时换成同一族颜色,转到哪儿就看不出来了。
48
+ 选择器上带 [data-tone] 是必需的:语气槽会沿继承流下来,不限定在写了语气的
49
+ 那个节点上,放在语气容器里的转圈会跟着一起改色 */
50
+ [data-scope='spinner'][data-part='root'][data-tone]::before {
51
+ border-block-start-color: var(--xh-spinner-fg, var(--xh-_tone, var(--xh-bg-brand)));
52
+ }
53
+
54
+ [data-scope='spinner'][data-part='label'] {
55
+ color: var(--xh-spinner-label-fg, var(--xh-fg-muted));
56
+ font-size: var(--xh-spinner-label-size, var(--xh-font-size-sm));
57
+ line-height: var(--xh-leading-none);
58
+ }
59
+
60
+ /* 减少动效:圆环停下并整圈换成虚线,静止的形状仍然读得出"这里还没好";
61
+ "在等什么"由 role=status 上的名字与可见文案继续承担 */
62
+ @media (prefers-reduced-motion: reduce) {
63
+ [data-scope='spinner'][data-part='root']::before {
64
+ border-style: dotted;
65
+ border-color: var(--xh-spinner-fg, var(--xh-bg-brand));
66
+ animation: none;
67
+ }
68
+
69
+ /* 静止态整圈同色,语气跟着铺满整圈 */
70
+ [data-scope='spinner'][data-part='root'][data-tone]::before {
71
+ border-color: var(--xh-spinner-fg, var(--xh-_tone, var(--xh-bg-brand)));
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,127 @@
1
+ @layer xihan.components {
2
+ /* 分工:**面板在排布轴上的尺寸**由连接层每帧写进内联样式(flex-basis / flex-grow / flex-shrink)。
3
+ 这份皮肤一条都不碰——内联优先级高于样式表,写了不但是死声明,
4
+ 还会在切换 orientation 的那一帧跟连接层抢位置。皮肤只管排布方向、跨轴尺寸、
5
+ 配色、光标与状态表现。
6
+
7
+ 三个角色节点上的 data-orientation 说的都是**面板怎么排**(与 root 上那条同源);
8
+ 分隔条自身的横竖与它垂直,那件事写在 aria-orientation 上,样式不去读 ARIA。 */
9
+
10
+ [data-scope='splitter'][data-part='root'] {
11
+ display: flex;
12
+ /* 跨轴尺寸由作者给:竖排的分栏必须先有确定的高度,才谈得上把它分成几份 */
13
+ align-items: stretch;
14
+ overflow: hidden;
15
+ border-radius: var(--xh-splitter-radius, var(--xh-shape-surface));
16
+ }
17
+
18
+ [data-scope='splitter'][data-part='root'][data-orientation='horizontal'] {
19
+ flex-direction: row;
20
+ }
21
+
22
+ [data-scope='splitter'][data-part='root'][data-orientation='vertical'] {
23
+ flex-direction: column;
24
+ }
25
+
26
+ /* 纯容器,焦点长在分隔条上,这里画环只会闪一下 */
27
+ [data-scope='splitter'][data-part='root']:focus-visible {
28
+ outline: none;
29
+ }
30
+
31
+ /* 禁用的整体压暗只做一次,落在最外层:面板与分隔条各自再叠一层 opacity 会越叠越黑 */
32
+ [data-scope='splitter'][data-part='root'][data-disabled] {
33
+ opacity: 0.6;
34
+ }
35
+
36
+ /* 拖动期间整块不许选中文字:手在分隔条上来回蹭时会顺带把两侧的正文刷成高亮 */
37
+ [data-scope='splitter'][data-part='root'][data-dragging] {
38
+ user-select: none;
39
+ }
40
+
41
+ /* 拖动中的光标写在容器上而不是分隔条上:那条线只有几像素宽,
42
+ 手一快指针就跑到面板上去了,光标随即变回箭头,看着像拖拽断了 */
43
+ [data-scope='splitter'][data-part='root'][data-orientation='horizontal'][data-dragging] {
44
+ cursor: col-resize;
45
+ }
46
+
47
+ [data-scope='splitter'][data-part='root'][data-orientation='vertical'][data-dragging] {
48
+ cursor: row-resize;
49
+ }
50
+
51
+ /* 面板自己不许把容器撑破:内容再宽也只能溢出自己这一格,
52
+ 否则连接层算好的比例会被一段长文本顶开 */
53
+ [data-scope='splitter'][data-part='panel'] {
54
+ position: relative;
55
+ overflow: hidden;
56
+ }
57
+
58
+ /* flex 项目的自动最小尺寸默认是内容宽,比 flex-basis 更硬——
59
+ 不把它挪开,连接层内联写的 basis / shrink 在内容超宽时会被静默架空。
60
+ 这两条给的不是尺寸,是"允许收到多小"的地板,因此不与内联样式冲突 */
61
+ [data-scope='splitter'][data-part='panel'][data-orientation='horizontal'] {
62
+ min-inline-size: 0;
63
+ }
64
+
65
+ [data-scope='splitter'][data-part='panel'][data-orientation='vertical'] {
66
+ min-block-size: 0;
67
+ }
68
+
69
+ [data-scope='splitter'][data-part='panel']:focus-visible {
70
+ outline: none;
71
+ }
72
+
73
+ /* 折叠到 0 时连边框都不该露出来:留一条缝比留一块面板更像坏了 */
74
+ [data-scope='splitter'][data-part='panel'][data-collapsed] {
75
+ border: none;
76
+ }
77
+
78
+ /* 分隔条自己的粗细归皮肤(连接层不碰它这条轴)。
79
+ flex: none 是必须的:它若跟着一起伸缩,面板的百分比就再也对不上了 */
80
+ [data-scope='splitter'][data-part='resize-trigger'] {
81
+ display: flex;
82
+ flex: none;
83
+ align-items: center;
84
+ justify-content: center;
85
+ background: var(--xh-splitter-trigger-bg, var(--xh-border-default));
86
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
87
+ }
88
+
89
+ [data-scope='splitter'][data-part='resize-trigger'][data-orientation='horizontal'] {
90
+ inline-size: var(--xh-splitter-trigger-thickness, var(--xh-space-1));
91
+ cursor: col-resize;
92
+ }
93
+
94
+ [data-scope='splitter'][data-part='resize-trigger'][data-orientation='vertical'] {
95
+ block-size: var(--xh-splitter-trigger-thickness, var(--xh-space-1));
96
+ cursor: row-resize;
97
+ }
98
+
99
+ [data-scope='splitter'][data-part='resize-trigger']:hover {
100
+ background: var(--xh-splitter-trigger-bg-hover, var(--xh-bg-subtle-active));
101
+ }
102
+
103
+ /* 只有正被拖的那条带 data-dragging:多条分隔条时全高亮就分不出手在哪一条上 */
104
+ [data-scope='splitter'][data-part='resize-trigger'][data-dragging] {
105
+ background: var(--xh-splitter-trigger-bg-dragging, var(--xh-bg-brand));
106
+ }
107
+
108
+ /* 焦点环往里画:分隔条只有几像素粗,往外画的那圈会被 root 的 overflow: hidden 切掉 */
109
+ [data-scope='splitter'][data-part='resize-trigger']:focus-visible {
110
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
111
+ outline-offset: calc(var(--xh-ring-offset) * -1);
112
+ }
113
+
114
+ /* 分隔条是 div、role=separator,原生 disabled 在它身上不生效,
115
+ 禁用只表达成 aria-disabled 与 data-disabled,写 :disabled 永远不命中 */
116
+ [data-scope='splitter'][data-part='resize-trigger'][data-disabled] {
117
+ background: var(--xh-splitter-trigger-bg-disabled, var(--xh-border-subtle));
118
+ cursor: not-allowed;
119
+ }
120
+
121
+ /* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
122
+ 不补的话作者给节点加 hidden 后它照样显示 */
123
+ [data-scope='splitter'][data-part='root'][hidden],
124
+ [data-scope='splitter'][data-part='resize-trigger'][hidden] {
125
+ display: none;
126
+ }
127
+ }
@@ -0,0 +1,67 @@
1
+ @layer xihan.components {
2
+ /* 三个尺寸档只换这几个私有槽,各段从 root 继承它们,换档不必给每个部件各写一条选择器 */
3
+ [data-scope='statistic'][data-part='root'] {
4
+ --xh-_statistic-label-size: var(--xh-font-size-sm);
5
+ --xh-_statistic-value-size: var(--xh-font-size-2xl);
6
+ --xh-_statistic-affix-size: var(--xh-font-size-md);
7
+ --xh-_statistic-row-gap: var(--xh-space-1);
8
+
9
+ /* 折行排布:标签独占一行,前缀、数值、后缀在下一行按基线对齐排在一起 */
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ align-items: baseline;
13
+ /* 前后缀默认贴着数值:货币符号与百分号中间留白就不成一个数了,要间距的写法自己开槽 */
14
+ column-gap: var(--xh-statistic-gap, var(--xh-space-0));
15
+ row-gap: var(--xh-statistic-row-gap, var(--xh-_statistic-row-gap));
16
+ color: var(--xh-statistic-fg, var(--xh-fg-default));
17
+ }
18
+
19
+ /* 上面声明了 display,会盖掉 UA 的 [hidden] 规则,收起态要在这里接回来 */
20
+ [data-scope='statistic'][data-part='root'][hidden] {
21
+ display: none;
22
+ }
23
+
24
+ /* —— 尺寸 —— */
25
+ [data-scope='statistic'][data-part='root'][data-size='sm'] {
26
+ --xh-_statistic-label-size: var(--xh-font-size-xs);
27
+ --xh-_statistic-value-size: var(--xh-font-size-xl);
28
+ --xh-_statistic-affix-size: var(--xh-font-size-sm);
29
+ --xh-_statistic-row-gap: var(--xh-space-0_5);
30
+ }
31
+
32
+ [data-scope='statistic'][data-part='root'][data-size='lg'] {
33
+ --xh-_statistic-label-size: var(--xh-font-size-md);
34
+ --xh-_statistic-value-size: var(--xh-font-size-3xl);
35
+ --xh-_statistic-affix-size: var(--xh-font-size-lg);
36
+ --xh-_statistic-row-gap: var(--xh-space-1_5);
37
+ }
38
+
39
+ /* —— 各段 —— */
40
+ /* 占满一整行,把前缀、数值、后缀挤到下一行去 */
41
+ [data-scope='statistic'][data-part='label'] {
42
+ flex: 0 0 100%;
43
+ color: var(--xh-statistic-label-fg, var(--xh-fg-muted));
44
+ font-size: var(--xh-statistic-label-font-size, var(--xh-_statistic-label-size));
45
+ font-weight: var(--xh-font-weight-regular);
46
+ line-height: var(--xh-leading-normal);
47
+ }
48
+
49
+ /* 等宽数字:逐位宽度一致,数值刷新时后面的字符不会左右挪动 */
50
+ [data-scope='statistic'][data-part='value'] {
51
+ color: var(--xh-statistic-value-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
52
+ font-size: var(--xh-statistic-value-font-size, var(--xh-_statistic-value-size));
53
+ font-variant-numeric: tabular-nums;
54
+ font-weight: var(--xh-font-weight-semibold);
55
+ line-height: var(--xh-leading-tight);
56
+ }
57
+
58
+ /* 前后缀比数值小一档、跟着数值的语气走;没写语气时退成弱前景 */
59
+ [data-scope='statistic'][data-part='prefix'],
60
+ [data-scope='statistic'][data-part='suffix'] {
61
+ color: var(--xh-statistic-affix-fg, var(--xh-_tone-fg, var(--xh-fg-muted)));
62
+ font-size: var(--xh-statistic-affix-font-size, var(--xh-_statistic-affix-size));
63
+ font-variant-numeric: tabular-nums;
64
+ font-weight: var(--xh-font-weight-regular);
65
+ line-height: var(--xh-leading-tight);
66
+ }
67
+ }