@xihan-ui/styles 1.0.0-alpha.1 → 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 (109) hide show
  1. package/CHANGELOG.md +80 -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 +5 -0
  9. package/css/badge.css +5 -0
  10. package/css/breadcrumb.css +5 -0
  11. package/css/button-group.css +5 -0
  12. package/css/button.css +15 -0
  13. package/css/calendar.css +5 -0
  14. package/css/card.css +5 -0
  15. package/css/carousel.css +5 -0
  16. package/css/cascader.css +8 -3
  17. package/css/checkbox-group.css +5 -0
  18. package/css/checkbox.css +5 -0
  19. package/css/clipboard.css +5 -0
  20. package/css/code-block.css +5 -0
  21. package/css/collapsible.css +5 -0
  22. package/css/color-picker.css +6 -1
  23. package/css/combobox.css +19 -0
  24. package/css/composer.css +5 -0
  25. package/css/context-menu.css +6 -8
  26. package/css/countdown.css +5 -0
  27. package/css/date-field.css +5 -0
  28. package/css/date-picker.css +6 -1
  29. package/css/descriptions.css +5 -0
  30. package/css/dialog.css +69 -9
  31. package/css/drawer.css +30 -9
  32. package/css/dynamic-input.css +5 -0
  33. package/css/editable.css +5 -0
  34. package/css/ellipsis.css +5 -0
  35. package/css/empty-state.css +5 -0
  36. package/css/field.css +5 -0
  37. package/css/file-upload.css +5 -0
  38. package/css/flex.css +5 -0
  39. package/css/float-button.css +5 -0
  40. package/css/form.css +6 -1
  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 +19 -6
  45. package/css/icon-wrapper.css +5 -0
  46. package/css/icon.css +5 -0
  47. package/css/image-viewer.css +31 -11
  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 +5 -0
  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 +19 -0
  57. package/css/menu.css +19 -0
  58. package/css/menubar.css +6 -8
  59. package/css/navigation-menu.css +6 -1
  60. package/css/number-animation.css +5 -0
  61. package/css/number-field.css +5 -0
  62. package/css/page-header.css +5 -0
  63. package/css/pagination.css +5 -0
  64. package/css/pin-input.css +5 -0
  65. package/css/popconfirm.css +28 -7
  66. package/css/popover.css +19 -0
  67. package/css/popselect.css +19 -0
  68. package/css/progress.css +5 -0
  69. package/css/qr-code.css +5 -0
  70. package/css/radio-group.css +5 -0
  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 +19 -0
  75. package/css/separator.css +5 -0
  76. package/css/side-nav.css +5 -0
  77. package/css/skeleton.css +5 -0
  78. package/css/slider.css +5 -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 +5 -0
  83. package/css/switch.css +14 -7
  84. package/css/table.css +5 -0
  85. package/css/tabs.css +5 -0
  86. package/css/tags-input.css +5 -0
  87. package/css/text-field.css +5 -0
  88. package/css/thread.css +5 -0
  89. package/css/time-field.css +5 -0
  90. package/css/time-picker.css +6 -1
  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 +5 -0
  96. package/css/toggle.css +5 -0
  97. package/css/toolbar.css +5 -0
  98. package/css/tooltip.css +19 -6
  99. package/css/tour.css +29 -9
  100. package/css/transfer.css +5 -0
  101. package/css/tree-select.css +19 -0
  102. package/css/tree.css +5 -0
  103. package/css/typography.css +5 -0
  104. package/css/virtualizer.css +5 -0
  105. package/css/watermark.css +5 -0
  106. package/index.css +0 -1
  107. package/index.unlayered.css +804 -153
  108. package/package.json +2 -3
  109. package/css/motion.css +0 -58
@@ -16,6 +16,11 @@
16
16
  /* 其余按层归属排列。 */
17
17
 
18
18
  /* styles/affix.css */
19
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
20
+ [data-scope='affix'] {
21
+ --xh-affix-skin: 1;
22
+ }
23
+
19
24
  /* 占位盒就是 content 在常规流里占的那块地方。
20
25
  这里不声明 display,也不写高度:吸住时冻结的高度由连接层量好写进内联样式(它量得到,样式表量不到),
21
26
  没吸住时高度就该跟着内容走。不给 display,UA 的 [hidden]{display:none} 也仍然压得住 */
@@ -43,6 +48,11 @@
43
48
  }
44
49
 
45
50
  /* styles/avatar-group.css */
51
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
52
+ [data-scope='avatar-group'] {
53
+ --xh-avatar-group-skin: 1;
54
+ }
55
+
46
56
  /* 一排叠放的头像:后一枚压在前一枚上。
47
57
  组内共用的直径与字号在容器上写一次,沿继承流给每一枚;自己写了档位的那一枚仍按自己的档走 */
48
58
  [data-scope='avatar-group'][data-part='root'] {
@@ -125,6 +135,11 @@
125
135
  }
126
136
 
127
137
  /* styles/back-top.css */
138
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
139
+ [data-scope='back-top'] {
140
+ --xh-back-top-skin: 1;
141
+ }
142
+
128
143
  /* 定位壳:钉在视口的尾下角,用逻辑属性,RTL 下自动换到另一侧。
129
144
  不声明 display —— 收起态由连接层写 hidden,UA 的 [hidden]{display:none} 得压得住 */
130
145
  [data-scope='back-top'][data-part='root'] {
@@ -186,6 +201,11 @@
186
201
  }
187
202
 
188
203
  /* styles/button-group.css */
204
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
205
+ [data-scope='button-group'] {
206
+ --xh-button-group-skin: 1;
207
+ }
208
+
189
209
  /* 一组按钮连成一条:段与段之间不留缝,靠共边接上,所以不设 gap。
190
210
  排布只能读 data-orientation——role=group 不收 aria-orientation,连接层根本不输出它。
191
211
  圆角槽位在容器上先收成 0,组内每段都取得到,两端的圆角再逐段补回来 */
@@ -317,6 +337,11 @@
317
337
  }
318
338
 
319
339
  /* styles/countdown.css */
340
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
341
+ [data-scope='countdown'] {
342
+ --xh-countdown-skin: 1;
343
+ }
344
+
320
345
  [data-scope='countdown'][data-part='root'] {
321
346
  display: inline-block;
322
347
  color: var(--xh-countdown-fg, var(--xh-fg-default));
@@ -338,6 +363,11 @@
338
363
  }
339
364
 
340
365
  /* styles/descriptions.css */
366
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
367
+ [data-scope='descriptions'] {
368
+ --xh-descriptions-skin: 1;
369
+ }
370
+
341
371
  [data-scope='descriptions'][data-part='root'] {
342
372
  /* 一个尺寸档只换这几个私有槽,每一格与格内两段都从根上继承它们,
343
373
  换档不必给每个部件各写一条选择器 */
@@ -538,6 +568,11 @@
538
568
  }
539
569
 
540
570
  /* styles/dynamic-input.css */
571
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
572
+ [data-scope='dynamic-input'] {
573
+ --xh-dynamic-input-skin: 1;
574
+ }
575
+
541
576
  /* 一行一条,纵向堆叠;新增把手跟在最后一行下面 */
542
577
  [data-scope='dynamic-input'][data-part='root'] {
543
578
  display: flex;
@@ -695,6 +730,11 @@
695
730
  }
696
731
 
697
732
  /* styles/ellipsis.css */
733
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
734
+ [data-scope='ellipsis'] {
735
+ --xh-ellipsis-skin: 1;
736
+ }
737
+
698
738
  /* 单行:一行装不下就收成省略号。
699
739
  行数由连接层写进这个盒子的内联 style,样式表这一行只是它缺席时的落点 */
700
740
  [data-scope='ellipsis'][data-part='root'] {
@@ -736,6 +776,11 @@
736
776
  }
737
777
 
738
778
  /* styles/flex.css */
779
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
780
+ [data-scope='flex'] {
781
+ --xh-flex-skin: 1;
782
+ }
783
+
739
784
  [data-scope='flex'][data-part='root'] {
740
785
  display: flex;
741
786
  flex-wrap: nowrap;
@@ -831,6 +876,11 @@
831
876
  }
832
877
 
833
878
  /* styles/float-button.css */
879
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
880
+ [data-scope='float-button'] {
881
+ --xh-float-button-skin: 1;
882
+ }
883
+
834
884
  /* 定位壳:钉在视口一角。贴边距离由连接层写进这个盒子的内联 style,
835
885
  样式表这一行只是它缺席时的落点;贴的是哪两条边看 data-placement。
836
886
  另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
@@ -952,6 +1002,11 @@
952
1002
  }
953
1003
 
954
1004
  /* styles/gradient-text.css */
1005
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1006
+ [data-scope='gradient-text'] {
1007
+ --xh-gradient-text-skin: 1;
1008
+ }
1009
+
955
1010
  /* 渐变画在背景上,再用 background-clip 把背景裁进字形里;前景必须透明才透得出底下的渐变。
956
1011
  两条 background-clip 都写:WebKit 只认带前缀那条。
957
1012
  -webkit-text-fill-color 在 WebKit 里决定字形填充色并盖过 color,也要一并透明。 */
@@ -1014,6 +1069,11 @@
1014
1069
  }
1015
1070
 
1016
1071
  /* styles/grid.css */
1072
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1073
+ [data-scope='grid'] {
1074
+ --xh-grid-skin: 1;
1075
+ }
1076
+
1017
1077
  [data-scope='grid'][data-part='root'] {
1018
1078
  display: grid;
1019
1079
  /* 各列等宽;下限写 0 而不是 auto,一段长文本才不会把自己那列撑宽 */
@@ -1442,6 +1502,11 @@
1442
1502
  }
1443
1503
 
1444
1504
  /* styles/highlight.css */
1505
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1506
+ [data-scope='highlight'] {
1507
+ --xh-highlight-skin: 1;
1508
+ }
1509
+
1445
1510
  /* 文本按原样显示:命中位置是按原串逐字符算的,折叠掉连续空格与换行会让看到的
1446
1511
  与算出来的对不上。pre-wrap 保留空白但仍在容器边界换行 */
1447
1512
  [data-scope='highlight'][data-part='root'] {
@@ -1463,6 +1528,11 @@
1463
1528
  }
1464
1529
 
1465
1530
  /* styles/icon-wrapper.css */
1531
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1532
+ [data-scope='icon-wrapper'] {
1533
+ --xh-icon-wrapper-skin: 1;
1534
+ }
1535
+
1466
1536
  /* 定直径的图标底座:图元在正中,底色、描边与形状由三轴决定。
1467
1537
  直径与图元直径分两个槽位,底座换档时里面的图元跟着一起换 */
1468
1538
  [data-scope='icon-wrapper'][data-part='root'] {
@@ -1527,6 +1597,11 @@
1527
1597
  }
1528
1598
 
1529
1599
  /* styles/infinite-scroll.css */
1600
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1601
+ [data-scope='infinite-scroll'] {
1602
+ --xh-infinite-scroll-skin: 1;
1603
+ }
1604
+
1530
1605
  /*
1531
1606
  * 列表外壳这一层刻意不给盒模型:滚的是页面还是作者自己的 overflow 容器、列表长什么样,
1532
1607
  * 都归作者的布局管,组件只往它身上挂 data-state / data-loading / data-disabled 供作者取用。
@@ -1549,6 +1624,11 @@
1549
1624
  }
1550
1625
 
1551
1626
  /* styles/layout.css */
1627
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1628
+ [data-scope='layout'] {
1629
+ --xh-layout-skin: 1;
1630
+ }
1631
+
1552
1632
  /* 页面骨架排成三行两列:头与脚各横贯一整行,侧栏与内容并排占中间那一行。
1553
1633
  缺哪一段,对应的行/列就没有条目,宽高自动收成 0,不必为"少写一段"另立规则。
1554
1634
 
@@ -1718,6 +1798,11 @@
1718
1798
  }
1719
1799
 
1720
1800
  /* styles/list.css */
1801
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1802
+ [data-scope='list'] {
1803
+ --xh-list-skin: 1;
1804
+ }
1805
+
1721
1806
  [data-scope='list'][data-part='root'] {
1722
1807
  /* 一个尺寸档只换这几个私有槽,条目与两行文字都从根上继承它们,
1723
1808
  换档不必给每个部件各写一条选择器 */
@@ -1835,6 +1920,11 @@
1835
1920
  }
1836
1921
 
1837
1922
  /* styles/log.css */
1923
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1924
+ [data-scope='log'] {
1925
+ --xh-log-skin: 1;
1926
+ }
1927
+
1838
1928
  /* 行高是本组件的定尺基准:视口按行数定高、每行排版,都从这一个槽位来。
1839
1929
  它的兜底值须与连接层内联高度里用的那份逐字一致,否则 rows 算出来的高度对不上行。 */
1840
1930
  [data-scope='log'][data-part='root'] {
@@ -1925,6 +2015,11 @@
1925
2015
  }
1926
2016
  }
1927
2017
 
2018
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2019
+ [data-scope='marquee'] {
2020
+ --xh-marquee-skin: 1;
2021
+ }
2022
+
1928
2023
  /*
1929
2024
  * 窗口:只露出轨道的一段。
1930
2025
  *
@@ -2081,6 +2176,23 @@
2081
2176
  }
2082
2177
 
2083
2178
  /* styles/mention.css */
2179
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
2180
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
2181
+ @keyframes xh-fade-in {
2182
+ from {
2183
+ opacity: 0;
2184
+ }
2185
+
2186
+ to {
2187
+ opacity: 1;
2188
+ }
2189
+ }
2190
+
2191
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2192
+ [data-scope='mention'] {
2193
+ --xh-mention-skin: 1;
2194
+ }
2195
+
2084
2196
  [data-scope='mention'][data-part='root'] {
2085
2197
  /* 尺寸档只换这四个私有槽,输入框与候选都从 root 继承它们,换档不必给每个部件各写一条选择器。
2086
2198
  浮层在 positioner 里、也是 root 的后代,一并继承 */
@@ -2295,6 +2407,11 @@
2295
2407
  }
2296
2408
 
2297
2409
  /* styles/number-animation.css */
2410
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2411
+ [data-scope='number-animation'] {
2412
+ --xh-number-animation-skin: 1;
2413
+ }
2414
+
2298
2415
  [data-scope='number-animation'][data-part='root'] {
2299
2416
  /* 不写尺寸就跟着上下文的字号走:这个数常常摆在别人的标题、卡片标题或统计数值槽里,
2300
2417
  自带一个字号只会跟摆放它的地方打架。三个档位各自换掉这个私有槽 */
@@ -2327,6 +2444,11 @@
2327
2444
  }
2328
2445
 
2329
2446
  /* styles/page-header.css */
2447
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2448
+ [data-scope='page-header'] {
2449
+ --xh-page-header-skin: 1;
2450
+ }
2451
+
2330
2452
  [data-scope='page-header'][data-part='root'] {
2331
2453
  /* 尺寸档只换这三个私有槽,各段从根上继承它们,换档不必给每个部件各写一条选择器 */
2332
2454
  --xh-_page-header-py: var(--xh-space-4);
@@ -2412,6 +2534,30 @@
2412
2534
  }
2413
2535
 
2414
2536
  /* styles/popconfirm.css */
2537
+ /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
2538
+ @keyframes xh-popconfirm-rotate {
2539
+ to {
2540
+ transform: rotate(1turn);
2541
+ }
2542
+ }
2543
+
2544
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
2545
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
2546
+ @keyframes xh-fade-in {
2547
+ from {
2548
+ opacity: 0;
2549
+ }
2550
+
2551
+ to {
2552
+ opacity: 1;
2553
+ }
2554
+ }
2555
+
2556
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2557
+ [data-scope='popconfirm'] {
2558
+ --xh-popconfirm-skin: 1;
2559
+ }
2560
+
2415
2561
  /* 根只框住触发器:浮层树靠 positioner 的固定定位飞出去,不占根的盒子 */
2416
2562
  [data-scope='popconfirm'][data-part='root'] {
2417
2563
  display: inline-block;
@@ -2533,13 +2679,6 @@
2533
2679
  color: var(--xh-popconfirm-confirm-fg, var(--xh-_tone-on, var(--xh-fg-on-brand)));
2534
2680
  }
2535
2681
 
2536
- /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
2537
- @keyframes xh-popconfirm-rotate {
2538
- to {
2539
- transform: rotate(1turn);
2540
- }
2541
- }
2542
-
2543
2682
  /* 异步确认挂起:按钮转圈、指针挂起;不是禁用,焦点与对比度都保持 */
2544
2683
  [data-scope='popconfirm'][data-part='confirm-trigger'][data-loading] {
2545
2684
  cursor: wait;
@@ -2585,6 +2724,23 @@
2585
2724
  }
2586
2725
 
2587
2726
  /* styles/popselect.css */
2727
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
2728
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
2729
+ @keyframes xh-fade-in {
2730
+ from {
2731
+ opacity: 0;
2732
+ }
2733
+
2734
+ to {
2735
+ opacity: 1;
2736
+ }
2737
+ }
2738
+
2739
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2740
+ [data-scope='popselect'] {
2741
+ --xh-popselect-skin: 1;
2742
+ }
2743
+
2588
2744
  [data-scope='popselect'][data-part='root'] {
2589
2745
  /* 尺寸档只换这四个私有槽,触发器与条目都从 root 继承它们,换档不必给每个部件各写一条选择器。
2590
2746
  浮层在 positioner 里、也是 root 的后代,一并继承 */
@@ -2807,6 +2963,11 @@
2807
2963
  }
2808
2964
 
2809
2965
  /* styles/qr-code.css */
2966
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2967
+ [data-scope='qr-code'] {
2968
+ --xh-qr-code-skin: 1;
2969
+ }
2970
+
2810
2971
  /*
2811
2972
  * 根 <svg>。深浅两色取固定档而不是语义前景/背景:语义色跟着主题走,深色主题下整张码
2812
2973
  * 会翻成浅底深模块的反相图,一部分读码器不认反相码。要换配色改下面这三个覆盖槽。
@@ -2879,65 +3040,12 @@
2879
3040
  letter-spacing: inherit;
2880
3041
  }
2881
3042
 
2882
- /* styles/motion.css */
2883
- @keyframes xh-spin {
2884
- to {
2885
- transform: rotate(360deg);
2886
- }
2887
- }
2888
-
2889
- @keyframes xh-fade-in {
2890
- from {
2891
- opacity: 0;
2892
- }
2893
-
2894
- to {
2895
- opacity: 1;
2896
- }
2897
- }
2898
-
2899
- @keyframes xh-fade-out {
2900
- from {
2901
- opacity: 1;
2902
- }
2903
-
2904
- to {
2905
- opacity: 0;
2906
- }
2907
- }
2908
-
2909
- @keyframes xh-dialog-in {
2910
- from {
2911
- opacity: 0;
2912
- transform: translateY(8px) scale(0.98);
2913
- }
2914
-
2915
- to {
2916
- opacity: 1;
2917
- transform: none;
2918
- }
2919
- }
2920
-
2921
- @keyframes xh-dialog-out {
2922
- from {
2923
- opacity: 1;
2924
- transform: none;
2925
- }
2926
-
2927
- to {
2928
- opacity: 0;
2929
- transform: translateY(8px) scale(0.98);
2930
- }
2931
- }
2932
-
2933
- @media (prefers-reduced-motion: reduce) {
2934
- [data-scope='dialog'] [data-part],
2935
- [data-scope='button'] [data-part] {
2936
- animation-duration: 0.01ms !important;
2937
- }
3043
+ /* styles/result.css */
3044
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3045
+ [data-scope='result'] {
3046
+ --xh-result-skin: 1;
2938
3047
  }
2939
3048
 
2940
- /* styles/result.css */
2941
3049
  [data-scope='result'][data-part='root'] {
2942
3050
  /* 三个尺寸档只换这几个私有槽,图标与标题都从 root 继承它们,
2943
3051
  换档不必给每个部件各写一条选择器 */
@@ -3042,6 +3150,11 @@
3042
3150
  }
3043
3151
 
3044
3152
  /* styles/statistic.css */
3153
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3154
+ [data-scope='statistic'] {
3155
+ --xh-statistic-skin: 1;
3156
+ }
3157
+
3045
3158
  /* 三个尺寸档只换这几个私有槽,各段从 root 继承它们,换档不必给每个部件各写一条选择器 */
3046
3159
  [data-scope='statistic'][data-part='root'] {
3047
3160
  --xh-_statistic-label-size: var(--xh-font-size-sm);
@@ -3109,6 +3222,11 @@
3109
3222
  }
3110
3223
 
3111
3224
  /* styles/time.css */
3225
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3226
+ [data-scope='time'] {
3227
+ --xh-time-skin: 1;
3228
+ }
3229
+
3112
3230
  [data-scope='time'][data-part='root'] {
3113
3231
  color: var(--xh-time-fg, var(--xh-fg-default));
3114
3232
  /* 等宽数字:秒数跳动时后面的字符不会左右挪 */
@@ -3129,6 +3247,11 @@
3129
3247
  }
3130
3248
 
3131
3249
  /* styles/timeline.css */
3250
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3251
+ [data-scope='timeline'] {
3252
+ --xh-timeline-skin: 1;
3253
+ }
3254
+
3132
3255
  [data-scope='timeline'][data-part='root'] {
3133
3256
  /* 尺寸档只换这几个私有槽,条目、圆点与文字都从 root 继承它们,
3134
3257
  换档不必给每个部件各写一条选择器 */
@@ -3413,6 +3536,11 @@
3413
3536
  }
3414
3537
 
3415
3538
  /* styles/typography.css */
3539
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3540
+ [data-scope='typography'] {
3541
+ --xh-typography-skin: 1;
3542
+ }
3543
+
3416
3544
  [data-scope='typography'][data-part='root'] {
3417
3545
  /* 尺寸档只换这几个私有槽,各段从根上继承它们,换档不必给每个部件各写一条选择器 */
3418
3546
  --xh-_typography-body-size: var(--xh-text-body-size);
@@ -3724,6 +3852,11 @@
3724
3852
  }
3725
3853
 
3726
3854
  /* styles/alert.css */
3855
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3856
+ [data-scope='alert'] {
3857
+ --xh-alert-skin: 1;
3858
+ }
3859
+
3727
3860
  [data-scope='alert'][data-part='root'] {
3728
3861
  /* 强调色随语气走,底色/描边/图标色都由它推导出来,换语气不必逐条属性各写一遍。
3729
3862
  没写 data-tone 时 --xh-_tone 没被声明,退回原来的 info 蓝 */
@@ -3832,6 +3965,11 @@
3832
3965
  }
3833
3966
 
3834
3967
  /* styles/empty-state.css */
3968
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3969
+ [data-scope='empty-state'] {
3970
+ --xh-empty-state-skin: 1;
3971
+ }
3972
+
3835
3973
  [data-scope='empty-state'][data-part='root'] {
3836
3974
  /* 三个尺寸档只换这几个私有槽,图标与标题都从 root 继承它们,
3837
3975
  换档不必给每个部件各写一条选择器 */
@@ -3922,6 +4060,11 @@
3922
4060
  }
3923
4061
  }
3924
4062
 
4063
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4064
+ [data-scope='skeleton'] {
4065
+ --xh-skeleton-skin: 1;
4066
+ }
4067
+
3925
4068
  /* 骨架容器:竖着码放各根骨架条 */
3926
4069
  [data-scope='skeleton'][data-part='root'] {
3927
4070
  display: flex;
@@ -3994,6 +4137,11 @@
3994
4137
  }
3995
4138
  }
3996
4139
 
4140
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4141
+ [data-scope='spinner'] {
4142
+ --xh-spinner-skin: 1;
4143
+ }
4144
+
3997
4145
  /* 圆环画在伪元素上,root 自身不转:转的只是图形,同一行里的文案要留在原地读得动 */
3998
4146
  [data-scope='spinner'][data-part='root'] {
3999
4147
  display: inline-flex;
@@ -4060,6 +4208,11 @@
4060
4208
  }
4061
4209
 
4062
4210
  /* styles/accordion.css */
4211
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4212
+ [data-scope='accordion'] {
4213
+ --xh-accordion-skin: 1;
4214
+ }
4215
+
4063
4216
  [data-scope='accordion'][data-part='root'] {
4064
4217
  /* 尺寸档只换这四个私有槽,标题栏从 root 继承它们,换档不必给每个部件各写一条选择器 */
4065
4218
  --xh-_accordion-trigger-h: var(--xh-control-h-md);
@@ -4168,6 +4321,11 @@
4168
4321
  }
4169
4322
 
4170
4323
  /* styles/anchor.css */
4324
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4325
+ [data-scope='anchor'] {
4326
+ --xh-anchor-skin: 1;
4327
+ }
4328
+
4171
4329
  /* 根节点是 nav 地标,不参与排版:整条目录的布局全在 list 上,
4172
4330
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
4173
4331
  [data-scope='anchor'][data-part='root'] {
@@ -4305,6 +4463,11 @@
4305
4463
  }
4306
4464
 
4307
4465
  /* styles/avatar.css */
4466
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4467
+ [data-scope='avatar'] {
4468
+ --xh-avatar-skin: 1;
4469
+ }
4470
+
4308
4471
  [data-scope='avatar'][data-part='root'] {
4309
4472
  position: relative;
4310
4473
  display: inline-flex;
@@ -4360,6 +4523,11 @@
4360
4523
  }
4361
4524
 
4362
4525
  /* styles/badge.css */
4526
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4527
+ [data-scope='badge'] {
4528
+ --xh-badge-skin: 1;
4529
+ }
4530
+
4363
4531
  [data-scope='badge'][data-part='root'] {
4364
4532
  display: inline-flex;
4365
4533
  align-items: center;
@@ -4410,6 +4578,11 @@
4410
4578
  }
4411
4579
 
4412
4580
  /* styles/breadcrumb.css */
4581
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4582
+ [data-scope='breadcrumb'] {
4583
+ --xh-breadcrumb-skin: 1;
4584
+ }
4585
+
4413
4586
  /* 根节点是 nav 地标,不参与排版:整条路径的行为全在 list 上,
4414
4587
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
4415
4588
  [data-scope='breadcrumb'][data-part='root'] {
@@ -4537,6 +4710,19 @@
4537
4710
  }
4538
4711
 
4539
4712
  /* styles/button.css */
4713
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
4714
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4715
+ @keyframes xh-spin {
4716
+ to {
4717
+ transform: rotate(360deg);
4718
+ }
4719
+ }
4720
+
4721
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4722
+ [data-scope='button'] {
4723
+ --xh-button-skin: 1;
4724
+ }
4725
+
4540
4726
  [data-scope='button'][data-part='root'] {
4541
4727
  /* 私有槽位:组件令牌 → 语义令牌两级回退,变体只改这几个槽位 */
4542
4728
  --xh-_bg: var(--xh-button-bg, var(--xh-bg-subtle));
@@ -4635,6 +4821,11 @@
4635
4821
  }
4636
4822
 
4637
4823
  /* styles/calendar.css */
4824
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4825
+ [data-scope='calendar'] {
4826
+ --xh-calendar-skin: 1;
4827
+ }
4828
+
4638
4829
  [data-scope='calendar'][data-part='root'] {
4639
4830
  display: flex;
4640
4831
  flex-direction: column;
@@ -4854,6 +5045,11 @@
4854
5045
  }
4855
5046
 
4856
5047
  /* styles/card.css */
5048
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5049
+ [data-scope='card'] {
5050
+ --xh-card-skin: 1;
5051
+ }
5052
+
4857
5053
  [data-scope='card'][data-part='root'] {
4858
5054
  display: flex;
4859
5055
  flex-direction: column;
@@ -4970,6 +5166,11 @@
4970
5166
  }
4971
5167
 
4972
5168
  /* styles/carousel.css */
5169
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5170
+ [data-scope='carousel'] {
5171
+ --xh-carousel-skin: 1;
5172
+ }
5173
+
4973
5174
  /* 根节点是 region 地标:把上一张 / 视口 / 下一张排成一行,指示点另起一行。
4974
5175
  两端按钮浮在视口上还是排在两侧由作者定,这里只给最朴素的一版排布 */
4975
5176
  [data-scope='carousel'][data-part='root'] {
@@ -5163,6 +5364,11 @@
5163
5364
  }
5164
5365
 
5165
5366
  /* styles/cascader.css */
5367
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5368
+ [data-scope='cascader'] {
5369
+ --xh-cascader-skin: 1;
5370
+ }
5371
+
5166
5372
  /* 解剖里没有把「触发器 + 清空按钮」裹在一起的 control 部件,一行是靠 flex-wrap 分出来的:
5167
5373
  标签占满整行把后面的挤到下一行,触发器与清空按钮就并排落在同一行上。
5168
5374
  这样作者少写标签、少写清空按钮,剩下的部件也不会塌 */
@@ -5441,13 +5647,13 @@
5441
5647
 
5442
5648
  [data-scope='cascader'][data-part='content'][data-state='open'] {
5443
5649
  /* 入场横移沿书写方向起始缘:位移量经私有槽供给关键帧,rtl 只翻符号 */
5444
- --xh-_cascader-slide: -0.25rem;
5650
+ --xh-_cascader-slide: calc(-1 * var(--xh-motion-distance-sm));
5445
5651
 
5446
5652
  animation: xh-cascader-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
5447
5653
  }
5448
5654
 
5449
5655
  [dir='rtl'] [data-scope='cascader'][data-part='content'][data-state='open'] {
5450
- --xh-_cascader-slide: 0.25rem;
5656
+ --xh-_cascader-slide: var(--xh-motion-distance-sm);
5451
5657
  }
5452
5658
 
5453
5659
  /* 一列:宽度由内容撑出、设下限防塌,高度定死——切换展开路径时浮层不上下跳动,
@@ -5723,7 +5929,7 @@
5723
5929
  @keyframes xh-cascader-in {
5724
5930
  from {
5725
5931
  opacity: 0;
5726
- translate: var(--xh-_cascader-slide, -0.25rem) 0;
5932
+ translate: var(--xh-_cascader-slide, calc(-1 * var(--xh-motion-distance-sm))) 0;
5727
5933
  }
5728
5934
 
5729
5935
  to {
@@ -5733,6 +5939,11 @@
5733
5939
  }
5734
5940
 
5735
5941
  /* styles/checkbox.css */
5942
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5943
+ [data-scope='checkbox'] {
5944
+ --xh-checkbox-skin: 1;
5945
+ }
5946
+
5736
5947
  [data-scope='checkbox'][data-part='root'] {
5737
5948
  /* 尺寸档只换方框边长这一个私有槽,勾的字号按边长的比例跟着走;
5738
5949
  指示器从 root 继承这两个槽,换档不必给每个部件各写一条选择器 */
@@ -5824,6 +6035,11 @@
5824
6035
  }
5825
6036
 
5826
6037
  /* styles/checkbox-group.css */
6038
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6039
+ [data-scope='checkbox-group'] {
6040
+ --xh-checkbox-group-skin: 1;
6041
+ }
6042
+
5827
6043
  /* 组容器:label、trigger、条目都是它的直接子节点,排布方式只能读 data-orientation——
5828
6044
  连接层明说了 role=group 不接受 aria-orientation,那个属性它根本没输出 */
5829
6045
  [data-scope='checkbox-group'][data-part='root'] {
@@ -6009,6 +6225,11 @@
6009
6225
  }
6010
6226
 
6011
6227
  /* styles/clipboard.css */
6228
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6229
+ [data-scope='clipboard'] {
6230
+ --xh-clipboard-skin: 1;
6231
+ }
6232
+
6012
6233
  /* 与文本框同一套堆叠:标签一行、输入行一行 */
6013
6234
  [data-scope='clipboard'][data-part='root'] {
6014
6235
  display: inline-flex;
@@ -6142,6 +6363,11 @@
6142
6363
  }
6143
6364
 
6144
6365
  /* styles/code-block.css */
6366
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6367
+ [data-scope='code-block'] {
6368
+ --xh-code-block-skin: 1;
6369
+ }
6370
+
6145
6371
  /* overflow: hidden 让内部 <pre> 的滚动内容沿圆角收边;不设 display,排布由作者决定 */
6146
6372
  [data-scope='code-block'][data-part='root'] {
6147
6373
  overflow: hidden;
@@ -6223,6 +6449,11 @@
6223
6449
  }
6224
6450
 
6225
6451
  /* styles/collapsible.css */
6452
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6453
+ [data-scope='collapsible'] {
6454
+ --xh-collapsible-skin: 1;
6455
+ }
6456
+
6226
6457
  /* 根容器自己不排版,这条只声明尺寸档的私有槽:触发按钮从 root 继承它们,
6227
6458
  换档不必给部件各写一条选择器 */
6228
6459
  [data-scope='collapsible'][data-part='root'] {
@@ -6289,7 +6520,7 @@
6289
6520
  @keyframes xh-color-picker-fade-in {
6290
6521
  from {
6291
6522
  opacity: 0;
6292
- scale: 0.98;
6523
+ scale: var(--xh-motion-scale-enter);
6293
6524
  }
6294
6525
 
6295
6526
  to {
@@ -6298,6 +6529,11 @@
6298
6529
  }
6299
6530
  }
6300
6531
 
6532
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6533
+ [data-scope='color-picker'] {
6534
+ --xh-color-picker-skin: 1;
6535
+ }
6536
+
6301
6537
  /* 定位分工:取色区拇指的两条轴(inset-inline-start / inset-block-start)、
6302
6538
  通道拇指的主轴(inset-inline-start)、浮层坐标、取色区底色、透明度轨道的渐变,
6303
6539
  全都由连接层每帧写进内联样式。这份皮肤一个都不碰:内联优先级高于样式表,
@@ -6724,6 +6960,23 @@
6724
6960
  }
6725
6961
 
6726
6962
  /* styles/combobox.css */
6963
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
6964
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
6965
+ @keyframes xh-fade-in {
6966
+ from {
6967
+ opacity: 0;
6968
+ }
6969
+
6970
+ to {
6971
+ opacity: 1;
6972
+ }
6973
+ }
6974
+
6975
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6976
+ [data-scope='combobox'] {
6977
+ --xh-combobox-skin: 1;
6978
+ }
6979
+
6727
6980
  [data-scope='combobox'][data-part='root'] {
6728
6981
  /* 尺寸档只换这五个私有槽,输入行、标题与候选都从 root 继承它们,
6729
6982
  换档不必给每个部件各写一条选择器。浮层在 positioner 里、也是 root 的后代,一并继承 */
@@ -7160,6 +7413,11 @@
7160
7413
  }
7161
7414
 
7162
7415
  /* styles/composer.css */
7416
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7417
+ [data-scope='composer'] {
7418
+ --xh-composer-skin: 1;
7419
+ }
7420
+
7163
7421
  /* 边框画在 root 上,内部 textarea 无边框;align-items: flex-end 让按钮随输入框长高贴着底边 */
7164
7422
  [data-scope='composer'][data-part='root'] {
7165
7423
  /* 输入与发送按钮共用的控件高度 */
@@ -7287,6 +7545,11 @@
7287
7545
  }
7288
7546
 
7289
7547
  /* styles/context-menu.css */
7548
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7549
+ [data-scope='context-menu'] {
7550
+ --xh-context-menu-skin: 1;
7551
+ }
7552
+
7290
7553
  /* 根只是把触发区与浮层圈在一起做作用域,不该在作者布局里多插一层盒子 */
7291
7554
  [data-scope='context-menu'][data-part='root'] {
7292
7555
  /* 尺寸档只换这四个私有槽,条目与分组标题都从 root 继承它们,
@@ -7390,13 +7653,6 @@
7390
7653
  animation: xh-context-menu-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
7391
7654
  }
7392
7655
 
7393
- /* 关掉动效的用户不该被涨开动画晃一下;这里只管本组件,公共那份不动 */
7394
- @media (prefers-reduced-motion: reduce) {
7395
- [data-scope='context-menu'][data-part='content'][data-state='open'] {
7396
- animation-duration: 0.01ms;
7397
- }
7398
- }
7399
-
7400
7656
  [data-scope='context-menu'][data-part='group'] {
7401
7657
  display: flex;
7402
7658
  flex-direction: column;
@@ -7568,7 +7824,7 @@
7568
7824
  @keyframes xh-context-menu-in {
7569
7825
  from {
7570
7826
  opacity: 0;
7571
- scale: 0.96;
7827
+ scale: var(--xh-motion-scale-enter);
7572
7828
  }
7573
7829
 
7574
7830
  to {
@@ -7578,6 +7834,11 @@
7578
7834
  }
7579
7835
 
7580
7836
  /* styles/date-field.css */
7837
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7838
+ [data-scope='date-field'] {
7839
+ --xh-date-field-skin: 1;
7840
+ }
7841
+
7581
7842
  /* 与文本框、数字框同一套堆叠:标签一行、分段框一行 */
7582
7843
  [data-scope='date-field'][data-part='root'] {
7583
7844
  /* 尺寸档只换这四个私有槽,标题与分段框都从 root 继承它们,换档不必给每个部件各写一条选择器 */
@@ -7778,6 +8039,11 @@
7778
8039
  }
7779
8040
 
7780
8041
  /* styles/date-picker.css */
8042
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
8043
+ [data-scope='date-picker'] {
8044
+ --xh-date-picker-skin: 1;
8045
+ }
8046
+
7781
8047
  /* 与文本框、分段日期同一套堆叠:标签一行、输入行一行 */
7782
8048
  [data-scope='date-picker'][data-part='root'] {
7783
8049
  display: inline-flex;
@@ -8061,7 +8327,7 @@
8061
8327
  @keyframes xh-date-picker-in {
8062
8328
  from {
8063
8329
  opacity: 0;
8064
- translate: 0 -4px;
8330
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
8065
8331
  }
8066
8332
 
8067
8333
  to {
@@ -8071,6 +8337,63 @@
8071
8337
  }
8072
8338
 
8073
8339
  /* styles/dialog.css */
8340
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
8341
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
8342
+ @keyframes xh-fade-in {
8343
+ from {
8344
+ opacity: 0;
8345
+ }
8346
+
8347
+ to {
8348
+ opacity: 1;
8349
+ }
8350
+ }
8351
+
8352
+ @keyframes xh-fade-out {
8353
+ from {
8354
+ opacity: 1;
8355
+ }
8356
+
8357
+ to {
8358
+ opacity: 0;
8359
+ }
8360
+ }
8361
+
8362
+ /* 幅度走令牌,减弱动效时由令牌层归零;位移与缩放用独立属性而非 transform 简写,
8363
+ 两者互不覆盖,手势期间写 translate 也不会把 scale 抹掉 */
8364
+ @keyframes xh-dialog-in {
8365
+ from {
8366
+ opacity: 0;
8367
+ translate: 0 var(--xh-motion-distance-md);
8368
+ scale: var(--xh-motion-scale-enter);
8369
+ }
8370
+
8371
+ to {
8372
+ opacity: 1;
8373
+ translate: 0 0;
8374
+ scale: 1;
8375
+ }
8376
+ }
8377
+
8378
+ @keyframes xh-dialog-out {
8379
+ from {
8380
+ opacity: 1;
8381
+ translate: 0 0;
8382
+ scale: 1;
8383
+ }
8384
+
8385
+ to {
8386
+ opacity: 0;
8387
+ translate: 0 var(--xh-motion-distance-md);
8388
+ scale: var(--xh-motion-scale-enter);
8389
+ }
8390
+ }
8391
+
8392
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
8393
+ [data-scope='dialog'] {
8394
+ --xh-dialog-skin: 1;
8395
+ }
8396
+
8074
8397
  [data-scope='dialog'][data-part='backdrop'] {
8075
8398
  position: fixed;
8076
8399
  inset: 0;
@@ -8082,8 +8405,9 @@
8082
8405
  animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
8083
8406
  }
8084
8407
 
8408
+ /* 退场补 forwards:动画播完到宿主真正卸载之间还有一帧,不定住终态遮罩会闪回全黑 */
8085
8409
  [data-scope='dialog'][data-part='backdrop'][data-state='closed'] {
8086
- animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
8410
+ animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
8087
8411
  }
8088
8412
 
8089
8413
  [data-scope='dialog'][data-part='positioner'] {
@@ -8120,13 +8444,14 @@
8120
8444
  box-shadow: var(--xh-dialog-shadow, var(--xh-elevation-3));
8121
8445
  }
8122
8446
 
8123
- /* 收起态:connect 会给 content 打 hidden,但上面那条 display 会盖掉 UA 的
8124
- [hidden]{display:none}。meta 里 positioner 并非必需部件,按最小合规结构
8125
- (只有 trigger + content)写时,没有这一条收起的对话框就一直摊在页面上。 */
8126
- [data-scope='dialog'][data-part='content'][hidden] {
8127
- display: none;
8128
- }
8129
-
8447
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 drawer 一致:
8448
+ 收起态连接层会给 content 打 hidden,而上面那条 display: flex 正是要盖掉 UA 的
8449
+ [hidden]{display:none}——退场动画得先能播。presence 读的是 content 的 animationName,
8450
+ 读到才申领租约、等 animationend 才卸载;一旦 display: none,元素不生成盒子、
8451
+ 动画根本不启动,探测器直接放弃租约,退场动画一帧都播不出来。
8452
+ 真正的收起由适配器兜住:Vue 卸载整棵,WC 写内联 style.display。
8453
+ 其余声明了 display 的角色节点仍补 [hidden],那几处没有退场动画。 */
8454
+
8130
8455
  /* —— 尺寸 —— */
8131
8456
  /* 只有最大宽度分档;中间档不写规则,缺省即中档。
8132
8457
  宽度上限之外的一切(内边距、字号、圆角)都不随档位动:弹层的语气归里面的内容表达。 */
@@ -8142,13 +8467,12 @@
8142
8467
  outline: none;
8143
8468
  }
8144
8469
 
8145
- /* 入场用 @starting-style 只驱动动画名切换;退场由 presence 保留 DOM 后播放 */
8146
8470
  [data-scope='dialog'][data-part='content'][data-state='open'] {
8147
8471
  animation: xh-dialog-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
8148
8472
  }
8149
8473
 
8150
8474
  [data-scope='dialog'][data-part='content'][data-state='closed'] {
8151
- animation: xh-dialog-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
8475
+ animation: xh-dialog-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
8152
8476
  }
8153
8477
 
8154
8478
  [data-scope='dialog'][data-part='title'] {
@@ -8198,6 +8522,28 @@
8198
8522
  }
8199
8523
 
8200
8524
  /* styles/drawer.css */
8525
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
8526
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
8527
+ @keyframes xh-fade-in {
8528
+ from {
8529
+ opacity: 0;
8530
+ }
8531
+
8532
+ to {
8533
+ opacity: 1;
8534
+ }
8535
+ }
8536
+
8537
+ @keyframes xh-fade-out {
8538
+ from {
8539
+ opacity: 1;
8540
+ }
8541
+
8542
+ to {
8543
+ opacity: 0;
8544
+ }
8545
+ }
8546
+
8201
8547
  /* 四条边各一对滑入/滑出。位移量用 translate 的百分比,参照的是面板自己的边框盒,
8202
8548
  所以不管 --xh-drawer-size 被改成多少,"正好推到视口外"这件事都成立。
8203
8549
 
@@ -8285,10 +8631,9 @@
8285
8631
  }
8286
8632
  }
8287
8633
 
8288
- @media (prefers-reduced-motion: reduce) {
8289
- [data-scope='drawer'][data-part] {
8290
- animation-duration: 0.01ms !important;
8291
- }
8634
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
8635
+ [data-scope='drawer'] {
8636
+ --xh-drawer-skin: 1;
8292
8637
  }
8293
8638
 
8294
8639
  /* root 留在页面原地,只是 data-side / data-state 的落点,不该凭空多出一层盒子把
@@ -8415,9 +8760,9 @@
8415
8760
  /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 dialog 一致。
8416
8761
  收起态连接层会给 content 打 hidden,而上面这条 display: flex 正是要盖掉
8417
8762
  UA 的 [hidden]{display:none}——退场动画得先能播:
8418
- Vue 侧 presence 读的是 content 的 animationName,读到就申领租约、等 animationend
8419
- 才卸载;一旦 display: none,动画根本不会启动,animationend 永不到达,
8420
- 租约挂死,面板就永久留在 DOM 里(每开合一次多一份)。
8763
+ presence 读的是 content 的 animationName,读到就申领租约、等 animationend 才卸载;
8764
+ 一旦 display: none,元素不生成盒子、动画根本不启动,退场探测器会直接放弃申领
8765
+ (否则就要等一个永不到来的 animationend),面板不播动画就地卸载。
8421
8766
  真正的收起两个适配器各自兜住了:Vue 卸载整棵,WC 写内联 style.display。
8422
8767
  其余声明了 display 的角色节点仍补了 [hidden],那几处没有退场动画,作者手写 hidden 要生效。 */
8423
8768
 
@@ -8568,6 +8913,11 @@
8568
8913
  }
8569
8914
 
8570
8915
  /* styles/editable.css */
8916
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
8917
+ [data-scope='editable'] {
8918
+ --xh-editable-skin: 1;
8919
+ }
8920
+
8571
8921
  /* 就地编辑是"一行文字里的一处可改内容":标题、显示区与按钮天然同行,
8572
8922
  所以根是一条横向的行,而不是文本框那种"标题一行、控件一行"的竖排。
8573
8923
  要竖排的作者把 flex-direction 覆盖掉即可,其余尺寸都长在各自的角色节点上 */
@@ -8817,6 +9167,11 @@
8817
9167
  }
8818
9168
 
8819
9169
  /* styles/field.css */
9170
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9171
+ [data-scope='field'] {
9172
+ --xh-field-skin: 1;
9173
+ }
9174
+
8820
9175
  [data-scope='field'][data-part='root'] {
8821
9176
  display: flex;
8822
9177
  flex-direction: column;
@@ -8913,6 +9268,11 @@
8913
9268
  }
8914
9269
 
8915
9270
  /* styles/file-upload.css */
9271
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9272
+ [data-scope='file-upload'] {
9273
+ --xh-file-upload-skin: 1;
9274
+ }
9275
+
8916
9276
  [data-scope='file-upload'][data-part='root'] {
8917
9277
  display: flex;
8918
9278
  flex-direction: column;
@@ -9211,6 +9571,11 @@
9211
9571
  }
9212
9572
 
9213
9573
  /* styles/form.css */
9574
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9575
+ [data-scope='form'] {
9576
+ --xh-form-skin: 1;
9577
+ }
9578
+
9214
9579
  /* 表单是一列字段:竖排、字段之间留一档间距。root 就是那个原生 <form> */
9215
9580
  [data-scope='form'][data-part='root'] {
9216
9581
  display: flex;
@@ -9396,7 +9761,7 @@
9396
9761
  @keyframes xh-form-summary-enter {
9397
9762
  from {
9398
9763
  opacity: 0;
9399
- translate: 0 calc(-1 * var(--xh-space-1));
9764
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
9400
9765
  }
9401
9766
 
9402
9767
  to {
@@ -9406,6 +9771,23 @@
9406
9771
  }
9407
9772
 
9408
9773
  /* styles/hover-card.css */
9774
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
9775
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
9776
+ @keyframes xh-fade-in {
9777
+ from {
9778
+ opacity: 0;
9779
+ }
9780
+
9781
+ to {
9782
+ opacity: 1;
9783
+ }
9784
+ }
9785
+
9786
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9787
+ [data-scope='hover-card'] {
9788
+ --xh-hover-card-skin: 1;
9789
+ }
9790
+
9409
9791
  /* 根节点只把 trigger 与浮层收在一处,不参与定位(坐标系仍由祖先的定位上下文决定) */
9410
9792
  [data-scope='hover-card'][data-part='root'] {
9411
9793
  display: inline-block;
@@ -9549,13 +9931,12 @@
9549
9931
  border-inline-start: 0;
9550
9932
  }
9551
9933
 
9552
- @media (prefers-reduced-motion: reduce) {
9553
- [data-scope='hover-card'][data-part='content'] {
9554
- animation-duration: 0.01ms !important;
9555
- }
9934
+ /* styles/icon.css */
9935
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9936
+ [data-scope='icon'] {
9937
+ --xh-icon-skin: 1;
9556
9938
  }
9557
9939
 
9558
- /* styles/icon.css */
9559
9940
  /*
9560
9941
  * 根 <svg>。直径、描边粗细、行内位置都由这里给,记录只带几何。
9561
9942
  * 不写 fill / stroke:记录里那两条呈现属性取 currentColor,改这里会把
@@ -9610,6 +9991,11 @@
9610
9991
  }
9611
9992
 
9612
9993
  /* styles/image.css */
9994
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9995
+ [data-scope='image'] {
9996
+ --xh-image-skin: 1;
9997
+ }
9998
+
9613
9999
  /* 尺寸交给三个变量而不是写死:这个组件既要能当封面图,也要能当头图与缩略图。
9614
10000
  给了 --xh-image-ratio 才有确定高度,回退内容与图片在同一个盒子里换人时不会跳。 */
9615
10001
  [data-scope='image'][data-part='root'] {
@@ -9655,6 +10041,33 @@
9655
10041
  }
9656
10042
 
9657
10043
  /* styles/image-viewer.css */
10044
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
10045
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
10046
+ @keyframes xh-fade-in {
10047
+ from {
10048
+ opacity: 0;
10049
+ }
10050
+
10051
+ to {
10052
+ opacity: 1;
10053
+ }
10054
+ }
10055
+
10056
+ @keyframes xh-fade-out {
10057
+ from {
10058
+ opacity: 1;
10059
+ }
10060
+
10061
+ to {
10062
+ opacity: 0;
10063
+ }
10064
+ }
10065
+
10066
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10067
+ [data-scope='image-viewer'] {
10068
+ --xh-image-viewer-skin: 1;
10069
+ }
10070
+
9658
10071
  [data-scope='image-viewer'][data-part='backdrop'] {
9659
10072
  position: fixed;
9660
10073
  inset: 0;
@@ -9668,7 +10081,7 @@
9668
10081
  }
9669
10082
 
9670
10083
  [data-scope='image-viewer'][data-part='backdrop'][data-state='closed'] {
9671
- animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
10084
+ animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
9672
10085
  }
9673
10086
 
9674
10087
  [data-scope='image-viewer'][data-part='positioner'] {
@@ -9697,11 +10110,7 @@
9697
10110
  }
9698
10111
 
9699
10112
  [data-scope='image-viewer'][data-part='content'][data-state='closed'] {
9700
- animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
9701
- }
9702
-
9703
- [data-scope='image-viewer'][data-part='content'][hidden] {
9704
- display: none;
10113
+ animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
9705
10114
  }
9706
10115
 
9707
10116
  [data-scope='image-viewer'][data-part='viewport'] {
@@ -9820,17 +10229,17 @@
9820
10229
  }
9821
10230
 
9822
10231
  @media (prefers-reduced-motion: reduce) {
9823
- [data-scope='image-viewer'][data-part='backdrop'],
9824
- [data-scope='image-viewer'][data-part='content'] {
9825
- animation-duration: 0.01ms;
9826
- }
9827
-
9828
10232
  [data-scope='image-viewer'][data-part='image'] {
9829
10233
  transition: none;
9830
10234
  }
9831
10235
  }
9832
10236
 
9833
10237
  /* styles/listbox.css */
10238
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10239
+ [data-scope='listbox'] {
10240
+ --xh-listbox-skin: 1;
10241
+ }
10242
+
9834
10243
  [data-scope='listbox'][data-part='root'] {
9835
10244
  display: flex;
9836
10245
  flex-direction: column;
@@ -10008,6 +10417,11 @@
10008
10417
  }
10009
10418
 
10010
10419
  /* styles/loading-bar.css */
10420
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10421
+ [data-scope='loading-bar'] {
10422
+ --xh-loading-bar-skin: 1;
10423
+ }
10424
+
10011
10425
  /*
10012
10426
  * 贴在视口顶边的一条细带。厚度那条轴(block-size)由连接层写进内联样式——
10013
10427
  * height 这个 prop 的缺省值在 connect 里收口,这里再声明一次只会被内联盖掉,
@@ -10074,6 +10488,23 @@
10074
10488
  }
10075
10489
 
10076
10490
  /* styles/menu.css */
10491
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
10492
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
10493
+ @keyframes xh-fade-in {
10494
+ from {
10495
+ opacity: 0;
10496
+ }
10497
+
10498
+ to {
10499
+ opacity: 1;
10500
+ }
10501
+ }
10502
+
10503
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10504
+ [data-scope='menu'] {
10505
+ --xh-menu-skin: 1;
10506
+ }
10507
+
10077
10508
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
10078
10509
  [data-scope='menu'][data-part='positioner'] {
10079
10510
  position: fixed;
@@ -10233,6 +10664,11 @@
10233
10664
  }
10234
10665
 
10235
10666
  /* styles/menubar.css */
10667
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10668
+ [data-scope='menubar'] {
10669
+ --xh-menubar-skin: 1;
10670
+ }
10671
+
10236
10672
  /* 一排 trigger。主轴跟着 data-orientation 走:菜单栏本身可以横排也可以竖排 */
10237
10673
  [data-scope='menubar'][data-part='root'] {
10238
10674
  /* 尺寸档只换这五个私有槽,trigger 与菜单里的条目都从 root 继承它们,
@@ -10389,13 +10825,6 @@
10389
10825
  animation: xh-menubar-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
10390
10826
  }
10391
10827
 
10392
- /* 关掉动效的用户不该被涨开动画晃一下;这里只管本组件,公共那份不动 */
10393
- @media (prefers-reduced-motion: reduce) {
10394
- [data-scope='menubar'][data-part='content'][data-state='open'] {
10395
- animation-duration: 0.01ms;
10396
- }
10397
- }
10398
-
10399
10828
  [data-scope='menubar'][data-part='group'] {
10400
10829
  display: flex;
10401
10830
  flex-direction: column;
@@ -10503,7 +10932,7 @@
10503
10932
  @keyframes xh-menubar-in {
10504
10933
  from {
10505
10934
  opacity: 0;
10506
- scale: 0.96;
10935
+ scale: var(--xh-motion-scale-enter);
10507
10936
  }
10508
10937
 
10509
10938
  to {
@@ -10517,7 +10946,7 @@
10517
10946
  @keyframes xh-navigation-menu-in {
10518
10947
  from {
10519
10948
  opacity: 0;
10520
- translate: 0 -4px;
10949
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
10521
10950
  }
10522
10951
 
10523
10952
  to {
@@ -10526,6 +10955,11 @@
10526
10955
  }
10527
10956
  }
10528
10957
 
10958
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10959
+ [data-scope='navigation-menu'] {
10960
+ --xh-navigation-menu-skin: 1;
10961
+ }
10962
+
10529
10963
  /* 根节点是 nav 地标,不参与排版;给 relative 是为了让共享外壳(viewport)有个定位参照系。
10530
10964
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
10531
10965
  [data-scope='navigation-menu'][data-part='root'] {
@@ -10781,6 +11215,11 @@
10781
11215
  }
10782
11216
 
10783
11217
  /* styles/number-field.css */
11218
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
11219
+ [data-scope='number-field'] {
11220
+ --xh-number-field-skin: 1;
11221
+ }
11222
+
10784
11223
  /* 与文本框同一套堆叠:标签一行、输入行一行。
10785
11224
  加减钮与输入框中间那层包裹归作者,这里不碰,三者各自把高度对齐即可成一体 */
10786
11225
  [data-scope='number-field'][data-part='root'] {
@@ -11000,6 +11439,11 @@
11000
11439
  }
11001
11440
 
11002
11441
  /* styles/pagination.css */
11442
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
11443
+ [data-scope='pagination'] {
11444
+ --xh-pagination-skin: 1;
11445
+ }
11446
+
11003
11447
  /* 根节点是 nav 地标,只负责把上一页 / 页码 / 下一页排成一行。
11004
11448
  页数为 0 时连接层会打 data-empty,这里不拿它做隐藏:作者常把「第 x-y 条」这类
11005
11449
  区间回显也写在 nav 里,整块藏掉会连那行字一起吞了,是否隐藏交给作者决定 */
@@ -11148,6 +11592,11 @@
11148
11592
  }
11149
11593
 
11150
11594
  /* styles/pin-input.css */
11595
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
11596
+ [data-scope='pin-input'] {
11597
+ --xh-pin-input-skin: 1;
11598
+ }
11599
+
11151
11600
  /* 与文本框、数字框同一套堆叠:标签一行、格子一行 */
11152
11601
  [data-scope='pin-input'][data-part='root'] {
11153
11602
  /* 尺寸档只换这四个私有槽,标题与格子都从 root 继承它们,换档不必给每个部件各写一条选择器 */
@@ -11305,6 +11754,23 @@
11305
11754
  }
11306
11755
 
11307
11756
  /* styles/popover.css */
11757
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
11758
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
11759
+ @keyframes xh-fade-in {
11760
+ from {
11761
+ opacity: 0;
11762
+ }
11763
+
11764
+ to {
11765
+ opacity: 1;
11766
+ }
11767
+ }
11768
+
11769
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
11770
+ [data-scope='popover'] {
11771
+ --xh-popover-skin: 1;
11772
+ }
11773
+
11308
11774
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
11309
11775
  [data-scope='popover'][data-part='positioner'] {
11310
11776
  position: fixed;
@@ -11459,6 +11925,11 @@
11459
11925
  }
11460
11926
 
11461
11927
  /* styles/progress.css */
11928
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
11929
+ [data-scope='progress'] {
11930
+ --xh-progress-skin: 1;
11931
+ }
11932
+
11462
11933
  /* 私有槽位:组件令牌 → 中档字面量两级回退。厚度写在 root 上而不是 track 上,
11463
11934
  尺寸档才改得动一处就够,track 靠继承拿到值。 */
11464
11935
  [data-scope='progress'][data-part='root'] {
@@ -11563,6 +12034,11 @@
11563
12034
  }
11564
12035
 
11565
12036
  /* styles/radio-group.css */
12037
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12038
+ [data-scope='radio-group'] {
12039
+ --xh-radio-group-skin: 1;
12040
+ }
12041
+
11566
12042
  [data-scope='radio-group'][data-part='root'] {
11567
12043
  /* 尺寸档只换这两个私有槽,标题与条目都从 root 继承它们,换档不必给每个部件各写一条选择器 */
11568
12044
  --xh-_radio-group-item-gap: var(--xh-control-gap-md);
@@ -11664,6 +12140,11 @@
11664
12140
  }
11665
12141
 
11666
12142
  /* styles/rating.css */
12143
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12144
+ [data-scope='rating'] {
12145
+ --xh-rating-skin: 1;
12146
+ }
12147
+
11667
12148
  /* position 是给表单影子做定位基准的:那份输入被连接层内联写成绝对定位,
11668
12149
  根上不留基准它就会贴到更外层的定位祖先上,原生校验提示跟着飘到页面别处。 */
11669
12150
  [data-scope='rating'][data-part='root'] {
@@ -11818,10 +12299,9 @@
11818
12299
  }
11819
12300
  }
11820
12301
 
11821
- @media (prefers-reduced-motion: reduce) {
11822
- [data-scope='scroll-area'] [data-part] {
11823
- animation-duration: 0.01ms !important;
11824
- }
12302
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12303
+ [data-scope='scroll-area'] {
12304
+ --xh-scroll-area-skin: 1;
11825
12305
  }
11826
12306
 
11827
12307
  /* 定位分工:滑块在**主轴**上的起点与长度由连接层每帧写进内联样式——
@@ -11979,6 +12459,23 @@
11979
12459
  }
11980
12460
 
11981
12461
  /* styles/select.css */
12462
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
12463
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
12464
+ @keyframes xh-fade-in {
12465
+ from {
12466
+ opacity: 0;
12467
+ }
12468
+
12469
+ to {
12470
+ opacity: 1;
12471
+ }
12472
+ }
12473
+
12474
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12475
+ [data-scope='select'] {
12476
+ --xh-select-skin: 1;
12477
+ }
12478
+
11982
12479
  [data-scope='select'][data-part='root'] {
11983
12480
  /* 尺寸档只换这五个私有槽,触发器、标题与条目都从 root 继承它们,
11984
12481
  换档不必给每个部件各写一条选择器。浮层在 positioner 里、也是 root 的后代,一并继承 */
@@ -12374,6 +12871,11 @@
12374
12871
  }
12375
12872
 
12376
12873
  /* styles/separator.css */
12874
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12875
+ [data-scope='separator'] {
12876
+ --xh-separator-skin: 1;
12877
+ }
12878
+
12377
12879
  [data-scope='separator'][data-part='root'] {
12378
12880
  border: 0;
12379
12881
  background: var(--xh-separator-color, var(--xh-border-default));
@@ -12391,6 +12893,11 @@
12391
12893
  }
12392
12894
 
12393
12895
  /* styles/side-nav.css */
12896
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
12897
+ [data-scope='side-nav'] {
12898
+ --xh-side-nav-skin: 1;
12899
+ }
12900
+
12394
12901
  [data-scope='side-nav'][data-part='root'] {
12395
12902
  inline-size: var(--xh-side-nav-w, 240px);
12396
12903
  display: flex;
@@ -12554,6 +13061,11 @@
12554
13061
  }
12555
13062
 
12556
13063
  /* styles/slider.css */
13064
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13065
+ [data-scope='slider'] {
13066
+ --xh-slider-skin: 1;
13067
+ }
13068
+
12557
13069
  /* 定位分工:已选区间与拇指在**主轴**上的起点与长度,由连接层每帧写进内联样式——
12558
13070
  水平是 inset-inline-start / inline-size,竖直是 inset-block-end / block-size。
12559
13071
  这份皮肤一个都不碰:内联优先级高于样式表,写了不但是死声明,
@@ -12806,6 +13318,11 @@
12806
13318
  这里一条声明都不给:给了 display / 尺寸反而会把它拽回布局里,在拇指内部撑出一块空白。 */
12807
13319
 
12808
13320
  /* styles/splitter.css */
13321
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13322
+ [data-scope='splitter'] {
13323
+ --xh-splitter-skin: 1;
13324
+ }
13325
+
12809
13326
  /* 分工:**面板在排布轴上的尺寸**由连接层每帧写进内联样式(flex-basis / flex-grow / flex-shrink)。
12810
13327
  这份皮肤一条都不碰——内联优先级高于样式表,写了不但是死声明,
12811
13328
  还会在切换 orientation 的那一帧跟连接层抢位置。皮肤只管排布方向、跨轴尺寸、
@@ -12933,6 +13450,11 @@
12933
13450
  }
12934
13451
 
12935
13452
  /* styles/steps.css */
13453
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13454
+ [data-scope='steps'] {
13455
+ --xh-steps-skin: 1;
13456
+ }
13457
+
12936
13458
  [data-scope='steps'][data-part='root'] {
12937
13459
  /* 尺寸档只换这三个私有槽,序号圆点、标题与说明都从 root 继承它们,
12938
13460
  换档不必给每个部件各写一条选择器 */
@@ -13185,6 +13707,18 @@
13185
13707
  }
13186
13708
 
13187
13709
  /* styles/switch.css */
13710
+ /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
13711
+ @keyframes xh-switch-rotate {
13712
+ to {
13713
+ transform: rotate(1turn);
13714
+ }
13715
+ }
13716
+
13717
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13718
+ [data-scope='switch'] {
13719
+ --xh-switch-skin: 1;
13720
+ }
13721
+
13188
13722
  [data-scope='switch'][data-part='root'] {
13189
13723
  /* 尺寸档只换轨道高度这一个私有槽,其余几何都从它算出来:
13190
13724
  滑块边长 = 轨道高 − 两条留白,轨道宽 = 两倍轨道高 − 两条留白,滑块行程因此正好等于自身边长 */
@@ -13245,13 +13779,6 @@
13245
13779
  translate: var(--xh-_switch-thumb-size) 0;
13246
13780
  }
13247
13781
 
13248
- /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
13249
- @keyframes xh-switch-rotate {
13250
- to {
13251
- transform: rotate(1turn);
13252
- }
13253
- }
13254
-
13255
13782
  /* 提交中:指针挂起、滑块里转圈;不是禁用,焦点与对比度都保持 */
13256
13783
  [data-scope='switch'][data-part='root'][data-loading] {
13257
13784
  cursor: wait;
@@ -13290,6 +13817,11 @@
13290
13817
  }
13291
13818
  }
13292
13819
 
13820
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13821
+ [data-scope='table'] {
13822
+ --xh-table-skin: 1;
13823
+ }
13824
+
13293
13825
  /* 表格自己滚动:吸顶表头与横向吸附列都要一个确定的滚动容器才钉得住 */
13294
13826
  [data-scope='table'][data-part='root'] {
13295
13827
  /* 密度档只换这两个私有槽:单元格与列标题从 root 继承前者,字号靠 font-size 本身继承下去,
@@ -13675,6 +14207,11 @@
13675
14207
  }
13676
14208
 
13677
14209
  /* styles/tabs.css */
14210
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14211
+ [data-scope='tabs'] {
14212
+ --xh-tabs-skin: 1;
14213
+ }
14214
+
13678
14215
  [data-scope='tabs'][data-part='root'] {
13679
14216
  /* 尺寸档只换这三个私有槽,标签从 root 继承它们,换档不必给每个部件各写一条选择器 */
13680
14217
  --xh-_tabs-trigger-h: var(--xh-control-h-md);
@@ -13832,6 +14369,11 @@
13832
14369
  }
13833
14370
 
13834
14371
  /* styles/tags-input.css */
14372
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14373
+ [data-scope='tags-input'] {
14374
+ --xh-tags-input-skin: 1;
14375
+ }
14376
+
13835
14377
  /* root 只负责纵向堆叠:标题一行、控件一行。可见的那个"框"长在 control 上,
13836
14378
  因为标签、输入框、清空按钮都在它里面,边框必须把三者一起圈住 */
13837
14379
  [data-scope='tags-input'][data-part='root'] {
@@ -14192,6 +14734,11 @@
14192
14734
  }
14193
14735
 
14194
14736
  /* styles/text-field.css */
14737
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14738
+ [data-scope='text-field'] {
14739
+ --xh-text-field-skin: 1;
14740
+ }
14741
+
14195
14742
  /* root 只负责纵向堆叠:标签一行、输入行一行。
14196
14743
  输入框与清空按钮中间那层包裹是作者自己写的、不在角色表里,
14197
14744
  所以尺寸与间距一律长在各自的角色节点上,不去假设那层存在 */
@@ -14400,6 +14947,11 @@
14400
14947
  }
14401
14948
 
14402
14949
  /* styles/thread.css */
14950
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14951
+ [data-scope='thread'] {
14952
+ --xh-thread-skin: 1;
14953
+ }
14954
+
14403
14955
  /* 自建定位上下文,作为绝对定位的回到底部按钮的参照系;
14404
14956
  block-size: 100% 让高度由外部决定,使滚动发生在内部。 */
14405
14957
  [data-scope='thread'][data-part='root'] {
@@ -14507,6 +15059,11 @@
14507
15059
  }
14508
15060
 
14509
15061
  /* styles/time-field.css */
15062
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15063
+ [data-scope='time-field'] {
15064
+ --xh-time-field-skin: 1;
15065
+ }
15066
+
14510
15067
  /* 与文本框、数字框同一套堆叠:标签一行、控件一行 */
14511
15068
  [data-scope='time-field'][data-part='root'] {
14512
15069
  /* 尺寸档只换这四个私有槽,标题与控件都从 root 继承它们,换档不必给每个部件各写一条选择器 */
@@ -14707,6 +15264,11 @@
14707
15264
  }
14708
15265
 
14709
15266
  /* styles/time-picker.css */
15267
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15268
+ [data-scope='time-picker'] {
15269
+ --xh-time-picker-skin: 1;
15270
+ }
15271
+
14710
15272
  /* 与文本框、时间输入同一套堆叠:标签一行、控件一行 */
14711
15273
  [data-scope='time-picker'][data-part='root'] {
14712
15274
  display: inline-flex;
@@ -15052,7 +15614,7 @@
15052
15614
  @keyframes xh-time-picker-panel-in {
15053
15615
  from {
15054
15616
  opacity: 0;
15055
- translate: 0 calc(-1 * var(--xh-space-1));
15617
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
15056
15618
  }
15057
15619
 
15058
15620
  to {
@@ -15070,33 +15632,34 @@
15070
15632
  @keyframes xh-toast-in {
15071
15633
  from {
15072
15634
  opacity: 0;
15073
- transform: translateY(8px) scale(0.98);
15635
+ translate: 0 var(--xh-motion-distance-md);
15636
+ scale: var(--xh-motion-scale-enter);
15074
15637
  }
15075
15638
 
15076
15639
  to {
15077
15640
  opacity: 1;
15078
- transform: none;
15641
+ translate: 0 0;
15642
+ scale: 1;
15079
15643
  }
15080
15644
  }
15081
15645
 
15082
15646
  @keyframes xh-toast-out {
15083
15647
  from {
15084
15648
  opacity: 1;
15085
- transform: none;
15649
+ translate: 0 0;
15650
+ scale: 1;
15086
15651
  }
15087
15652
 
15088
15653
  to {
15089
15654
  opacity: 0;
15090
- transform: translateY(4px) scale(0.96);
15655
+ translate: 0 var(--xh-motion-distance-sm);
15656
+ scale: var(--xh-motion-scale-enter);
15091
15657
  }
15092
15658
  }
15093
15659
 
15094
- /* 通知是自己冒出来的,用户没按任何键:减弱动效的诉求在这里比别处更硬。
15095
- !important 在低层里反而更强(重要声明的层序是反的),足以压住组件层的动画。 */
15096
- @media (prefers-reduced-motion: reduce) {
15097
- [data-scope='toast'][data-part] {
15098
- animation-duration: 0.01ms !important;
15099
- }
15660
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15661
+ [data-scope='toast'] {
15662
+ --xh-toast-skin: 1;
15100
15663
  }
15101
15664
 
15102
15665
  [data-scope='toast'][data-part='root'] {
@@ -15255,6 +15818,11 @@
15255
15818
  }
15256
15819
 
15257
15820
  /* styles/toaster.css */
15821
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15822
+ [data-scope='toaster'] {
15823
+ --xh-toaster-skin: 1;
15824
+ }
15825
+
15258
15826
  /* 地标容器不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
15259
15827
  root 只是给读屏一个可跳转的落点。它若留下一个块盒,写在页面中段的用法
15260
15828
  (按钮和队列摆在一起)就会凭空多出一行空白。
@@ -15324,6 +15892,11 @@
15324
15892
  }
15325
15893
 
15326
15894
  /* styles/toggle.css */
15895
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15896
+ [data-scope='toggle'] {
15897
+ --xh-toggle-skin: 1;
15898
+ }
15899
+
15327
15900
  [data-scope='toggle'][data-part='root'] {
15328
15901
  /* 私有槽位:组件令牌 → 语义令牌两级回退,变体只改这几个槽位 */
15329
15902
  --xh-_bg: var(--xh-toggle-bg, transparent);
@@ -15427,6 +16000,11 @@
15427
16000
  }
15428
16001
 
15429
16002
  /* styles/toggle-group.css */
16003
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16004
+ [data-scope='toggle-group'] {
16005
+ --xh-toggle-group-skin: 1;
16006
+ }
16007
+
15430
16008
  /* 分段控件:段与段之间不留缝,靠共边连成一体,所以 root 不设 gap。
15431
16009
  排布只能读 data-orientation——aria-orientation 在多选模式下连接层根本不输出(role=group 不收) */
15432
16010
  [data-scope='toggle-group'][data-part='root'] {
@@ -15587,6 +16165,11 @@
15587
16165
  }
15588
16166
 
15589
16167
  /* styles/toolbar.css */
16168
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16169
+ [data-scope='toolbar'] {
16170
+ --xh-toolbar-skin: 1;
16171
+ }
16172
+
15590
16173
  /* 一条控件带:条目之间留固定间距,分隔线再把它们切成语义上的几段。
15591
16174
  排布只能读 data-orientation——它与 aria-orientation 同源,但样式不该去读 ARIA */
15592
16175
  [data-scope='toolbar'][data-part='root'] {
@@ -15701,6 +16284,23 @@
15701
16284
  }
15702
16285
 
15703
16286
  /* styles/tooltip.css */
16287
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
16288
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
16289
+ @keyframes xh-fade-in {
16290
+ from {
16291
+ opacity: 0;
16292
+ }
16293
+
16294
+ to {
16295
+ opacity: 1;
16296
+ }
16297
+ }
16298
+
16299
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16300
+ [data-scope='tooltip'] {
16301
+ --xh-tooltip-skin: 1;
16302
+ }
16303
+
15704
16304
  [data-scope='tooltip'][data-part='trigger'] {
15705
16305
  display: inline-flex;
15706
16306
  align-items: center;
@@ -15808,18 +16408,34 @@
15808
16408
  inset-inline-start: calc(var(--xh-_tooltip-arrow-size) / -2);
15809
16409
  }
15810
16410
 
15811
- @media (prefers-reduced-motion: reduce) {
15812
- [data-scope='tooltip'][data-part='content'] {
15813
- animation-duration: 0.01ms !important;
16411
+ /* styles/tour.css */
16412
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
16413
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
16414
+ @keyframes xh-fade-in {
16415
+ from {
16416
+ opacity: 0;
16417
+ }
16418
+
16419
+ to {
16420
+ opacity: 1;
16421
+ }
16422
+ }
16423
+
16424
+ @keyframes xh-fade-out {
16425
+ from {
16426
+ opacity: 1;
16427
+ }
16428
+
16429
+ to {
16430
+ opacity: 0;
15814
16431
  }
15815
16432
  }
15816
16433
 
15817
- /* styles/tour.css */
15818
16434
  /* 气泡贴着目标探出来:纯淡入分不清它是从哪个元素长出来的 */
15819
16435
  @keyframes xh-tour-content-in {
15820
16436
  from {
15821
16437
  opacity: 0;
15822
- translate: 0 4px;
16438
+ translate: 0 var(--xh-motion-distance-sm);
15823
16439
  }
15824
16440
 
15825
16441
  to {
@@ -15832,7 +16448,7 @@
15832
16448
  @keyframes xh-tour-spotlight-in {
15833
16449
  from {
15834
16450
  opacity: 0;
15835
- scale: 1.04;
16451
+ scale: calc(2 - var(--xh-motion-scale-enter));
15836
16452
  }
15837
16453
 
15838
16454
  to {
@@ -15841,11 +16457,9 @@
15841
16457
  }
15842
16458
  }
15843
16459
 
15844
- @media (prefers-reduced-motion: reduce) {
15845
- [data-scope='tour'] [data-part] {
15846
- animation-duration: 0.01ms !important;
15847
- transition-duration: 0.01ms !important;
15848
- }
16460
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16461
+ [data-scope='tour'] {
16462
+ --xh-tour-skin: 1;
15849
16463
  }
15850
16464
 
15851
16465
  /* 根节点只是几个浮层的归属容器,不参与排版。
@@ -16122,6 +16736,11 @@
16122
16736
  }
16123
16737
 
16124
16738
  /* styles/transfer.css */
16739
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16740
+ [data-scope='transfer'] {
16741
+ --xh-transfer-skin: 1;
16742
+ }
16743
+
16125
16744
  /* 三栏栅格:两侧面板各占一栏、跨两行,中间那栏上下各放一个搬运按钮,
16126
16745
  两个按钮在中线处相遇。栅格的列号本身就是随书写方向走的(第 1 栏永远在行首侧),
16127
16746
  dir=rtl 时整块自动镜像,不必另写一套。
@@ -16442,6 +17061,11 @@
16442
17061
  }
16443
17062
 
16444
17063
  /* styles/tree.css */
17064
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17065
+ [data-scope='tree'] {
17066
+ --xh-tree-skin: 1;
17067
+ }
17068
+
16445
17069
  [data-scope='tree'][data-part='root'] {
16446
17070
  display: flex;
16447
17071
  flex-direction: column;
@@ -16649,6 +17273,23 @@
16649
17273
  }
16650
17274
 
16651
17275
  /* styles/tree-select.css */
17276
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
17277
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
17278
+ @keyframes xh-fade-in {
17279
+ from {
17280
+ opacity: 0;
17281
+ }
17282
+
17283
+ to {
17284
+ opacity: 1;
17285
+ }
17286
+ }
17287
+
17288
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17289
+ [data-scope='tree-select'] {
17290
+ --xh-tree-select-skin: 1;
17291
+ }
17292
+
16652
17293
  /* 解剖里没有把「触发器 + 清空按钮」裹在一起的 control 部件,一行是靠 flex-wrap 分出来的:
16653
17294
  标签占满整行把后面的挤到下一行,触发器与清空按钮就并排落在同一行上。
16654
17295
  这样作者少写标签、少写清空按钮,剩下的部件也不会塌 */
@@ -17098,6 +17739,11 @@
17098
17739
  }
17099
17740
 
17100
17741
  /* styles/virtualizer.css */
17742
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17743
+ [data-scope='virtualizer'] {
17744
+ --xh-virtualizer-skin: 1;
17745
+ }
17746
+
17101
17747
  /* 定位分工:条目在**主轴**上的位移、以及 content 在主轴上的总长,
17102
17748
  由连接层每帧写进内联样式(竖向是 inset-block-start / block-size,横向是
17103
17749
  inset-inline-start / inline-size)。这份皮肤一个都不碰:内联优先级高于样式表,
@@ -17202,6 +17848,11 @@
17202
17848
  }
17203
17849
 
17204
17850
  /* styles/watermark.css */
17851
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17852
+ [data-scope='watermark'] {
17853
+ --xh-watermark-skin: 1;
17854
+ }
17855
+
17205
17856
  /*
17206
17857
  * 盖水印的那块地。层叠上下文就地隔离,印子只压在这块地里,不会盖到组件外面去。
17207
17858
  */