@xihan-ui/styles 3.1.0 → 4.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.
Files changed (290) hide show
  1. package/CHANGELOG.md +470 -0
  2. package/component-tokens.d.ts +230 -60
  3. package/components.tokens.json +5156 -1557
  4. package/css/accordion.css +47 -20
  5. package/css/alert.css +16 -17
  6. package/css/anchor.css +2 -2
  7. package/css/approval.css +41 -17
  8. package/css/avatar-group.css +9 -12
  9. package/css/avatar.css +20 -18
  10. package/css/back-top.css +21 -7
  11. package/css/badge.css +5 -5
  12. package/css/breadcrumb.css +18 -16
  13. package/css/button-group.css +4 -6
  14. package/css/button.css +13 -12
  15. package/css/calendar-picker.css +178 -95
  16. package/css/calendar-range-picker.css +207 -122
  17. package/css/card.css +34 -6
  18. package/css/carousel.css +94 -46
  19. package/css/cartesian-chart.css +11 -11
  20. package/css/cascader.css +51 -39
  21. package/css/checkbox-group.css +9 -6
  22. package/css/checkbox.css +5 -4
  23. package/css/citation.css +9 -4
  24. package/css/clipboard.css +20 -4
  25. package/css/code-view.css +6 -6
  26. package/css/collapsible.css +29 -14
  27. package/css/color-field.css +4 -4
  28. package/css/color-picker.css +77 -23
  29. package/css/color-slider.css +10 -8
  30. package/css/color-swatch-picker.css +14 -9
  31. package/css/combobox.css +26 -14
  32. package/css/command.css +14 -9
  33. package/css/context-menu.css +10 -5
  34. package/css/date-field.css +12 -6
  35. package/css/date-picker.css +178 -109
  36. package/css/date-range-picker.css +199 -130
  37. package/css/description.css +10 -6
  38. package/css/descriptions.css +47 -19
  39. package/css/dialog.css +50 -35
  40. package/css/diff-view.css +8 -8
  41. package/css/drawer.css +75 -21
  42. package/css/editable.css +15 -41
  43. package/css/empty-state.css +21 -3
  44. package/css/field-array.css +5 -2
  45. package/css/field.css +17 -18
  46. package/css/fieldset.css +33 -13
  47. package/css/file-upload.css +66 -33
  48. package/css/float-button.css +60 -35
  49. package/css/floating-panel.css +1 -1
  50. package/css/form.css +30 -16
  51. package/css/graph-chart.css +2 -2
  52. package/css/grid-list.css +1 -1
  53. package/css/highlight.css +5 -5
  54. package/css/hover-card.css +19 -12
  55. package/css/image-viewer.css +77 -27
  56. package/css/image.css +13 -5
  57. package/css/infinite-scroll.css +8 -4
  58. package/css/input-group.css +74 -26
  59. package/css/kbd.css +1 -1
  60. package/css/label.css +27 -11
  61. package/css/layout.css +17 -10
  62. package/css/list.css +13 -9
  63. package/css/listbox.css +12 -7
  64. package/css/loading-bar.css +3 -0
  65. package/css/mention.css +11 -9
  66. package/css/menu.css +10 -5
  67. package/css/menubar.css +13 -8
  68. package/css/message-feed.css +1 -1
  69. package/css/navigation-menu.css +2 -2
  70. package/css/notification.css +132 -49
  71. package/css/number-animation.css +2 -2
  72. package/css/number-field.css +75 -52
  73. package/css/page-header.css +64 -27
  74. package/css/pagination.css +35 -38
  75. package/css/password-input.css +12 -68
  76. package/css/pin-input.css +18 -26
  77. package/css/popconfirm.css +23 -14
  78. package/css/popover.css +18 -12
  79. package/css/progress.css +14 -13
  80. package/css/prompt-input.css +3 -3
  81. package/css/question-flow.css +41 -15
  82. package/css/radar-chart.css +6 -6
  83. package/css/radio-group.css +120 -55
  84. package/css/rating.css +32 -15
  85. package/css/select.css +16 -12
  86. package/css/separator.css +24 -6
  87. package/css/side-nav.css +29 -24
  88. package/css/signature-pad.css +23 -9
  89. package/css/skeleton.css +12 -12
  90. package/css/slider.css +77 -48
  91. package/css/sortable.css +2 -2
  92. package/css/sparkline.css +8 -2
  93. package/css/spinner.css +40 -20
  94. package/css/statistic.css +14 -14
  95. package/css/steps.css +115 -84
  96. package/css/switch.css +9 -7
  97. package/css/table.css +29 -12
  98. package/css/tabs.css +35 -12
  99. package/css/tag-group.css +17 -6
  100. package/css/tag.css +54 -29
  101. package/css/tags-input.css +39 -20
  102. package/css/text-field.css +5 -5
  103. package/css/time-field.css +4 -4
  104. package/css/time-picker.css +150 -64
  105. package/css/time-range-picker.css +91 -62
  106. package/css/timeline.css +37 -20
  107. package/css/timer.css +3 -3
  108. package/css/toggle-group.css +4 -4
  109. package/css/tool-call.css +13 -11
  110. package/css/toolbar.css +6 -5
  111. package/css/tooltip.css +16 -17
  112. package/css/tour.css +14 -7
  113. package/css/transfer.css +22 -16
  114. package/css/tree-select.css +12 -12
  115. package/css/tree.css +26 -25
  116. package/css/typography.css +28 -25
  117. package/dist/css/accordion.css +296 -0
  118. package/dist/css/affix.css +47 -0
  119. package/dist/css/alert.css +246 -0
  120. package/dist/css/anchor.css +252 -0
  121. package/dist/css/approval.css +525 -0
  122. package/dist/css/avatar-group.css +96 -0
  123. package/dist/css/avatar.css +100 -0
  124. package/dist/css/back-top.css +175 -0
  125. package/dist/css/badge.css +205 -0
  126. package/dist/css/bar-code.css +62 -0
  127. package/dist/css/breadcrumb.css +232 -0
  128. package/dist/css/button-group.css +261 -0
  129. package/dist/css/button.css +216 -0
  130. package/dist/css/calendar-picker.css +550 -0
  131. package/dist/css/calendar-range-picker.css +639 -0
  132. package/dist/css/card.css +249 -0
  133. package/dist/css/carousel.css +726 -0
  134. package/dist/css/cartesian-chart.css +830 -0
  135. package/dist/css/cascader.css +973 -0
  136. package/dist/css/checkbox-group.css +361 -0
  137. package/dist/css/checkbox.css +258 -0
  138. package/dist/css/citation.css +475 -0
  139. package/dist/css/clipboard.css +331 -0
  140. package/dist/css/code-view.css +374 -0
  141. package/dist/css/collapsible.css +200 -0
  142. package/dist/css/color-field.css +176 -0
  143. package/dist/css/color-picker.css +649 -0
  144. package/dist/css/color-slider.css +283 -0
  145. package/dist/css/color-swatch-picker.css +250 -0
  146. package/dist/css/color-swatch.css +35 -0
  147. package/dist/css/combobox.css +578 -0
  148. package/dist/css/command.css +404 -0
  149. package/dist/css/context-menu.css +425 -0
  150. package/dist/css/date-field.css +317 -0
  151. package/dist/css/date-picker.css +931 -0
  152. package/dist/css/date-range-picker.css +949 -0
  153. package/dist/css/description.css +71 -0
  154. package/dist/css/descriptions.css +327 -0
  155. package/dist/css/dialog.css +470 -0
  156. package/dist/css/diff-view.css +513 -0
  157. package/dist/css/download-trigger.css +151 -0
  158. package/dist/css/drawer.css +606 -0
  159. package/dist/css/editable.css +269 -0
  160. package/dist/css/empty-state.css +181 -0
  161. package/dist/css/field-array.css +229 -0
  162. package/dist/css/field.css +165 -0
  163. package/dist/css/fieldset.css +122 -0
  164. package/dist/css/file-upload.css +462 -0
  165. package/dist/css/flex.css +441 -0
  166. package/dist/css/float-button.css +579 -0
  167. package/dist/css/floating-panel.css +429 -0
  168. package/dist/css/focus.css +46 -0
  169. package/dist/css/forced-colors.css +93 -0
  170. package/dist/css/form.css +407 -0
  171. package/dist/css/funnel-chart.css +106 -0
  172. package/dist/css/graph-chart.css +205 -0
  173. package/dist/css/grid-list.css +235 -0
  174. package/dist/css/grid.css +1201 -0
  175. package/dist/css/heatmap.css +552 -0
  176. package/dist/css/hierarchy-chart.css +298 -0
  177. package/dist/css/highlight.css +41 -0
  178. package/dist/css/hover-card.css +233 -0
  179. package/dist/css/icon.css +225 -0
  180. package/dist/css/image-cropper.css +373 -0
  181. package/dist/css/image-viewer.css +588 -0
  182. package/dist/css/image.css +106 -0
  183. package/dist/css/infinite-scroll.css +81 -0
  184. package/dist/css/input-group.css +323 -0
  185. package/dist/css/json-viewer.css +379 -0
  186. package/dist/css/kbd.css +72 -0
  187. package/dist/css/label.css +94 -0
  188. package/dist/css/layers.css +7 -0
  189. package/dist/css/layout.css +379 -0
  190. package/dist/css/liquid.css +106 -0
  191. package/dist/css/list.css +156 -0
  192. package/dist/css/listbox.css +395 -0
  193. package/dist/css/loading-bar.css +144 -0
  194. package/dist/css/log.css +306 -0
  195. package/dist/css/markdown-stream.css +149 -0
  196. package/dist/css/marquee.css +378 -0
  197. package/dist/css/masonry.css +70 -0
  198. package/dist/css/matrix-code.css +67 -0
  199. package/dist/css/mention.css +395 -0
  200. package/dist/css/menu.css +369 -0
  201. package/dist/css/menubar.css +461 -0
  202. package/dist/css/message-feed.css +318 -0
  203. package/dist/css/navigation-menu.css +513 -0
  204. package/dist/css/notification.css +865 -0
  205. package/dist/css/number-animation.css +44 -0
  206. package/dist/css/number-field.css +275 -0
  207. package/dist/css/overlay-arrow.css +56 -0
  208. package/dist/css/page-header.css +221 -0
  209. package/dist/css/pagination.css +447 -0
  210. package/dist/css/password-input.css +335 -0
  211. package/dist/css/pie-chart.css +247 -0
  212. package/dist/css/pin-input.css +191 -0
  213. package/dist/css/pointer.css +36 -0
  214. package/dist/css/popconfirm.css +329 -0
  215. package/dist/css/popover.css +285 -0
  216. package/dist/css/progress.css +502 -0
  217. package/dist/css/prompt-input.css +260 -0
  218. package/dist/css/question-flow.css +579 -0
  219. package/dist/css/radar-chart.css +233 -0
  220. package/dist/css/radio-group.css +663 -0
  221. package/dist/css/rating.css +311 -0
  222. package/dist/css/reasoning.css +343 -0
  223. package/dist/css/reset.css +117 -0
  224. package/dist/css/resizable.css +242 -0
  225. package/dist/css/sankey-chart.css +174 -0
  226. package/dist/css/scroll-area.css +240 -0
  227. package/dist/css/scrollbar.css +204 -0
  228. package/dist/css/select.css +616 -0
  229. package/dist/css/separator.css +140 -0
  230. package/dist/css/side-nav.css +481 -0
  231. package/dist/css/signature-pad.css +193 -0
  232. package/dist/css/skeleton.css +161 -0
  233. package/dist/css/slider.css +403 -0
  234. package/dist/css/sortable.css +228 -0
  235. package/dist/css/sparkline.css +170 -0
  236. package/dist/css/spinner.css +256 -0
  237. package/dist/css/splitter.css +159 -0
  238. package/dist/css/statistic.css +137 -0
  239. package/dist/css/steps.css +658 -0
  240. package/dist/css/switch.css +353 -0
  241. package/dist/css/table.css +1162 -0
  242. package/dist/css/tabs.css +967 -0
  243. package/dist/css/tag-group.css +258 -0
  244. package/dist/css/tag.css +335 -0
  245. package/dist/css/tags-input.css +341 -0
  246. package/dist/css/text-field.css +197 -0
  247. package/dist/css/time-field.css +277 -0
  248. package/dist/css/time-picker.css +793 -0
  249. package/dist/css/time-range-picker.css +775 -0
  250. package/dist/css/timeline.css +440 -0
  251. package/dist/css/timer.css +123 -0
  252. package/dist/css/timestamp.css +34 -0
  253. package/dist/css/toggle-group.css +424 -0
  254. package/dist/css/toggle.css +146 -0
  255. package/dist/css/tone.css +189 -0
  256. package/dist/css/tool-call.css +431 -0
  257. package/dist/css/toolbar.css +366 -0
  258. package/dist/css/tooltip.css +217 -0
  259. package/dist/css/tour.css +446 -0
  260. package/dist/css/transfer.css +644 -0
  261. package/dist/css/tree-select.css +878 -0
  262. package/dist/css/tree.css +734 -0
  263. package/dist/css/truncate.css +108 -0
  264. package/dist/css/typography.css +475 -0
  265. package/dist/css/undefined.css +58 -0
  266. package/dist/css/virtualizer.css +166 -0
  267. package/dist/css/visually-hidden.css +20 -0
  268. package/dist/css/watermark.css +82 -0
  269. package/dist/family/action-control.css +493 -0
  270. package/dist/family/chart.css +537 -0
  271. package/dist/family/check-mark.css +94 -0
  272. package/dist/family/choice-card.css +97 -0
  273. package/dist/family/collection-item.css +768 -0
  274. package/dist/family/field-chrome.css +296 -0
  275. package/dist/family/loading-ring.css +102 -0
  276. package/dist/family/material.css +72 -0
  277. package/dist/family/menu-choice.css +56 -0
  278. package/dist/family/motion.css +363 -0
  279. package/dist/family/swatch.css +59 -0
  280. package/dist/family/tag-list.css +65 -0
  281. package/family/action-control.css +33 -36
  282. package/family/chart.css +57 -0
  283. package/family/collection-item.css +12 -8
  284. package/family/field-chrome.css +28 -19
  285. package/family/loading-ring.css +20 -13
  286. package/family/swatch.css +4 -4
  287. package/family/tag-list.css +6 -0
  288. package/index.css +10349 -8756
  289. package/index.unlayered.css +10350 -8758
  290. package/package.json +165 -164
@@ -0,0 +1,644 @@
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
5
+
6
+ /* 定义 transfer 样式。 */
7
+
8
+ @import '../family/action-control.css';
9
+ @import '../family/check-mark.css';
10
+ @import '../family/collection-item.css';
11
+ @import '../family/field-chrome.css';
12
+ @import '../family/loading-ring.css';
13
+ @import '../family/motion.css';
14
+
15
+ @layer xihan.components {
16
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17
+ .xh-scope-transfer {
18
+ --xh-transfer-skin: 1;
19
+ }
20
+
21
+ /* 三栏栅格:宽档两侧面板各占一栏、跨两行,中间那栏上下各放一个搬运按钮;
22
+ 窄档四个节点改按行叠放,中栏被两个按钮各跨一半、宽度收成零,两钮因此仍在中线相遇。
23
+ 两档共用这一份轨道声明,换档靠四个子节点各自换安放。
24
+ 栅格的列号本身就是随书写方向走的(第 1 栏永远在行首侧),dir=rtl 时整块自动镜像。
25
+ 中间那栏没有对应的角色节点(anatomy 里两个按钮是 root 的直接子节点),
26
+ 所以只能按位置显式安放,不能靠自动流——自动流会把"往回搬"甩到目标面板的位置上 */
27
+ .xh-scope-transfer[data-part='root'] {
28
+ /* 条目外的字形(空态占位里作者塞的图标)按档取尺,缺省 md;条目内的字形由家族随 data-xh-collection-size
29
+ 下发,搬运钮内的按 Action Control icon 档取,勾选格里的勾按边长比例取 */
30
+ --xh-icon-size: var(--xh-transfer-icon-size, var(--xh-glyph-size-md));
31
+ /* 两侧定高小列表的自绘条挂在根上:根是条子的定位盒(面板不定位),轨道底色关掉才不会在列表边缘糊出一条灰带 */
32
+ --xh-scrollbar-track-bg: transparent;
33
+
34
+ /* 尺寸档只换这六个私有槽,面板头、搜索框、条目与勾选格都从 root 继承它们,
35
+ 换档不必给每个部件各写一条选择器 */
36
+ --xh-_transfer-item-py: var(--xh-list-option-py-md);
37
+ /* 行至少一个同档控件高(md 32px),勾选格、文字与悬停面都有落脚的余量 */
38
+ --xh-_transfer-item-h: var(--xh-control-h-md);
39
+ --xh-_transfer-h: var(--xh-control-h-md);
40
+ --xh-_transfer-px: var(--xh-control-px-md);
41
+ --xh-_transfer-gap: var(--xh-control-gap-md);
42
+ --xh-_transfer-font-size: var(--xh-control-font-md);
43
+ --xh-_transfer-box: var(--xh-control-indicator-md);
44
+
45
+ /* 勾选格的填色随语气走;没写 data-tone 时退回品牌色 */
46
+ --xh-_transfer-accent: var(--xh-_tone, var(--xh-bg-brand));
47
+ --xh-_transfer-on-accent: var(--xh-_tone-on, var(--xh-fg-on-brand));
48
+
49
+ position: relative;
50
+ display: grid;
51
+ grid-template-rows: auto auto;
52
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
53
+ gap: var(--xh-transfer-gap, var(--xh-space-5));
54
+ align-items: center;
55
+ color: var(--xh-transfer-fg, var(--xh-fg-default));
56
+ }
57
+
58
+ /* —— 尺寸 —— */
59
+ /* 缺省档写在上面的基础规则里 */
60
+ .xh-scope-transfer[data-part='root'][data-size='sm'] {
61
+ --xh-icon-size: var(--xh-transfer-icon-size, var(--xh-glyph-size-sm));
62
+ --xh-_transfer-item-py: var(--xh-list-option-py-sm);
63
+ --xh-_transfer-item-h: var(--xh-control-h-sm);
64
+ --xh-_transfer-h: var(--xh-control-h-sm);
65
+ --xh-_transfer-px: var(--xh-control-px-sm);
66
+ --xh-_transfer-gap: var(--xh-control-gap-sm);
67
+ --xh-_transfer-font-size: var(--xh-control-font-sm);
68
+ --xh-_transfer-box: var(--xh-control-indicator-sm);
69
+ }
70
+
71
+ .xh-scope-transfer[data-part='root'][data-size='lg'] {
72
+ --xh-icon-size: var(--xh-transfer-icon-size, var(--xh-glyph-size-lg));
73
+ --xh-_transfer-item-py: var(--xh-list-option-py-lg);
74
+ --xh-_transfer-item-h: var(--xh-control-h-lg);
75
+ --xh-_transfer-h: var(--xh-control-h-lg);
76
+ --xh-_transfer-px: var(--xh-control-px-lg);
77
+ --xh-_transfer-gap: var(--xh-control-gap-lg);
78
+ --xh-_transfer-font-size: var(--xh-control-font-lg);
79
+ --xh-_transfer-box: var(--xh-control-indicator-lg);
80
+ }
81
+
82
+ /* 校验失败:两侧面板换成错误描边,与其余表单控件同一套表达 */
83
+ .xh-scope-transfer[data-part='root'][data-invalid]
84
+ :is(.xh-scope-transfer[data-part='source-panel'], .xh-scope-transfer[data-part='target-panel']) {
85
+ border-color: var(--xh-transfer-panel-border-invalid, var(--xh-border-invalid));
86
+ }
87
+
88
+ /* 只读勾不动也搬不动,但不是禁用:颜色照常,只把"可点"这个暗示收回来。
89
+ 排掉禁用项是因为这条选择器权重高过条目那条,不排就会把禁用的手势指示覆盖回 default */
90
+ .xh-scope-transfer[data-part='root'][data-readonly]
91
+ .xh-scope-transfer[data-part='item']:not([data-disabled]) {
92
+ cursor: default;
93
+ }
94
+
95
+ /* 窄档:源面板在上、目标面板在下,各自跨满三栏 */
96
+ .xh-scope-transfer[data-part='source-panel'] {
97
+ grid-row: 1;
98
+ grid-column: 1 / 4;
99
+ }
100
+
101
+ .xh-scope-transfer[data-part='target-panel'] {
102
+ grid-row: 3;
103
+ grid-column: 1 / 4;
104
+ }
105
+
106
+ /* 两钮同占中间一行,各跨到中栏为止,一个贴行尾侧、一个贴行首侧,
107
+ 因此夹着中线成对出现,而不是各自漂在半行中央 */
108
+ .xh-scope-transfer[data-part='to-target-trigger'] {
109
+ grid-row: 2;
110
+ grid-column: 1 / 3;
111
+ justify-self: end;
112
+ }
113
+
114
+ .xh-scope-transfer[data-part='to-source-trigger'] {
115
+ grid-row: 2;
116
+ grid-column: 2 / 4;
117
+ justify-self: start;
118
+ }
119
+
120
+ .xh-scope-transfer[data-part='source-panel'],
121
+ .xh-scope-transfer[data-part='target-panel'] {
122
+ display: flex;
123
+ flex-direction: column;
124
+ block-size: 100%;
125
+ min-inline-size: 0;
126
+ border: var(--xh-stroke-thin) solid var(--xh-transfer-panel-border, var(--xh-border-default));
127
+ border-radius: var(--xh-transfer-panel-radius, var(--xh-shape-surface));
128
+ background: var(--xh-transfer-panel-bg, var(--xh-bg-surface));
129
+ overflow: hidden;
130
+ }
131
+
132
+ /* 整体禁用只写在 root 与各角色节点上;面板自己也带 data-disabled,观感一处收口 */
133
+ .xh-scope-transfer[data-part='source-panel'][data-disabled],
134
+ .xh-scope-transfer[data-part='target-panel'][data-disabled] {
135
+ background: var(--xh-transfer-panel-bg-disabled, var(--xh-bg-muted));
136
+ }
137
+
138
+ /* 面板内三个角色的槽都带 panel- 段,与部件名逐字对上。
139
+ 栏头是一条淡底:靠底色与下面的列表分开,不再画分隔线;上下 12px,单行约 40px 高 */
140
+ .xh-scope-transfer[data-part='panel-header'] {
141
+ display: flex;
142
+ gap: var(--xh-transfer-panel-header-gap, var(--xh-_transfer-gap));
143
+ align-items: center;
144
+ padding-block: var(--xh-transfer-panel-header-py, var(--xh-space-3));
145
+ padding-inline: var(--xh-transfer-panel-header-px, var(--xh-_transfer-px));
146
+ background: var(--xh-transfer-panel-header-bg, var(--xh-bg-muted));
147
+ }
148
+
149
+ /* 标题占满剩余宽度,把计数挤到行尾侧 */
150
+ .xh-scope-transfer[data-part='panel-title'] {
151
+ flex: 1;
152
+ min-inline-size: 0;
153
+ overflow: hidden;
154
+ color: var(--xh-transfer-panel-title-fg, var(--xh-fg-default));
155
+ /* 面板标头是 Surface 内的标题:14 / 500 */
156
+ font-size: var(--xh-transfer-panel-title-font-size, var(--xh-text-label-size));
157
+ font-weight: var(--xh-transfer-panel-title-font-weight, var(--xh-font-weight-medium));
158
+ line-height: var(--xh-leading-none);
159
+ white-space: nowrap;
160
+ text-overflow: ellipsis;
161
+ }
162
+
163
+ .xh-scope-transfer[data-part='panel-count'] {
164
+ flex: none;
165
+ color: var(--xh-transfer-panel-count-fg, var(--xh-fg-subtle));
166
+ font-size: var(--xh-transfer-panel-count-font-size, var(--xh-text-caption-size));
167
+ line-height: var(--xh-leading-none);
168
+ font-variant-numeric: tabular-nums;
169
+ }
170
+
171
+ /* 连接层只给数字(data-checked-count / data-count),文案是作者的事:
172
+ 语言、量词、单复数都由他定。作者什么都不写时这里补出"勾中/可见",
173
+ 写了内容就用作者的(:empty 只命中空节点) */
174
+ .xh-scope-transfer[data-part='panel-count']:empty::after {
175
+ content: attr(data-checked-count) ' / ' attr(data-count);
176
+ }
177
+
178
+ /* 面板内嵌的搜索框:通栏一行,控件高与字号随尺寸档,只画一道面内分隔的下划线(取面材质的分隔令牌);
179
+ 重置与占位前景由字段家族按 data-xh-field-input 给 */
180
+ .xh-scope-transfer[data-part='search'] {
181
+ --xh-field-placeholder-fg: var(--xh-transfer-placeholder-fg, var(--xh-fg-subtle));
182
+ /* 自动填充铺的底取所在面板的面,不取画布:否则框内比周围亮出(或暗出)一块 */
183
+ --xh-field-autofill-bg: var(--xh-bg-surface);
184
+
185
+ display: block;
186
+ flex: none;
187
+ inline-size: 100%;
188
+ block-size: var(--xh-transfer-search-h, var(--xh-_transfer-h));
189
+ padding-block: 0;
190
+ padding-inline: var(--xh-transfer-search-px, var(--xh-_transfer-px));
191
+ border: 0;
192
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-transfer-search-border, var(--xh-material-solid-separator));
193
+ background: var(--xh-transfer-search-bg, transparent);
194
+ color: var(--xh-transfer-search-fg, var(--xh-fg-default));
195
+ font: inherit;
196
+ font-size: var(--xh-transfer-search-font-size, var(--xh-_transfer-font-size));
197
+ }
198
+
199
+ /* 聚焦不画环:插入符就是焦点指示。框没有外壳,全局那圈键盘焦点环只会压在通栏一行上 */
200
+ .xh-scope-transfer[data-part='search']:focus-visible {
201
+ outline: none;
202
+ }
203
+
204
+ /* 单体控件的禁用是原生 disabled,样式只能写 :disabled;集合条目才读 data-disabled */
205
+ .xh-scope-transfer[data-part='search']:disabled {
206
+ color: var(--xh-fg-disabled);
207
+ }
208
+
209
+ /* 两侧列表定高:高度只由这个槽给,与条目数无关。左右两块因此恒等高,
210
+ 搬走条目、搜索筛掉条目、整侧搬空,面板都停在原地不缩。
211
+ flex-basis 取 auto 而不是 0,块尺寸才是这一栏真正的主轴基准 */
212
+ .xh-scope-transfer[data-part='list'] {
213
+ display: flex;
214
+ flex: 1 1 auto;
215
+ flex-direction: column;
216
+ gap: var(--xh-transfer-list-gap, var(--xh-list-option-gap));
217
+ /* 行通栏:列表不留内衬,行面直接贴到面板两缘 */
218
+ block-size: var(--xh-transfer-list-h, var(--xh-viewport-h-sm));
219
+ padding-block: var(--xh-transfer-list-py, var(--xh-space-0));
220
+ padding-inline: var(--xh-transfer-list-px, var(--xh-space-0));
221
+ overflow: auto;
222
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
223
+ }
224
+
225
+ /* 刷新:这一侧已有条目时后台在取,保留上一帧,列表按 micro 淡下,数据到了再淡回;在途占位此时让位 */
226
+ .xh-scope-transfer[data-part='list'][aria-busy='true'] {
227
+ opacity: var(--xh-state-disabled-opacity);
228
+ }
229
+
230
+ /* Virtualizer viewport 才是真正的滚动层。此时 list 只负责 Transfer 的定高,
231
+ 不再用内边距和自身滚动制造第二个窗口;viewport 铺满整块内容区,
232
+ 贴着它量出的自绘滚动条也就从列表顶一直落到列表底。 */
233
+ .xh-scope-transfer[data-part='list'][data-xh-virtualized] {
234
+ gap: 0;
235
+ min-block-size: 0;
236
+ padding: 0;
237
+ overflow: hidden;
238
+ }
239
+
240
+ /* Vue / React 的 virtualizer root 在 list 外,下面第一条只命中 viewport;
241
+ Web Components 的 Light DOM root 在 list 内,两条一起命中。
242
+ Web 作者把 xh-virtualizer 宿主设为 display: contents 后,root 会直接参与 list 的 flex 排布。 */
243
+ .xh-scope-transfer[data-part='list'][data-xh-virtualized]
244
+ .xh-scope-virtualizer[data-part='root'] {
245
+ flex: 1 1 auto;
246
+ min-block-size: 0;
247
+ block-size: 100%;
248
+ }
249
+
250
+ .xh-scope-transfer[data-part='list'][data-xh-virtualized]
251
+ .xh-scope-virtualizer[data-part='viewport'] {
252
+ min-block-size: 0;
253
+ block-size: 100%;
254
+ }
255
+
256
+ /* 焦点在列表外时容器自己进 Tab 序列兜底,落焦不画环:高亮永远长在条目上 */
257
+ .xh-scope-transfer[data-part='list']:focus-visible {
258
+ outline: none;
259
+ }
260
+
261
+ /* 空态占位:待在面板里、list 的兄弟(列表框只许拥有 option 与 group)。
262
+ 盒归面板,这里只画一句居中的次要文字 */
263
+ .xh-scope-transfer[data-part='empty'] {
264
+ display: block;
265
+ flex: none;
266
+ padding-block: var(--xh-transfer-empty-py, var(--xh-space-3));
267
+ padding-inline: var(--xh-transfer-empty-px, var(--xh-_transfer-px));
268
+ color: var(--xh-transfer-empty-fg, var(--xh-fg-muted));
269
+ font-size: var(--xh-transfer-empty-font-size, var(--xh-_transfer-font-size));
270
+ line-height: var(--xh-leading-none);
271
+ text-align: center;
272
+ }
273
+
274
+ /* 上面给了 display,UA 的 [hidden]{display:none} 已被盖掉,这里补回来 */
275
+ .xh-scope-transfer[data-part='empty'][hidden] {
276
+ display: none;
277
+ }
278
+
279
+ .xh-scope-transfer[data-part='empty'][data-disabled] {
280
+ color: var(--xh-fg-disabled);
281
+ }
282
+
283
+ /* 在途占位:与空态占位同一个位置、同一副观感,两者不同屏 */
284
+ .xh-scope-transfer[data-part='loading'] {
285
+ display: flex;
286
+ align-items: center;
287
+ justify-content: center;
288
+ gap: var(--xh-_transfer-gap);
289
+ flex: none;
290
+ padding-block: var(--xh-transfer-loading-py, var(--xh-space-3));
291
+ padding-inline: var(--xh-transfer-loading-px, var(--xh-_transfer-px));
292
+ color: var(--xh-transfer-loading-fg, var(--xh-fg-muted));
293
+ font-size: var(--xh-transfer-loading-font-size, var(--xh-_transfer-font-size));
294
+ line-height: var(--xh-leading-none);
295
+ text-align: center;
296
+ }
297
+
298
+ .xh-scope-transfer[data-part='loading'][hidden] {
299
+ display: none;
300
+ }
301
+
302
+ /* 首次加载:文案前一枚加载环,由加载环配方画(连接层投影 data-xh-loading-ring 与 data-loading),
303
+ 直径取所在尺寸档的图标档 */
304
+ .xh-scope-transfer[data-part='loading']::before {
305
+ content: '';
306
+ flex: none;
307
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
308
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
309
+ }
310
+
311
+ .xh-scope-transfer[data-part='loading'][data-disabled] {
312
+ color: var(--xh-fg-disabled);
313
+ }
314
+
315
+ .xh-scope-transfer[data-part='group'] {
316
+ display: flex;
317
+ flex: none;
318
+ flex-direction: column;
319
+ gap: var(--xh-transfer-group-gap, var(--xh-list-option-gap));
320
+ }
321
+
322
+ .xh-scope-transfer[data-part='group'][hidden] {
323
+ display: none;
324
+ }
325
+
326
+ /* 组内条目搬到对面、或被搜索筛掉时都只是打 hidden,一条不剩的分组连标题一起撤下,
327
+ 免得列表里留着一排够不着的标题 */
328
+ .xh-scope-transfer[data-part='group']:not(:has([data-part='item']:not([hidden]))) {
329
+ display: none;
330
+ }
331
+
332
+ /* 组间留白只加在后继分组上:首组顶上已经有 list 的内边距,再加一层会显得头重 */
333
+ .xh-scope-transfer[data-part='group'] + .xh-scope-transfer[data-part='group'] {
334
+ margin-block-start: var(--xh-transfer-group-spacing, var(--xh-space-1_5));
335
+ }
336
+
337
+ /* 分组标题不是选项、进不了导航,画成小号次要文字,
338
+ 内缩与条目对齐(同一个 padding-inline),标题与条目文字才在一条竖线上 */
339
+ .xh-scope-transfer[data-part='group-label'] {
340
+ display: block;
341
+ padding-block: var(--xh-transfer-group-label-py, var(--xh-space-1));
342
+ padding-inline: var(--xh-transfer-group-label-px, var(--xh-_transfer-px));
343
+ color: var(--xh-transfer-group-label-fg, var(--xh-fg-muted));
344
+ font-size: var(--xh-transfer-group-label-font-size, var(--xh-text-caption-size));
345
+ font-weight: var(--xh-transfer-group-label-font-weight, var(--xh-font-weight-medium));
346
+ line-height: var(--xh-leading-none);
347
+ user-select: none;
348
+ }
349
+
350
+ .xh-scope-transfer[data-part='group-label'][hidden] {
351
+ display: none;
352
+ }
353
+
354
+ .xh-scope-transfer[data-part='group-label'][data-disabled] {
355
+ color: var(--xh-fg-disabled);
356
+ }
357
+
358
+ /* 条目走 Collection Item 的 page 语境(页内持久集合):悬停 / 高亮 / 按下面(白底承载 hover 100 →
359
+ pressed 200)与勾选行的选中面(品牌淡底 + 淡底前景,selected+hover 20% / +pressed 28%)都由家族按
360
+ aria-selected / aria-disabled 给出,标记由行首的勾选方框承担;禁用面(字色降级、not-allowed、不换面)
361
+ 也归家族。这里只把公开槽映射到桥接槽。
362
+ 布局保持 flex 而不用家族网格:间距统一由行的 gap 给,家族按槽下发的外边距(--xh-collection-gap)归零 */
363
+ .xh-scope-transfer[data-part='item'] {
364
+ --xh-collection-block-padding: var(--xh-transfer-item-py, var(--xh-_transfer-item-py));
365
+ --xh-collection-inline-padding: var(--xh-transfer-item-px, var(--xh-_transfer-px));
366
+ --xh-collection-gap: 0;
367
+ --xh-collection-font-size: var(--xh-transfer-item-font-size, var(--xh-_transfer-font-size));
368
+ --xh-collection-radius: var(--xh-transfer-item-radius, 0);
369
+ /* 作者的图标尺槽经桥接槽下发到条目,家族缺省按 data-xh-collection-size 取档 */
370
+ --xh-collection-glyph-size: var(--xh-transfer-icon-size, var(--xh-_collection-glyph-size));
371
+ --xh-collection-fg-rest: var(--xh-transfer-item-fg, var(--xh-fg-default));
372
+ --xh-collection-fg-hover: var(--xh-transfer-item-fg, var(--xh-fg-default));
373
+ --xh-collection-fg-keyboard-highlight: var(--xh-transfer-item-fg, var(--xh-fg-default));
374
+ --xh-collection-fg-pressed: var(--xh-transfer-item-fg, var(--xh-fg-default));
375
+ --xh-collection-fg-selected: var(--xh-transfer-item-fg-selected, var(--xh-fg-on-brand-subtle));
376
+ --xh-collection-fg-selected-hover: var(--xh-transfer-item-fg-selected, var(--xh-fg-on-brand-subtle));
377
+ --xh-collection-fg-selected-highlight: var(--xh-transfer-item-fg-selected, var(--xh-fg-on-brand-subtle));
378
+ --xh-collection-fg-selected-pressed: var(--xh-transfer-item-fg-selected, var(--xh-fg-on-brand-subtle));
379
+ --xh-collection-bg-hover: var(--xh-transfer-item-bg-hover, var(--xh-bg-subtle));
380
+ --xh-collection-bg-keyboard-highlight: var(--xh-transfer-item-bg-hover, var(--xh-bg-subtle));
381
+ --xh-collection-bg-pressed: var(--xh-transfer-item-bg-pressed, var(--xh-bg-subtle-hover));
382
+ --xh-collection-bg-selected: var(--xh-transfer-item-bg-selected, var(--xh-bg-brand-subtle));
383
+ /* data-highlighted 跟的是连接层记的焦点条目(指针点选也会落焦):只换面,焦点环在 :focus-visible 下再接回 */
384
+ --xh-collection-outline-keyboard-highlight: transparent;
385
+ --xh-collection-outline-selected-highlight: transparent;
386
+
387
+ display: flex;
388
+ flex: none;
389
+ gap: var(--xh-transfer-item-gap, var(--xh-_transfer-gap));
390
+ align-items: center;
391
+ min-block-size: var(--xh-transfer-item-h, var(--xh-_transfer-item-h));
392
+ /* 行高留出文字的上下伸展空间,行内那层 overflow:hidden 才不会把字削掉 */
393
+ line-height: var(--xh-transfer-item-leading, var(--xh-leading-normal));
394
+ white-space: nowrap;
395
+ user-select: none;
396
+ }
397
+
398
+ /* 键盘焦点出现时环才接回并立即到位,不压在背景过渡的中间帧上 */
399
+ .xh-scope-transfer[data-part='item']:focus-visible:not(:hover) {
400
+ --xh-collection-outline-keyboard-highlight: var(--xh-ring-focus);
401
+ --xh-collection-outline-selected-highlight: var(--xh-ring-focus);
402
+
403
+ transition: none;
404
+ }
405
+
406
+ .xh-scope-transfer[data-part='item-text'] {
407
+ flex: 1;
408
+ min-inline-size: 0;
409
+ overflow: hidden;
410
+ white-space: nowrap;
411
+ text-overflow: ellipsis;
412
+ }
413
+
414
+ /* 条目的勾选格与全选格共用同一套盒子,并成一条规则写:分开写迟早只改到一半,
415
+ 两个方框就此走形。全选格没有对应的角色节点(它自己就是按钮),由伪元素补出来 */
416
+ .xh-scope-transfer[data-part='item-checkbox'],
417
+ .xh-scope-transfer[data-part='select-all-trigger']::before {
418
+ /* 方框里的勾按边长的比例取尺(与 Checkbox 同一比例),不吃家族按档下发的行内字形尺 */
419
+ --xh-icon-size: calc(var(--xh-transfer-checkbox-size, var(--xh-_transfer-box)) * 0.75);
420
+
421
+ display: inline-flex;
422
+ flex: none;
423
+ align-items: center;
424
+ justify-content: center;
425
+ inline-size: var(--xh-transfer-checkbox-size, var(--xh-_transfer-box));
426
+ block-size: var(--xh-transfer-checkbox-size, var(--xh-_transfer-box));
427
+ border: var(--xh-stroke-thin) solid var(--xh-transfer-checkbox-border, var(--xh-border-strong));
428
+ border-radius: var(--xh-transfer-checkbox-radius, var(--xh-shape-inset));
429
+ background: var(--xh-transfer-checkbox-bg, transparent);
430
+ color: var(--xh-transfer-checkbox-fg, var(--xh-_transfer-on-accent));
431
+ font-size: var(--xh-transfer-checkbox-font-size, calc(var(--xh-_transfer-box) * 0.75));
432
+ line-height: var(--xh-leading-none);
433
+ transition:
434
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
435
+ border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
436
+ }
437
+
438
+ /* content 只能给伪元素,绝不能并进上面那条:content 落在普通元素上会顶掉它的全部子节点,
439
+ item-checkbox 里作者写的图标就此消失 */
440
+ .xh-scope-transfer[data-part='select-all-trigger']::before {
441
+ content: '';
442
+ }
443
+
444
+ /* 勾中即填色。全选格三态里 all 与 some 都算"有值",与条目共用同一副填色 */
445
+ .xh-scope-transfer[data-part='item-checkbox'][data-state='checked'],
446
+ .xh-scope-transfer[data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate'])::before {
447
+ border-color: var(--xh-transfer-checkbox-border-checked, var(--xh-_transfer-accent));
448
+ background: var(--xh-transfer-checkbox-bg-checked, var(--xh-_transfer-accent));
449
+ }
450
+
451
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
452
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的 */
453
+ .xh-scope-transfer[data-part='item-checkbox'][data-state='checked']:focus-visible {
454
+ --xh-_ring-color: currentColor;
455
+ }
456
+
457
+ /* 格子里的勾与全选格的三态标记(all 打勾、some 打横杠、none 留空)由勾选标记配方画:常驻、按状态淡变
458
+ 并轻缩放。条目的格子是真实节点,标记是它的 ::before;全选格自己就是按钮,方框只能是行首那颗 ::before,
459
+ 标记是 ::after、叠在方框正中——两支桥接槽写在全选格上 */
460
+
461
+ .xh-scope-transfer[data-part='item-checkbox'][data-disabled] {
462
+ border-color: var(--xh-transfer-checkbox-border-disabled, var(--xh-border-default));
463
+ background: var(--xh-transfer-checkbox-bg-disabled, var(--xh-bg-muted));
464
+ }
465
+
466
+ /* 全选格是原生按钮(三态经 aria-checked 上报,激活由平台负责),禁用同时打原生 disabled 与 data-disabled。
467
+ 它是「方框 + 文案」的整行命中区:接 Action Control text 档、ghost 形态,悬停 / 按下 / 禁用面与过渡由家族给
468
+ (白底承载 hover 100 → pressed 200),按下只换面不缩放(--xh-action-scale-pressed: none),勾选回执落在方框上;
469
+ 盒随内容收宽、高度取 xs 档的 24px 命中地板(方框 16px 居中其间),text 档的内距与最小宽度归零。
470
+ position 是给叠在方框上的那颗字形 ::after 当定位基准 */
471
+ .xh-scope-transfer[data-part='select-all-trigger'] {
472
+ /* 叠在方框上的那颗字形 ::after 与方框里的勾同一把尺 */
473
+ --xh-icon-size: calc(var(--xh-transfer-checkbox-size, var(--xh-_transfer-box)) * 0.75);
474
+ /* 勾选标记叠在行首方框正中:方框边长与标记色交给配方 */
475
+ --xh-check-mark-box-size: var(--xh-transfer-checkbox-size, var(--xh-_transfer-box));
476
+ --xh-check-mark-fg: var(--xh-transfer-checkbox-fg, var(--xh-_transfer-on-accent));
477
+
478
+ --xh-action-min-inline-size: 0;
479
+ --xh-action-padding-inline: 0;
480
+ --xh-action-gap: var(--xh-transfer-select-all-gap, var(--xh-control-gap-sm));
481
+ /* 全选格是嵌在面板头里的勾选小块:inset 档圆角(身份表登记) */
482
+ --xh-action-radius: var(--xh-transfer-select-all-radius, var(--xh-shape-inset));
483
+ --xh-action-bg-hover: var(--xh-transfer-select-all-bg-hover, var(--xh-_action-variant-bg-hover));
484
+ --xh-action-bg-pressed: var(--xh-transfer-select-all-bg-pressed, var(--xh-_action-variant-bg-pressed));
485
+ --xh-action-fg-rest: var(--xh-transfer-select-all-fg, var(--xh-fg-muted));
486
+ --xh-action-fg-hover: var(--xh-transfer-select-all-fg, var(--xh-fg-muted));
487
+ --xh-action-fg-pressed: var(--xh-transfer-select-all-fg, var(--xh-fg-muted));
488
+ --xh-action-fg-focus-visible: var(--xh-transfer-select-all-fg, var(--xh-fg-muted));
489
+ --xh-action-font-size: var(--xh-transfer-select-all-font-size, var(--xh-text-caption-size));
490
+ --xh-action-scale-pressed: none;
491
+
492
+ flex: none;
493
+ justify-content: start;
494
+ padding: 0;
495
+ font-weight: var(--xh-font-weight-medium);
496
+ }
497
+
498
+ /* 两颗搬运钮是只有字形的离散动作钮:接 Action Control 的 icon 档、subtle 形态(淡底、无边,
499
+ 淡底阶梯 hover 200 → pressed 300),盒、焦点环、粗指针热区与禁用面由家族给。
500
+ 钮是正方盒,按 sm 档取一个控件高,正方盒取圆形 */
501
+ .xh-scope-transfer[data-part='to-target-trigger'],
502
+ .xh-scope-transfer[data-part='to-source-trigger'] {
503
+ --xh-action-visual-size: var(--xh-transfer-trigger-size, var(--xh-_action-profile-visual-size));
504
+ --xh-action-min-inline-size: var(--xh-transfer-trigger-size, var(--xh-_action-profile-visual-size));
505
+ --xh-action-padding-inline: var(--xh-transfer-trigger-px, var(--xh-_action-profile-padding-inline));
506
+ --xh-action-radius: var(--xh-transfer-trigger-radius, var(--xh-shape-circle));
507
+ --xh-action-border-rest: var(--xh-transfer-trigger-border, var(--xh-_action-variant-border-rest));
508
+ --xh-action-border-hover: var(--xh-transfer-trigger-border, var(--xh-_action-variant-border-hover));
509
+ --xh-action-border-pressed: var(--xh-transfer-trigger-border, var(--xh-_action-variant-border-pressed));
510
+ --xh-action-bg-rest: var(--xh-transfer-trigger-bg, var(--xh-_action-variant-bg-rest));
511
+ --xh-action-bg-hover: var(--xh-transfer-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
512
+ --xh-action-bg-pressed: var(--xh-transfer-trigger-bg-active, var(--xh-_action-variant-bg-pressed));
513
+ --xh-action-fg-rest: var(--xh-transfer-trigger-fg, var(--xh-_action-variant-fg-rest));
514
+ --xh-action-fg-hover: var(--xh-transfer-trigger-fg, var(--xh-_action-variant-fg-hover));
515
+ --xh-action-fg-pressed: var(--xh-transfer-trigger-fg, var(--xh-_action-variant-fg-pressed));
516
+ --xh-action-shadow-hover: var(--xh-transfer-trigger-shadow-hover, none);
517
+ --xh-action-shadow-pressed: var(--xh-transfer-trigger-shadow-active, none);
518
+ --xh-action-font-size: var(--xh-transfer-trigger-font-size, var(--xh-text-label-size));
519
+ /* 作者塞进钮里的图标与皮肤画的兜底箭头同一把尺:按 icon 档取字形尺寸。
520
+ 配方尚未把 profile 字形档灌进 --xh-icon-size,钮内字形先按 icon 档逐钮取值 */
521
+ --xh-icon-size: var(--xh-transfer-icon-size, var(--xh-_action-profile-glyph-size));
522
+ }
523
+
524
+ /* 上面凡是给了 display 的角色节点都要补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
525
+ 不补的话收起态整个失效。连接层真正会写 hidden 的是 search(searchable 关掉时)、
526
+ item(不属于本侧、或被搜索筛掉)、item-checkbox(oneWay 下的右侧),
527
+ 其余几个是作者自己收起时的兜底 */
528
+ .xh-scope-transfer[data-part='root'][hidden],
529
+ .xh-scope-transfer[data-part='source-panel'][hidden],
530
+ .xh-scope-transfer[data-part='target-panel'][hidden],
531
+ .xh-scope-transfer[data-part='panel-header'][hidden],
532
+ .xh-scope-transfer[data-part='search'][hidden],
533
+ .xh-scope-transfer[data-part='list'][hidden],
534
+ .xh-scope-transfer[data-part='item'][hidden],
535
+ .xh-scope-transfer[data-part='item-checkbox'][hidden],
536
+ .xh-scope-transfer[data-part='select-all-trigger'][hidden],
537
+ .xh-scope-transfer[data-part='to-target-trigger'][hidden],
538
+ .xh-scope-transfer[data-part='to-source-trigger'][hidden] {
539
+ display: none;
540
+ }
541
+
542
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中。
543
+ 堆叠时目标面板在下方,箭头因此朝下与朝上,指的是条目真正要去的方向 */
544
+ .xh-scope-transfer[data-part='to-source-trigger']:empty::before {
545
+ content: '';
546
+ display: inline-block;
547
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
548
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
549
+ vertical-align: var(--xh-glyph-baseline-shift);
550
+ background-color: currentColor;
551
+ -webkit-mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
552
+ mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
553
+ }
554
+
555
+ .xh-scope-transfer[data-part='to-target-trigger']:empty::before {
556
+ content: '';
557
+ display: inline-block;
558
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
559
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
560
+ vertical-align: var(--xh-glyph-baseline-shift);
561
+ background-color: currentColor;
562
+ -webkit-mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
563
+ mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
564
+ }
565
+
566
+ /* 宽档:视口放得下两块面板,回到并排——两侧面板各占一栏、跨两行,
567
+ 中间那栏上下各放一个搬运按钮,上格贴底、下格贴顶,两钮夹着中线相遇 */
568
+ @media (min-width: 640px) {
569
+ .xh-scope-transfer[data-part='source-panel'] {
570
+ grid-row: 1 / 3;
571
+ grid-column: 1;
572
+ }
573
+
574
+ .xh-scope-transfer[data-part='target-panel'] {
575
+ grid-row: 1 / 3;
576
+ grid-column: 3;
577
+ }
578
+
579
+ .xh-scope-transfer[data-part='to-target-trigger'] {
580
+ grid-row: 1;
581
+ grid-column: 2;
582
+ align-self: end;
583
+ justify-self: stretch;
584
+ }
585
+
586
+ .xh-scope-transfer[data-part='to-source-trigger'] {
587
+ grid-row: 2;
588
+ grid-column: 2;
589
+ align-self: start;
590
+ justify-self: stretch;
591
+ }
592
+
593
+ /* 单向组合的唯一动作跨过两行,中心才与两侧面板的中心重合。 */
594
+ .xh-scope-transfer[data-part='root'][data-one-way]
595
+ > .xh-scope-transfer[data-part='to-target-trigger'] {
596
+ grid-row: 1 / 3;
597
+ align-self: center;
598
+ }
599
+
600
+ /* 并排时目标面板在行尾侧,箭头改回朝行尾与朝行首。
601
+ 盒的量法与窄档那两条逐字相同:兜底字形的盒必须按 --xh-icon-size 量,
602
+ 作者换成自己的图标才和皮肤画的一样大 */
603
+ .xh-scope-transfer[data-part='to-source-trigger']:empty::before {
604
+ content: '';
605
+ display: inline-block;
606
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
607
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
608
+ vertical-align: var(--xh-glyph-baseline-shift);
609
+ background-color: currentColor;
610
+ -webkit-mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
611
+ mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
612
+ }
613
+
614
+ .xh-scope-transfer[data-part='to-target-trigger']:empty::before {
615
+ content: '';
616
+ display: inline-block;
617
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
618
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
619
+ vertical-align: var(--xh-glyph-baseline-shift);
620
+ background-color: currentColor;
621
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
622
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
623
+ }
624
+ }
625
+
626
+ @media (forced-colors: active) {
627
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
628
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
629
+ 按钮面上取 ButtonText,悬停与按下时家族把按钮涂成 Highlight、字形换 HighlightText;
630
+ 禁用取 GrayText */
631
+ .xh-scope-transfer:is([data-part='to-source-trigger'], [data-part='to-target-trigger']):empty::before {
632
+ forced-color-adjust: none;
633
+ background-color: ButtonText;
634
+ }
635
+
636
+ .xh-scope-transfer:is([data-part='to-source-trigger'], [data-part='to-target-trigger']):not([data-disabled]):not([data-loading]):is(:hover, :active, [data-pressed]):empty::before {
637
+ background-color: HighlightText;
638
+ }
639
+
640
+ .xh-scope-transfer:is([data-part='to-source-trigger'], [data-part='to-target-trigger'])[data-disabled]:empty::before {
641
+ background-color: GrayText;
642
+ }
643
+ }
644
+ }