@xihan-ui/styles 1.0.0-alpha.1 → 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +61 -5
  4. package/css/affix.css +5 -0
  5. package/css/alert.css +35 -5
  6. package/css/anchor.css +12 -7
  7. package/css/avatar-group.css +8 -3
  8. package/css/avatar.css +8 -3
  9. package/css/back-top.css +21 -1
  10. package/css/badge.css +21 -2
  11. package/css/breadcrumb.css +29 -4
  12. package/css/button-group.css +19 -13
  13. package/css/button.css +57 -11
  14. package/css/calendar.css +124 -2
  15. package/css/card.css +10 -5
  16. package/css/carousel.css +41 -5
  17. package/css/cascader.css +188 -102
  18. package/css/checkbox-group.css +46 -19
  19. package/css/checkbox.css +59 -8
  20. package/css/clipboard.css +7 -1
  21. package/css/code-block.css +17 -7
  22. package/css/collapsible.css +47 -2
  23. package/css/color-picker.css +117 -46
  24. package/css/combobox.css +132 -52
  25. package/css/composer.css +10 -3
  26. package/css/context-menu.css +101 -75
  27. package/css/countdown.css +5 -0
  28. package/css/date-field.css +96 -14
  29. package/css/date-picker.css +281 -65
  30. package/css/descriptions.css +7 -2
  31. package/css/dialog.css +109 -22
  32. package/css/download-trigger.css +76 -0
  33. package/css/drawer.css +75 -23
  34. package/css/dynamic-input.css +73 -17
  35. package/css/editable.css +17 -10
  36. package/css/ellipsis.css +6 -1
  37. package/css/empty-state.css +12 -7
  38. package/css/field.css +14 -6
  39. package/css/fieldset.css +69 -0
  40. package/css/file-upload.css +50 -7
  41. package/css/flex.css +5 -0
  42. package/css/float-button.css +21 -1
  43. package/css/floating-panel.css +310 -0
  44. package/css/form.css +10 -5
  45. package/css/gradient-text.css +5 -0
  46. package/css/grid.css +5 -0
  47. package/css/heatmap.css +410 -0
  48. package/css/highlight.css +6 -1
  49. package/css/hotkeys.css +90 -0
  50. package/css/hover-card.css +58 -50
  51. package/css/icon-wrapper.css +5 -0
  52. package/css/icon.css +5 -0
  53. package/css/image-cropper.css +231 -0
  54. package/css/image-viewer.css +167 -22
  55. package/css/image.css +7 -2
  56. package/css/infinite-scroll.css +6 -1
  57. package/css/json-viewer.css +241 -0
  58. package/css/layout.css +11 -10
  59. package/css/list.css +13 -8
  60. package/css/listbox.css +25 -4
  61. package/css/loading-bar.css +12 -1
  62. package/css/log.css +6 -1
  63. package/css/marquee.css +14 -0
  64. package/css/masonry.css +63 -0
  65. package/css/mention.css +105 -32
  66. package/css/menu.css +131 -46
  67. package/css/menubar.css +150 -66
  68. package/css/navigation-menu.css +59 -29
  69. package/css/number-animation.css +8 -3
  70. package/css/number-field.css +178 -16
  71. package/css/overlay-arrow.css +51 -0
  72. package/css/page-header.css +10 -5
  73. package/css/pagination.css +18 -13
  74. package/css/password-input.css +356 -0
  75. package/css/pin-input.css +18 -10
  76. package/css/popconfirm.css +73 -16
  77. package/css/popover.css +88 -44
  78. package/css/popselect.css +201 -52
  79. package/css/progress.css +52 -7
  80. package/css/qr-code.css +6 -1
  81. package/css/radio-group.css +19 -8
  82. package/css/rating.css +7 -2
  83. package/css/reset.css +17 -0
  84. package/css/result.css +11 -6
  85. package/css/scroll-area.css +65 -94
  86. package/css/scrollbar.css +167 -0
  87. package/css/segmented.css +215 -0
  88. package/css/select.css +292 -124
  89. package/css/separator.css +7 -2
  90. package/css/side-nav.css +116 -19
  91. package/css/signature-pad.css +144 -0
  92. package/css/skeleton.css +12 -1
  93. package/css/slider.css +15 -10
  94. package/css/space.css +117 -0
  95. package/css/spinner.css +31 -11
  96. package/css/splitter.css +5 -0
  97. package/css/statistic.css +14 -9
  98. package/css/steps.css +30 -8
  99. package/css/switch.css +62 -13
  100. package/css/table.css +136 -37
  101. package/css/tabs.css +9 -4
  102. package/css/tag.css +177 -0
  103. package/css/tags-input.css +83 -40
  104. package/css/text-field.css +154 -36
  105. package/css/thread.css +6 -1
  106. package/css/time-field.css +102 -16
  107. package/css/time-picker.css +264 -69
  108. package/css/time.css +5 -0
  109. package/css/timeline.css +15 -10
  110. package/css/timer.css +119 -0
  111. package/css/toast.css +46 -21
  112. package/css/toaster.css +6 -1
  113. package/css/toggle-group.css +5 -0
  114. package/css/toggle.css +11 -6
  115. package/css/tone.css +10 -5
  116. package/css/toolbar.css +6 -1
  117. package/css/tooltip.css +54 -38
  118. package/css/tour.css +128 -63
  119. package/css/transfer.css +73 -17
  120. package/css/tree-select.css +203 -83
  121. package/css/tree.css +90 -1
  122. package/css/typography.css +9 -4
  123. package/css/undefined.css +11 -1
  124. package/css/virtualizer.css +8 -1
  125. package/css/watermark.css +6 -2
  126. package/index.css +17 -1
  127. package/index.unlayered.css +9394 -2883
  128. package/package.json +19 -4
  129. package/css/motion.css +0 -58
package/css/timer.css ADDED
@@ -0,0 +1,119 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='timer'] {
4
+ --xh-timer-skin: 1;
5
+ }
6
+
7
+ /* 三个尺寸档只换这几个私有槽,各部件从 root 继承它们,换档不必给每个部件各写一条选择器 */
8
+ [data-scope='timer'][data-part='root'] {
9
+ --xh-_timer-digit-size: var(--xh-text-heading-2-size);
10
+ --xh-_timer-gap: var(--xh-space-3);
11
+ --xh-_timer-control-h: var(--xh-control-h-md);
12
+ --xh-_timer-control-px: var(--xh-control-px-md);
13
+ --xh-_timer-control-gap: var(--xh-control-gap-md);
14
+
15
+ display: inline-flex;
16
+ align-items: center;
17
+ gap: var(--xh-timer-gap, var(--xh-_timer-gap));
18
+ color: var(--xh-timer-fg, var(--xh-fg-default));
19
+ }
20
+
21
+ /* 上面声明了 display,会盖掉 UA 的 [hidden] 规则,收起态要在这里接回来 */
22
+ [data-scope='timer'][data-part='root'][hidden] {
23
+ display: none;
24
+ }
25
+
26
+ /* —— 尺寸 —— */
27
+ [data-scope='timer'][data-part='root'][data-size='sm'] {
28
+ --xh-_timer-digit-size: var(--xh-text-heading-3-size);
29
+ --xh-_timer-gap: var(--xh-space-2);
30
+ --xh-_timer-control-h: var(--xh-control-h-sm);
31
+ --xh-_timer-control-px: var(--xh-control-px-sm);
32
+ --xh-_timer-control-gap: var(--xh-control-gap-sm);
33
+ }
34
+
35
+ [data-scope='timer'][data-part='root'][data-size='lg'] {
36
+ --xh-_timer-digit-size: var(--xh-text-heading-1-size);
37
+ --xh-_timer-gap: var(--xh-space-4);
38
+ --xh-_timer-control-h: var(--xh-control-h-lg);
39
+ --xh-_timer-control-px: var(--xh-control-px-lg);
40
+ --xh-_timer-control-gap: var(--xh-control-gap-lg);
41
+ }
42
+
43
+ /* —— 时间区 —— */
44
+ /* 等宽数字:逐位宽度一致,秒数换位时分隔符与后面的段都不会左右挪动。
45
+ direction 钉成 ltr:每段是一个独立的 flex 项,主轴方向跟着文字方向走,
46
+ 不钉住的话 rtl 页面上时分秒会整体倒过来排——时间串的读序两个方向都一样。 */
47
+ [data-scope='timer'][data-part='area'] {
48
+ display: inline-flex;
49
+ align-items: baseline;
50
+ direction: ltr;
51
+ color: var(--xh-timer-area-fg, var(--xh-fg-default));
52
+ font-size: var(--xh-timer-digit-font-size, var(--xh-_timer-digit-size));
53
+ font-variant-numeric: tabular-nums;
54
+ font-weight: var(--xh-font-weight-semibold);
55
+ line-height: var(--xh-leading-tight);
56
+ }
57
+
58
+ [data-scope='timer'][data-part='area'][hidden] {
59
+ display: none;
60
+ }
61
+
62
+ /* 走完之后这串数字不再是活的信息,退一档;暂停在半路的仍是要盯着看的数,不退 */
63
+ [data-scope='timer'][data-part='area'][data-state='completed'] {
64
+ color: var(--xh-timer-completed-fg, var(--xh-fg-muted));
65
+ }
66
+
67
+ /* 记号只是排版,比数字弱一档、两侧留一点气口 */
68
+ [data-scope='timer'][data-part='separator'] {
69
+ padding-inline: var(--xh-timer-separator-px, var(--xh-space-0_5));
70
+ color: var(--xh-timer-separator-fg, var(--xh-fg-subtle));
71
+ font-weight: var(--xh-font-weight-regular);
72
+ }
73
+
74
+ /* —— 起停按钮 —— */
75
+ [data-scope='timer'][data-part='control'] {
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ gap: var(--xh-timer-control-gap, var(--xh-_timer-control-gap));
80
+ block-size: var(--xh-timer-control-h, var(--xh-_timer-control-h));
81
+ padding-inline: var(--xh-timer-control-px, var(--xh-_timer-control-px));
82
+ border: var(--xh-stroke-thin) solid var(--xh-timer-control-border, var(--xh-border-control));
83
+ border-radius: var(--xh-timer-control-radius, var(--xh-shape-control));
84
+ background: var(--xh-timer-control-bg, var(--xh-bg-surface));
85
+ color: var(--xh-timer-control-fg, var(--xh-fg-default));
86
+ font-size: var(--xh-text-label-size);
87
+ font-weight: var(--xh-text-label-weight);
88
+ line-height: var(--xh-leading-none);
89
+ cursor: pointer;
90
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
91
+ }
92
+
93
+ [data-scope='timer'][data-part='control'][hidden] {
94
+ display: none;
95
+ }
96
+
97
+ [data-scope='timer'][data-part='control']:hover {
98
+ border-color: var(--xh-timer-control-border-hover, var(--xh-border-control-hover));
99
+ background: var(--xh-timer-control-bg-hover, var(--xh-bg-subtle-hover));
100
+ }
101
+
102
+ [data-scope='timer'][data-part='control']:active {
103
+ background: var(--xh-timer-control-bg-active, var(--xh-bg-subtle-active));
104
+ }
105
+
106
+ [data-scope='timer'][data-part='control']:focus-visible {
107
+ border-color: var(--xh-timer-control-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
108
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
109
+ outline-offset: var(--xh-ring-offset);
110
+ }
111
+
112
+ /* 作者把按钮禁掉时的样子。文字改用 fg-disabled 就不再叠 opacity,两条一起上会掉到读不出来 */
113
+ [data-scope='timer'][data-part='control']:disabled {
114
+ border-color: var(--xh-timer-control-border-disabled, var(--xh-border-subtle));
115
+ background: var(--xh-timer-control-bg-disabled, var(--xh-bg-muted));
116
+ color: var(--xh-fg-disabled);
117
+ cursor: not-allowed;
118
+ }
119
+ }
package/css/toast.css CHANGED
@@ -7,59 +7,63 @@
7
7
  @keyframes xh-toast-in {
8
8
  from {
9
9
  opacity: 0;
10
- transform: translateY(8px) scale(0.98);
10
+ translate: 0 var(--xh-motion-distance-md);
11
+ scale: var(--xh-motion-scale-enter);
11
12
  }
12
13
 
13
14
  to {
14
15
  opacity: 1;
15
- transform: none;
16
+ translate: 0 0;
17
+ scale: 1;
16
18
  }
17
19
  }
18
20
 
19
21
  @keyframes xh-toast-out {
20
22
  from {
21
23
  opacity: 1;
22
- transform: none;
24
+ translate: 0 0;
25
+ scale: 1;
23
26
  }
24
27
 
25
28
  to {
26
29
  opacity: 0;
27
- transform: translateY(4px) scale(0.96);
28
- }
29
- }
30
-
31
- /* 通知是自己冒出来的,用户没按任何键:减弱动效的诉求在这里比别处更硬。
32
- !important 在低层里反而更强(重要声明的层序是反的),足以压住组件层的动画。 */
33
- @media (prefers-reduced-motion: reduce) {
34
- [data-scope='toast'][data-part] {
35
- animation-duration: 0.01ms !important;
30
+ translate: 0 var(--xh-motion-distance-md);
31
+ scale: var(--xh-motion-scale-enter);
36
32
  }
37
33
  }
38
34
  }
39
35
 
40
36
  @layer xihan.components {
37
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
38
+ [data-scope='toast'] {
39
+ --xh-toast-skin: 1;
40
+ }
41
+
41
42
  [data-scope='toast'][data-part='root'] {
43
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
44
+ --xh-icon-size: var(--xh-toast-icon-size, var(--xh-glyph-size-text));
45
+
42
46
  display: flex;
43
47
  flex-direction: column;
44
48
  gap: var(--xh-toast-gap, var(--xh-space-1));
45
- inline-size: var(--xh-toast-w, 20rem);
49
+ inline-size: var(--xh-toast-w, var(--xh-overlay-max-w));
46
50
  /* 摞是整面视口宽的定位面且带内边距,取 100% 就等于自动让出两侧留白,
47
51
  窄屏上不必再算一遍 viewport 减法 */
48
52
  max-inline-size: 100%;
49
- padding-block: var(--xh-toast-py, var(--xh-space-3));
50
- padding-inline: var(--xh-toast-px, var(--xh-space-4));
53
+ padding-block: var(--xh-toast-py, var(--xh-surface-py-sm));
54
+ padding-inline: var(--xh-toast-px, var(--xh-surface-px-sm));
51
55
  border: var(--xh-stroke-thin) solid var(--xh-toast-border, var(--xh-border-default));
52
56
  /* 语气色条做成起始侧的粗边,而不是伪元素:圆角与阴影都不用再对第二遍。
53
57
  两条必须排在 border 简写之后,否则被简写重置回细边与常规描边色。
54
58
  颜色由 connect 从 type 派生的 data-tone 经语气层给出,作者写 --xh-toast-accent
55
59
  就能把某一条整体改色;两者都没有时退回原来的 info 蓝 */
56
- border-inline-start-width: var(--xh-toast-accent-width, 4px);
60
+ border-inline-start-width: var(--xh-toast-accent-width, var(--xh-space-1));
57
61
  border-inline-start-color: var(--xh-toast-accent, var(--xh-_tone-soft, var(--xh-color-info-500)));
58
62
  border-radius: var(--xh-toast-radius, var(--xh-shape-surface));
59
63
  background: var(--xh-toast-bg, var(--xh-bg-surface-raised));
60
64
  color: var(--xh-toast-fg, var(--xh-fg-default));
61
- box-shadow: var(--xh-toast-shadow, var(--xh-elevation-3));
62
- font-size: var(--xh-toast-font-size, var(--xh-font-size-sm));
65
+ box-shadow: var(--xh-toast-shadow, var(--xh-elevation-sheet));
66
+ font-size: var(--xh-toast-font-size, var(--xh-text-secondary-size));
63
67
  line-height: var(--xh-toast-leading, var(--xh-leading-normal));
64
68
  /* 摞的定位面整面铺开且不吃指针,卡片必须自己吃回来:
65
69
  悬停按住计时、按钮可点、焦点进出,全指着这一条 */
@@ -93,7 +97,7 @@
93
97
  /* 作者可能把它写成 h2/p,外边距得先归零,否则卡片内的行距对不上 */
94
98
  margin: 0;
95
99
  color: var(--xh-toast-title-fg, var(--xh-fg-default));
96
- font-size: var(--xh-toast-title-font-size, var(--xh-font-size-md));
100
+ font-size: var(--xh-toast-title-font-size, var(--xh-text-label-size));
97
101
  font-weight: var(--xh-toast-title-font-weight, var(--xh-font-weight-semibold));
98
102
  line-height: var(--xh-toast-title-leading, var(--xh-leading-tight));
99
103
  }
@@ -101,7 +105,7 @@
101
105
  [data-scope='toast'][data-part='description'] {
102
106
  margin: 0;
103
107
  color: var(--xh-toast-description-fg, var(--xh-fg-muted));
104
- font-size: var(--xh-toast-description-font-size, var(--xh-font-size-sm));
108
+ font-size: var(--xh-toast-description-font-size, var(--xh-text-secondary-size));
105
109
  }
106
110
 
107
111
  /* 没给文案的那一个仍然要留在 DOM 里(aria-labelledby / aria-describedby 指着它),
@@ -168,6 +172,10 @@
168
172
  font: inherit;
169
173
  line-height: var(--xh-leading-none);
170
174
  cursor: pointer;
175
+ transition:
176
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
177
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
178
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
171
179
  }
172
180
 
173
181
  /* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半:
@@ -177,10 +185,15 @@
177
185
  }
178
186
 
179
187
  [data-scope='toast'][data-part='close-trigger']:hover:not(:disabled) {
180
- background: var(--xh-toast-close-bg-hover, var(--xh-bg-subtle));
188
+ background: var(--xh-toast-close-bg-hover, var(--xh-bg-subtle-hover));
181
189
  color: var(--xh-toast-close-fg-hover, var(--xh-fg-default));
182
190
  }
183
191
 
192
+ [data-scope='toast'][data-part='close-trigger']:active {
193
+ background: var(--xh-toast-close-bg-active, var(--xh-bg-subtle-active));
194
+ scale: var(--xh-motion-scale-press);
195
+ }
196
+
184
197
  /* 单体控件用原生 disabled。常规路径下它与 hidden 同时出现看不见,
185
198
  但作者若在覆盖层把收起改了回来,至少还能看出这颗叉是按不动的 */
186
199
  [data-scope='toast'][data-part='close-trigger']:disabled {
@@ -192,4 +205,16 @@
192
205
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
193
206
  outline-offset: var(--xh-ring-offset);
194
207
  }
208
+
209
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
210
+ [data-scope='toast'][data-part='close-trigger']:empty::before {
211
+ content: '';
212
+ display: inline-block;
213
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
214
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
215
+ vertical-align: var(--xh-glyph-baseline-shift);
216
+ background-color: currentColor;
217
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
218
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
219
+ }
195
220
  }
package/css/toaster.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toaster'] {
4
+ --xh-toaster-skin: 1;
5
+ }
6
+
2
7
  /* 地标容器不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
3
8
  root 只是给读屏一个可跳转的落点。它若留下一个块盒,写在页面中段的用法
4
9
  (按钮和队列摆在一起)就会凭空多出一行空白。
@@ -25,7 +30,7 @@
25
30
  position: fixed;
26
31
  inset-block: 0;
27
32
  inset-inline: 0;
28
- z-index: var(--xh-layer-toast);
33
+ z-index: var(--xh-toaster-layer, var(--xh-layer-toast));
29
34
  display: flex;
30
35
  flex-direction: column;
31
36
  /* 基线按默认落位 bottom-end 写,下面只覆盖跟它不同的那几个位 */
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toggle-group'] {
4
+ --xh-toggle-group-skin: 1;
5
+ }
6
+
2
7
  /* 分段控件:段与段之间不留缝,靠共边连成一体,所以 root 不设 gap。
3
8
  排布只能读 data-orientation——aria-orientation 在多选模式下连接层根本不输出(role=group 不收) */
4
9
  [data-scope='toggle-group'][data-part='root'] {
package/css/toggle.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toggle'] {
4
+ --xh-toggle-skin: 1;
5
+ }
6
+
2
7
  [data-scope='toggle'][data-part='root'] {
3
8
  /* 私有槽位:组件令牌 → 语义令牌两级回退,变体只改这几个槽位 */
4
9
  --xh-_bg: var(--xh-toggle-bg, transparent);
@@ -90,14 +95,14 @@
90
95
 
91
96
  /* —— 尺寸 —— */
92
97
  [data-scope='toggle'][data-part='root'][data-size='sm'] {
93
- block-size: var(--xh-control-h-sm);
94
- padding-inline: var(--xh-control-px-sm);
95
- font-size: var(--xh-font-size-sm);
98
+ block-size: var(--xh-toggle-h, var(--xh-control-h-sm));
99
+ padding-inline: var(--xh-toggle-px, var(--xh-control-px-sm));
100
+ font-size: var(--xh-toggle-font-size, var(--xh-control-font-sm));
96
101
  }
97
102
 
98
103
  [data-scope='toggle'][data-part='root'][data-size='lg'] {
99
- block-size: var(--xh-control-h-lg);
100
- padding-inline: var(--xh-control-px-lg);
101
- font-size: var(--xh-font-size-lg);
104
+ block-size: var(--xh-toggle-h, var(--xh-control-h-lg));
105
+ padding-inline: var(--xh-toggle-px, var(--xh-control-px-lg));
106
+ font-size: var(--xh-toggle-font-size, var(--xh-control-font-lg));
102
107
  }
103
108
  }
package/css/tone.css CHANGED
@@ -18,6 +18,10 @@
18
18
  *
19
19
  * 这两个槽用的都是固定原语而不是 --xh-fg-default:实心底本身是原语色、不随主题翻,
20
20
  * 配色若跟着主题翻,暗色下就会变成白字压在浅黄底上(实测对比度 2.70)。
21
+ *
22
+ * brand 是例外:那一族的色相归使用者,所以它的底与前景走 --xh-bg-brand / --xh-fg-on-brand
23
+ * 这两个语义令牌。缺省主题下它们就解析成 brand-600 与 neutral-0,与其余五族同值;
24
+ * 改写过品牌色的使用者只改这两个令牌,实心底与它上面的字就一起跟着走。
21
25
  */
22
26
  @layer xihan.components {
23
27
  [data-tone] {
@@ -46,9 +50,9 @@
46
50
  }
47
51
 
48
52
  [data-tone='brand'] {
49
- --xh-_tone: var(--xh-color-brand-600);
53
+ --xh-_tone: var(--xh-bg-brand);
50
54
  --xh-_tone-soft: var(--xh-color-brand-500);
51
- --xh-_tone-on: var(--xh-color-neutral-0);
55
+ --xh-_tone-on: var(--xh-fg-on-brand);
52
56
  --xh-_tone-shift: var(--xh-color-neutral-950);
53
57
  }
54
58
 
@@ -88,12 +92,13 @@
88
92
 
89
93
  /* 主色本体在各自的底上有两族够不到 3:1:黄在白底上只有 2.70,中性在深色底上只有 2.54。
90
94
  语气色是固定原语、不随主题翻,所以这两族只能按主题各兜一次。
91
- 浅色是缺省态(不写 data-theme 也算浅色),深色靠属性选择器压过它 */
95
+ 浅色是缺省态(不写 data-theme 也算浅色),深色靠属性选择器压过它。
96
+ data-theme 写在语气容器自己身上还是写在祖先上都算,两种用法都成立 */
92
97
  [data-tone='warning'] {
93
98
  --xh-_tone-border-control: var(--xh-color-warning-700);
94
99
  }
95
100
 
96
- [data-theme='dark'] [data-tone='warning'] {
101
+ :is([data-theme='dark'] *, [data-theme='dark'])[data-tone='warning'] {
97
102
  --xh-_tone-border-control: var(--xh-color-warning-600);
98
103
  }
99
104
 
@@ -101,7 +106,7 @@
101
106
  --xh-_tone-border-control: var(--xh-color-neutral-600);
102
107
  }
103
108
 
104
- [data-theme='dark'] [data-tone='neutral'] {
109
+ :is([data-theme='dark'] *, [data-theme='dark'])[data-tone='neutral'] {
105
110
  --xh-_tone-border-control: var(--xh-color-neutral-550);
106
111
  }
107
112
  }
package/css/toolbar.css CHANGED
@@ -1,4 +1,9 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='toolbar'] {
4
+ --xh-toolbar-skin: 1;
5
+ }
6
+
2
7
  /* 一条控件带:条目之间留固定间距,分隔线再把它们切成语义上的几段。
3
8
  排布只能读 data-orientation——它与 aria-orientation 同源,但样式不该去读 ARIA */
4
9
  [data-scope='toolbar'][data-part='root'] {
@@ -96,7 +101,7 @@
96
101
  [data-scope='toolbar'][data-part='separator'] {
97
102
  flex: none;
98
103
  align-self: stretch;
99
- border-radius: var(--xh-toolbar-separator-radius, var(--xh-radius-full));
104
+ border-radius: var(--xh-toolbar-separator-radius, var(--xh-shape-pill));
100
105
  background: var(--xh-toolbar-separator-color, var(--xh-border-default));
101
106
  }
102
107
 
package/css/tooltip.css CHANGED
@@ -1,4 +1,37 @@
1
+ @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-pop-in {
5
+ from {
6
+ opacity: 0;
7
+ scale: var(--xh-motion-scale-enter);
8
+ }
9
+
10
+ to {
11
+ opacity: 1;
12
+ scale: 1;
13
+ }
14
+ }
15
+
16
+ @keyframes xh-pop-out {
17
+ from {
18
+ opacity: 1;
19
+ scale: 1;
20
+ }
21
+
22
+ to {
23
+ opacity: 0;
24
+ scale: var(--xh-motion-scale-enter);
25
+ }
26
+ }
27
+ }
28
+
1
29
  @layer xihan.components {
30
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
31
+ [data-scope='tooltip'] {
32
+ --xh-tooltip-skin: 1;
33
+ }
34
+
2
35
  [data-scope='tooltip'][data-part='trigger'] {
3
36
  display: inline-flex;
4
37
  align-items: center;
@@ -21,7 +54,7 @@
21
54
  position: fixed;
22
55
  inset-block-start: 0;
23
56
  inset-inline-start: 0;
24
- z-index: var(--xh-layer-tooltip);
57
+ z-index: var(--xh-tooltip-layer, var(--xh-layer-tooltip));
25
58
  /* 浮层不承载交互:指针必须能穿过去点到底下的东西 */
26
59
  pointer-events: none;
27
60
  }
@@ -36,25 +69,36 @@
36
69
  箭头是它的后代,语气槽一并继承 */
37
70
  --xh-_tooltip-py: var(--xh-space-1);
38
71
  --xh-_tooltip-px: var(--xh-space-2);
39
- --xh-_tooltip-font-size: var(--xh-font-size-sm);
72
+ --xh-_tooltip-font-size: var(--xh-text-secondary-size);
40
73
 
41
74
  /* 与 positioner 相反:浮层本体要能接指针,指针停在提示上就不该收起
42
75
  (长文案需要停留细看)。positioner 仍是 none,空白区域照样点得穿。 */
76
+ /* 显式声明 display 是为了盖掉 UA 的 [hidden]{display:none}:收起那一帧 content 仍带 hidden,
77
+ 盒子得先在,退场动画才播得出来。真正的收起由宿主在退场结束后落成内联 display */
78
+ display: block;
43
79
  pointer-events: auto;
44
80
  max-inline-size: var(--xh-tooltip-max-w, var(--xh-overlay-max-w));
45
81
  padding-block: var(--xh-tooltip-py, var(--xh-_tooltip-py));
46
82
  padding-inline: var(--xh-tooltip-px, var(--xh-_tooltip-px));
83
+ /* 这里刻意用 control 而不是浮层那档 surface:提示气泡通常只有一行字、高度接近控件,
84
+ 8px 圆角在这个尺寸上占比过大,看着会发胖。档位定义里为此单列了一条 */
47
85
  border-radius: var(--xh-tooltip-radius, var(--xh-shape-control));
48
86
  /* 实心底与其上的文字色随语气走。没写 data-tone 时两个槽都没被声明,退回原来的取值 */
49
87
  background: var(--xh-tooltip-bg, var(--xh-_tone, var(--xh-fg-default)));
50
88
  color: var(--xh-tooltip-fg, var(--xh-_tone-on, var(--xh-bg-surface)));
51
89
  font-size: var(--xh-tooltip-font-size, var(--xh-_tooltip-font-size));
52
90
  line-height: var(--xh-leading-normal);
53
- box-shadow: var(--xh-tooltip-shadow, var(--xh-elevation-2));
91
+ box-shadow: var(--xh-tooltip-shadow, var(--xh-elevation-floating));
54
92
  }
55
93
 
56
94
  [data-scope='tooltip'][data-part='content'][data-state='open'] {
57
- animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
95
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
96
+ }
97
+
98
+ /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
99
+ 免得动画结束到真收起之间闪一下原样 */
100
+ [data-scope='tooltip'][data-part='content'][data-state='closed'] {
101
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
58
102
  }
59
103
 
60
104
  /* —— 尺寸 —— */
@@ -63,52 +107,24 @@
63
107
  [data-scope='tooltip'][data-part='content'][data-size='sm'] {
64
108
  --xh-_tooltip-py: var(--xh-space-0_5);
65
109
  --xh-_tooltip-px: var(--xh-space-1_5);
66
- --xh-_tooltip-font-size: var(--xh-font-size-xs);
110
+ --xh-_tooltip-font-size: var(--xh-control-caption-sm);
67
111
  }
68
112
 
69
113
  [data-scope='tooltip'][data-part='content'][data-size='lg'] {
70
114
  --xh-_tooltip-py: var(--xh-space-1_5);
71
115
  --xh-_tooltip-px: var(--xh-space-2_5);
72
- --xh-_tooltip-font-size: var(--xh-font-size-md);
116
+ --xh-_tooltip-font-size: var(--xh-control-caption-lg);
73
117
  }
74
118
 
75
- /* 箭头是旋转 45° 的方块,按自报的落定朝向贴在 content 对侧边上;
119
+ /* 箭头的底色与描边色,几何在 overlay-arrow.css。
76
120
  交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中 */
77
121
  [data-scope='tooltip'][data-part='arrow'] {
78
- --xh-_tooltip-arrow-size: var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size));
79
122
  --xh-_tooltip-arrow-x: 50%;
80
123
  --xh-_tooltip-arrow-y: 50%;
124
+ --xh-_overlay-arrow-size: var(--xh-tooltip-arrow-size, var(--xh-overlay-arrow-size));
125
+ --xh-_overlay-arrow-x: var(--xh-_tooltip-arrow-x);
126
+ --xh-_overlay-arrow-y: var(--xh-_tooltip-arrow-y);
81
127
 
82
- position: absolute;
83
- inline-size: var(--xh-_tooltip-arrow-size);
84
- block-size: var(--xh-_tooltip-arrow-size);
85
128
  background: var(--xh-tooltip-bg, var(--xh-_tone, var(--xh-fg-default)));
86
- transform: rotate(45deg);
87
- }
88
-
89
- [data-scope='tooltip'][data-part='arrow'][data-placement^='bottom'] {
90
- inset-block-start: calc(var(--xh-_tooltip-arrow-size) / -2);
91
- inset-inline-start: calc(var(--xh-_tooltip-arrow-x) - var(--xh-_tooltip-arrow-size) / 2);
92
- }
93
-
94
- [data-scope='tooltip'][data-part='arrow'][data-placement^='top'] {
95
- inset-block-end: calc(var(--xh-_tooltip-arrow-size) / -2);
96
- inset-inline-start: calc(var(--xh-_tooltip-arrow-x) - var(--xh-_tooltip-arrow-size) / 2);
97
- }
98
-
99
- [data-scope='tooltip'][data-part='arrow'][data-placement^='left'] {
100
- inset-block-start: calc(var(--xh-_tooltip-arrow-y) - var(--xh-_tooltip-arrow-size) / 2);
101
- inset-inline-end: calc(var(--xh-_tooltip-arrow-size) / -2);
102
- }
103
-
104
- [data-scope='tooltip'][data-part='arrow'][data-placement^='right'] {
105
- inset-block-start: calc(var(--xh-_tooltip-arrow-y) - var(--xh-_tooltip-arrow-size) / 2);
106
- inset-inline-start: calc(var(--xh-_tooltip-arrow-size) / -2);
107
- }
108
-
109
- @media (prefers-reduced-motion: reduce) {
110
- [data-scope='tooltip'][data-part='content'] {
111
- animation-duration: 0.01ms !important;
112
- }
113
129
  }
114
130
  }