@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/slider.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='slider'] {
4
+ --xh-slider-skin: 1;
5
+ }
6
+
2
7
  /* 定位分工:已选区间与拇指在**主轴**上的起点与长度,由连接层每帧写进内联样式——
3
8
  水平是 inset-inline-start / inline-size,竖直是 inset-block-end / block-size。
4
9
  这份皮肤一个都不碰:内联优先级高于样式表,写了不但是死声明,
@@ -186,6 +191,61 @@
186
191
  --xh-_track-thickness: var(--xh-slider-track-thickness, var(--xh-space-2));
187
192
  }
188
193
 
194
+ /* —— 刻度:圆点钉在轨道上、文案排在轨道外侧,坐标由连接层按百分比内联给出 —— */
195
+ [data-scope='slider'][data-part='marks'] {
196
+ position: absolute;
197
+ inset: 0;
198
+ pointer-events: none;
199
+ }
200
+
201
+ [data-scope='slider'][data-part='mark'] {
202
+ position: absolute;
203
+ inset-block-start: 50%;
204
+ inline-size: var(--xh-slider-mark-size, var(--xh-space-1));
205
+ block-size: var(--xh-slider-mark-size, var(--xh-space-1));
206
+ border-radius: var(--xh-shape-pill);
207
+ background: var(--xh-slider-mark-bg, var(--xh-border-strong));
208
+ translate: -50% -50%;
209
+ }
210
+
211
+ /* 落进已选区间的刻度点跟 range 同色 */
212
+ [data-scope='slider'][data-part='mark'][data-active] {
213
+ background: var(--xh-slider-mark-bg-active, var(--xh-_tone, var(--xh-bg-brand)));
214
+ }
215
+
216
+ [data-scope='slider'][data-part='mark-label'] {
217
+ position: absolute;
218
+ inset-block-start: 100%;
219
+ margin-block-start: var(--xh-slider-mark-label-gap, var(--xh-space-1));
220
+ color: var(--xh-slider-mark-label-fg, var(--xh-fg-subtle));
221
+ font-size: var(--xh-slider-mark-label-font-size, var(--xh-font-size-xs));
222
+ line-height: var(--xh-leading-none);
223
+ white-space: nowrap;
224
+ translate: -50% 0;
225
+ cursor: pointer;
226
+ pointer-events: auto;
227
+ user-select: none;
228
+ }
229
+
230
+ [data-scope='slider'][data-part='mark-label'][data-active] {
231
+ color: var(--xh-slider-mark-label-fg-active, var(--xh-fg-default));
232
+ }
233
+
234
+ /* 竖直轨道:点与文案换轴,坐标由连接层写在 block 轴上 */
235
+ [data-scope='slider'][data-part='root'][data-orientation='vertical'] [data-part='mark'] {
236
+ inset-block-start: auto;
237
+ inset-inline-start: 50%;
238
+ translate: -50% 50%;
239
+ }
240
+
241
+ [data-scope='slider'][data-part='root'][data-orientation='vertical'] [data-part='mark-label'] {
242
+ inset-block-start: auto;
243
+ inset-inline-start: 100%;
244
+ margin-block-start: 0;
245
+ margin-inline-start: var(--xh-slider-mark-label-gap, var(--xh-space-1));
246
+ translate: 0 50%;
247
+ }
248
+
189
249
  /* display 会盖掉 UA 的 [hidden]{display:none},凡是被赋了 display 的角色节点都要显式让位 */
190
250
  [data-scope='slider'][data-part='root'][hidden],
191
251
  [data-scope='slider'][data-part='control'][hidden] {
package/css/spinner.css CHANGED
@@ -1,4 +1,4 @@
1
- @layer xihan.components {
1
+ @layer xihan.motion {
2
2
  /* 转圈的关键帧定义在本文件里。皮肤可以按需单独引入,
3
3
  引用别处文件里的动画名时那份文件不一定在场,动画会静默地整个不跑 */
4
4
  @keyframes xh-spinner-rotate {
@@ -6,6 +6,14 @@
6
6
  transform: rotate(1turn);
7
7
  }
8
8
  }
9
+ }
10
+
11
+ @layer xihan.components {
12
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13
+ [data-scope='spinner'] {
14
+ --xh-spinner-skin: 1;
15
+ }
16
+
9
17
 
10
18
  /* 圆环画在伪元素上,root 自身不转:转的只是图形,同一行里的文案要留在原地读得动 */
11
19
  [data-scope='spinner'][data-part='root'] {
package/css/splitter.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='splitter'] {
4
+ --xh-splitter-skin: 1;
5
+ }
6
+
2
7
  /* 分工:**面板在排布轴上的尺寸**由连接层每帧写进内联样式(flex-basis / flex-grow / flex-shrink)。
3
8
  这份皮肤一条都不碰——内联优先级高于样式表,写了不但是死声明,
4
9
  还会在切换 orientation 的那一帧跟连接层抢位置。皮肤只管排布方向、跨轴尺寸、
package/css/statistic.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='statistic'] {
4
+ --xh-statistic-skin: 1;
5
+ }
6
+
2
7
  /* 三个尺寸档只换这几个私有槽,各段从 root 继承它们,换档不必给每个部件各写一条选择器 */
3
8
  [data-scope='statistic'][data-part='root'] {
4
9
  --xh-_statistic-label-size: var(--xh-font-size-sm);
package/css/steps.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='steps'] {
4
+ --xh-steps-skin: 1;
5
+ }
6
+
2
7
  [data-scope='steps'][data-part='root'] {
3
8
  /* 尺寸档只换这三个私有槽,序号圆点、标题与说明都从 root 继承它们,
4
9
  换档不必给每个部件各写一条选择器 */
@@ -176,8 +181,8 @@
176
181
  }
177
182
 
178
183
  [data-scope='steps'][data-part='item'][data-disabled] [data-scope='steps'][data-part='indicator'] {
179
- border-color: var(--xh-fg-disabled);
180
- color: var(--xh-fg-disabled);
184
+ border-color: var(--xh-steps-indicator-border-disabled, var(--xh-fg-disabled));
185
+ color: var(--xh-steps-indicator-fg-disabled, var(--xh-fg-disabled));
181
186
  }
182
187
 
183
188
  /* 标题与说明都在右列:不给 display,网格布局会替它们块级化,
package/css/switch.css CHANGED
@@ -1,4 +1,18 @@
1
+ @layer xihan.motion {
2
+ /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
3
+ @keyframes xh-switch-rotate {
4
+ to {
5
+ transform: rotate(1turn);
6
+ }
7
+ }
8
+ }
9
+
1
10
  @layer xihan.components {
11
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12
+ [data-scope='switch'] {
13
+ --xh-switch-skin: 1;
14
+ }
15
+
2
16
  [data-scope='switch'][data-part='root'] {
3
17
  /* 尺寸档只换轨道高度这一个私有槽,其余几何都从它算出来:
4
18
  滑块边长 = 轨道高 − 两条留白,轨道宽 = 两倍轨道高 − 两条留白,滑块行程因此正好等于自身边长 */
@@ -58,4 +72,24 @@
58
72
  [data-scope='switch'][data-part='thumb'][data-state='checked'] {
59
73
  translate: var(--xh-_switch-thumb-size) 0;
60
74
  }
75
+
76
+ /* 提交中:指针挂起、滑块里转圈;不是禁用,焦点与对比度都保持 */
77
+ [data-scope='switch'][data-part='root'][data-loading] {
78
+ cursor: wait;
79
+ }
80
+
81
+ [data-scope='switch'][data-part='thumb'][data-loading] {
82
+ display: grid;
83
+ place-items: center;
84
+ }
85
+
86
+ [data-scope='switch'][data-part='thumb'][data-loading]::after {
87
+ content: '';
88
+ inline-size: 60%;
89
+ block-size: 60%;
90
+ border: var(--xh-stroke-thin) solid transparent;
91
+ border-block-start-color: var(--xh-switch-loading-fg, var(--xh-bg-brand));
92
+ border-radius: var(--xh-shape-pill);
93
+ animation: xh-switch-rotate var(--xh-switch-loading-duration, calc(var(--xh-duration-slow) * 2)) linear infinite;
94
+ }
61
95
  }
package/css/table.css CHANGED
@@ -18,6 +18,11 @@
18
18
  }
19
19
 
20
20
  @layer xihan.components {
21
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
22
+ [data-scope='table'] {
23
+ --xh-table-skin: 1;
24
+ }
25
+
21
26
  /* 表格自己滚动:吸顶表头与横向吸附列都要一个确定的滚动容器才钉得住 */
22
27
  [data-scope='table'][data-part='root'] {
23
28
  /* 密度档只换这两个私有槽:单元格与列标题从 root 继承前者,字号靠 font-size 本身继承下去,
@@ -135,10 +140,10 @@
135
140
  border-block-end: none;
136
141
  }
137
142
 
138
- /* 键盘高亮与指针高亮共用一套底色。data-highlighted 跟的是连接层记的焦点行,
143
+ /* 悬停与键盘锚点共用中性灰轻档。data-highlighted 跟的是连接层记的焦点行,
139
144
  与选中互相独立:可以停在一个没被选中的行上 */
140
145
  [data-scope='table'][data-part='body'] > [data-scope='table'][data-part='row']:not([data-disabled]):is(:hover, [data-highlighted]) {
141
- background: var(--xh-table-row-bg-highlight, var(--xh-bg-subtle-hover));
146
+ background: var(--xh-table-row-bg-hover, var(--xh-bg-subtle));
142
147
  }
143
148
 
144
149
  /* 选中比高亮更"实":它表达的是数据状态,翻页回来还在 */
@@ -223,14 +228,14 @@
223
228
  切换选中不引起行宽抖动 */
224
229
  [data-scope='table'][data-part='select-all-trigger'],
225
230
  [data-scope='table'][data-part='row-select-trigger'] {
226
- border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-strong));
231
+ border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-control));
227
232
  color: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
228
233
  visibility: visible;
229
234
  }
230
235
 
231
236
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='all'], [data-state='some']),
232
237
  [data-scope='table'][data-part='row-select-trigger'][data-selected] {
233
- border-color: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
238
+ border-color: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
234
239
  background: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
235
240
  }
236
241
 
@@ -379,7 +384,7 @@
379
384
  }
380
385
 
381
386
  /* 两个状态节点常挂,只在表体为空时才显形 */
382
- [data-scope='table'][data-part='empty-state'],
387
+ [data-scope='table'][data-part='empty'],
383
388
  [data-scope='table'][data-part='loading-state'] {
384
389
  display: flex;
385
390
  flex-direction: column;
@@ -393,7 +398,7 @@
393
398
  text-align: center;
394
399
  }
395
400
 
396
- [data-scope='table'][data-part='empty-state'][hidden],
401
+ [data-scope='table'][data-part='empty'][hidden],
397
402
  [data-scope='table'][data-part='loading-state'][hidden] {
398
403
  display: none;
399
404
  }
package/css/tabs.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='tabs'] {
4
+ --xh-tabs-skin: 1;
5
+ }
6
+
2
7
  [data-scope='tabs'][data-part='root'] {
3
8
  /* 尺寸档只换这三个私有槽,标签从 root 继承它们,换档不必给每个部件各写一条选择器 */
4
9
  --xh-_tabs-trigger-h: var(--xh-control-h-md);
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='tags-input'] {
4
+ --xh-tags-input-skin: 1;
5
+ }
6
+
2
7
  /* root 只负责纵向堆叠:标题一行、控件一行。可见的那个"框"长在 control 上,
3
8
  因为标签、输入框、清空按钮都在它里面,边框必须把三者一起圈住 */
4
9
  [data-scope='tags-input'][data-part='root'] {
@@ -12,8 +17,8 @@
12
17
  --xh-_tags-input-label-font-size: var(--xh-text-label-size);
13
18
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
14
19
  --xh-_tags-input-control-bg: var(--xh-bg-canvas);
15
- --xh-_tags-input-control-border: var(--xh-border-default);
16
- --xh-_tags-input-control-border-hover: var(--xh-border-strong);
20
+ --xh-_tags-input-control-border: var(--xh-border-control);
21
+ --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
17
22
  /* 聚焦环与标签块的强调色随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的取值 */
18
23
  --xh-_tags-input-ring: var(--xh-ring-focus);
19
24
  --xh-_tags-input-accent: var(--xh-_tone, var(--xh-bg-brand));
@@ -35,22 +40,22 @@
35
40
  不做 solid:实心填充盖住了"这里能打字"这件事,输入框用不上它 */
36
41
  [data-scope='tags-input'][data-part='root'][data-variant='outline'] {
37
42
  --xh-_tags-input-control-bg: var(--xh-bg-canvas);
38
- --xh-_tags-input-control-border: var(--xh-border-default);
39
- --xh-_tags-input-control-border-hover: var(--xh-border-strong);
43
+ --xh-_tags-input-control-border: var(--xh-border-control);
44
+ --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
40
45
  }
41
46
 
42
47
  /* 填充式:底色圈出可输入的范围,描边让位给底色 */
43
48
  [data-scope='tags-input'][data-part='root'][data-variant='subtle'] {
44
49
  --xh-_tags-input-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
45
50
  --xh-_tags-input-control-border: transparent;
46
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
51
+ --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
47
52
  }
48
53
 
49
54
  /* 无边框、透明底:静息时框完全隐入背景,可见反馈全靠悬停描边与聚焦环 */
50
55
  [data-scope='tags-input'][data-part='root'][data-variant='ghost'] {
51
56
  --xh-_tags-input-control-bg: transparent;
52
57
  --xh-_tags-input-control-border: transparent;
53
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
58
+ --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
54
59
  }
55
60
 
56
61
  /* —— 尺寸 —— */
@@ -290,7 +295,7 @@
290
295
  max-inline-size: 100%;
291
296
  padding-block: var(--xh-tags-input-item-py, var(--xh-space-1));
292
297
  padding-inline: var(--xh-tags-input-item-px, var(--xh-space-2));
293
- border: var(--xh-stroke-thin) solid var(--xh-tags-input-item-input-border, var(--xh-border-strong));
298
+ border: var(--xh-stroke-thin) solid var(--xh-tags-input-item-input-border, var(--xh-border-control));
294
299
  border-radius: var(--xh-tags-input-item-radius, var(--xh-shape-pill));
295
300
  background: var(--xh-tags-input-item-input-bg, var(--xh-bg-canvas));
296
301
  color: var(--xh-tags-input-item-input-fg, var(--xh-fg-default));
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='text-field'] {
4
+ --xh-text-field-skin: 1;
5
+ }
6
+
2
7
  /* root 只负责纵向堆叠:标签一行、输入行一行。
3
8
  输入框与清空按钮中间那层包裹是作者自己写的、不在角色表里,
4
9
  所以尺寸与间距一律长在各自的角色节点上,不去假设那层存在 */
@@ -13,13 +18,13 @@
13
18
 
14
19
  /* 形态档只换这三个私有槽:底、常态描边、悬停描边 */
15
20
  --xh-_text-field-bg: var(--xh-bg-canvas);
16
- --xh-_text-field-border: var(--xh-border-default);
17
- --xh-_text-field-border-hover: var(--xh-border-strong);
21
+ --xh-_text-field-border: var(--xh-border-control);
22
+ --xh-_text-field-border-hover: var(--xh-border-control-hover);
18
23
 
19
24
  /* 语气只落在聚焦这一处:环与聚焦态描边。正文颜色不归它管。
20
25
  没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色与常态描边 */
21
26
  --xh-_text-field-ring: var(--xh-ring-focus);
22
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-default)));
27
+ --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control)));
23
28
 
24
29
  display: inline-flex;
25
30
  flex-direction: column;
@@ -54,9 +59,9 @@
54
59
  输入框没有实心档:填满一个要往里打字的框,字与底就没法同时读 */
55
60
  [data-scope='text-field'][data-part='root'][data-variant='outline'] {
56
61
  --xh-_text-field-bg: var(--xh-bg-canvas);
57
- --xh-_text-field-border: var(--xh-border-default);
58
- --xh-_text-field-border-hover: var(--xh-border-strong);
59
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-default)));
62
+ --xh-_text-field-border: var(--xh-border-control);
63
+ --xh-_text-field-border-hover: var(--xh-border-control-hover);
64
+ --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control)));
60
65
  }
61
66
 
62
67
  /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
@@ -64,16 +69,16 @@
64
69
  [data-scope='text-field'][data-part='root'][data-variant='subtle'] {
65
70
  --xh-_text-field-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
66
71
  --xh-_text-field-border: transparent;
67
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-default));
68
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-default));
72
+ --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
73
+ --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control));
69
74
  }
70
75
 
71
76
  /* 无框:底与描边都透明,平时只看得见字,悬停与聚焦才浮出边界 */
72
77
  [data-scope='text-field'][data-part='root'][data-variant='ghost'] {
73
78
  --xh-_text-field-bg: transparent;
74
79
  --xh-_text-field-border: transparent;
75
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-default));
76
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-default));
80
+ --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
81
+ --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control));
77
82
  }
78
83
 
79
84
  [data-scope='text-field'][data-part='label'] {
@@ -102,6 +107,19 @@
102
107
  transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
103
108
  }
104
109
 
110
+ /* 多行宿主:定高换成行数撑高,纵向留出内边距;autoSize 接管高度后拉柄与滚动都收掉 */
111
+ [data-scope='text-field'][data-part='input'][data-multiline] {
112
+ block-size: auto;
113
+ min-block-size: var(--xh-text-field-input-h, var(--xh-_text-field-h));
114
+ padding-block: var(--xh-text-field-textarea-py, var(--xh-space-2));
115
+ resize: vertical;
116
+ }
117
+
118
+ [data-scope='text-field'][data-part='input'][data-multiline][data-autosize] {
119
+ overflow: hidden;
120
+ resize: none;
121
+ }
122
+
105
123
  [data-scope='text-field'][data-part='input']::placeholder {
106
124
  color: var(--xh-text-field-placeholder-fg, var(--xh-fg-subtle));
107
125
  }
package/css/thread.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='thread'] {
4
+ --xh-thread-skin: 1;
5
+ }
6
+
2
7
  /* 自建定位上下文,作为绝对定位的回到底部按钮的参照系;
3
8
  block-size: 100% 让高度由外部决定,使滚动发生在内部。 */
4
9
  [data-scope='thread'][data-part='root'] {
@@ -57,7 +62,7 @@
57
62
  min-inline-size: var(--xh-thread-scroll-button-h, var(--xh-control-h-md));
58
63
  block-size: var(--xh-thread-scroll-button-h, var(--xh-control-h-md));
59
64
  padding-inline: var(--xh-thread-scroll-button-px, var(--xh-control-px-md));
60
- border: var(--xh-stroke-thin) solid var(--xh-thread-scroll-button-border, var(--xh-border-default));
65
+ border: var(--xh-stroke-thin) solid var(--xh-thread-scroll-button-border, var(--xh-border-control));
61
66
  border-radius: var(--xh-thread-scroll-button-radius, var(--xh-shape-pill));
62
67
  background: var(--xh-thread-scroll-button-bg, var(--xh-bg-surface));
63
68
  color: var(--xh-thread-scroll-button-fg, var(--xh-fg-default));
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='time-field'] {
4
+ --xh-time-field-skin: 1;
5
+ }
6
+
2
7
  /* 与文本框、数字框同一套堆叠:标签一行、控件一行 */
3
8
  [data-scope='time-field'][data-part='root'] {
4
9
  /* 尺寸档只换这四个私有槽,标题与控件都从 root 继承它们,换档不必给每个部件各写一条选择器 */
@@ -8,8 +13,8 @@
8
13
  --xh-_time-field-label-font-size: var(--xh-text-label-size);
9
14
  /* 形态档只换这三个私有槽:底色与两档描边 */
10
15
  --xh-_time-field-control-bg: var(--xh-bg-canvas);
11
- --xh-_time-field-control-border: var(--xh-border-default);
12
- --xh-_time-field-control-border-hover: var(--xh-border-strong);
16
+ --xh-_time-field-control-border: var(--xh-border-control);
17
+ --xh-_time-field-control-border-hover: var(--xh-border-control-hover);
13
18
  /* 聚焦描边与段位反白随语气走。没写 data-tone 时这几个 --xh-_tone* 没被声明,退回原来的焦点色与品牌色 */
14
19
  --xh-_time-field-ring: var(--xh-ring-focus);
15
20
  --xh-_time-field-segment-bg: var(--xh-_tone, var(--xh-bg-brand));
@@ -39,15 +44,15 @@
39
44
  /* 描边式:与缺省等价,写出来是为了三档形态在皮肤里都看得见 */
40
45
  [data-scope='time-field'][data-part='root'][data-variant='outline'] {
41
46
  --xh-_time-field-control-bg: var(--xh-bg-canvas);
42
- --xh-_time-field-control-border: var(--xh-border-default);
43
- --xh-_time-field-control-border-hover: var(--xh-border-strong);
47
+ --xh-_time-field-control-border: var(--xh-border-control);
48
+ --xh-_time-field-control-border-hover: var(--xh-border-control-hover);
44
49
  }
45
50
 
46
51
  /* 填充式:底色顶替描边,悬停时才浮出一道淡边 */
47
52
  [data-scope='time-field'][data-part='root'][data-variant='subtle'] {
48
53
  --xh-_time-field-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
49
54
  --xh-_time-field-control-border: transparent;
50
- --xh-_time-field-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
55
+ --xh-_time-field-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
51
56
  }
52
57
 
53
58
  /* 无框式:底与边都让开,可见反馈只剩聚焦那一档 */
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='time-picker'] {
4
+ --xh-time-picker-skin: 1;
5
+ }
6
+
2
7
  /* 与文本框、时间输入同一套堆叠:标签一行、控件一行 */
3
8
  [data-scope='time-picker'][data-part='root'] {
4
9
  display: inline-flex;
@@ -35,7 +40,7 @@
35
40
  block-size: var(--xh-time-picker-control-h, var(--xh-control-h-md));
36
41
  padding-inline: var(--xh-time-picker-control-px, var(--xh-control-px-md));
37
42
  padding-block: 0;
38
- border: var(--xh-stroke-thin) solid var(--xh-time-picker-control-border, var(--xh-border-default));
43
+ border: var(--xh-stroke-thin) solid var(--xh-time-picker-control-border, var(--xh-border-control));
39
44
  border-radius: var(--xh-time-picker-control-radius, var(--xh-shape-control));
40
45
  background: var(--xh-time-picker-control-bg, var(--xh-bg-canvas));
41
46
  color: var(--xh-time-picker-control-fg, var(--xh-fg-default));
@@ -54,7 +59,7 @@
54
59
 
55
60
  /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
56
61
  [data-scope='time-picker'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
57
- border-color: var(--xh-time-picker-control-border-hover, var(--xh-border-strong));
62
+ border-color: var(--xh-time-picker-control-border-hover, var(--xh-border-control-hover));
58
63
  }
59
64
 
60
65
  /* 焦点真正落在段或按钮上,但整块看起来才是一个控件:内部有焦点时整框亮起来。
@@ -242,8 +247,7 @@
242
247
  max-block-size: var(--xh-time-picker-column-max-h, 12rem);
243
248
  padding-inline: var(--xh-time-picker-column-px, var(--xh-space-1));
244
249
  overflow-y: auto;
245
- /* 滚动容器在某些浏览器里会被自动塞进 Tab 序列,落焦时不画环——
246
- 焦点该落在格上,列只在整列被界卡空时才兜底占一个 Tab 位 */
250
+ /* 滚动容器在某些浏览器里会被自动塞进 Tab 序列,是否画环见下方按 tabindex 分档的两条 */
247
251
  scrollbar-width: thin;
248
252
  }
249
253
 
@@ -256,51 +260,62 @@
256
260
  border-inline-start: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-border-subtle));
257
261
  }
258
262
 
259
- [data-scope='time-picker'][data-part='column']:focus-visible {
263
+ /* 焦点落在列上有两种情形:指针打开、这一段还空着、还没有任何格当锚点,或整列被界裁空。
264
+ 那一刻它认领着 Tab 位,环画在列内沿;有锚点时环长在格上,列不再画 */
265
+ [data-scope='time-picker'][data-part='column'][tabindex='0']:focus-visible {
266
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
267
+ outline-offset: calc(-1 * var(--xh-ring-width));
268
+ }
269
+
270
+ [data-scope='time-picker'][data-part='column']:not([tabindex='0']):focus-visible {
260
271
  outline: none;
261
272
  }
262
273
 
263
- [data-scope='time-picker'][data-part='option'] {
274
+ [data-scope='time-picker'][data-part='item'] {
264
275
  display: flex;
265
276
  flex: none;
266
277
  align-items: center;
267
278
  justify-content: center;
268
- padding-block: var(--xh-time-picker-option-py, var(--xh-space-1));
269
- padding-inline: var(--xh-time-picker-option-px, var(--xh-space-2));
270
- border-radius: var(--xh-time-picker-option-radius, var(--xh-shape-control));
271
- color: var(--xh-time-picker-option-fg, var(--xh-fg-default));
272
- font-size: var(--xh-time-picker-option-font-size, var(--xh-text-body-size));
279
+ padding-block: var(--xh-time-picker-item-py, var(--xh-space-1_5));
280
+ padding-inline: var(--xh-time-picker-item-px, var(--xh-control-px-md));
281
+ border-radius: var(--xh-time-picker-item-radius, var(--xh-shape-control));
282
+ color: var(--xh-time-picker-item-fg, var(--xh-fg-default));
283
+ font-size: var(--xh-time-picker-item-font-size, var(--xh-text-body-size));
284
+ /* 居中的单个数字格没有截断层,行高保持紧排,列内多露几格 */
273
285
  line-height: var(--xh-leading-none);
274
286
  white-space: nowrap;
275
287
  cursor: pointer;
276
288
  user-select: none;
289
+ transition:
290
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
291
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
277
292
  }
278
293
 
279
294
  /* 作者自己藏掉某几格时要让位,有 display 就得补这条 */
280
- [data-scope='time-picker'][data-part='option'][hidden] {
295
+ [data-scope='time-picker'][data-part='item'][hidden] {
281
296
  display: none;
282
297
  }
283
298
 
284
- /* 焦点所在与选中互相独立:可以停在一个没被选中的格上 */
285
- [data-scope='time-picker'][data-part='option'][data-highlighted]:not([data-disabled]),
286
- [data-scope='time-picker'][data-part='option']:hover:not([data-disabled]) {
287
- background: var(--xh-time-picker-option-bg-highlight, var(--xh-bg-subtle-hover));
299
+ /* 悬停与键盘锚点共用中性灰轻档;焦点所在与选中互相独立:可以停在一个没被选中的格上 */
300
+ [data-scope='time-picker'][data-part='item'][data-highlighted]:not([data-disabled]),
301
+ [data-scope='time-picker'][data-part='item']:hover:not([data-disabled]) {
302
+ background: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
288
303
  }
289
304
 
290
- [data-scope='time-picker'][data-part='option'][data-state='checked'] {
291
- background: var(--xh-time-picker-option-bg-checked, var(--xh-bg-brand));
292
- color: var(--xh-time-picker-option-fg-checked, var(--xh-fg-on-brand));
293
- font-weight: var(--xh-time-picker-option-weight-checked, var(--xh-font-weight-medium));
305
+ [data-scope='time-picker'][data-part='item'][data-state='checked'] {
306
+ background: var(--xh-time-picker-item-bg-checked, var(--xh-bg-brand));
307
+ color: var(--xh-time-picker-item-fg-checked, var(--xh-fg-on-brand));
308
+ font-weight: var(--xh-time-picker-item-weight-checked, var(--xh-font-weight-medium));
294
309
  }
295
310
 
296
- /* 选中格上再落焦点或悬停时,底色留在品牌色一侧:上面那条中性高亮的选择器更具体,
311
+ /* 选中格上再落焦点或悬停时,底色留在品牌色一侧:上面那条中性轻档的选择器更具体,
297
312
  不写这条就只有底色被换走、文字仍是品牌底上的反白色 */
298
- [data-scope='time-picker'][data-part='option'][data-state='checked'][data-highlighted]:not([data-disabled]),
299
- [data-scope='time-picker'][data-part='option'][data-state='checked']:hover:not([data-disabled]) {
300
- background: var(--xh-time-picker-option-bg-checked-highlight, var(--xh-bg-brand-hover));
313
+ [data-scope='time-picker'][data-part='item'][data-state='checked'][data-highlighted]:not([data-disabled]),
314
+ [data-scope='time-picker'][data-part='item'][data-state='checked']:hover:not([data-disabled]) {
315
+ background: var(--xh-time-picker-item-bg-checked-hover, var(--xh-bg-brand-hover));
301
316
  }
302
317
 
303
- [data-scope='time-picker'][data-part='option']:focus-visible {
318
+ [data-scope='time-picker'][data-part='item']:focus-visible {
304
319
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
305
320
  /* 往内收:选项在滚动列里挨着排,环画在外沿会被列的溢出裁掉 */
306
321
  outline-offset: calc(-1 * var(--xh-ring-offset));
@@ -308,7 +323,7 @@
308
323
 
309
324
  /* 禁用走 aria-disabled 而非原生 disabled(原生 disabled 不派 click,禁用守卫就走不到),
310
325
  所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
311
- [data-scope='time-picker'][data-part='option'][data-disabled] {
326
+ [data-scope='time-picker'][data-part='item'][data-disabled] {
312
327
  color: var(--xh-fg-disabled);
313
328
  cursor: not-allowed;
314
329
  }
@@ -336,7 +351,7 @@
336
351
  @keyframes xh-time-picker-panel-in {
337
352
  from {
338
353
  opacity: 0;
339
- translate: 0 calc(-1 * var(--xh-space-1));
354
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
340
355
  }
341
356
 
342
357
  to {
package/css/time.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='time'] {
4
+ --xh-time-skin: 1;
5
+ }
6
+
2
7
  [data-scope='time'][data-part='root'] {
3
8
  color: var(--xh-time-fg, var(--xh-fg-default));
4
9
  /* 等宽数字:秒数跳动时后面的字符不会左右挪 */
package/css/timeline.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='timeline'] {
4
+ --xh-timeline-skin: 1;
5
+ }
6
+
2
7
  [data-scope='timeline'][data-part='root'] {
3
8
  /* 尺寸档只换这几个私有槽,条目、圆点与文字都从 root 继承它们,
4
9
  换档不必给每个部件各写一条选择器 */