@xihan-ui/styles 1.0.0-alpha.1 → 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 (129) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +61 -5
  4. package/css/affix.css +5 -0
  5. package/css/alert.css +35 -5
  6. package/css/anchor.css +12 -7
  7. package/css/avatar-group.css +8 -3
  8. package/css/avatar.css +8 -3
  9. package/css/back-top.css +21 -1
  10. package/css/badge.css +21 -2
  11. package/css/breadcrumb.css +29 -4
  12. package/css/button-group.css +19 -13
  13. package/css/button.css +57 -11
  14. package/css/calendar.css +124 -2
  15. package/css/card.css +10 -5
  16. package/css/carousel.css +41 -5
  17. package/css/cascader.css +188 -102
  18. package/css/checkbox-group.css +46 -19
  19. package/css/checkbox.css +59 -8
  20. package/css/clipboard.css +7 -1
  21. package/css/code-block.css +17 -7
  22. package/css/collapsible.css +47 -2
  23. package/css/color-picker.css +117 -46
  24. package/css/combobox.css +132 -52
  25. package/css/composer.css +10 -3
  26. package/css/context-menu.css +101 -75
  27. package/css/countdown.css +5 -0
  28. package/css/date-field.css +96 -14
  29. package/css/date-picker.css +281 -65
  30. package/css/descriptions.css +7 -2
  31. package/css/dialog.css +109 -22
  32. package/css/download-trigger.css +76 -0
  33. package/css/drawer.css +75 -23
  34. package/css/dynamic-input.css +73 -17
  35. package/css/editable.css +17 -10
  36. package/css/ellipsis.css +6 -1
  37. package/css/empty-state.css +12 -7
  38. package/css/field.css +14 -6
  39. package/css/fieldset.css +69 -0
  40. package/css/file-upload.css +50 -7
  41. package/css/flex.css +5 -0
  42. package/css/float-button.css +21 -1
  43. package/css/floating-panel.css +310 -0
  44. package/css/form.css +10 -5
  45. package/css/gradient-text.css +5 -0
  46. package/css/grid.css +5 -0
  47. package/css/heatmap.css +410 -0
  48. package/css/highlight.css +6 -1
  49. package/css/hotkeys.css +90 -0
  50. package/css/hover-card.css +58 -50
  51. package/css/icon-wrapper.css +5 -0
  52. package/css/icon.css +5 -0
  53. package/css/image-cropper.css +231 -0
  54. package/css/image-viewer.css +167 -22
  55. package/css/image.css +7 -2
  56. package/css/infinite-scroll.css +6 -1
  57. package/css/json-viewer.css +241 -0
  58. package/css/layout.css +11 -10
  59. package/css/list.css +13 -8
  60. package/css/listbox.css +25 -4
  61. package/css/loading-bar.css +12 -1
  62. package/css/log.css +6 -1
  63. package/css/marquee.css +14 -0
  64. package/css/masonry.css +63 -0
  65. package/css/mention.css +105 -32
  66. package/css/menu.css +131 -46
  67. package/css/menubar.css +150 -66
  68. package/css/navigation-menu.css +59 -29
  69. package/css/number-animation.css +8 -3
  70. package/css/number-field.css +178 -16
  71. package/css/overlay-arrow.css +51 -0
  72. package/css/page-header.css +10 -5
  73. package/css/pagination.css +18 -13
  74. package/css/password-input.css +356 -0
  75. package/css/pin-input.css +18 -10
  76. package/css/popconfirm.css +73 -16
  77. package/css/popover.css +88 -44
  78. package/css/popselect.css +201 -52
  79. package/css/progress.css +52 -7
  80. package/css/qr-code.css +6 -1
  81. package/css/radio-group.css +19 -8
  82. package/css/rating.css +7 -2
  83. package/css/reset.css +17 -0
  84. package/css/result.css +11 -6
  85. package/css/scroll-area.css +65 -94
  86. package/css/scrollbar.css +167 -0
  87. package/css/segmented.css +215 -0
  88. package/css/select.css +292 -124
  89. package/css/separator.css +7 -2
  90. package/css/side-nav.css +116 -19
  91. package/css/signature-pad.css +144 -0
  92. package/css/skeleton.css +12 -1
  93. package/css/slider.css +15 -10
  94. package/css/space.css +117 -0
  95. package/css/spinner.css +31 -11
  96. package/css/splitter.css +5 -0
  97. package/css/statistic.css +14 -9
  98. package/css/steps.css +30 -8
  99. package/css/switch.css +62 -13
  100. package/css/table.css +136 -37
  101. package/css/tabs.css +9 -4
  102. package/css/tag.css +177 -0
  103. package/css/tags-input.css +83 -40
  104. package/css/text-field.css +154 -36
  105. package/css/thread.css +6 -1
  106. package/css/time-field.css +102 -16
  107. package/css/time-picker.css +264 -69
  108. package/css/time.css +5 -0
  109. package/css/timeline.css +15 -10
  110. package/css/timer.css +119 -0
  111. package/css/toast.css +46 -21
  112. package/css/toaster.css +6 -1
  113. package/css/toggle-group.css +5 -0
  114. package/css/toggle.css +11 -6
  115. package/css/tone.css +10 -5
  116. package/css/toolbar.css +6 -1
  117. package/css/tooltip.css +54 -38
  118. package/css/tour.css +128 -63
  119. package/css/transfer.css +73 -17
  120. package/css/tree-select.css +203 -83
  121. package/css/tree.css +90 -1
  122. package/css/typography.css +9 -4
  123. package/css/undefined.css +11 -1
  124. package/css/virtualizer.css +8 -1
  125. package/css/watermark.css +6 -2
  126. package/index.css +17 -1
  127. package/index.unlayered.css +9394 -2883
  128. package/package.json +19 -4
  129. package/css/motion.css +0 -58
package/css/editable.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='editable'] {
4
+ --xh-editable-skin: 1;
5
+ }
6
+
2
7
  /* 就地编辑是"一行文字里的一处可改内容":标题、显示区与按钮天然同行,
3
8
  所以根是一条横向的行,而不是文本框那种"标题一行、控件一行"的竖排。
4
9
  要竖排的作者把 flex-direction 覆盖掉即可,其余尺寸都长在各自的角色节点上 */
@@ -29,8 +34,7 @@
29
34
  cursor: not-allowed;
30
35
  }
31
36
 
32
- /* 预览区与输入框轮流上场,两者在同一处落脚:
33
- area 定死最小宽高,切换形态时这一块不会忽大忽小地跳 */
37
+ /* 预览区与输入框轮流上场,两者在同一处落脚:area 给这一处定最小宽高 */
34
38
  [data-scope='editable'][data-part='area'] {
35
39
  display: inline-flex;
36
40
  align-items: center;
@@ -42,21 +46,23 @@
42
46
  display: none;
43
47
  }
44
48
 
45
- /* 预览区的内边距与边框要和输入框对齐:只有描边是透明的,
46
- 否则从预览切到编辑时文字会左右挪一下 */
49
+ /* 预览区的高度、内边距与边框都和输入框取同一档,只有描边是透明的:
50
+ 单行值定在控件档上,多行值才往下长 */
47
51
  [data-scope='editable'][data-part='preview'] {
48
- display: inline-block;
52
+ display: inline-flex;
53
+ align-items: center;
49
54
  inline-size: 100%;
55
+ min-block-size: var(--xh-editable-preview-min-h, var(--xh-control-h-md));
50
56
  padding-inline: var(--xh-editable-preview-px, var(--xh-control-px-md));
51
57
  padding-block: 0;
52
58
  border: var(--xh-stroke-thin) solid transparent;
53
59
  border-radius: var(--xh-editable-preview-radius, var(--xh-shape-control));
54
60
  color: var(--xh-editable-preview-fg, var(--xh-fg-default));
55
61
  font-size: var(--xh-editable-preview-font-size, var(--xh-text-body-size));
56
- line-height: var(--xh-editable-preview-line-height, var(--xh-control-h-md));
57
- /* 值里的换行与连续空格照原样显示,但过长的行仍要能断开 */
62
+ line-height: var(--xh-leading-normal);
63
+ /* 值里的换行与连续空格照原样显示,过长的行断开而不撑破弹性行 */
58
64
  white-space: pre-wrap;
59
- overflow-wrap: break-word;
65
+ overflow-wrap: anywhere;
60
66
  }
61
67
 
62
68
  /* 编辑态由连接层给 hidden;上面那条 display 会盖掉 UA 规则,少了这条就收不起来 */
@@ -135,12 +141,13 @@
135
141
  }
136
142
 
137
143
  [data-scope='editable'][data-part='input']:focus-visible {
144
+ border-color: var(--xh-editable-input-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
138
145
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
139
146
  outline-offset: var(--xh-ring-offset);
140
147
  }
141
148
 
142
149
  [data-scope='editable'][data-part='input'][data-invalid] {
143
- border-color: var(--xh-editable-input-border-invalid, var(--xh-color-danger-500));
150
+ border-color: var(--xh-editable-input-border-invalid, var(--xh-border-invalid));
144
151
  }
145
152
 
146
153
  /* 只读仍可聚焦、可复制,不置灰,只把底色压下去表示"改不动" */
@@ -183,7 +190,7 @@
183
190
  background: var(--xh-editable-trigger-bg, var(--xh-bg-subtle));
184
191
  color: var(--xh-editable-trigger-fg, var(--xh-fg-default));
185
192
  font-family: inherit;
186
- font-size: var(--xh-editable-trigger-font-size, var(--xh-font-size-sm));
193
+ font-size: var(--xh-editable-trigger-font-size, var(--xh-text-secondary-size));
187
194
  line-height: var(--xh-leading-none);
188
195
  white-space: nowrap;
189
196
  cursor: pointer;
package/css/ellipsis.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='ellipsis'] {
4
+ --xh-ellipsis-skin: 1;
5
+ }
6
+
2
7
  /* 单行:一行装不下就收成省略号。
3
8
  行数由连接层写进这个盒子的内联 style,样式表这一行只是它缺席时的落点 */
4
9
  [data-scope='ellipsis'][data-part='root'] {
@@ -22,7 +27,7 @@
22
27
  }
23
28
 
24
29
  /* 铺开:裁剪整个撤掉。写在两档之后,压得住上面同权重的那两条 */
25
- [data-scope='ellipsis'][data-part='root'][data-expanded] {
30
+ [data-scope='ellipsis'][data-part='root'][data-state='open'] {
26
31
  display: block;
27
32
  overflow: visible;
28
33
  white-space: normal;
@@ -1,11 +1,16 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='empty-state'] {
4
+ --xh-empty-state-skin: 1;
5
+ }
6
+
2
7
  [data-scope='empty-state'][data-part='root'] {
3
8
  /* 三个尺寸档只换这几个私有槽,图标与标题都从 root 继承它们,
4
9
  换档不必给每个部件各写一条选择器 */
5
10
  --xh-_empty-state-gap: var(--xh-stack-gap-md);
6
11
  --xh-_empty-state-py: var(--xh-section-py);
7
- --xh-_empty-state-icon-size: 2.5rem;
8
- --xh-_empty-state-title-size: var(--xh-font-size-lg);
12
+ --xh-_empty-state-icon-size: var(--xh-glyph-size-2xl);
13
+ --xh-_empty-state-title-size: var(--xh-control-font-lg);
9
14
  /* 说明的读行宽度:整句话不收窄就会拉成一条难读的长行 */
10
15
  --xh-_empty-state-measure: 32rem;
11
16
 
@@ -28,15 +33,15 @@
28
33
  [data-scope='empty-state'][data-part='root'][data-size='sm'] {
29
34
  --xh-_empty-state-gap: var(--xh-space-2);
30
35
  --xh-_empty-state-py: var(--xh-space-4);
31
- --xh-_empty-state-icon-size: 2rem;
32
- --xh-_empty-state-title-size: var(--xh-font-size-md);
36
+ --xh-_empty-state-icon-size: var(--xh-glyph-size-xl);
37
+ --xh-_empty-state-title-size: var(--xh-control-font-md);
33
38
  }
34
39
 
35
40
  [data-scope='empty-state'][data-part='root'][data-size='lg'] {
36
41
  --xh-_empty-state-gap: var(--xh-space-6);
37
42
  --xh-_empty-state-py: var(--xh-space-8);
38
- --xh-_empty-state-icon-size: 3.5rem;
39
- --xh-_empty-state-title-size: var(--xh-font-size-xl);
43
+ --xh-_empty-state-icon-size: var(--xh-glyph-size-3xl);
44
+ --xh-_empty-state-title-size: var(--xh-text-heading-3-size);
40
45
  }
41
46
 
42
47
  [data-scope='empty-state'][data-part='icon'] {
@@ -48,7 +53,7 @@
48
53
  inline-size: var(--xh-empty-state-icon-size, var(--xh-_empty-state-icon-size));
49
54
  color: var(--xh-empty-state-icon-fg, var(--xh-fg-subtle));
50
55
  /* 图标常是一个字形,字号跟着图标框走,line-height 不再另占高度 */
51
- font-size: var(--xh-empty-state-icon-font-size, var(--xh-font-size-3xl));
56
+ font-size: var(--xh-empty-state-icon-font-size, var(--xh-text-heading-1-size));
52
57
  line-height: var(--xh-leading-none);
53
58
  }
54
59
 
package/css/field.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='field'] {
4
+ --xh-field-skin: 1;
5
+ }
6
+
2
7
  [data-scope='field'][data-part='root'] {
3
8
  display: flex;
4
9
  flex-direction: column;
@@ -17,8 +22,10 @@
17
22
  [data-scope='form'][data-part='root'][data-layout='horizontal'] [data-scope='field'][data-part='label'] {
18
23
  grid-column: 1;
19
24
  justify-self: end;
20
- /* 与控件的首行文字对齐:按控件高度撑一行再居中 */
21
- line-height: var(--xh-control-h-md);
25
+ /* 与控件的首行文字对齐:行高保持正文行距(标签折行时每行不会撑成一个控件高),
26
+ 上下留白把单行文本盒撑到控件高度;配的是哪一档控件由 --xh-field-control-h 告诉它 */
27
+ line-height: var(--xh-field-label-leading, var(--xh-leading-normal));
28
+ padding-block: calc((var(--xh-field-control-h, var(--xh-control-h-md)) - 1lh) / 2);
22
29
  }
23
30
 
24
31
  [data-scope='form'][data-part='root'][data-layout='horizontal'][data-label-align='start'] [data-scope='field'][data-part='label'] {
@@ -42,7 +49,7 @@
42
49
 
43
50
  /* 必填星号:跟着根上的 data-required 亮,选填不标 */
44
51
  [data-scope='field'][data-part='root'][data-required] [data-part='label']::after {
45
- content: '*';
52
+ content: var(--xh-glyph-mark-required);
46
53
  margin-inline-start: var(--xh-space-1);
47
54
  color: var(--xh-field-label-star, var(--xh-fg-danger));
48
55
  }
@@ -60,12 +67,13 @@
60
67
  }
61
68
 
62
69
  [data-scope='field'][data-part='control']:focus-visible {
70
+ border-color: var(--xh-field-control-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
63
71
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
64
72
  outline-offset: var(--xh-ring-offset);
65
73
  }
66
74
 
67
75
  [data-scope='field'][data-part='control'][data-invalid] {
68
- border-color: var(--xh-field-control-border-invalid, var(--xh-color-danger-500));
76
+ border-color: var(--xh-field-control-border-invalid, var(--xh-border-invalid));
69
77
  }
70
78
 
71
79
  /* 禁用由作者在控件上落原生 disabled,样式统一走 data-disabled */
@@ -78,7 +86,7 @@
78
86
  [data-scope='field'][data-part='description'] {
79
87
  margin: 0;
80
88
  color: var(--xh-field-description-fg, var(--xh-fg-muted));
81
- font-size: var(--xh-field-description-font-size, var(--xh-font-size-sm));
89
+ font-size: var(--xh-field-description-font-size, var(--xh-text-secondary-size));
82
90
  line-height: var(--xh-leading-normal);
83
91
  }
84
92
 
@@ -90,7 +98,7 @@
90
98
  [data-scope='field'][data-part='error-text'] {
91
99
  margin: 0;
92
100
  color: var(--xh-field-error-fg, var(--xh-fg-danger));
93
- font-size: var(--xh-field-error-font-size, var(--xh-font-size-sm));
101
+ font-size: var(--xh-field-error-font-size, var(--xh-text-secondary-size));
94
102
  line-height: var(--xh-leading-normal);
95
103
  }
96
104
  }
@@ -0,0 +1,69 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='fieldset'] {
4
+ --xh-fieldset-skin: 1;
5
+ }
6
+
7
+ /* 抹掉 UA 给 <fieldset> 的边框、内外边距与 min-content 下限,间距全部改由令牌给。
8
+ display 落在 fieldset 的匿名内容盒上:首个 <legend> 不在这个盒子里,
9
+ 所以 gap 只作用于组内各块,legend 与内容之间的留白由 legend 自己的下外边距给。 */
10
+ [data-scope='fieldset'][data-part='root'] {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--xh-fieldset-gap, var(--xh-space-4));
14
+ margin: 0;
15
+ border: 0;
16
+ padding: 0;
17
+ min-inline-size: 0;
18
+ }
19
+
20
+ [data-scope='fieldset'][data-part='root'][hidden] {
21
+ display: none;
22
+ }
23
+
24
+ [data-scope='fieldset'][data-part='legend'] {
25
+ padding: 0;
26
+ margin-block-end: var(--xh-fieldset-legend-gap, var(--xh-space-2));
27
+ color: var(--xh-fieldset-legend-fg, var(--xh-fg-default));
28
+ font-size: var(--xh-fieldset-legend-font-size, var(--xh-text-label-size));
29
+ font-weight: var(--xh-fieldset-legend-font-weight, var(--xh-text-label-weight));
30
+ line-height: var(--xh-leading-tight);
31
+ }
32
+
33
+ /* 整组无效时组标题转警示色:没渲染错误文案的字段集上,这是屏幕上唯一变化的东西 */
34
+ [data-scope='fieldset'][data-part='root'][data-invalid] > [data-scope='fieldset'][data-part='legend'] {
35
+ color: var(--xh-fieldset-legend-fg-invalid, var(--xh-fg-danger));
36
+ }
37
+
38
+ /* 整组禁用时组标题跟着变淡;组内控件由原生 fieldset[disabled] 各自呈现禁用态。
39
+ 选择器与上一条同权重且排在后面,禁用与无效同时为真时以禁用为准。 */
40
+ [data-scope='fieldset'][data-part='root'] > [data-scope='fieldset'][data-part='legend'][data-disabled] {
41
+ color: var(--xh-fieldset-legend-fg-disabled, var(--xh-fg-subtle));
42
+ }
43
+
44
+ /* 必填星号:跟着根上的 data-required 亮,选填不标 */
45
+ [data-scope='fieldset'][data-part='root'][data-required] > [data-scope='fieldset'][data-part='legend']::after {
46
+ content: var(--xh-glyph-mark-required);
47
+ margin-inline-start: var(--xh-space-1);
48
+ color: var(--xh-fieldset-legend-star, var(--xh-fg-danger));
49
+ }
50
+
51
+ [data-scope='fieldset'][data-part='helper-text'] {
52
+ margin: 0;
53
+ color: var(--xh-fieldset-helper-fg, var(--xh-fg-muted));
54
+ font-size: var(--xh-fieldset-helper-font-size, var(--xh-text-secondary-size));
55
+ line-height: var(--xh-leading-normal);
56
+ }
57
+
58
+ [data-scope='fieldset'][data-part='helper-text'][data-disabled] {
59
+ color: var(--xh-fieldset-helper-fg-disabled, var(--xh-fg-subtle));
60
+ }
61
+
62
+ /* 不 invalid 时节点带 hidden:此处不声明 display,交给浏览器的 [hidden] 规则收起 */
63
+ [data-scope='fieldset'][data-part='error-text'] {
64
+ margin: 0;
65
+ color: var(--xh-fieldset-error-fg, var(--xh-fg-danger));
66
+ font-size: var(--xh-fieldset-error-font-size, var(--xh-text-secondary-size));
67
+ line-height: var(--xh-leading-normal);
68
+ }
69
+ }
@@ -1,5 +1,13 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='file-upload'] {
4
+ --xh-file-upload-skin: 1;
5
+ }
6
+
2
7
  [data-scope='file-upload'][data-part='root'] {
8
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
9
+ --xh-icon-size: var(--xh-file-upload-icon-size, var(--xh-glyph-size-text));
10
+
3
11
  display: flex;
4
12
  flex-direction: column;
5
13
  gap: var(--xh-file-upload-gap, var(--xh-space-3));
@@ -67,7 +75,7 @@
67
75
  }
68
76
 
69
77
  [data-scope='file-upload'][data-part='dropzone'][data-invalid] {
70
- border-color: var(--xh-file-upload-dropzone-border-invalid, var(--xh-color-danger-500));
78
+ border-color: var(--xh-file-upload-dropzone-border-invalid, var(--xh-border-invalid));
71
79
  }
72
80
 
73
81
  /* 投放区是 div,没有原生 disabled 可用,禁用态只能靠 data-disabled 表达,写 :disabled 永远不命中 */
@@ -210,7 +218,7 @@
210
218
  [data-scope='file-upload'][data-part='item-size-text'] {
211
219
  flex: none;
212
220
  color: var(--xh-file-upload-size-fg, var(--xh-fg-subtle));
213
- font-size: var(--xh-file-upload-size-font-size, var(--xh-font-size-xs));
221
+ font-size: var(--xh-file-upload-size-font-size, var(--xh-text-caption-size));
214
222
  font-variant-numeric: tabular-nums;
215
223
  white-space: nowrap;
216
224
  }
@@ -225,8 +233,8 @@
225
233
  flex: none;
226
234
  align-items: center;
227
235
  justify-content: center;
228
- inline-size: var(--xh-file-upload-delete-size, var(--xh-control-h-sm));
229
- block-size: var(--xh-file-upload-delete-size, var(--xh-control-h-sm));
236
+ inline-size: var(--xh-file-upload-delete-size, var(--xh-control-action-size));
237
+ block-size: var(--xh-file-upload-delete-size, var(--xh-control-action-size));
230
238
  padding: 0;
231
239
  border: 0;
232
240
  border-radius: var(--xh-file-upload-delete-radius, var(--xh-shape-control));
@@ -235,6 +243,9 @@
235
243
  font-family: inherit;
236
244
  line-height: var(--xh-leading-none);
237
245
  cursor: pointer;
246
+ transition:
247
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
248
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
238
249
  }
239
250
 
240
251
  [data-scope='file-upload'][data-part='item-delete-trigger'][hidden] {
@@ -246,6 +257,12 @@
246
257
  color: var(--xh-file-upload-delete-fg-hover, var(--xh-fg-danger-hover));
247
258
  }
248
259
 
260
+ /* 按下:换到按压档底色并轻微下压,松手弹回;禁用钮不压 */
261
+ [data-scope='file-upload'][data-part='item-delete-trigger']:not(:disabled):active {
262
+ background: var(--xh-file-upload-delete-bg-active, var(--xh-bg-subtle-active));
263
+ scale: var(--xh-motion-scale-press);
264
+ }
265
+
249
266
  [data-scope='file-upload'][data-part='item-delete-trigger']:focus-visible {
250
267
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
251
268
  outline-offset: var(--xh-ring-offset);
@@ -256,8 +273,7 @@
256
273
  cursor: not-allowed;
257
274
  }
258
275
 
259
- /* 清空是收尾动作,画成不带底色的文字按钮:它比"选择文件"次要,
260
- 且列表为空时连接层会给原生 disabled,那时它本就该看着点不动 */
276
+ /* 清空是收尾动作,画成不带底色的文字按钮:它比"选择文件"次要 */
261
277
  [data-scope='file-upload'][data-part='clear-trigger'] {
262
278
  display: inline-flex;
263
279
  flex: none;
@@ -272,9 +288,12 @@
272
288
  background: transparent;
273
289
  color: var(--xh-file-upload-clear-fg, var(--xh-fg-muted));
274
290
  font-family: inherit;
275
- font-size: var(--xh-file-upload-clear-font-size, var(--xh-font-size-xs));
291
+ font-size: var(--xh-file-upload-clear-font-size, var(--xh-text-caption-size));
276
292
  line-height: var(--xh-leading-none);
277
293
  cursor: pointer;
294
+ transition:
295
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
296
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
278
297
  }
279
298
 
280
299
  [data-scope='file-upload'][data-part='clear-trigger'][hidden] {
@@ -286,13 +305,37 @@
286
305
  color: var(--xh-file-upload-clear-fg-hover, var(--xh-fg-default));
287
306
  }
288
307
 
308
+ /* 按下:换到按压档底色并轻微下压,松手弹回;禁用钮不压 */
309
+ [data-scope='file-upload'][data-part='clear-trigger']:not(:disabled):active {
310
+ background: var(--xh-file-upload-clear-bg-active, var(--xh-bg-subtle-active));
311
+ scale: var(--xh-motion-scale-press);
312
+ }
313
+
289
314
  [data-scope='file-upload'][data-part='clear-trigger']:focus-visible {
290
315
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
291
316
  outline-offset: var(--xh-ring-offset);
292
317
  }
293
318
 
319
+ /* 空列表时按钮照常可按(收起它会让焦点掉回 body),只把前景压淡一档 */
320
+ [data-scope='file-upload'][data-part='clear-trigger'][data-empty] {
321
+ color: var(--xh-fg-subtle);
322
+ }
323
+
294
324
  [data-scope='file-upload'][data-part='clear-trigger']:disabled {
295
325
  color: var(--xh-fg-disabled);
296
326
  cursor: not-allowed;
297
327
  }
328
+
329
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
330
+ [data-scope='file-upload'][data-part='item-delete-trigger']:empty::before,
331
+ [data-scope='file-upload'][data-part='clear-trigger']:empty::before {
332
+ content: '';
333
+ display: inline-block;
334
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
335
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
336
+ vertical-align: var(--xh-glyph-baseline-shift);
337
+ background-color: currentColor;
338
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
339
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
340
+ }
298
341
  }
package/css/flex.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='flex'] {
4
+ --xh-flex-skin: 1;
5
+ }
6
+
2
7
  [data-scope='flex'][data-part='root'] {
3
8
  display: flex;
4
9
  flex-wrap: nowrap;
@@ -1,10 +1,18 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='float-button'] {
4
+ --xh-float-button-skin: 1;
5
+ }
6
+
2
7
  /* 定位壳:钉在视口一角。贴边距离由连接层写进这个盒子的内联 style,
3
8
  样式表这一行只是它缺席时的落点;贴的是哪两条边看 data-placement。
4
9
  另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
5
10
  transform / filter / backdrop-filter / contain,包含块就被抢走,整组立刻贴错位置——
6
11
  所以别往覆盖钩子里加这几个属性。 */
7
12
  [data-scope='float-button'][data-part='root'] {
13
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
14
+ --xh-icon-size: var(--xh-float-button-icon-size, var(--xh-glyph-size-text));
15
+
8
16
  --xh-_float-button-offset: var(--xh-space-6);
9
17
  /* 触发器与展开的每一条动作共用这两个私有槽,换档只改这里 */
10
18
  --xh-_float-button-size: var(--xh-float-button-size, var(--xh-control-h-lg));
@@ -62,7 +70,7 @@
62
70
  background: var(--xh-float-button-bg, var(--xh-bg-surface-raised));
63
71
  color: var(--xh-float-button-fg, var(--xh-fg-default));
64
72
  /* 浮在内容之上,靠投影与页面拉开层次 */
65
- box-shadow: var(--xh-elevation-3);
73
+ box-shadow: var(--xh-float-button-shadow, var(--xh-elevation-sheet));
66
74
  cursor: pointer;
67
75
  transition:
68
76
  background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
@@ -118,4 +126,16 @@
118
126
  block-size: var(--xh-_float-button-size);
119
127
  border-radius: var(--xh-_float-button-radius);
120
128
  }
129
+
130
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
131
+ [data-scope='float-button'][data-part='trigger']:empty::before {
132
+ content: '';
133
+ display: inline-block;
134
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
135
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
136
+ vertical-align: var(--xh-glyph-baseline-shift);
137
+ background-color: currentColor;
138
+ -webkit-mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
139
+ mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
140
+ }
121
141
  }