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

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 (110) hide show
  1. package/CHANGELOG.md +341 -0
  2. package/css/accordion.css +5 -0
  3. package/css/affix.css +5 -0
  4. package/css/alert.css +5 -0
  5. package/css/anchor.css +5 -0
  6. package/css/avatar-group.css +5 -0
  7. package/css/avatar.css +5 -0
  8. package/css/back-top.css +7 -2
  9. package/css/badge.css +5 -0
  10. package/css/breadcrumb.css +5 -0
  11. package/css/button-group.css +6 -1
  12. package/css/button.css +16 -1
  13. package/css/calendar.css +6 -1
  14. package/css/card.css +5 -0
  15. package/css/carousel.css +7 -2
  16. package/css/cascader.css +204 -24
  17. package/css/checkbox-group.css +25 -20
  18. package/css/checkbox.css +6 -1
  19. package/css/clipboard.css +8 -3
  20. package/css/code-block.css +5 -0
  21. package/css/collapsible.css +5 -0
  22. package/css/color-picker.css +27 -6
  23. package/css/combobox.css +42 -20
  24. package/css/composer.css +6 -1
  25. package/css/context-menu.css +62 -34
  26. package/css/countdown.css +5 -0
  27. package/css/date-field.css +10 -5
  28. package/css/date-picker.css +72 -3
  29. package/css/descriptions.css +5 -0
  30. package/css/dialog.css +69 -9
  31. package/css/drawer.css +33 -12
  32. package/css/dynamic-input.css +7 -2
  33. package/css/editable.css +11 -6
  34. package/css/ellipsis.css +5 -0
  35. package/css/empty-state.css +5 -0
  36. package/css/field.css +37 -1
  37. package/css/file-upload.css +8 -3
  38. package/css/flex.css +5 -0
  39. package/css/float-button.css +7 -2
  40. package/css/form.css +23 -6
  41. package/css/gradient-text.css +5 -0
  42. package/css/grid.css +5 -0
  43. package/css/highlight.css +5 -0
  44. package/css/hover-card.css +34 -17
  45. package/css/icon-wrapper.css +5 -0
  46. package/css/icon.css +5 -0
  47. package/css/image-viewer.css +196 -0
  48. package/css/image.css +5 -0
  49. package/css/infinite-scroll.css +5 -0
  50. package/css/layout.css +5 -0
  51. package/css/list.css +5 -0
  52. package/css/listbox.css +14 -6
  53. package/css/loading-bar.css +5 -0
  54. package/css/log.css +5 -0
  55. package/css/marquee.css +5 -0
  56. package/css/mention.css +33 -22
  57. package/css/menu.css +57 -23
  58. package/css/menubar.css +34 -25
  59. package/css/navigation-menu.css +6 -1
  60. package/css/number-animation.css +5 -0
  61. package/css/number-field.css +21 -16
  62. package/css/page-header.css +5 -0
  63. package/css/pagination.css +5 -0
  64. package/css/pin-input.css +11 -6
  65. package/css/popconfirm.css +44 -0
  66. package/css/popover.css +34 -11
  67. package/css/popselect.css +50 -16
  68. package/css/progress.css +73 -1
  69. package/css/qr-code.css +5 -0
  70. package/css/radio-group.css +6 -1
  71. package/css/rating.css +5 -0
  72. package/css/result.css +5 -0
  73. package/css/scroll-area.css +5 -6
  74. package/css/select.css +167 -17
  75. package/css/separator.css +5 -0
  76. package/css/side-nav.css +168 -0
  77. package/css/skeleton.css +5 -0
  78. package/css/slider.css +60 -0
  79. package/css/spinner.css +9 -1
  80. package/css/splitter.css +5 -0
  81. package/css/statistic.css +5 -0
  82. package/css/steps.css +7 -2
  83. package/css/switch.css +34 -0
  84. package/css/table.css +11 -6
  85. package/css/tabs.css +5 -0
  86. package/css/tags-input.css +12 -7
  87. package/css/text-field.css +28 -10
  88. package/css/thread.css +6 -1
  89. package/css/time-field.css +10 -5
  90. package/css/time-picker.css +42 -27
  91. package/css/time.css +5 -0
  92. package/css/timeline.css +5 -0
  93. package/css/toast.css +13 -12
  94. package/css/toaster.css +5 -0
  95. package/css/toggle-group.css +6 -1
  96. package/css/toggle.css +6 -1
  97. package/css/tone.css +22 -0
  98. package/css/toolbar.css +5 -0
  99. package/css/tooltip.css +39 -21
  100. package/css/tour.css +45 -21
  101. package/css/transfer.css +16 -9
  102. package/css/tree-select.css +45 -18
  103. package/css/tree.css +13 -5
  104. package/css/typography.css +5 -0
  105. package/css/virtualizer.css +5 -0
  106. package/css/watermark.css +5 -0
  107. package/index.css +6 -3
  108. package/index.unlayered.css +2325 -588
  109. package/package.json +4 -3
  110. package/css/motion.css +0 -58
package/css/toast.css CHANGED
@@ -7,37 +7,38 @@
7
7
  @keyframes xh-toast-in {
8
8
  from {
9
9
  opacity: 0;
10
- transform: translateY(8px) scale(0.98);
10
+ translate: 0 var(--xh-motion-distance-md);
11
+ scale: var(--xh-motion-scale-enter);
11
12
  }
12
13
 
13
14
  to {
14
15
  opacity: 1;
15
- transform: none;
16
+ translate: 0 0;
17
+ scale: 1;
16
18
  }
17
19
  }
18
20
 
19
21
  @keyframes xh-toast-out {
20
22
  from {
21
23
  opacity: 1;
22
- transform: none;
24
+ translate: 0 0;
25
+ scale: 1;
23
26
  }
24
27
 
25
28
  to {
26
29
  opacity: 0;
27
- transform: translateY(4px) scale(0.96);
28
- }
29
- }
30
-
31
- /* 通知是自己冒出来的,用户没按任何键:减弱动效的诉求在这里比别处更硬。
32
- !important 在低层里反而更强(重要声明的层序是反的),足以压住组件层的动画。 */
33
- @media (prefers-reduced-motion: reduce) {
34
- [data-scope='toast'][data-part] {
35
- animation-duration: 0.01ms !important;
30
+ translate: 0 var(--xh-motion-distance-sm);
31
+ scale: var(--xh-motion-scale-enter);
36
32
  }
37
33
  }
38
34
  }
39
35
 
40
36
  @layer xihan.components {
37
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
38
+ [data-scope='toast'] {
39
+ --xh-toast-skin: 1;
40
+ }
41
+
41
42
  [data-scope='toast'][data-part='root'] {
42
43
  display: flex;
43
44
  flex-direction: column;
package/css/toaster.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toaster'] {
4
+ --xh-toaster-skin: 1;
5
+ }
6
+
2
7
  /* 地标容器不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
3
8
  root 只是给读屏一个可跳转的落点。它若留下一个块盒,写在页面中段的用法
4
9
  (按钮和队列摆在一起)就会凭空多出一行空白。
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toggle-group'] {
4
+ --xh-toggle-group-skin: 1;
5
+ }
6
+
2
7
  /* 分段控件:段与段之间不留缝,靠共边连成一体,所以 root 不设 gap。
3
8
  排布只能读 data-orientation——aria-orientation 在多选模式下连接层根本不输出(role=group 不收) */
4
9
  [data-scope='toggle-group'][data-part='root'] {
@@ -31,7 +36,7 @@
31
36
  --xh-_bg-hover: var(--xh-toggle-group-item-bg-hover, var(--xh-bg-subtle-hover));
32
37
  --xh-_bg-active: var(--xh-toggle-group-item-bg-active, var(--xh-bg-subtle-active));
33
38
  --xh-_fg: var(--xh-toggle-group-item-fg, var(--xh-fg-default));
34
- --xh-_border: var(--xh-toggle-group-item-border, var(--xh-border-default));
39
+ --xh-_border: var(--xh-toggle-group-item-border, var(--xh-border-control));
35
40
 
36
41
  /* 相邻两段靠负外边距压掉一条重边,谁的描边浮在上面必须能指定,
37
42
  因此条目必须是定位元素——静态元素的 z-index 不生效 */
package/css/toggle.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toggle'] {
4
+ --xh-toggle-skin: 1;
5
+ }
6
+
2
7
  [data-scope='toggle'][data-part='root'] {
3
8
  /* 私有槽位:组件令牌 → 语义令牌两级回退,变体只改这几个槽位 */
4
9
  --xh-_bg: var(--xh-toggle-bg, transparent);
@@ -68,7 +73,7 @@
68
73
  --xh-_bg-pressed: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active));
69
74
  --xh-_fg-pressed: var(--xh-_tone-fg, var(--xh-fg-default));
70
75
 
71
- border-color: var(--xh-_tone-border, var(--xh-border-default));
76
+ border-color: var(--xh-_tone-border-control, var(--xh-border-control));
72
77
  }
73
78
 
74
79
  [data-scope='toggle'][data-part='root'][data-variant='ghost'] {
package/css/tone.css CHANGED
@@ -38,6 +38,9 @@
38
38
  --xh-_tone-subtle-hover: color-mix(in oklab, var(--xh-_tone) 20%, var(--xh-bg-surface));
39
39
  --xh-_tone-subtle-active: color-mix(in oklab, var(--xh-_tone) 28%, var(--xh-bg-surface));
40
40
  --xh-_tone-border: color-mix(in oklab, var(--xh-_tone) 40%, var(--xh-bg-surface));
41
+ /* 控件的可操作区边界要 3:1,兑了底色的 --xh-_tone-border 六族全在 1.44–2.18,够不着。
42
+ 这一支直接取主色本体;两族在各自的底上仍不够,在下面按主题单独兜 */
43
+ --xh-_tone-border-control: var(--xh-_tone);
41
44
  /* 在普通背景上表达该语气的文字色:往前景色兑,浅色态变深、深色态变浅 */
42
45
  --xh-_tone-fg: color-mix(in oklab, var(--xh-_tone) 72%, var(--xh-fg-default));
43
46
  }
@@ -82,4 +85,23 @@
82
85
  --xh-_tone-on: var(--xh-color-neutral-950);
83
86
  --xh-_tone-shift: var(--xh-color-neutral-0);
84
87
  }
88
+
89
+ /* 主色本体在各自的底上有两族够不到 3:1:黄在白底上只有 2.70,中性在深色底上只有 2.54。
90
+ 语气色是固定原语、不随主题翻,所以这两族只能按主题各兜一次。
91
+ 浅色是缺省态(不写 data-theme 也算浅色),深色靠属性选择器压过它 */
92
+ [data-tone='warning'] {
93
+ --xh-_tone-border-control: var(--xh-color-warning-700);
94
+ }
95
+
96
+ [data-theme='dark'] [data-tone='warning'] {
97
+ --xh-_tone-border-control: var(--xh-color-warning-600);
98
+ }
99
+
100
+ [data-tone='neutral'] {
101
+ --xh-_tone-border-control: var(--xh-color-neutral-600);
102
+ }
103
+
104
+ [data-theme='dark'] [data-tone='neutral'] {
105
+ --xh-_tone-border-control: var(--xh-color-neutral-550);
106
+ }
85
107
  }
package/css/toolbar.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toolbar'] {
4
+ --xh-toolbar-skin: 1;
5
+ }
6
+
2
7
  /* 一条控件带:条目之间留固定间距,分隔线再把它们切成语义上的几段。
3
8
  排布只能读 data-orientation——它与 aria-orientation 同源,但样式不该去读 ARIA */
4
9
  [data-scope='toolbar'][data-part='root'] {
package/css/tooltip.css CHANGED
@@ -1,4 +1,23 @@
1
+ @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-fade-in {
5
+ from {
6
+ opacity: 0;
7
+ }
8
+
9
+ to {
10
+ opacity: 1;
11
+ }
12
+ }
13
+ }
14
+
1
15
  @layer xihan.components {
16
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17
+ [data-scope='tooltip'] {
18
+ --xh-tooltip-skin: 1;
19
+ }
20
+
2
21
  [data-scope='tooltip'][data-part='trigger'] {
3
22
  display: inline-flex;
4
23
  align-items: center;
@@ -72,38 +91,37 @@
72
91
  --xh-_tooltip-font-size: var(--xh-font-size-md);
73
92
  }
74
93
 
75
- /* 箭头是旋转 45° 的方块,按落定朝向贴在 content 对侧边的中点 */
94
+ /* 箭头是旋转 45° 的方块,按自报的落定朝向贴在 content 对侧边上;
95
+ 交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中 */
76
96
  [data-scope='tooltip'][data-part='arrow'] {
97
+ --xh-_tooltip-arrow-size: var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size));
98
+ --xh-_tooltip-arrow-x: 50%;
99
+ --xh-_tooltip-arrow-y: 50%;
100
+
77
101
  position: absolute;
78
- inline-size: var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size));
79
- block-size: var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size));
102
+ inline-size: var(--xh-_tooltip-arrow-size);
103
+ block-size: var(--xh-_tooltip-arrow-size);
80
104
  background: var(--xh-tooltip-bg, var(--xh-_tone, var(--xh-fg-default)));
81
105
  transform: rotate(45deg);
82
106
  }
83
107
 
84
- [data-scope='tooltip'][data-part='positioner'][data-placement^='bottom'] [data-scope='tooltip'][data-part='arrow'] {
85
- inset-block-start: calc(var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / -2);
86
- inset-inline-start: calc(50% - var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / 2);
108
+ [data-scope='tooltip'][data-part='arrow'][data-placement^='bottom'] {
109
+ inset-block-start: calc(var(--xh-_tooltip-arrow-size) / -2);
110
+ inset-inline-start: calc(var(--xh-_tooltip-arrow-x) - var(--xh-_tooltip-arrow-size) / 2);
87
111
  }
88
112
 
89
- [data-scope='tooltip'][data-part='positioner'][data-placement^='top'] [data-scope='tooltip'][data-part='arrow'] {
90
- inset-block-end: calc(var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / -2);
91
- inset-inline-start: calc(50% - var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / 2);
113
+ [data-scope='tooltip'][data-part='arrow'][data-placement^='top'] {
114
+ inset-block-end: calc(var(--xh-_tooltip-arrow-size) / -2);
115
+ inset-inline-start: calc(var(--xh-_tooltip-arrow-x) - var(--xh-_tooltip-arrow-size) / 2);
92
116
  }
93
117
 
94
- [data-scope='tooltip'][data-part='positioner'][data-placement^='left'] [data-scope='tooltip'][data-part='arrow'] {
95
- inset-block-start: calc(50% - var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / 2);
96
- inset-inline-end: calc(var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / -2);
118
+ [data-scope='tooltip'][data-part='arrow'][data-placement^='left'] {
119
+ inset-block-start: calc(var(--xh-_tooltip-arrow-y) - var(--xh-_tooltip-arrow-size) / 2);
120
+ inset-inline-end: calc(var(--xh-_tooltip-arrow-size) / -2);
97
121
  }
98
122
 
99
- [data-scope='tooltip'][data-part='positioner'][data-placement^='right'] [data-scope='tooltip'][data-part='arrow'] {
100
- inset-block-start: calc(50% - var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / 2);
101
- inset-inline-start: calc(var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size)) / -2);
102
- }
103
-
104
- @media (prefers-reduced-motion: reduce) {
105
- [data-scope='tooltip'][data-part='content'] {
106
- animation-duration: 0.01ms !important;
107
- }
123
+ [data-scope='tooltip'][data-part='arrow'][data-placement^='right'] {
124
+ inset-block-start: calc(var(--xh-_tooltip-arrow-y) - var(--xh-_tooltip-arrow-size) / 2);
125
+ inset-inline-start: calc(var(--xh-_tooltip-arrow-size) / -2);
108
126
  }
109
127
  }
package/css/tour.css CHANGED
@@ -1,9 +1,31 @@
1
1
  @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-fade-in {
5
+ from {
6
+ opacity: 0;
7
+ }
8
+
9
+ to {
10
+ opacity: 1;
11
+ }
12
+ }
13
+
14
+ @keyframes xh-fade-out {
15
+ from {
16
+ opacity: 1;
17
+ }
18
+
19
+ to {
20
+ opacity: 0;
21
+ }
22
+ }
23
+
2
24
  /* 气泡贴着目标探出来:纯淡入分不清它是从哪个元素长出来的 */
3
25
  @keyframes xh-tour-content-in {
4
26
  from {
5
27
  opacity: 0;
6
- translate: 0 4px;
28
+ translate: 0 var(--xh-motion-distance-sm);
7
29
  }
8
30
 
9
31
  to {
@@ -16,7 +38,7 @@
16
38
  @keyframes xh-tour-spotlight-in {
17
39
  from {
18
40
  opacity: 0;
19
- scale: 1.04;
41
+ scale: calc(2 - var(--xh-motion-scale-enter));
20
42
  }
21
43
 
22
44
  to {
@@ -24,16 +46,14 @@
24
46
  scale: 1;
25
47
  }
26
48
  }
27
-
28
- @media (prefers-reduced-motion: reduce) {
29
- [data-scope='tour'] [data-part] {
30
- animation-duration: 0.01ms !important;
31
- transition-duration: 0.01ms !important;
32
- }
33
- }
34
49
  }
35
50
 
36
51
  @layer xihan.components {
52
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
53
+ [data-scope='tour'] {
54
+ --xh-tour-skin: 1;
55
+ }
56
+
37
57
  /* 根节点只是几个浮层的归属容器,不参与排版。
38
58
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
39
59
  [data-scope='tour'][data-part='root'] {
@@ -211,7 +231,7 @@
211
231
  }
212
232
 
213
233
  [data-scope='tour'][data-part='prev-trigger'] {
214
- border-color: var(--xh-border-default);
234
+ border-color: var(--xh-border-control);
215
235
  color: var(--xh-fg-default);
216
236
  }
217
237
 
@@ -261,11 +281,15 @@
261
281
  }
262
282
 
263
283
  /* 箭头是旋转 45° 的方块,只保留朝向目标那两条边的描边;
264
- 引擎不产出箭头偏移,因此沿交叉轴固定居中。居中步没有锚点,连接层会给它发 hidden */
284
+ 交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中。居中步没有锚点,连接层会给它发 hidden */
265
285
  [data-scope='tour'][data-part='arrow'] {
286
+ --xh-_tour-arrow-size: var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size));
287
+ --xh-_tour-arrow-x: 50%;
288
+ --xh-_tour-arrow-y: 50%;
289
+
266
290
  position: absolute;
267
- inline-size: var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size));
268
- block-size: var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size));
291
+ inline-size: var(--xh-_tour-arrow-size);
292
+ block-size: var(--xh-_tour-arrow-size);
269
293
  background: var(--xh-tour-bg, var(--xh-bg-surface));
270
294
  border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-border-default));
271
295
  rotate: 45deg;
@@ -276,29 +300,29 @@
276
300
  }
277
301
 
278
302
  [data-scope='tour'][data-part='arrow'][data-placement^='bottom'] {
279
- inset-block-start: calc(var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / -2);
280
- inset-inline-start: calc(50% - var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / 2);
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);
281
305
  border-block-end: 0;
282
306
  border-inline-end: 0;
283
307
  }
284
308
 
285
309
  [data-scope='tour'][data-part='arrow'][data-placement^='top'] {
286
- inset-block-end: calc(var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / -2);
287
- inset-inline-start: calc(50% - var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / 2);
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);
288
312
  border-block-start: 0;
289
313
  border-inline-start: 0;
290
314
  }
291
315
 
292
316
  [data-scope='tour'][data-part='arrow'][data-placement^='right'] {
293
- inset-inline-start: calc(var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / -2);
294
- inset-block-start: calc(50% - var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / 2);
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);
295
319
  border-block-start: 0;
296
320
  border-inline-end: 0;
297
321
  }
298
322
 
299
323
  [data-scope='tour'][data-part='arrow'][data-placement^='left'] {
300
- inset-inline-end: calc(var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / -2);
301
- inset-block-start: calc(50% - var(--xh-tour-arrow-size, var(--xh-overlay-arrow-size)) / 2);
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);
302
326
  border-block-end: 0;
303
327
  border-inline-start: 0;
304
328
  }
package/css/transfer.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='transfer'] {
4
+ --xh-transfer-skin: 1;
5
+ }
6
+
2
7
  /* 三栏栅格:两侧面板各占一栏、跨两行,中间那栏上下各放一个搬运按钮,
3
8
  两个按钮在中线处相遇。栅格的列号本身就是随书写方向走的(第 1 栏永远在行首侧),
4
9
  dir=rtl 时整块自动镜像,不必另写一套。
@@ -59,7 +64,7 @@
59
64
  gap: var(--xh-transfer-header-gap, var(--xh-control-gap-md));
60
65
  align-items: center;
61
66
  padding-block: var(--xh-transfer-header-py, var(--xh-space-2));
62
- padding-inline: var(--xh-transfer-header-px, var(--xh-control-px-sm));
67
+ padding-inline: var(--xh-transfer-header-px, var(--xh-control-px-md));
63
68
  border-block-end: var(--xh-stroke-thin) solid var(--xh-transfer-panel-border, var(--xh-border-default));
64
69
  }
65
70
 
@@ -95,9 +100,9 @@
95
100
  display: block;
96
101
  inline-size: 100%;
97
102
  block-size: var(--xh-transfer-search-h, var(--xh-control-h-sm));
98
- padding-inline: var(--xh-transfer-search-px, var(--xh-control-px-sm));
103
+ padding-inline: var(--xh-transfer-search-px, var(--xh-control-px-md));
99
104
  border: 0;
100
- border-block-end: var(--xh-stroke-thin) solid var(--xh-transfer-panel-border, var(--xh-border-default));
105
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-transfer-search-border, var(--xh-border-control));
101
106
  background: var(--xh-transfer-search-bg, transparent);
102
107
  color: var(--xh-transfer-search-fg, var(--xh-fg-default));
103
108
  font: inherit;
@@ -136,8 +141,8 @@
136
141
  flex: none;
137
142
  gap: var(--xh-transfer-item-gap, var(--xh-control-gap-md));
138
143
  align-items: center;
139
- padding-block: var(--xh-transfer-item-py, var(--xh-space-1));
140
- padding-inline: var(--xh-transfer-item-px, var(--xh-control-px-sm));
144
+ padding-block: var(--xh-transfer-item-py, var(--xh-space-1_5));
145
+ padding-inline: var(--xh-transfer-item-px, var(--xh-control-px-md));
141
146
  border-radius: var(--xh-transfer-item-radius, var(--xh-shape-control));
142
147
  color: var(--xh-transfer-item-fg, var(--xh-fg-default));
143
148
  font-size: var(--xh-transfer-item-font-size, var(--xh-text-body-size));
@@ -146,13 +151,15 @@
146
151
  white-space: nowrap;
147
152
  cursor: pointer;
148
153
  user-select: none;
149
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
154
+ transition:
155
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
156
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
150
157
  }
151
158
 
152
- /* 键盘高亮与指针悬停共用一套底色:条目本身承载焦点,不另画描边。
159
+ /* 悬停与键盘锚点共用中性灰轻档:条目本身承载焦点,不另画描边。
153
160
  data-highlighted 跟的是连接层记的焦点条目,与勾选互相独立 */
154
161
  [data-scope='transfer'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted]) {
155
- background: var(--xh-transfer-item-bg-highlight, var(--xh-bg-subtle-hover));
162
+ background: var(--xh-transfer-item-bg-hover, var(--xh-bg-subtle));
156
163
  }
157
164
 
158
165
  [data-scope='transfer'][data-part='item']:focus-visible {
@@ -185,7 +192,7 @@
185
192
  justify-content: center;
186
193
  inline-size: var(--xh-transfer-checkbox-size, 16px);
187
194
  block-size: var(--xh-transfer-checkbox-size, 16px);
188
- border: var(--xh-stroke-thin) solid var(--xh-transfer-checkbox-border, var(--xh-border-default));
195
+ border: var(--xh-stroke-thin) solid var(--xh-transfer-checkbox-border, var(--xh-border-control));
189
196
  border-radius: var(--xh-transfer-checkbox-radius, var(--xh-radius-sm));
190
197
  background: var(--xh-transfer-checkbox-bg, var(--xh-bg-canvas));
191
198
  color: var(--xh-transfer-checkbox-fg, var(--xh-fg-on-brand));
@@ -1,4 +1,23 @@
1
+ @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-fade-in {
5
+ from {
6
+ opacity: 0;
7
+ }
8
+
9
+ to {
10
+ opacity: 1;
11
+ }
12
+ }
13
+ }
14
+
1
15
  @layer xihan.components {
16
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17
+ [data-scope='tree-select'] {
18
+ --xh-tree-select-skin: 1;
19
+ }
20
+
2
21
  /* 解剖里没有把「触发器 + 清空按钮」裹在一起的 control 部件,一行是靠 flex-wrap 分出来的:
3
22
  标签占满整行把后面的挤到下一行,触发器与清空按钮就并排落在同一行上。
4
23
  这样作者少写标签、少写清空按钮,剩下的部件也不会塌 */
@@ -12,8 +31,8 @@
12
31
 
13
32
  /* 形态档只换触发框的描边与底色这三个槽,浮层与树不跟着变:
14
33
  变的是「这是个输入位」的表达方式,不是弹出内容的表达方式 */
15
- --xh-_tree-select-border: var(--xh-border-default);
16
- --xh-_tree-select-border-hover: var(--xh-border-strong);
34
+ --xh-_tree-select-border: var(--xh-border-control);
35
+ --xh-_tree-select-border-hover: var(--xh-border-control-hover);
17
36
  --xh-_tree-select-bg: var(--xh-bg-canvas);
18
37
 
19
38
  /* 选中行的文字色随语气走,没写 data-tone 时退回品牌强调色 */
@@ -34,15 +53,15 @@
34
53
  /* 形态只决定描边与底色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的中性配色 */
35
54
  /* outline 就是缺省那一身:描边加画布底,写出来只为让三档并列可读 */
36
55
  [data-scope='tree-select'][data-part='root'][data-variant='outline'] {
37
- --xh-_tree-select-border: var(--xh-border-default);
38
- --xh-_tree-select-border-hover: var(--xh-border-strong);
56
+ --xh-_tree-select-border: var(--xh-border-control);
57
+ --xh-_tree-select-border-hover: var(--xh-border-control-hover);
39
58
  --xh-_tree-select-bg: var(--xh-bg-canvas);
40
59
  }
41
60
 
42
61
  /* subtle 是填充式:底色接过「这里能点」的表达,描边随之让位 */
43
62
  [data-scope='tree-select'][data-part='root'][data-variant='subtle'] {
44
63
  --xh-_tree-select-border: transparent;
45
- --xh-_tree-select-border-hover: var(--xh-_tone-border, var(--xh-border-default));
64
+ --xh-_tree-select-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
46
65
  --xh-_tree-select-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
47
66
  }
48
67
 
@@ -117,10 +136,9 @@
117
136
  border-color: var(--xh-tree-select-trigger-border-hover, var(--xh-_tree-select-border-hover));
118
137
  }
119
138
 
120
- /* trigger 是整个控件唯一的 Tab 停靠点(展开后停靠点才移进树里),落焦必须看得见。
121
- 语气落在环上:没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色 */
139
+ /* trigger 是整个控件唯一的 Tab 停靠点(展开后停靠点才移进树里),落焦必须看得见 */
122
140
  [data-scope='tree-select'][data-part='trigger']:focus-visible {
123
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
141
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
124
142
  outline-offset: var(--xh-ring-offset);
125
143
  }
126
144
 
@@ -219,7 +237,7 @@
219
237
  /* 清空按钮退出了 Tab 序列(tabindex=-1),正常操作走不到这里;
220
238
  留着是给程序化聚焦兜底,落焦时得看得见 */
221
239
  [data-scope='tree-select'][data-part='clear-trigger']:focus-visible {
222
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
240
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
223
241
  outline-offset: var(--xh-ring-offset);
224
242
  }
225
243
 
@@ -285,8 +303,14 @@
285
303
  display: none;
286
304
  }
287
305
 
288
- /* 没有锚点时容器自己进 Tab 序列兜底,落焦不画环:高亮永远长在行上 */
289
- [data-scope='tree-select'][data-part='tree']:focus-visible {
306
+ /* 焦点落在树容器上只有一种情形:指针打开、还没有任何行当锚点。那一刻它认领着 Tab 位,
307
+ 环画在内沿,用户才看得出键盘此刻在哪儿;有锚点时环长在行上,容器不再画 */
308
+ [data-scope='tree-select'][data-part='tree'][tabindex='0']:focus-visible {
309
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
310
+ outline-offset: calc(-1 * var(--xh-ring-width));
311
+ }
312
+
313
+ [data-scope='tree-select'][data-part='tree']:not([tabindex='0']):focus-visible {
290
314
  outline: none;
291
315
  }
292
316
 
@@ -297,7 +321,7 @@
297
321
  }
298
322
 
299
323
  [data-scope='tree-select'][data-part='branch']:focus-visible > [data-scope='tree-select'][data-part='branch-control'] {
300
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
324
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
301
325
  /* 往内收:行是撑满宽度的,环画在外沿会被容器裁掉 */
302
326
  outline-offset: calc(-1 * var(--xh-ring-width));
303
327
  }
@@ -308,8 +332,8 @@
308
332
  display: flex;
309
333
  align-items: center;
310
334
  gap: var(--xh-tree-select-row-gap, var(--xh-_tree-select-gap));
311
- padding-block: var(--xh-tree-select-row-py, var(--xh-space-1));
312
- padding-inline: var(--xh-tree-select-row-px, var(--xh-control-px-sm));
335
+ padding-block: var(--xh-tree-select-row-py, var(--xh-space-1_5));
336
+ padding-inline: var(--xh-tree-select-row-px, var(--xh-control-px-md));
313
337
  border-radius: var(--xh-tree-select-row-radius, var(--xh-shape-control));
314
338
  color: var(--xh-tree-select-row-fg, var(--xh-fg-default));
315
339
  font-size: var(--xh-tree-select-row-font-size, var(--xh-_tree-select-font-size));
@@ -318,6 +342,9 @@
318
342
  white-space: nowrap;
319
343
  cursor: pointer;
320
344
  user-select: none;
345
+ transition:
346
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
347
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
321
348
  }
322
349
 
323
350
  [data-scope='tree-select'][data-part='item'][hidden],
@@ -325,11 +352,11 @@
325
352
  display: none;
326
353
  }
327
354
 
328
- /* 键盘高亮与指针高亮共用一套底色。data-highlighted 跟的是连接层记的焦点行,
329
- 与选中互相独立:可以停在一个没被选中的节点上 */
355
+ /* 悬停与键盘锚点共用中性灰轻档:data-highlighted 跟的是连接层记的焦点行,
356
+ 与选中互相独立,键盘落焦另有聚焦环标记位置 */
330
357
  [data-scope='tree-select'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted]),
331
358
  [data-scope='tree-select'][data-part='branch-control']:not([data-disabled]):is(:hover, [data-highlighted]) {
332
- background: var(--xh-tree-select-row-bg-highlight, var(--xh-bg-subtle-hover));
359
+ background: var(--xh-tree-select-row-bg-hover, var(--xh-bg-subtle));
333
360
  }
334
361
 
335
362
  /* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色整条通道留给高亮,
@@ -342,7 +369,7 @@
342
369
 
343
370
  /* 叶子自己就是 treeitem,环直接画在它身上 */
344
371
  [data-scope='tree-select'][data-part='item']:focus-visible {
345
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
372
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
346
373
  outline-offset: calc(-1 * var(--xh-ring-width));
347
374
  }
348
375
 
package/css/tree.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='tree'] {
4
+ --xh-tree-skin: 1;
5
+ }
6
+
2
7
  [data-scope='tree'][data-part='root'] {
3
8
  display: flex;
4
9
  flex-direction: column;
@@ -70,8 +75,8 @@
70
75
  display: flex;
71
76
  align-items: center;
72
77
  gap: var(--xh-tree-row-gap, var(--xh-control-gap-md));
73
- padding-block: var(--xh-tree-row-py, var(--xh-space-1));
74
- padding-inline: var(--xh-tree-row-px, var(--xh-control-px-sm));
78
+ padding-block: var(--xh-tree-row-py, var(--xh-space-1_5));
79
+ padding-inline: var(--xh-tree-row-px, var(--xh-control-px-md));
75
80
  border-radius: var(--xh-tree-row-radius, var(--xh-shape-control));
76
81
  color: var(--xh-tree-row-fg, var(--xh-fg-default));
77
82
  font-size: var(--xh-tree-row-font-size, var(--xh-text-body-size));
@@ -80,6 +85,9 @@
80
85
  white-space: nowrap;
81
86
  cursor: pointer;
82
87
  user-select: none;
88
+ transition:
89
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
90
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
83
91
  }
84
92
 
85
93
  [data-scope='tree'][data-part='item'][hidden],
@@ -87,11 +95,11 @@
87
95
  display: none;
88
96
  }
89
97
 
90
- /* 键盘高亮与指针高亮共用一套底色。data-highlighted 跟的是连接层记的焦点行,
91
- 与选中互相独立:可以停在一个没被选中的节点上 */
98
+ /* 悬停与键盘锚点共用中性灰轻档:data-highlighted 跟的是连接层记的焦点行,
99
+ 与选中互相独立,键盘落焦另有聚焦环标记位置 */
92
100
  [data-scope='tree'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted]),
93
101
  [data-scope='tree'][data-part='branch-control']:not([data-disabled]):is(:hover, [data-highlighted]) {
94
- background: var(--xh-tree-row-bg-highlight, var(--xh-bg-subtle-hover));
102
+ background: var(--xh-tree-row-bg-hover, var(--xh-bg-subtle));
95
103
  }
96
104
 
97
105
  /* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色整条通道留给高亮,
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='typography'] {
4
+ --xh-typography-skin: 1;
5
+ }
6
+
2
7
  [data-scope='typography'][data-part='root'] {
3
8
  /* 尺寸档只换这几个私有槽,各段从根上继承它们,换档不必给每个部件各写一条选择器 */
4
9
  --xh-_typography-body-size: var(--xh-text-body-size);
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='virtualizer'] {
4
+ --xh-virtualizer-skin: 1;
5
+ }
6
+
2
7
  /* 定位分工:条目在**主轴**上的位移、以及 content 在主轴上的总长,
3
8
  由连接层每帧写进内联样式(竖向是 inset-block-start / block-size,横向是
4
9
  inset-inline-start / inline-size)。这份皮肤一个都不碰:内联优先级高于样式表,
package/css/watermark.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='watermark'] {
4
+ --xh-watermark-skin: 1;
5
+ }
6
+
2
7
  /*
3
8
  * 盖水印的那块地。层叠上下文就地隔离,印子只压在这块地里,不会盖到组件外面去。
4
9
  */