@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/cascader.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='cascader'] {
4
+ --xh-cascader-skin: 1;
5
+ }
6
+
2
7
  /* 解剖里没有把「触发器 + 清空按钮」裹在一起的 control 部件,一行是靠 flex-wrap 分出来的:
3
8
  标签占满整行把后面的挤到下一行,触发器与清空按钮就并排落在同一行上。
4
9
  这样作者少写标签、少写清空按钮,剩下的部件也不会塌 */
@@ -12,13 +17,16 @@
12
17
 
13
18
  /* 形态档只换触发框的描边与底色这三个槽,浮层与列不跟着变:
14
19
  变的是「这是个输入位」的表达方式,不是弹出内容的表达方式 */
15
- --xh-_cascader-border: var(--xh-border-default);
16
- --xh-_cascader-border-hover: var(--xh-border-strong);
20
+ --xh-_cascader-border: var(--xh-border-control);
21
+ --xh-_cascader-border-hover: var(--xh-border-control-hover);
17
22
  --xh-_cascader-bg: var(--xh-bg-canvas);
18
23
 
19
24
  /* 选中条目的文字色随语气走,没写 data-tone 时退回品牌强调色 */
20
25
  --xh-_cascader-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
21
26
 
27
+ /* 展开路径的底色:随语气走淡底,没写 data-tone 时退回品牌淡底 */
28
+ --xh-_cascader-active-bg: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
29
+
22
30
  display: inline-flex;
23
31
  flex-wrap: wrap;
24
32
  align-items: center;
@@ -34,15 +42,15 @@
34
42
  /* 形态只决定描边与底色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的中性配色 */
35
43
  /* outline 就是缺省那一身:描边加画布底,写出来只为让三档并列可读 */
36
44
  [data-scope='cascader'][data-part='root'][data-variant='outline'] {
37
- --xh-_cascader-border: var(--xh-border-default);
38
- --xh-_cascader-border-hover: var(--xh-border-strong);
45
+ --xh-_cascader-border: var(--xh-border-control);
46
+ --xh-_cascader-border-hover: var(--xh-border-control-hover);
39
47
  --xh-_cascader-bg: var(--xh-bg-canvas);
40
48
  }
41
49
 
42
50
  /* subtle 是填充式:底色接过「这里能点」的表达,描边随之让位 */
43
51
  [data-scope='cascader'][data-part='root'][data-variant='subtle'] {
44
52
  --xh-_cascader-border: transparent;
45
- --xh-_cascader-border-hover: var(--xh-_tone-border, var(--xh-border-default));
53
+ --xh-_cascader-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
46
54
  --xh-_cascader-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
47
55
  }
48
56
 
@@ -118,9 +126,9 @@
118
126
  }
119
127
 
120
128
  /* trigger 是整个控件唯一的 Tab 停靠点(展开后停靠点才移进列里),落焦必须看得见。
121
- 语气落在环上:没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色 */
129
+ 聚焦环恒用固定环色,不随语气走 */
122
130
  [data-scope='cascader'][data-part='trigger']:focus-visible {
123
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
131
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
124
132
  outline-offset: var(--xh-ring-offset);
125
133
  }
126
134
 
@@ -171,6 +179,11 @@
171
179
  display: none;
172
180
  }
173
181
 
182
+ /* 没写内容就由皮肤画箭头;作者往部件里塞了自己的图形,这条规则即不命中 */
183
+ [data-scope='cascader'][data-part='indicator']:empty::before {
184
+ content: '▾';
185
+ }
186
+
174
187
  [data-scope='cascader'][data-part='indicator'][data-state='open'] {
175
188
  rotate: 180deg;
176
189
  }
@@ -216,7 +229,7 @@
216
229
  /* 清空按钮退出了 Tab 序列(tabindex=-1),正常操作走不到这里;
217
230
  留着是给程序化聚焦兜底,落焦时得看得见 */
218
231
  [data-scope='cascader'][data-part='clear-trigger']:focus-visible {
219
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
232
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
220
233
  outline-offset: var(--xh-ring-offset);
221
234
  }
222
235
 
@@ -268,16 +281,24 @@
268
281
  }
269
282
 
270
283
  [data-scope='cascader'][data-part='content'][data-state='open'] {
284
+ /* 入场横移沿书写方向起始缘:位移量经私有槽供给关键帧,rtl 只翻符号 */
285
+ --xh-_cascader-slide: calc(-1 * var(--xh-motion-distance-sm));
286
+
271
287
  animation: xh-cascader-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
272
288
  }
273
289
 
274
- /* 一列:自己定宽、自己滚。列与列之间用一条分隔线,比留白更能说明「这是下一级」 */
290
+ [dir='rtl'] [data-scope='cascader'][data-part='content'][data-state='open'] {
291
+ --xh-_cascader-slide: var(--xh-motion-distance-sm);
292
+ }
293
+
294
+ /* 一列:宽度由内容撑出、设下限防塌,高度定死——切换展开路径时浮层不上下跳动,
295
+ 溢出的条目在列内自己滚。列与列之间用一条分隔线,比留白更能说明「这是下一级」 */
275
296
  [data-scope='cascader'][data-part='column'] {
276
297
  display: flex;
277
298
  flex: none;
278
299
  flex-direction: column;
279
- inline-size: var(--xh-cascader-column-w, 11rem);
280
- max-block-size: var(--xh-cascader-column-max-h, 16rem);
300
+ min-inline-size: var(--xh-cascader-column-min-w, 7rem);
301
+ block-size: var(--xh-cascader-column-h, 11.25rem);
281
302
  padding-block: var(--xh-cascader-column-py, var(--xh-space-1));
282
303
  padding-inline: var(--xh-cascader-column-px, var(--xh-space-1));
283
304
  overflow-y: auto;
@@ -295,8 +316,14 @@
295
316
  border-inline-start: var(--xh-stroke-thin) solid var(--xh-cascader-column-divider, var(--xh-border-subtle));
296
317
  }
297
318
 
298
- /* 列不进 Tab 序列也不承载焦点,落焦不画环:高亮永远长在条目上 */
299
- [data-scope='cascader'][data-part='column']:focus-visible {
319
+ /* 焦点落在根列上只有一种情形:指针打开、无选中值、还没有任何条目当锚点。
320
+ 那一刻它认领着 Tab 位,环画在列内沿;有锚点时环长在条目上,列不再画 */
321
+ [data-scope='cascader'][data-part='column'][tabindex='0']:focus-visible {
322
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
323
+ outline-offset: calc(-1 * var(--xh-ring-width));
324
+ }
325
+
326
+ [data-scope='cascader'][data-part='column']:not([tabindex='0']):focus-visible {
300
327
  outline: none;
301
328
  }
302
329
 
@@ -304,8 +331,9 @@
304
331
  display: flex;
305
332
  align-items: center;
306
333
  gap: var(--xh-cascader-row-gap, var(--xh-_cascader-gap));
307
- padding-block: var(--xh-cascader-row-py, var(--xh-space-1));
308
- padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-sm));
334
+ max-inline-size: var(--xh-cascader-row-max-w, 25rem);
335
+ padding-block: var(--xh-cascader-row-py, var(--xh-space-1_5));
336
+ padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-md));
309
337
  border-radius: var(--xh-cascader-row-radius, var(--xh-shape-control));
310
338
  color: var(--xh-cascader-row-fg, var(--xh-fg-default));
311
339
  font-size: var(--xh-cascader-row-font-size, var(--xh-_cascader-font-size));
@@ -314,6 +342,9 @@
314
342
  white-space: nowrap;
315
343
  cursor: pointer;
316
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);
317
348
  }
318
349
 
319
350
  /* 条目常挂不卸载:不属于当前这一列的那些靠 hidden 收起。
@@ -322,14 +353,21 @@
322
353
  display: none;
323
354
  }
324
355
 
325
- /* 指针悬停、键盘高亮与展开路径共用同一张底:三者都是「此刻停在这儿」,
326
- data-highlighted 跟的是连接层记的焦点条目 */
327
- [data-scope='cascader'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted], [data-active]) {
328
- background: var(--xh-cascader-row-bg-highlight, var(--xh-bg-subtle-hover));
356
+ /* 底色分两档、靠色相分家:悬停与键盘锚点是中性灰轻档,展开路径是品牌淡底加粗。
357
+ hover 恒中性灰、不接语气槽——两档同色相的话路径就认不出来了。
358
+ 悬停展开把路径挪走后留在原地的锚点降回轻档,每列至多一条路径高亮 */
359
+ [data-scope='cascader'][data-part='item']:not([data-disabled]):is(:hover, [data-highlighted]) {
360
+ background: var(--xh-cascader-row-bg-hover, var(--xh-bg-subtle));
329
361
  }
330
362
 
331
- /* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色整条通道留给悬停,
332
- 两者因此能同时看见 */
363
+ /* 必须排在轻档之后:锚点走到路径上时同特指度靠书写顺序压过轻档 */
364
+ [data-scope='cascader'][data-part='item']:not([data-disabled])[data-active] {
365
+ background: var(--xh-cascader-row-bg-active, var(--xh-_cascader-active-bg));
366
+ font-weight: var(--xh-cascader-row-active-font-weight, var(--xh-font-weight-semibold));
367
+ }
368
+
369
+ /* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色强档归展开路径、轻档归悬停,
370
+ 三者因此能同时看见 */
333
371
  [data-scope='cascader'][data-part='item'][data-selected] {
334
372
  color: var(--xh-cascader-row-fg-selected, var(--xh-_cascader-selected-fg));
335
373
  font-weight: var(--xh-cascader-row-selected-font-weight, var(--xh-font-weight-medium));
@@ -337,7 +375,7 @@
337
375
 
338
376
  /* 条目自己就是 option,环直接画在它身上;往内收,行是撑满列宽的,环画在外沿会被裁掉 */
339
377
  [data-scope='cascader'][data-part='item']:focus-visible {
340
- outline: var(--xh-ring-width) solid var(--xh-_tone, var(--xh-ring-focus));
378
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
341
379
  outline-offset: calc(-1 * var(--xh-ring-width));
342
380
  }
343
381
 
@@ -348,6 +386,28 @@
348
386
  cursor: not-allowed;
349
387
  }
350
388
 
389
+ /* 分支条目行尾画右向小箭头:不点开也看得出还有下一级。
390
+ 全边框描好后抹掉块末与行首两边,剩下的直角旋成箭头;位置由 item-text 的 flex:1 顶到行尾 */
391
+ [data-scope='cascader'][data-part='item'][data-branch]::after {
392
+ content: '';
393
+ flex: none;
394
+ inline-size: var(--xh-cascader-branch-arrow-size, var(--xh-space-1_5));
395
+ block-size: var(--xh-cascader-branch-arrow-size, var(--xh-space-1_5));
396
+ border: var(--xh-glyph-stroke-light) solid var(--xh-cascader-branch-arrow-fg, var(--xh-fg-subtle));
397
+ border-block-end: 0;
398
+ border-inline-start: 0;
399
+ rotate: 45deg;
400
+ }
401
+
402
+ /* rtl 下剩下的是块首与行末(物理左上)两边,反向旋 45 度才指向行进方向 */
403
+ [dir='rtl'] [data-scope='cascader'][data-part='item'][data-branch]::after {
404
+ rotate: -45deg;
405
+ }
406
+
407
+ [data-scope='cascader'][data-part='item'][data-branch][data-disabled]::after {
408
+ border-color: var(--xh-fg-disabled);
409
+ }
410
+
351
411
  [data-scope='cascader'][data-part='item-text'] {
352
412
  flex: 1;
353
413
  min-inline-size: 0;
@@ -362,7 +422,7 @@
362
422
  flex: none;
363
423
  align-items: center;
364
424
  justify-content: center;
365
- inline-size: var(--xh-cascader-indicator-size, var(--xh-control-indicator-size));
425
+ inline-size: var(--xh-cascader-item-indicator-size, var(--xh-control-indicator-size));
366
426
  color: var(--xh-cascader-item-indicator-fg, var(--xh-_tone, var(--xh-bg-brand)));
367
427
  visibility: hidden;
368
428
  }
@@ -371,22 +431,142 @@
371
431
  display: none;
372
432
  }
373
433
 
434
+ /* 没写内容就由皮肤画勾;作者往部件里塞了自己的图形,这条规则即不命中 */
435
+ [data-scope='cascader'][data-part='item-indicator']:empty::before {
436
+ content: '✓';
437
+ }
438
+
374
439
  [data-scope='cascader'][data-part='item-indicator'][data-selected] {
375
440
  visibility: visible;
376
441
  }
377
442
 
443
+ /* 级联勾选的半选态只在皮肤自绘(:empty)时露面画横杠:
444
+ 作者塞了自己的选中图形时,半选放出来会顶着一个语义相反的勾,表达交还作者 */
445
+ [data-scope='cascader'][data-part='item-indicator'][data-indeterminate]:empty {
446
+ visibility: visible;
447
+ }
448
+
449
+ [data-scope='cascader'][data-part='item-indicator'][data-indeterminate]:not([data-selected]):empty::before {
450
+ content: '−';
451
+ font-weight: var(--xh-font-weight-semibold);
452
+ }
453
+
378
454
  [data-scope='cascader'][data-part='item-indicator'][data-disabled] {
379
455
  color: var(--xh-fg-disabled);
380
456
  }
457
+
458
+ /* —— 搜索视图:输入框横占整行排在列上方,候选列表替换列视图 —— */
459
+ [data-scope='cascader'][data-part='content']:has([data-part='input']:not([hidden])) {
460
+ flex-wrap: wrap;
461
+ }
462
+
463
+ [data-scope='cascader'][data-part='input'] {
464
+ flex-basis: 100%;
465
+ min-inline-size: 0;
466
+ padding-block: var(--xh-cascader-input-py, var(--xh-space-2));
467
+ padding-inline: var(--xh-cascader-input-px, var(--xh-control-px-md));
468
+ border: none;
469
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-cascader-content-border, var(--xh-border-default));
470
+ border-start-start-radius: inherit;
471
+ border-start-end-radius: inherit;
472
+ background: none;
473
+ color: inherit;
474
+ font-family: inherit;
475
+ font-size: var(--xh-cascader-input-font-size, var(--xh-_cascader-font-size));
476
+ line-height: var(--xh-leading-normal);
477
+ }
478
+
479
+ [data-scope='cascader'][data-part='input']:focus-visible {
480
+ outline: none;
481
+ }
482
+
483
+ [data-scope='cascader'][data-part='input'][hidden] {
484
+ display: none;
485
+ }
486
+
487
+ [data-scope='cascader'][data-part='search-list'] {
488
+ display: flex;
489
+ flex-basis: 100%;
490
+ flex-direction: column;
491
+ max-block-size: var(--xh-cascader-search-max-h, 11.25rem);
492
+ padding: var(--xh-cascader-search-p, var(--xh-space-1));
493
+ overflow-y: auto;
494
+ }
495
+
496
+ [data-scope='cascader'][data-part='search-list'][hidden] {
497
+ display: none;
498
+ }
499
+
500
+ /* 无候选时列表自身不占位,空态交给 empty 部件出面 */
501
+ [data-scope='cascader'][data-part='search-list'][data-empty] {
502
+ padding: 0;
503
+ }
504
+
505
+ /* 搜索视图里列整体让位 */
506
+ [data-scope='cascader'][data-part='content'][data-searching] [data-part='column'] {
507
+ display: none;
508
+ }
509
+
510
+ /* 候选与列内条目同一套行度量,虚拟高亮与悬停同用轻档 */
511
+ [data-scope='cascader'][data-part='search-item'] {
512
+ padding-block: var(--xh-cascader-row-py, var(--xh-space-1_5));
513
+ padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-md));
514
+ overflow: hidden;
515
+ border-radius: var(--xh-cascader-row-radius, var(--xh-shape-control));
516
+ color: var(--xh-cascader-row-fg, var(--xh-fg-default));
517
+ font-size: var(--xh-cascader-row-font-size, var(--xh-_cascader-font-size));
518
+ line-height: var(--xh-cascader-row-leading, var(--xh-leading-normal));
519
+ text-overflow: ellipsis;
520
+ white-space: nowrap;
521
+ cursor: pointer;
522
+ user-select: none;
523
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
524
+ }
525
+
526
+ [data-scope='cascader'][data-part='search-item']:not([data-disabled]):is(:hover, [data-highlighted]) {
527
+ background: var(--xh-cascader-row-bg-hover, var(--xh-bg-subtle));
528
+ }
529
+
530
+ [data-scope='cascader'][data-part='search-item'][data-disabled] {
531
+ color: var(--xh-fg-disabled);
532
+ cursor: not-allowed;
533
+ }
534
+
535
+ [data-scope='cascader'][data-part='search-item'][hidden] {
536
+ display: none;
537
+ }
538
+
539
+ /* —— 空态:当前视图没有条目时由 empty 部件出面,文案由适配器或作者供给,皮肤只管排版 —— */
540
+ /* 根列没有条目时那条空列让位,占位面接管整个浮层 */
541
+ [data-scope='cascader'][data-part='content'][data-empty] [data-part='column'] {
542
+ display: none;
543
+ }
544
+
545
+ [data-scope='cascader'][data-part='empty'] {
546
+ display: flex;
547
+ flex: 1 1 100%;
548
+ align-items: center;
549
+ justify-content: center;
550
+ min-inline-size: var(--xh-cascader-column-min-w, 7rem);
551
+ min-block-size: var(--xh-cascader-empty-min-h, 5rem);
552
+ padding: var(--xh-cascader-empty-p, var(--xh-space-3));
553
+ color: var(--xh-cascader-empty-fg, var(--xh-fg-subtle));
554
+ font-size: var(--xh-cascader-row-font-size, var(--xh-_cascader-font-size));
555
+ }
556
+
557
+ [data-scope='cascader'][data-part='empty'][hidden] {
558
+ display: none;
559
+ }
381
560
  }
382
561
 
383
562
  @layer xihan.motion {
384
563
  /* 浮层是横向长出来的:淡入之外再沿书写方向起始缘推一小段,观感上像列被「拉开」。
564
+ 位移量从 content 上的私有槽取,rtl 侧翻符号后同一份关键帧两个方向都对。
385
565
  关键帧写在本文件里、名字带组件前缀,不动公共的那一份 */
386
566
  @keyframes xh-cascader-in {
387
567
  from {
388
568
  opacity: 0;
389
- translate: -0.25rem 0;
569
+ translate: var(--xh-_cascader-slide, calc(-1 * var(--xh-motion-distance-sm))) 0;
390
570
  }
391
571
 
392
572
  to {
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='checkbox-group'] {
4
+ --xh-checkbox-group-skin: 1;
5
+ }
6
+
2
7
  /* 组容器:label、trigger、条目都是它的直接子节点,排布方式只能读 data-orientation——
3
8
  连接层明说了 role=group 不接受 aria-orientation,那个属性它根本没输出 */
4
9
  [data-scope='checkbox-group'][data-part='root'] {
@@ -70,19 +75,19 @@
70
75
  /* 全选格与条目格共用同一套盒子,并成一条规则写:分开写迟早只改到一半,两个方框就此走形。
71
76
  尺寸与选中态照 checkbox 的 root 搬,同一份视觉语言在单体与集合里必须一致。
72
77
  trigger 那格没有对应的角色节点(anatomy 到 trigger 为止),只能由伪元素补出来 */
73
- [data-scope='checkbox-group'][data-part='item-control'],
78
+ [data-scope='checkbox-group'][data-part='indicator'],
74
79
  [data-scope='checkbox-group'][data-part='trigger']::before {
75
80
  display: inline-flex;
76
81
  flex: none;
77
82
  align-items: center;
78
83
  justify-content: center;
79
- inline-size: var(--xh-checkbox-group-control-size, 16px);
80
- block-size: var(--xh-checkbox-group-control-size, 16px);
81
- border: var(--xh-stroke-thin) solid var(--xh-checkbox-group-control-border, var(--xh-border-default));
82
- border-radius: var(--xh-checkbox-group-control-radius, var(--xh-radius-sm));
83
- background: var(--xh-checkbox-group-control-bg, var(--xh-bg-canvas));
84
- color: var(--xh-checkbox-group-control-fg, var(--xh-fg-on-brand));
85
- font-size: var(--xh-checkbox-group-control-font-size, 12px);
84
+ inline-size: var(--xh-checkbox-group-indicator-size, 16px);
85
+ block-size: var(--xh-checkbox-group-indicator-size, 16px);
86
+ border: var(--xh-stroke-thin) solid var(--xh-checkbox-group-indicator-border, var(--xh-border-control));
87
+ border-radius: var(--xh-checkbox-group-indicator-radius, var(--xh-radius-sm));
88
+ background: var(--xh-checkbox-group-indicator-bg, var(--xh-bg-canvas));
89
+ color: var(--xh-checkbox-group-indicator-fg, var(--xh-fg-on-brand));
90
+ font-size: var(--xh-checkbox-group-indicator-font-size, 12px);
86
91
  line-height: var(--xh-leading-none);
87
92
  transition:
88
93
  background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
@@ -90,7 +95,7 @@
90
95
  }
91
96
 
92
97
  /* content 只能给伪元素,绝不能并进上面那条:content 落在普通元素上会顶掉它的全部子节点,
93
- item-control 里作者写的图标就此消失 */
98
+ indicator 里作者写的图标就此消失 */
94
99
  [data-scope='checkbox-group'][data-part='trigger']::before {
95
100
  content: '';
96
101
  }
@@ -98,19 +103,19 @@
98
103
  /* 悬停只加深空方框的描边。已选中的那一格必须排除:这条选择器的权重高过下面那条填色规则,
99
104
  不排除就会在悬停时把 brand 描边换回灰色,方框看起来"缺了一圈" */
100
105
  [data-scope='checkbox-group'][data-part='item']:not([data-disabled]):hover
101
- [data-scope='checkbox-group'][data-part='item-control']:not([data-state='checked']) {
102
- border-color: var(--xh-checkbox-group-control-border-hover, var(--xh-border-strong));
106
+ [data-scope='checkbox-group'][data-part='indicator']:not([data-state='checked']) {
107
+ border-color: var(--xh-checkbox-group-indicator-border-hover, var(--xh-border-control-hover));
103
108
  }
104
109
 
105
110
  /* 选中即填色:条目是二态,全选格三态里 all 与 some 都算"有值",共用同一副填色 */
106
- [data-scope='checkbox-group'][data-part='item-control'][data-state='checked'],
111
+ [data-scope='checkbox-group'][data-part='indicator'][data-state='checked'],
107
112
  [data-scope='checkbox-group'][data-part='trigger']:is([data-state='all'], [data-state='some'])::before {
108
- border-color: var(--xh-checkbox-group-control-border-checked, var(--xh-bg-brand));
109
- background: var(--xh-checkbox-group-control-bg-checked, var(--xh-bg-brand));
113
+ border-color: var(--xh-checkbox-group-indicator-border-checked, var(--xh-bg-brand));
114
+ background: var(--xh-checkbox-group-indicator-bg-checked, var(--xh-bg-brand));
110
115
  }
111
116
 
112
- /* 勾号由皮肤补,作者不必自己往 item-control 里塞字符 */
113
- [data-scope='checkbox-group'][data-part='item-control'][data-state='checked']::before {
117
+ /* 勾号由皮肤补,作者不必自己往 indicator 里塞字符 */
118
+ [data-scope='checkbox-group'][data-part='indicator'][data-state='checked']::before {
114
119
  content: '✓';
115
120
  }
116
121
 
@@ -126,8 +131,8 @@
126
131
 
127
132
  /* 校验失败标在每个方框上:root 上的 data-invalid 是唯一出处,条目自己不带这个属性 */
128
133
  [data-scope='checkbox-group'][data-part='root'][data-invalid]
129
- [data-scope='checkbox-group'][data-part='item-control'] {
130
- border-color: var(--xh-checkbox-group-control-border-invalid, var(--xh-color-danger-500));
134
+ [data-scope='checkbox-group'][data-part='indicator'] {
135
+ border-color: var(--xh-checkbox-group-indicator-border-invalid, var(--xh-color-danger-500));
131
136
  }
132
137
 
133
138
  [data-scope='checkbox-group'][data-part='item-text'] {
@@ -170,7 +175,7 @@
170
175
  /* 表单出口:连接层已经把整套视觉隐藏写进内联 style(absolute + 1px + clip-path),
171
176
  这里绝不能再补 display:none——那份输入必须留在布局里,原生校验提示要有处可贴。
172
177
  只补一条不吃指针,免得它挡住条目的点击 */
173
- [data-scope='checkbox-group'][data-part='item-hidden-input'] {
178
+ [data-scope='checkbox-group'][data-part='hidden-input'] {
174
179
  pointer-events: none;
175
180
  }
176
181
 
@@ -178,7 +183,7 @@
178
183
  不补的话作者给节点加 hidden 后它照样显示 */
179
184
  [data-scope='checkbox-group'][data-part='root'][hidden],
180
185
  [data-scope='checkbox-group'][data-part='item'][hidden],
181
- [data-scope='checkbox-group'][data-part='item-control'][hidden],
186
+ [data-scope='checkbox-group'][data-part='indicator'][hidden],
182
187
  [data-scope='checkbox-group'][data-part='trigger'][hidden] {
183
188
  display: none;
184
189
  }
package/css/checkbox.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='checkbox'] {
4
+ --xh-checkbox-skin: 1;
5
+ }
6
+
2
7
  [data-scope='checkbox'][data-part='root'] {
3
8
  /* 尺寸档只换方框边长这一个私有槽,勾的字号按边长的比例跟着走;
4
9
  指示器从 root 继承这两个槽,换档不必给每个部件各写一条选择器 */
@@ -18,7 +23,7 @@
18
23
  inline-size: var(--xh-_checkbox-box);
19
24
  block-size: var(--xh-_checkbox-box);
20
25
  padding: 0;
21
- border: 1px solid var(--xh-checkbox-border, var(--xh-border-default));
26
+ border: 1px solid var(--xh-checkbox-border, var(--xh-border-control));
22
27
  border-radius: var(--xh-radius-sm);
23
28
  background: var(--xh-checkbox-bg, var(--xh-bg-canvas));
24
29
  color: var(--xh-checkbox-fg, var(--xh-_checkbox-on-accent));
package/css/clipboard.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='clipboard'] {
4
+ --xh-clipboard-skin: 1;
5
+ }
6
+
2
7
  /* 与文本框同一套堆叠:标签一行、输入行一行 */
3
8
  [data-scope='clipboard'][data-part='root'] {
4
9
  display: inline-flex;
@@ -38,7 +43,7 @@
38
43
  block-size: var(--xh-clipboard-input-h, var(--xh-control-h-md));
39
44
  padding-inline: var(--xh-clipboard-input-px, var(--xh-control-px-md));
40
45
  padding-block: 0;
41
- border: var(--xh-stroke-thin) solid var(--xh-clipboard-input-border, var(--xh-border-default));
46
+ border: var(--xh-stroke-thin) solid var(--xh-clipboard-input-border, var(--xh-border-control));
42
47
  border-radius: var(--xh-clipboard-input-radius, var(--xh-shape-control));
43
48
  /* 只读态压低底色表示"改不动",但仍可聚焦、可选中复制 */
44
49
  background: var(--xh-clipboard-input-bg, var(--xh-bg-subtle));
@@ -66,7 +71,7 @@
66
71
  block-size: var(--xh-clipboard-trigger-h, var(--xh-control-h-md));
67
72
  padding-inline: var(--xh-clipboard-trigger-px, var(--xh-control-px-md));
68
73
  padding-block: 0;
69
- border: var(--xh-stroke-thin) solid var(--xh-clipboard-trigger-border, var(--xh-border-default));
74
+ border: var(--xh-stroke-thin) solid var(--xh-clipboard-trigger-border, var(--xh-border-control));
70
75
  border-radius: var(--xh-clipboard-trigger-radius, var(--xh-shape-control));
71
76
  background: var(--xh-clipboard-trigger-bg, var(--xh-bg-canvas));
72
77
  color: var(--xh-clipboard-trigger-fg, var(--xh-fg-default));
@@ -89,7 +94,7 @@
89
94
  }
90
95
 
91
96
  [data-scope='clipboard'][data-part='trigger']:hover {
92
- border-color: var(--xh-clipboard-trigger-border-hover, var(--xh-border-strong));
97
+ border-color: var(--xh-clipboard-trigger-border-hover, var(--xh-border-control-hover));
93
98
  background: var(--xh-clipboard-trigger-bg-hover, var(--xh-bg-subtle-hover));
94
99
  }
95
100
 
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='code-block'] {
4
+ --xh-code-block-skin: 1;
5
+ }
6
+
2
7
  /* overflow: hidden 让内部 <pre> 的滚动内容沿圆角收边;不设 display,排布由作者决定 */
3
8
  [data-scope='code-block'][data-part='root'] {
4
9
  overflow: hidden;
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='collapsible'] {
4
+ --xh-collapsible-skin: 1;
5
+ }
6
+
2
7
  /* 根容器自己不排版,这条只声明尺寸档的私有槽:触发按钮从 root 继承它们,
3
8
  换档不必给部件各写一条选择器 */
4
9
  [data-scope='collapsible'][data-part='root'] {
@@ -2,7 +2,7 @@
2
2
  @keyframes xh-color-picker-fade-in {
3
3
  from {
4
4
  opacity: 0;
5
- scale: 0.98;
5
+ scale: var(--xh-motion-scale-enter);
6
6
  }
7
7
 
8
8
  to {
@@ -13,6 +13,11 @@
13
13
  }
14
14
 
15
15
  @layer xihan.components {
16
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17
+ [data-scope='color-picker'] {
18
+ --xh-color-picker-skin: 1;
19
+ }
20
+
16
21
  /* 定位分工:取色区拇指的两条轴(inset-inline-start / inset-block-start)、
17
22
  通道拇指的主轴(inset-inline-start)、浮层坐标、取色区底色、透明度轨道的渐变,
18
23
  全都由连接层每帧写进内联样式。这份皮肤一个都不碰:内联优先级高于样式表,
@@ -43,7 +48,7 @@
43
48
  min-inline-size: var(--xh-color-picker-trigger-min-w, 9rem);
44
49
  block-size: var(--xh-color-picker-trigger-h, var(--xh-control-h-md));
45
50
  padding-inline: var(--xh-color-picker-trigger-px, var(--xh-control-px-md));
46
- border: var(--xh-stroke-thin) solid var(--xh-color-picker-trigger-border, var(--xh-border-default));
51
+ border: var(--xh-stroke-thin) solid var(--xh-color-picker-trigger-border, var(--xh-border-control));
47
52
  border-radius: var(--xh-color-picker-trigger-radius, var(--xh-shape-control));
48
53
  background: var(--xh-color-picker-trigger-bg, var(--xh-bg-canvas));
49
54
  color: var(--xh-color-picker-trigger-fg, var(--xh-fg-default));
@@ -55,7 +60,7 @@
55
60
  }
56
61
 
57
62
  [data-scope='color-picker'][data-part='trigger']:hover:not(:disabled) {
58
- border-color: var(--xh-color-picker-trigger-border-hover, var(--xh-border-strong));
63
+ border-color: var(--xh-color-picker-trigger-border-hover, var(--xh-border-control-hover));
59
64
  }
60
65
 
61
66
  [data-scope='color-picker'][data-part='trigger']:focus-visible {
@@ -301,7 +306,7 @@
301
306
  min-inline-size: 0;
302
307
  block-size: var(--xh-color-picker-input-h, var(--xh-control-h-sm));
303
308
  padding-inline: var(--xh-color-picker-input-px, var(--xh-control-px-sm));
304
- border: var(--xh-stroke-thin) solid var(--xh-color-picker-input-border, var(--xh-border-default));
309
+ border: var(--xh-stroke-thin) solid var(--xh-color-picker-input-border, var(--xh-border-control));
305
310
  border-radius: var(--xh-color-picker-input-radius, var(--xh-shape-control));
306
311
  background: var(--xh-color-picker-input-bg, var(--xh-bg-canvas));
307
312
  color: inherit;
@@ -341,7 +346,7 @@
341
346
  inline-size: var(--xh-color-picker-action-size, 1.75rem);
342
347
  block-size: var(--xh-color-picker-action-size, 1.75rem);
343
348
  padding: 0;
344
- border: var(--xh-stroke-thin) solid var(--xh-color-picker-action-border, var(--xh-border-default));
349
+ border: var(--xh-stroke-thin) solid var(--xh-color-picker-action-border, var(--xh-border-control));
345
350
  border-radius: var(--xh-color-picker-action-radius, var(--xh-shape-control));
346
351
  background: var(--xh-color-picker-action-bg, transparent);
347
352
  color: var(--xh-color-picker-action-fg, var(--xh-fg-muted));
@@ -385,7 +390,7 @@
385
390
  inline-size: var(--xh-color-picker-swatch-item-size, 1.25rem);
386
391
  block-size: var(--xh-color-picker-swatch-item-size, 1.25rem);
387
392
  padding: 0;
388
- border: var(--xh-stroke-thin) solid var(--xh-color-picker-swatch-border, var(--xh-border-default));
393
+ border: var(--xh-stroke-thin) solid var(--xh-color-picker-swatch-border, var(--xh-border-control));
389
394
  border-radius: var(--xh-color-picker-swatch-radius, var(--xh-radius-sm));
390
395
  cursor: pointer;
391
396
  }
@@ -421,4 +426,20 @@
421
426
  [data-scope='color-picker'][data-part='swatch-group'][hidden] {
422
427
  display: none;
423
428
  }
429
+
430
+ /* 连接层把它写成 type=hidden,UA 自己就不渲染;这里的视觉隐藏是给元素升级前那一瞬兜底
431
+ (作者手写的是一个普通 input,升级完成前它是可见的文本框)。
432
+ 刻意不写 display:写了反而会盖掉 UA 对 type=hidden 的收起,把它显出来 */
433
+ [data-scope='color-picker'][data-part='hidden-input'] {
434
+ position: absolute;
435
+ inline-size: 1px;
436
+ block-size: 1px;
437
+ padding: 0;
438
+ margin: -1px;
439
+ border: 0;
440
+ overflow: hidden;
441
+ clip-path: inset(50%);
442
+ white-space: nowrap;
443
+ pointer-events: none;
444
+ }
424
445
  }