@xihan-ui/styles 1.0.0-alpha.2 → 1.0.0-alpha.3

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 (118) hide show
  1. package/CHANGELOG.md +447 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +56 -5
  4. package/css/alert.css +30 -5
  5. package/css/anchor.css +7 -7
  6. package/css/avatar-group.css +3 -3
  7. package/css/avatar.css +3 -3
  8. package/css/back-top.css +16 -1
  9. package/css/badge.css +16 -2
  10. package/css/breadcrumb.css +24 -4
  11. package/css/button-group.css +14 -13
  12. package/css/button.css +42 -11
  13. package/css/calendar.css +119 -2
  14. package/css/card.css +5 -5
  15. package/css/carousel.css +36 -5
  16. package/css/cascader.css +183 -102
  17. package/css/checkbox-group.css +41 -19
  18. package/css/checkbox.css +54 -8
  19. package/css/clipboard.css +2 -1
  20. package/css/code-block.css +12 -7
  21. package/css/collapsible.css +42 -2
  22. package/css/color-picker.css +111 -45
  23. package/css/combobox.css +114 -53
  24. package/css/composer.css +5 -3
  25. package/css/context-menu.css +97 -69
  26. package/css/date-field.css +91 -14
  27. package/css/date-picker.css +276 -65
  28. package/css/descriptions.css +2 -2
  29. package/css/dialog.css +40 -13
  30. package/css/download-trigger.css +76 -0
  31. package/css/drawer.css +45 -14
  32. package/css/dynamic-input.css +68 -17
  33. package/css/editable.css +12 -10
  34. package/css/ellipsis.css +1 -1
  35. package/css/empty-state.css +7 -7
  36. package/css/field.css +9 -6
  37. package/css/fieldset.css +69 -0
  38. package/css/file-upload.css +45 -7
  39. package/css/float-button.css +16 -1
  40. package/css/floating-panel.css +310 -0
  41. package/css/form.css +4 -4
  42. package/css/heatmap.css +410 -0
  43. package/css/highlight.css +1 -1
  44. package/css/hotkeys.css +90 -0
  45. package/css/hover-card.css +40 -45
  46. package/css/image-cropper.css +231 -0
  47. package/css/image-viewer.css +137 -12
  48. package/css/image.css +2 -2
  49. package/css/infinite-scroll.css +1 -1
  50. package/css/json-viewer.css +241 -0
  51. package/css/layout.css +6 -10
  52. package/css/list.css +8 -8
  53. package/css/listbox.css +20 -4
  54. package/css/loading-bar.css +7 -1
  55. package/css/log.css +1 -1
  56. package/css/marquee.css +9 -0
  57. package/css/masonry.css +63 -0
  58. package/css/mention.css +87 -33
  59. package/css/menu.css +113 -47
  60. package/css/menubar.css +146 -60
  61. package/css/navigation-menu.css +54 -29
  62. package/css/number-animation.css +3 -3
  63. package/css/number-field.css +173 -16
  64. package/css/overlay-arrow.css +51 -0
  65. package/css/page-header.css +5 -5
  66. package/css/pagination.css +13 -13
  67. package/css/password-input.css +356 -0
  68. package/css/pin-input.css +13 -10
  69. package/css/popconfirm.css +46 -10
  70. package/css/popover.css +70 -45
  71. package/css/popselect.css +183 -53
  72. package/css/progress.css +47 -7
  73. package/css/qr-code.css +1 -1
  74. package/css/radio-group.css +14 -8
  75. package/css/rating.css +2 -2
  76. package/css/reset.css +17 -0
  77. package/css/result.css +6 -6
  78. package/css/scroll-area.css +61 -89
  79. package/css/scrollbar.css +167 -0
  80. package/css/segmented.css +215 -0
  81. package/css/select.css +274 -125
  82. package/css/separator.css +2 -2
  83. package/css/side-nav.css +111 -19
  84. package/css/signature-pad.css +144 -0
  85. package/css/skeleton.css +7 -1
  86. package/css/slider.css +10 -10
  87. package/css/space.css +117 -0
  88. package/css/spinner.css +22 -10
  89. package/css/statistic.css +9 -9
  90. package/css/steps.css +25 -8
  91. package/css/switch.css +48 -6
  92. package/css/table.css +131 -37
  93. package/css/tabs.css +4 -4
  94. package/css/tag.css +177 -0
  95. package/css/tags-input.css +78 -40
  96. package/css/text-field.css +149 -36
  97. package/css/thread.css +1 -1
  98. package/css/time-field.css +97 -16
  99. package/css/time-picker.css +259 -69
  100. package/css/timeline.css +10 -10
  101. package/css/timer.css +119 -0
  102. package/css/toast.css +34 -10
  103. package/css/toaster.css +1 -1
  104. package/css/toggle.css +6 -6
  105. package/css/tone.css +10 -5
  106. package/css/toolbar.css +1 -1
  107. package/css/tooltip.css +36 -33
  108. package/css/tour.css +103 -58
  109. package/css/transfer.css +68 -17
  110. package/css/tree-select.css +185 -84
  111. package/css/tree.css +85 -1
  112. package/css/typography.css +4 -4
  113. package/css/undefined.css +11 -1
  114. package/css/virtualizer.css +3 -1
  115. package/css/watermark.css +1 -2
  116. package/index.css +17 -0
  117. package/index.unlayered.css +8659 -2799
  118. package/package.json +19 -3
package/css/tour.css CHANGED
@@ -21,16 +21,27 @@
21
21
  }
22
22
  }
23
23
 
24
- /* 气泡贴着目标探出来:纯淡入分不清它是从哪个元素长出来的 */
25
- @keyframes xh-tour-content-in {
24
+ @keyframes xh-pop-in {
26
25
  from {
27
26
  opacity: 0;
28
- translate: 0 var(--xh-motion-distance-sm);
27
+ scale: var(--xh-motion-scale-enter);
29
28
  }
30
29
 
31
30
  to {
32
31
  opacity: 1;
33
- translate: 0 0;
32
+ scale: 1;
33
+ }
34
+ }
35
+
36
+ @keyframes xh-pop-out {
37
+ from {
38
+ opacity: 1;
39
+ scale: 1;
40
+ }
41
+
42
+ to {
43
+ opacity: 0;
44
+ scale: var(--xh-motion-scale-enter);
34
45
  }
35
46
  }
36
47
 
@@ -46,6 +57,19 @@
46
57
  scale: 1;
47
58
  }
48
59
  }
60
+
61
+ /* 退场反向放大淡出,与进场对称 */
62
+ @keyframes xh-tour-spotlight-out {
63
+ from {
64
+ opacity: 1;
65
+ scale: 1;
66
+ }
67
+
68
+ to {
69
+ opacity: 0;
70
+ scale: calc(2 - var(--xh-motion-scale-enter));
71
+ }
72
+ }
49
73
  }
50
74
 
51
75
  @layer xihan.components {
@@ -57,6 +81,9 @@
57
81
  /* 根节点只是几个浮层的归属容器,不参与排版。
58
82
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
59
83
  [data-scope='tour'][data-part='root'] {
84
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
85
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-text));
86
+
60
87
  color: var(--xh-tour-fg, var(--xh-fg-default));
61
88
  }
62
89
 
@@ -64,7 +91,7 @@
64
91
  [data-scope='tour'][data-part='backdrop'] {
65
92
  position: fixed;
66
93
  inset: 0;
67
- z-index: var(--xh-tour-backdrop-z, var(--xh-layer-modal));
94
+ z-index: var(--xh-tour-backdrop-layer, var(--xh-layer-modal));
68
95
  background: var(--xh-tour-backdrop-bg, var(--xh-bg-overlay));
69
96
  }
70
97
 
@@ -77,14 +104,14 @@
77
104
  }
78
105
 
79
106
  [data-scope='tour'][data-part='backdrop'][data-state='closed'] {
80
- animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
107
+ animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
81
108
  }
82
109
 
83
110
  /* 挖洞的高亮框。位置与尺寸由连接层量出来写进内联 style(position/inset/尺寸那几条轴归它),
84
111
  这里只管长相:一圈描边 + 一片铺满视口的投影当暗幕,中间那块因此是亮的——
85
112
  这就是"洞"。不吃指针:它盖在目标上面,吃了的话目标就再也点不动了 */
86
113
  [data-scope='tour'][data-part='spotlight'] {
87
- z-index: var(--xh-tour-spotlight-z, var(--xh-layer-modal));
114
+ z-index: var(--xh-tour-spotlight-layer, var(--xh-layer-modal));
88
115
  pointer-events: none;
89
116
  border-radius: var(--xh-tour-spotlight-radius, var(--xh-shape-surface));
90
117
  box-shadow:
@@ -106,18 +133,29 @@
106
133
  animation: xh-tour-spotlight-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
107
134
  }
108
135
 
136
+ /* 退场与气泡并行播,同一段时长;收起那一帧 hidden 由宿主押后到气泡的退场结束 */
137
+ [data-scope='tour'][data-part='spotlight'][data-state='closed'] {
138
+ animation: xh-tour-spotlight-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
139
+ }
140
+
109
141
  /* 高亮框在场时遮罩让位:暗幕已经由那圈铺满视口的投影负责,
110
142
  两层叠加会把页面压得过暗,而且洞里也会跟着变暗——洞就白挖了。
111
- 居中步的高亮框带 hidden,此时遮罩照常压暗(那一步本来就没有要突出的元素) */
112
- [data-scope='tour'][data-part='root']:has([data-scope='tour'][data-part='spotlight']:not([hidden]))
113
- [data-scope='tour'][data-part='backdrop'] {
143
+ 居中步的高亮框带 hidden,此时遮罩照常压暗(那一步本来就没有要突出的元素)。
144
+ 两条兄弟选择器各管一个方向,谁写在前面都算数:遮罩与高亮框同为浮层落点里的兄弟,
145
+ 不再共有 root 这个祖先 */
146
+ [data-scope='tour'][data-part='backdrop']:has(~ [data-scope='tour'][data-part='spotlight']:not([hidden])),
147
+ [data-scope='tour'][data-part='spotlight']:not([hidden]) ~ [data-scope='tour'][data-part='backdrop'] {
114
148
  background: transparent;
115
149
  }
116
150
 
117
151
  /* 空壳不吃指针,交互只发生在 content 上。
118
152
  锚定步的坐标由定位引擎写进内联 style,这里不碰那两条轴 */
119
153
  [data-scope='tour'][data-part='positioner'] {
120
- z-index: var(--xh-tour-positioner-z, var(--xh-layer-popover));
154
+ /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,气泡继承它限高;
155
+ 居中步与尚未落位时不额外限高 */
156
+ --xh-_tour-available-h: 100vh;
157
+
158
+ z-index: var(--xh-tour-positioner-layer, var(--xh-layer-popover));
121
159
  pointer-events: none;
122
160
  }
123
161
 
@@ -142,21 +180,22 @@
142
180
  flex-direction: column;
143
181
  gap: var(--xh-tour-gap, var(--xh-space-2));
144
182
  inline-size: max-content;
145
- max-inline-size: var(--xh-tour-max-w, 22rem);
146
- padding-block: var(--xh-tour-py, var(--xh-space-4));
147
- padding-inline: var(--xh-tour-px, var(--xh-control-px-lg));
183
+ max-inline-size: var(--xh-tour-max-w, var(--xh-overlay-max-w-lg));
184
+ padding-block: var(--xh-tour-py, var(--xh-surface-py-md));
185
+ padding-inline: var(--xh-tour-px, var(--xh-surface-px-md));
186
+ /* 引导步骤的正文长度由作者定,矮视口下不限高气泡会整块伸出视口 */
187
+ max-block-size: min(var(--xh-tour-max-h, var(--xh-overlay-max-h)), var(--xh-_tour-available-h));
148
188
  border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-border-default));
149
189
  border-radius: var(--xh-tour-radius, var(--xh-shape-surface));
150
190
  background: var(--xh-tour-bg, var(--xh-bg-surface));
151
191
  color: var(--xh-tour-fg, var(--xh-fg-default));
152
- box-shadow: var(--xh-tour-shadow, var(--xh-elevation-3));
192
+ box-shadow: var(--xh-tour-shadow, var(--xh-elevation-sheet));
153
193
  pointer-events: auto;
154
194
  }
155
195
 
156
- /* display 会盖掉 hidden 属性的 UA 规则,收起态显式让位 */
157
- [data-scope='tour'][data-part='content'][hidden] {
158
- display: none;
159
- }
196
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 popover 一致:
197
+ 收起态连接层会给 content 打 hidden,补上这条退场动画就一帧都播不出来。
198
+ 真正的收起由退场闸门落成内联 display,节点始终留在原地。 */
160
199
 
161
200
  /* 焦点落在气泡本身(Enter/Space 归"下一步"管),但它是纯容器,不画焦点环 */
162
201
  [data-scope='tour'][data-part='content']:focus-visible {
@@ -164,7 +203,13 @@
164
203
  }
165
204
 
166
205
  [data-scope='tour'][data-part='content'][data-state='open'] {
167
- animation: xh-tour-content-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
206
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
207
+ }
208
+
209
+ /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
210
+ 免得动画结束到收起落下来之间闪一下原样 */
211
+ [data-scope='tour'][data-part='content'][data-state='closed'] {
212
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
168
213
  }
169
214
 
170
215
  [data-scope='tour'][data-part='title'] {
@@ -178,7 +223,7 @@
178
223
  否则长标题会直接钻到按钮底下。只在真有关闭按钮时让位。 */
179
224
  [data-scope='tour'][data-part='content']:has([data-scope='tour'][data-part='close-trigger'])
180
225
  [data-scope='tour'][data-part='title'] {
181
- padding-inline-end: calc(var(--xh-control-h-sm) + var(--xh-space-2));
226
+ padding-inline-end: calc(var(--xh-tour-close-size, var(--xh-control-h-sm)) + var(--xh-space-2));
182
227
  }
183
228
 
184
229
  [data-scope='tour'][data-part='description'] {
@@ -190,7 +235,7 @@
190
235
 
191
236
  /* "第 m 步,共 n 步":辅助信息,字号压一档,与按钮排在同一行的两端 */
192
237
  [data-scope='tour'][data-part='progress-text'] {
193
- font-size: var(--xh-tour-progress-font-size, var(--xh-font-size-xs));
238
+ font-size: var(--xh-tour-progress-font-size, var(--xh-text-caption-size));
194
239
  color: var(--xh-tour-progress-fg, var(--xh-fg-subtle));
195
240
  }
196
241
 
@@ -204,7 +249,7 @@
204
249
  padding-inline: var(--xh-control-px-md);
205
250
  border: var(--xh-stroke-thin) solid transparent;
206
251
  border-radius: var(--xh-shape-control);
207
- font-size: var(--xh-font-size-sm);
252
+ font-size: var(--xh-text-secondary-size);
208
253
  cursor: pointer;
209
254
  }
210
255
 
@@ -254,13 +299,16 @@
254
299
  display: inline-flex;
255
300
  align-items: center;
256
301
  justify-content: center;
257
- block-size: var(--xh-control-h-sm);
258
- inline-size: var(--xh-control-h-sm);
302
+ block-size: var(--xh-tour-close-size, var(--xh-control-h-sm));
303
+ inline-size: var(--xh-tour-close-size, var(--xh-control-h-sm));
259
304
  border: 0;
260
- border-radius: var(--xh-shape-control);
305
+ border-radius: var(--xh-tour-close-radius, var(--xh-shape-control));
261
306
  background: transparent;
262
307
  color: var(--xh-fg-muted);
263
308
  cursor: pointer;
309
+ transition:
310
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
311
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
264
312
  }
265
313
 
266
314
  [data-scope='tour'][data-part='close-trigger'][hidden] {
@@ -268,10 +316,15 @@
268
316
  }
269
317
 
270
318
  [data-scope='tour'][data-part='close-trigger']:hover {
271
- background: var(--xh-bg-subtle);
319
+ background: var(--xh-tour-close-bg-hover, var(--xh-bg-subtle-hover));
272
320
  color: var(--xh-fg-default);
273
321
  }
274
322
 
323
+ [data-scope='tour'][data-part='close-trigger']:active {
324
+ background: var(--xh-tour-close-bg-active, var(--xh-bg-subtle-active));
325
+ scale: var(--xh-motion-scale-press);
326
+ }
327
+
275
328
  [data-scope='tour'][data-part='prev-trigger']:focus-visible,
276
329
  [data-scope='tour'][data-part='next-trigger']:focus-visible,
277
330
  [data-scope='tour'][data-part='skip-trigger']:focus-visible,
@@ -280,50 +333,42 @@
280
333
  outline-offset: var(--xh-ring-offset);
281
334
  }
282
335
 
283
- /* 箭头是旋转 45° 的方块,只保留朝向目标那两条边的描边;
284
- 交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中。居中步没有锚点,连接层会给它发 hidden */
336
+ /* 箭头的底色与描边色,几何在 overlay-arrow.css。
337
+ 交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中 */
285
338
  [data-scope='tour'][data-part='arrow'] {
286
- --xh-_tour-arrow-size: var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size));
287
339
  --xh-_tour-arrow-x: 50%;
288
340
  --xh-_tour-arrow-y: 50%;
341
+ --xh-_overlay-arrow-size: var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size));
342
+ --xh-_overlay-arrow-x: var(--xh-_tour-arrow-x);
343
+ --xh-_overlay-arrow-y: var(--xh-_tour-arrow-y);
289
344
 
290
- position: absolute;
291
- inline-size: var(--xh-_tour-arrow-size);
292
- block-size: var(--xh-_tour-arrow-size);
293
345
  background: var(--xh-tour-bg, var(--xh-bg-surface));
294
346
  border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-border-default));
295
- rotate: 45deg;
296
347
  }
297
348
 
349
+ /* 居中步没有锚点,连接层会给箭头发 hidden */
298
350
  [data-scope='tour'][data-part='arrow'][hidden] {
299
351
  display: none;
300
352
  }
301
353
 
302
- [data-scope='tour'][data-part='arrow'][data-placement^='bottom'] {
303
- inset-block-start: calc(var(--xh-_tour-arrow-size) / -2);
304
- inset-inline-start: calc(var(--xh-_tour-arrow-x) - var(--xh-_tour-arrow-size) / 2);
305
- border-block-end: 0;
306
- border-inline-end: 0;
307
- }
308
-
309
- [data-scope='tour'][data-part='arrow'][data-placement^='top'] {
310
- inset-block-end: calc(var(--xh-_tour-arrow-size) / -2);
311
- inset-inline-start: calc(var(--xh-_tour-arrow-x) - var(--xh-_tour-arrow-size) / 2);
312
- border-block-start: 0;
313
- border-inline-start: 0;
314
- }
315
-
316
- [data-scope='tour'][data-part='arrow'][data-placement^='right'] {
317
- inset-inline-start: calc(var(--xh-_tour-arrow-size) / -2);
318
- inset-block-start: calc(var(--xh-_tour-arrow-y) - var(--xh-_tour-arrow-size) / 2);
319
- border-block-start: 0;
320
- border-inline-end: 0;
354
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
355
+ [data-scope='tour'][data-part='close-trigger']:empty::before {
356
+ content: '';
357
+ display: inline-block;
358
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
359
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
360
+ vertical-align: var(--xh-glyph-baseline-shift);
361
+ background-color: currentColor;
362
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
363
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
321
364
  }
365
+ }
322
366
 
323
- [data-scope='tour'][data-part='arrow'][data-placement^='left'] {
324
- inset-inline-end: calc(var(--xh-_tour-arrow-size) / -2);
325
- inset-block-start: calc(var(--xh-_tour-arrow-y) - var(--xh-_tour-arrow-size) / 2);
326
- border-block-end: 0;
327
- border-inline-start: 0;
367
+ @layer xihan.components {
368
+ /* 气泡限高之后只让正文让步:标题与上下步按钮滚出视线就点不到了 */
369
+ [data-scope='tour'][data-part='description'] {
370
+ flex: 1 1 auto;
371
+ min-block-size: 0;
372
+ overflow-y: auto;
328
373
  }
329
374
  }
package/css/transfer.css CHANGED
@@ -10,6 +10,9 @@
10
10
  中间那栏没有对应的角色节点(anatomy 里两个按钮是 root 的直接子节点),
11
11
  所以只能按位置显式安放,不能靠自动流——自动流会把"往左搬"甩到右侧面板的位置上 */
12
12
  [data-scope='transfer'][data-part='root'] {
13
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
14
+ --xh-icon-size: var(--xh-transfer-icon-size, var(--xh-glyph-size-text));
15
+
13
16
  display: grid;
14
17
  grid-template-rows: 1fr 1fr;
15
18
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
@@ -84,7 +87,7 @@
84
87
  [data-scope='transfer'][data-part='panel-count'] {
85
88
  flex: none;
86
89
  color: var(--xh-transfer-count-fg, var(--xh-fg-subtle));
87
- font-size: var(--xh-transfer-count-font-size, var(--xh-font-size-xs));
90
+ font-size: var(--xh-transfer-count-font-size, var(--xh-text-caption-size));
88
91
  line-height: var(--xh-leading-none);
89
92
  font-variant-numeric: tabular-nums;
90
93
  }
@@ -120,12 +123,14 @@
120
123
  cursor: not-allowed;
121
124
  }
122
125
 
126
+ /* 两侧列表定高:高度只由这个槽给,与条目数无关。左右两块因此恒等高,
127
+ 搬走条目、搜索筛掉条目、整侧搬空,面板都停在原地不缩。
128
+ flex-basis 取 auto 而不是 0,块尺寸才是这一栏真正的主轴基准 */
123
129
  [data-scope='transfer'][data-part='list'] {
124
130
  display: flex;
125
- flex: 1;
131
+ flex: 1 1 auto;
126
132
  flex-direction: column;
127
- min-block-size: var(--xh-transfer-list-min-h, 8rem);
128
- max-block-size: var(--xh-transfer-list-max-h, 16rem);
133
+ block-size: var(--xh-transfer-list-h, var(--xh-viewport-h-md));
129
134
  padding-block: var(--xh-transfer-list-py, var(--xh-space-1));
130
135
  padding-inline: var(--xh-transfer-list-px, var(--xh-space-1));
131
136
  overflow: auto;
@@ -190,13 +195,13 @@
190
195
  flex: none;
191
196
  align-items: center;
192
197
  justify-content: center;
193
- inline-size: var(--xh-transfer-checkbox-size, 16px);
194
- block-size: var(--xh-transfer-checkbox-size, 16px);
198
+ inline-size: var(--xh-transfer-checkbox-size, var(--xh-control-indicator-size));
199
+ block-size: var(--xh-transfer-checkbox-size, var(--xh-control-indicator-size));
195
200
  border: var(--xh-stroke-thin) solid var(--xh-transfer-checkbox-border, var(--xh-border-control));
196
- border-radius: var(--xh-transfer-checkbox-radius, var(--xh-radius-sm));
201
+ border-radius: var(--xh-transfer-checkbox-radius, var(--xh-shape-inset));
197
202
  background: var(--xh-transfer-checkbox-bg, var(--xh-bg-canvas));
198
203
  color: var(--xh-transfer-checkbox-fg, var(--xh-fg-on-brand));
199
- font-size: var(--xh-transfer-checkbox-font-size, 12px);
204
+ font-size: var(--xh-transfer-checkbox-font-size, calc(var(--xh-control-indicator-size) * 0.75));
200
205
  line-height: var(--xh-leading-none);
201
206
  transition:
202
207
  background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
@@ -211,24 +216,47 @@
211
216
 
212
217
  /* 勾中即填色。全选格三态里 all 与 some 都算"有值",与条目共用同一副填色 */
213
218
  [data-scope='transfer'][data-part='item-checkbox'][data-state='checked'],
214
- [data-scope='transfer'][data-part='select-all-trigger']:is([data-state='all'], [data-state='some'])::before {
219
+ [data-scope='transfer'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate'])::before {
215
220
  border-color: var(--xh-transfer-checkbox-border-checked, var(--xh-bg-brand));
216
221
  background: var(--xh-transfer-checkbox-bg-checked, var(--xh-bg-brand));
217
222
  }
218
223
 
219
- /* 勾号由皮肤补,作者不必自己往格子里塞字符 */
220
- [data-scope='transfer'][data-part='item-checkbox'][data-state='checked']::before {
221
- content: '✓';
224
+ /* 没写内容就由皮肤画勾;作者往格子里塞了自己的图形,这条规则即不命中。
225
+ 底下两处(全选格的两态)不带这条守卫:那里的 ::before 是方框本身,
226
+ 而触发器里装的是全选那行文字,:empty 恒不命中,加了勾号会整个消失 */
227
+ [data-scope='transfer'][data-part='item-checkbox'][data-state='checked']:empty::before {
228
+ content: '';
229
+ display: inline-block;
230
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
231
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
232
+ vertical-align: var(--xh-glyph-baseline-shift);
233
+ background-color: currentColor;
234
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
235
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
222
236
  }
223
237
 
224
238
  /* 全选格的三态:all 打勾、some 打横杠、none 留空。
225
239
  some 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state */
226
- [data-scope='transfer'][data-part='select-all-trigger'][data-state='all']::before {
227
- content: '✓';
240
+ [data-scope='transfer'][data-part='select-all-trigger'][data-state='checked']::before {
241
+ content: '';
242
+ display: inline-block;
243
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
244
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
245
+ vertical-align: var(--xh-glyph-baseline-shift);
246
+ background-color: currentColor;
247
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
248
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
228
249
  }
229
250
 
230
- [data-scope='transfer'][data-part='select-all-trigger'][data-state='some']::before {
231
- content: '−';
251
+ [data-scope='transfer'][data-part='select-all-trigger'][data-state='indeterminate']::before {
252
+ content: '';
253
+ display: inline-block;
254
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
255
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
256
+ vertical-align: var(--xh-glyph-baseline-shift);
257
+ background-color: currentColor;
258
+ -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
259
+ mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
232
260
  }
233
261
 
234
262
  [data-scope='transfer'][data-part='item-checkbox'][data-disabled] {
@@ -248,7 +276,7 @@
248
276
  border-radius: var(--xh-transfer-select-all-radius, var(--xh-shape-control));
249
277
  background: none;
250
278
  color: var(--xh-transfer-select-all-fg, var(--xh-fg-muted));
251
- font-size: var(--xh-transfer-select-all-font-size, var(--xh-font-size-xs));
279
+ font-size: var(--xh-transfer-select-all-font-size, var(--xh-text-caption-size));
252
280
  font-weight: var(--xh-font-weight-medium);
253
281
  line-height: var(--xh-leading-none);
254
282
  cursor: pointer;
@@ -322,4 +350,27 @@
322
350
  [data-scope='transfer'][data-part='to-source-trigger'][hidden] {
323
351
  display: none;
324
352
  }
353
+
354
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
355
+ [data-scope='transfer'][data-part='to-source-trigger']:empty::before {
356
+ content: '';
357
+ display: inline-block;
358
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
359
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
360
+ vertical-align: var(--xh-glyph-baseline-shift);
361
+ background-color: currentColor;
362
+ -webkit-mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
363
+ mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
364
+ }
365
+
366
+ [data-scope='transfer'][data-part='to-target-trigger']:empty::before {
367
+ content: '';
368
+ display: inline-block;
369
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
370
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
371
+ vertical-align: var(--xh-glyph-baseline-shift);
372
+ background-color: currentColor;
373
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
374
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
375
+ }
325
376
  }