@xihan-ui/styles 1.0.0 → 2.0.0

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 (171) hide show
  1. package/CHANGELOG.md +5146 -6
  2. package/README.md +22 -2
  3. package/component-tokens.d.ts +4212 -0
  4. package/component-tokens.js +2 -0
  5. package/components.tokens.json +80116 -0
  6. package/css/accordion.css +131 -75
  7. package/css/affix.css +16 -1
  8. package/css/alert.css +114 -67
  9. package/css/anchor.css +99 -27
  10. package/css/approval.css +461 -0
  11. package/css/avatar-group.css +14 -6
  12. package/css/avatar.css +33 -9
  13. package/css/back-top.css +103 -48
  14. package/css/badge.css +42 -14
  15. package/css/bar-code.css +62 -0
  16. package/css/breadcrumb.css +40 -21
  17. package/css/button-group.css +146 -24
  18. package/css/button.css +116 -99
  19. package/css/calendar-picker.css +448 -0
  20. package/css/calendar-range-picker.css +517 -0
  21. package/css/card.css +54 -77
  22. package/css/carousel.css +412 -68
  23. package/css/cascader.css +429 -246
  24. package/css/checkbox-group.css +225 -77
  25. package/css/checkbox.css +174 -37
  26. package/css/clipboard.css +266 -47
  27. package/css/code-view.css +279 -0
  28. package/css/collapsible.css +108 -63
  29. package/css/color-field.css +158 -0
  30. package/css/color-picker.css +172 -184
  31. package/css/color-slider.css +274 -0
  32. package/css/color-swatch-picker.css +243 -0
  33. package/css/color-swatch.css +35 -0
  34. package/css/combobox.css +267 -273
  35. package/css/command.css +399 -0
  36. package/css/context-menu.css +183 -108
  37. package/css/date-field.css +94 -121
  38. package/css/date-picker.css +486 -249
  39. package/css/date-range-picker.css +559 -0
  40. package/css/description.css +51 -0
  41. package/css/descriptions.css +133 -87
  42. package/css/dialog.css +247 -68
  43. package/css/diff-view.css +428 -0
  44. package/css/download-trigger.css +155 -46
  45. package/css/drawer.css +194 -111
  46. package/css/editable.css +172 -152
  47. package/css/empty-state.css +80 -11
  48. package/css/field-array.css +190 -0
  49. package/css/field.css +84 -31
  50. package/css/fieldset.css +51 -18
  51. package/css/file-upload.css +134 -36
  52. package/css/flex.css +20 -1
  53. package/css/float-button.css +238 -57
  54. package/css/floating-panel.css +173 -92
  55. package/css/focus.css +46 -0
  56. package/css/forced-colors.css +93 -0
  57. package/css/form.css +254 -77
  58. package/css/gradient-text.css +34 -10
  59. package/css/grid.css +516 -5
  60. package/css/heatmap.css +87 -29
  61. package/css/highlight.css +20 -5
  62. package/css/hover-card.css +97 -47
  63. package/css/icon-wrapper.css +15 -3
  64. package/css/icon.css +74 -8
  65. package/css/image-cropper.css +143 -29
  66. package/css/image-viewer.css +150 -89
  67. package/css/image.css +30 -1
  68. package/css/infinite-scroll.css +51 -1
  69. package/css/input-group.css +277 -0
  70. package/css/json-viewer.css +102 -45
  71. package/css/kbd.css +72 -0
  72. package/css/label.css +78 -0
  73. package/css/layers.css +5 -0
  74. package/css/layout.css +175 -31
  75. package/css/list.css +24 -3
  76. package/css/listbox.css +208 -67
  77. package/css/loading-bar.css +52 -3
  78. package/css/log.css +144 -9
  79. package/css/markdown-stream.css +149 -0
  80. package/css/marquee.css +27 -1
  81. package/css/masonry.css +7 -0
  82. package/css/matrix-code.css +67 -0
  83. package/css/mention.css +234 -152
  84. package/css/menu.css +180 -83
  85. package/css/menubar.css +204 -136
  86. package/css/message-feed.css +197 -0
  87. package/css/navigation-menu.css +144 -90
  88. package/css/notification.css +178 -100
  89. package/css/number-animation.css +7 -0
  90. package/css/number-field.css +120 -277
  91. package/css/overlay-arrow.css +12 -7
  92. package/css/page-header.css +99 -14
  93. package/css/pagination.css +175 -135
  94. package/css/password-input.css +222 -219
  95. package/css/pin-input.css +101 -67
  96. package/css/pointer.css +36 -0
  97. package/css/popconfirm.css +185 -94
  98. package/css/popover.css +121 -77
  99. package/css/progress.css +60 -12
  100. package/css/prompt-input.css +224 -0
  101. package/css/question-flow.css +513 -0
  102. package/css/radio-group.css +147 -30
  103. package/css/rating.css +193 -43
  104. package/css/reasoning.css +336 -0
  105. package/css/reset.css +84 -6
  106. package/css/resizable.css +237 -0
  107. package/css/scroll-area.css +68 -7
  108. package/css/scrollbar.css +47 -13
  109. package/css/segmented.css +94 -29
  110. package/css/select.css +288 -274
  111. package/css/separator.css +101 -1
  112. package/css/side-nav.css +133 -75
  113. package/css/signature-pad.css +74 -54
  114. package/css/skeleton.css +84 -11
  115. package/css/slider.css +132 -39
  116. package/css/sortable.css +198 -0
  117. package/css/spinner.css +126 -12
  118. package/css/splitter.css +29 -8
  119. package/css/statistic.css +55 -0
  120. package/css/steps.css +206 -72
  121. package/css/switch.css +268 -36
  122. package/css/table.css +695 -118
  123. package/css/tabs.css +604 -42
  124. package/css/tag-group.css +219 -0
  125. package/css/tag.css +118 -28
  126. package/css/tags-input.css +156 -274
  127. package/css/text-field.css +101 -249
  128. package/css/time-field.css +100 -128
  129. package/css/time-picker.css +323 -252
  130. package/css/time-range-picker.css +719 -0
  131. package/css/timeline.css +202 -68
  132. package/css/timer.css +56 -52
  133. package/css/timestamp.css +34 -0
  134. package/css/toast.css +373 -144
  135. package/css/toggle-group.css +309 -76
  136. package/css/toggle.css +116 -85
  137. package/css/tone.css +47 -0
  138. package/css/tool-call.css +421 -0
  139. package/css/toolbar.css +181 -33
  140. package/css/tooltip.css +107 -36
  141. package/css/tour.css +183 -152
  142. package/css/transfer.css +351 -138
  143. package/css/tree-select.css +323 -216
  144. package/css/tree.css +294 -62
  145. package/css/truncate.css +65 -0
  146. package/css/typography.css +228 -5
  147. package/css/undefined.css +10 -1
  148. package/css/virtualizer.css +9 -10
  149. package/css/visually-hidden.css +7 -0
  150. package/css/watermark.css +7 -0
  151. package/family/action-control.css +487 -0
  152. package/family/collection-item.css +721 -0
  153. package/family/field-chrome.css +298 -0
  154. package/family/motion.css +166 -0
  155. package/family/swatch.css +59 -0
  156. package/index.css +41705 -126
  157. package/index.unlayered.css +33692 -17339
  158. package/package.json +51 -17
  159. package/css/calendar.css +0 -367
  160. package/css/code-block.css +0 -91
  161. package/css/composer.css +0 -134
  162. package/css/countdown.css +0 -26
  163. package/css/dynamic-input.css +0 -220
  164. package/css/ellipsis.css +0 -52
  165. package/css/hotkeys.css +0 -90
  166. package/css/popselect.css +0 -391
  167. package/css/qr-code.css +0 -55
  168. package/css/result.css +0 -119
  169. package/css/space.css +0 -117
  170. package/css/thread.css +0 -120
  171. package/css/time.css +0 -25
package/css/tour.css CHANGED
@@ -1,50 +1,15 @@
1
- @layer xihan.motion {
2
- /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
- 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
- @keyframes xh-fade-in {
5
- from {
6
- opacity: 0;
7
- }
8
-
9
- to {
10
- opacity: 1;
11
- }
12
- }
13
-
14
- @keyframes xh-fade-out {
15
- from {
16
- opacity: 1;
17
- }
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
18
5
 
19
- to {
20
- opacity: 0;
21
- }
22
- }
6
+ /* 定义 tour 样式。 */
23
7
 
24
- @keyframes xh-pop-in {
25
- from {
26
- opacity: 0;
27
- scale: var(--xh-motion-scale-enter);
28
- }
29
-
30
- to {
31
- opacity: 1;
32
- scale: 1;
33
- }
34
- }
35
-
36
- @keyframes xh-pop-out {
37
- from {
38
- opacity: 1;
39
- scale: 1;
40
- }
41
-
42
- to {
43
- opacity: 0;
44
- scale: var(--xh-motion-scale-enter);
45
- }
46
- }
8
+ /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立。 */
9
+ @import '../family/motion.css';
10
+ @import '../family/action-control.css';
47
11
 
12
+ @layer xihan.motion {
48
13
  /* 高亮框落定时那一下呼吸:换步时视线要跟着它走,纯位移太容易被漏看 */
49
14
  @keyframes xh-tour-spotlight-in {
50
15
  from {
@@ -58,7 +23,7 @@
58
23
  }
59
24
  }
60
25
 
61
- /* 退场反向放大淡出,与进场对称 */
26
+ /* 退场反向放大淡出,幅度比进场浅一档 */
62
27
  @keyframes xh-tour-spotlight-out {
63
28
  from {
64
29
  opacity: 1;
@@ -67,7 +32,7 @@
67
32
 
68
33
  to {
69
34
  opacity: 0;
70
- scale: calc(2 - var(--xh-motion-scale-enter));
35
+ scale: calc(2 - var(--xh-motion-scale-exit));
71
36
  }
72
37
  }
73
38
  }
@@ -81,8 +46,8 @@
81
46
  /* 根节点只是几个浮层的归属容器,不参与排版。
82
47
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
83
48
  [data-scope='tour'][data-part='root'] {
84
- /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
85
- --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-text));
49
+ /* 作者塞进部件里的图标按控件档取字形尺(md = 20px);四颗按钮各自再按 sm 档收一档 */
50
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-md));
86
51
 
87
52
  color: var(--xh-tour-fg, var(--xh-fg-default));
88
53
  }
@@ -90,14 +55,14 @@
90
55
  /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
91
56
  关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
92
57
  [data-scope='tour'][data-part='content'] {
93
- --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-text));
58
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-md));
94
59
  }
95
60
 
96
61
  /* 遮罩:整页压暗,把注意力逼到高亮框那一块上 */
97
62
  [data-scope='tour'][data-part='backdrop'] {
98
63
  position: fixed;
99
64
  inset: 0;
100
- z-index: var(--xh-tour-backdrop-layer, var(--xh-layer-modal));
65
+ z-index: var(--xh-tour-backdrop-layer, var(--xh-_layer, var(--xh-layer-modal)));
101
66
  background: var(--xh-tour-backdrop-bg, var(--xh-bg-overlay));
102
67
  }
103
68
 
@@ -117,18 +82,29 @@
117
82
  这里只管长相:一圈描边 + 一片铺满视口的投影当暗幕,中间那块因此是亮的——
118
83
  这就是"洞"。不吃指针:它盖在目标上面,吃了的话目标就再也点不动了 */
119
84
  [data-scope='tour'][data-part='spotlight'] {
120
- z-index: var(--xh-tour-spotlight-layer, var(--xh-layer-modal));
85
+ --xh-_tour-spotlight-shroud: transparent;
86
+ --xh-_tour-spotlight-radius: var(--xh-shape-surface);
87
+
88
+ z-index: var(--xh-tour-spotlight-layer, var(--xh-_layer, var(--xh-layer-modal)));
121
89
  pointer-events: none;
122
- border-radius: var(--xh-tour-spotlight-radius, var(--xh-shape-surface));
90
+ border-radius: var(
91
+ --xh-tour-spotlight-radius,
92
+ var(--xh-_tour-spotlight-radius, var(--xh-shape-surface))
93
+ );
123
94
  box-shadow:
124
95
  0 0 0 var(--xh-stroke-thick) var(--xh-tour-spotlight-ring, var(--xh-ring-focus)),
125
- 0 0 0 100vmax var(--xh-tour-spotlight-shroud, var(--xh-bg-overlay));
96
+ 0 0 0 100vmax var(--xh-_tour-spotlight-shroud);
126
97
  /* 换步时框自己滑过去,用户的视线跟得上;逻辑属性照样可过渡 */
127
98
  transition:
128
- inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
129
- inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
130
- inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
131
- block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
99
+ inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
100
+ inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
101
+ inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
102
+ block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
103
+ border-radius var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous);
104
+ }
105
+
106
+ [data-scope='tour'][data-part='spotlight'][data-dimmed] {
107
+ --xh-_tour-spotlight-shroud: var(--xh-tour-spotlight-shroud, var(--xh-bg-overlay));
132
108
  }
133
109
 
134
110
  [data-scope='tour'][data-part='spotlight'][hidden] {
@@ -136,7 +112,7 @@
136
112
  }
137
113
 
138
114
  [data-scope='tour'][data-part='spotlight'][data-state='open'] {
139
- animation: xh-tour-spotlight-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
115
+ animation: xh-tour-spotlight-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
140
116
  }
141
117
 
142
118
  /* 退场与气泡并行播,同一段时长;收起那一帧 hidden 由宿主押后到气泡的退场结束 */
@@ -144,13 +120,9 @@
144
120
  animation: xh-tour-spotlight-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
145
121
  }
146
122
 
147
- /* 高亮框在场时遮罩让位:暗幕已经由那圈铺满视口的投影负责,
148
- 两层叠加会把页面压得过暗,而且洞里也会跟着变暗——洞就白挖了。
149
- 居中步的高亮框带 hidden,此时遮罩照常压暗(那一步本来就没有要突出的元素)。
150
- 两条兄弟选择器各管一个方向,谁写在前面都算数:遮罩与高亮框同为浮层落点里的兄弟,
151
- 不再共有 root 这个祖先 */
152
- [data-scope='tour'][data-part='backdrop']:has(~ [data-scope='tour'][data-part='spotlight']:not([hidden])),
153
- [data-scope='tour'][data-part='spotlight']:not([hidden]) ~ [data-scope='tour'][data-part='backdrop'] {
123
+ /* 锚定步的暗幕由 Spotlight 自己挖洞,Backdrop 只负责拦截背景交互。状态直接由连接层给,
124
+ 不依赖两个 Portal shell 在落点里的相对顺序。 */
125
+ [data-scope='tour'][data-part='backdrop'][data-position='anchored'] {
154
126
  background: transparent;
155
127
  }
156
128
 
@@ -160,8 +132,11 @@
160
132
  /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,气泡继承它限高;
161
133
  居中步与尚未落位时不额外限高 */
162
134
  --xh-_tour-available-h: 100vh;
135
+ /* 落定那一侧的可用宽度,同样由定位引擎经内联自定义属性写进来,行内轴据此夹取;
136
+ 引擎没算(尚未落位 / 无引擎 / 贴边归零)时退到视口宽 */
137
+ --xh-_tour-available-w: 100vw;
163
138
 
164
- z-index: var(--xh-tour-positioner-layer, var(--xh-layer-popover));
139
+ z-index: var(--xh-tour-positioner-layer, var(--xh-_layer, var(--xh-layer-popover)));
165
140
  pointer-events: none;
166
141
  }
167
142
 
@@ -180,36 +155,64 @@
180
155
  display: none;
181
156
  }
182
157
 
158
+ /* 缩放原点与进场位移按落定的那一侧给:气泡从贴着锚点的那条边涨开、沿主轴退让一小段。
159
+ 两个槽由 content 继承。只认锚定步:居中步没有锚点,data-placement 仍带着缺省值。
160
+ placement 是物理方向(引擎按 top / right / bottom / left 出值),origin 与 translate
161
+ 也是物理量,两边同轴,不随书写方向翻 */
162
+ [data-scope='tour'][data-part='positioner'][data-position='anchored'][data-placement^='top'] {
163
+ --xh-_overlay-origin-y: 100%;
164
+ --xh-_overlay-enter-down: 1;
165
+ }
166
+
167
+ [data-scope='tour'][data-part='positioner'][data-position='anchored'][data-placement^='bottom'] {
168
+ --xh-_overlay-origin-y: 0;
169
+ --xh-_overlay-enter-up: 1;
170
+ }
171
+
172
+ [data-scope='tour'][data-part='positioner'][data-position='anchored'][data-placement^='left'] {
173
+ --xh-_overlay-origin-x: 100%;
174
+ --xh-_overlay-enter-right: 1;
175
+ }
176
+
177
+ [data-scope='tour'][data-part='positioner'][data-position='anchored'][data-placement^='right'] {
178
+ --xh-_overlay-origin-x: 0;
179
+ --xh-_overlay-enter-left: 1;
180
+ }
181
+
183
182
  [data-scope='tour'][data-part='content'] {
184
183
  position: relative;
185
184
  display: flex;
186
185
  flex-direction: column;
187
186
  gap: var(--xh-tour-gap, var(--xh-space-2));
188
187
  inline-size: max-content;
189
- max-inline-size: var(--xh-tour-max-w, var(--xh-overlay-max-w-lg));
188
+ /* 静态档与落位后的可用宽度取小:窄视口下面板伸出去,最右侧的内容就点不到了 */
189
+ max-inline-size: min(var(--xh-tour-max-w, var(--xh-overlay-max-w-lg)), var(--xh-_tour-available-w));
190
190
  padding-block: var(--xh-tour-py, var(--xh-surface-py-md));
191
191
  padding-inline: var(--xh-tour-px, var(--xh-surface-px-md));
192
192
  /* 引导步骤的正文长度由作者定,矮视口下不限高气泡会整块伸出视口 */
193
193
  max-block-size: min(var(--xh-tour-max-h, var(--xh-overlay-max-h)), var(--xh-_tour-available-h));
194
- border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-border-default));
195
- border-radius: var(--xh-tour-radius, var(--xh-shape-surface));
196
- background: var(--xh-tour-bg, var(--xh-bg-surface));
197
- color: var(--xh-tour-fg, var(--xh-fg-default));
198
- box-shadow: var(--xh-tour-shadow, var(--xh-elevation-sheet));
194
+ /* M4 sheet 三件套(§8.4),与 dialog 同源:1px 描边是它的边界,不透明底,影只是加成 */
195
+ border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-material-elevated-border));
196
+ border-radius: var(--xh-tour-radius, var(--xh-shape-overlay));
197
+ background: var(--xh-tour-bg, var(--xh-material-elevated-bg));
198
+ color: var(--xh-tour-fg, var(--xh-material-elevated-fg));
199
+ box-shadow: var(--xh-tour-shadow, var(--xh-material-elevated-shadow));
199
200
  pointer-events: auto;
201
+ /* 进退场的缩放锚在贴着锚点的那条边上;两个分量由 positioner 按 placement 写进私有槽 */
202
+ transform-origin: var(--xh-_overlay-origin-x, 50%) var(--xh-_overlay-origin-y, 50%);
200
203
  }
201
204
 
202
205
  /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 popover 一致:
203
206
  收起态连接层会给 content 打 hidden,补上这条退场动画就一帧都播不出来。
204
207
  真正的收起由退场闸门落成内联 display,节点始终留在原地。 */
205
208
 
206
- /* 焦点落在气泡本身(Enter/Space 归"下一步"管),但它是纯容器,不画焦点环 */
207
- [data-scope='tour'][data-part='content']:focus-visible {
208
- outline: none;
209
- }
209
+ /* 焦点落在气泡本身,Enter / Space 落在它身上推进下一步:它是可操作目标,
210
+ 环由 focus.css 的默认内收环画,这里不另写 */
210
211
 
211
212
  [data-scope='tour'][data-part='content'][data-state='open'] {
212
- animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
213
+ animation: xh-overlay-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
214
+ /* 只在开着的这一档挂:合成层随 data-state 一起收走,收起后不再占着 */
215
+ will-change: opacity, scale, translate;
213
216
  }
214
217
 
215
218
  /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
@@ -229,13 +232,14 @@
229
232
  否则长标题会直接钻到按钮底下。只在真有关闭按钮时让位。 */
230
233
  [data-scope='tour'][data-part='content']:has([data-scope='tour'][data-part='close-trigger'])
231
234
  [data-scope='tour'][data-part='title'] {
232
- padding-inline-end: calc(var(--xh-tour-close-size, var(--xh-control-h-sm)) + var(--xh-space-2));
235
+ padding-inline-end: calc(var(--xh-tour-close-size, var(--xh-control-h-sm)) + var(--xh-surface-action-inset));
233
236
  }
234
237
 
238
+ /* 说明文字走说明档(§6.4):13px + fg-muted */
235
239
  [data-scope='tour'][data-part='description'] {
236
240
  margin: 0;
237
- font-size: var(--xh-text-body-size);
238
- line-height: var(--xh-text-body-leading);
241
+ font-size: var(--xh-text-secondary-size);
242
+ line-height: var(--xh-leading-normal);
239
243
  color: var(--xh-tour-description-fg, var(--xh-fg-muted));
240
244
  }
241
245
 
@@ -245,100 +249,107 @@
245
249
  color: var(--xh-tour-progress-fg, var(--xh-fg-subtle));
246
250
  }
247
251
 
248
- [data-scope='tour'][data-part='prev-trigger'],
249
- [data-scope='tour'][data-part='next-trigger'],
250
- [data-scope='tour'][data-part='skip-trigger'] {
252
+ /* 圆点组:一步一颗,横排 */
253
+ [data-scope='tour'][data-part='progress-indicator'] {
251
254
  display: inline-flex;
252
255
  align-items: center;
253
- justify-content: center;
254
- block-size: var(--xh-control-h-sm);
255
- padding-inline: var(--xh-tour-skip-trigger-px, var(--xh-control-px-md));
256
- border: var(--xh-stroke-thin) solid transparent;
257
- border-radius: var(--xh-tour-action-radius, var(--xh-shape-control));
258
- font-size: var(--xh-text-secondary-size);
259
- cursor: pointer;
256
+ gap: var(--xh-tour-progress-indicator-gap, var(--xh-space-1));
260
257
  }
261
258
 
262
- [data-scope='tour'][data-part='prev-trigger'][hidden],
263
- [data-scope='tour'][data-part='next-trigger'][hidden],
264
- [data-scope='tour'][data-part='skip-trigger'][hidden] {
259
+ [data-scope='tour'][data-part='progress-indicator'][hidden] {
265
260
  display: none;
266
261
  }
267
262
 
268
- /* 主按钮:整条引导的主线动作 */
269
- [data-scope='tour'][data-part='next-trigger'] {
270
- background: var(--xh-tour-next-bg, var(--xh-bg-brand));
271
- color: var(--xh-tour-next-fg, var(--xh-fg-on-brand));
263
+ /* 圆点:8px 正圆取 circle(§6.3 分页点统一款),未走到的一档取中性描边色。
264
+ 宽度与底色都随状态换,换步那一下能看出进度在推进 */
265
+ [data-scope='tour'][data-part='progress-dot'] {
266
+ inline-size: var(--xh-space-2);
267
+ block-size: var(--xh-space-2);
268
+ border-radius: var(--xh-shape-circle);
269
+ background: var(--xh-tour-progress-dot-bg, var(--xh-border-default));
270
+ transition:
271
+ inline-size var(--xh-motion-duration-micro) var(--xh-motion-ease-continuous),
272
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
272
273
  }
273
274
 
274
- [data-scope='tour'][data-part='next-trigger']:hover {
275
- background: var(--xh-tour-next-bg-hover, var(--xh-bg-brand-hover));
275
+ /* 走过的步:中性色加重一档 */
276
+ [data-scope='tour'][data-part='progress-dot'][data-complete] {
277
+ background: var(--xh-tour-progress-dot-bg-complete, var(--xh-border-strong));
276
278
  }
277
279
 
278
- [data-scope='tour'][data-part='prev-trigger'],
279
- [data-scope='tour'][data-part='skip-trigger'] {
280
- background: transparent;
281
- color: var(--xh-fg-muted);
280
+ /* 当前步:拉成 20px 胶囊并换品牌色;一维对象取 pill */
281
+ [data-scope='tour'][data-part='progress-dot'][data-current] {
282
+ inline-size: var(--xh-space-5);
283
+ border-radius: var(--xh-shape-pill);
284
+ background: var(--xh-tour-progress-dot-bg-current, var(--xh-bg-brand));
282
285
  }
283
286
 
284
- [data-scope='tour'][data-part='prev-trigger'] {
285
- border-color: var(--xh-border-control);
286
- color: var(--xh-fg-default);
287
- }
288
-
289
- [data-scope='tour'][data-part='prev-trigger']:hover:not(:disabled),
290
- [data-scope='tour'][data-part='skip-trigger']:hover {
291
- background: var(--xh-bg-subtle);
287
+ /*
288
+ * —— 末行三颗按钮 ——
289
+ * 上一步 / 下一步 / 跳过都是气泡末行的文字按钮(§9.1):盒型、sm 档几何、四态面、0.97 按压并换底、粗指针命中区与
290
+ * 强制色由家族配方按连接层投影的 data-xh-action-variant / -size 给出。这里只把公开槽桥接到矩阵之前
291
+ * (使用者槽 → 形态矩阵 → 家族缺省)与几何映射;内衬与圆角槽三颗共用。
292
+ */
293
+ [data-scope='tour'][data-part='prev-trigger'],
294
+ [data-scope='tour'][data-part='next-trigger'],
295
+ [data-scope='tour'][data-part='skip-trigger'] {
296
+ --xh-action-padding-inline: var(--xh-tour-skip-trigger-px, var(--xh-_action-profile-padding-inline));
297
+ --xh-action-radius: var(--xh-tour-action-radius, var(--xh-shape-control));
298
+ /* 作者塞进按钮的图标随档取字形尺(sm = 16px) */
299
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-_action-profile-glyph-size));
292
300
  }
293
301
 
294
- /* 单体控件用原生 disabled(集合条目才用 [data-disabled]):首步的上一步就是这个形态 */
295
- [data-scope='tour'][data-part='prev-trigger']:disabled {
296
- color: var(--xh-fg-disabled);
297
- border-color: var(--xh-border-subtle);
298
- cursor: not-allowed;
302
+ [data-scope='tour'][data-part='prev-trigger'][hidden],
303
+ [data-scope='tour'][data-part='next-trigger'][hidden],
304
+ [data-scope='tour'][data-part='skip-trigger'][hidden] {
305
+ display: none;
299
306
  }
300
307
 
308
+ /* 下一步是整条引导的主线动作,显式 solid(§7.2 第 2 条):底、字与影三组使用者槽桥到配方 solid 列之前 */
309
+ [data-scope='tour'][data-part='next-trigger'] {
310
+ --xh-action-bg-rest: var(--xh-tour-next-bg, var(--xh-_action-variant-bg-rest));
311
+ --xh-action-bg-hover: var(--xh-tour-next-bg-hover, var(--xh-_action-variant-bg-hover));
312
+ --xh-action-bg-focus-visible: var(--xh-tour-next-bg, var(--xh-_action-variant-bg-focus-visible));
313
+ --xh-action-fg-rest: var(--xh-tour-next-fg, var(--xh-_action-variant-fg-rest));
314
+ --xh-action-fg-hover: var(--xh-tour-next-fg, var(--xh-_action-variant-fg-hover));
315
+ --xh-action-fg-pressed: var(--xh-tour-next-fg, var(--xh-_action-variant-fg-pressed));
316
+ --xh-action-fg-focus-visible: var(--xh-tour-next-fg, var(--xh-_action-variant-fg-focus-visible));
317
+ --xh-action-shadow-rest: var(--xh-tour-next-shadow, none);
318
+ }
319
+
320
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
321
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的 */
322
+ [data-scope='tour'][data-part='next-trigger'][data-xh-action-variant='solid']:focus-visible {
323
+ --xh-action-ring-color-focus-visible: currentColor;
324
+ }
325
+
326
+ /*
327
+ * 关闭钮是气泡角落的单图标钮(§9.1):正方盒、sm 档几何、ghost 四态面、0.97 按压并换底与粗指针命中区
328
+ * 由家族配方给出——白面上走画布承载阶梯悬停 --xh-bg-subtle(100)→ 按下 --xh-bg-subtle-hover(200),
329
+ * 焦点面透明吃库环。这里只把公开槽桥接到矩阵之前(使用者槽 → 形态矩阵 → 家族缺省)与摆放;
330
+ * 静息前景取 muted 字色,悬停 / 按下 / 聚焦回到 fg-default。
331
+ */
301
332
  [data-scope='tour'][data-part='close-trigger'] {
333
+ --xh-action-visual-size: var(--xh-tour-close-size, var(--xh-_action-profile-visual-size));
334
+ --xh-action-radius: var(--xh-tour-close-radius, var(--xh-shape-control));
335
+ --xh-action-bg-hover: var(--xh-tour-close-bg-hover, var(--xh-_action-variant-bg-hover));
336
+ --xh-action-bg-pressed: var(--xh-tour-close-bg-active, var(--xh-_action-variant-bg-pressed));
337
+ --xh-action-fg-rest: var(--xh-tour-close-fg, var(--xh-fg-muted));
338
+ --xh-action-fg-hover: var(--xh-tour-close-fg-hover, var(--xh-_action-variant-fg-hover));
339
+ --xh-action-fg-pressed: var(--xh-tour-close-fg-hover, var(--xh-_action-variant-fg-pressed));
340
+ --xh-action-fg-focus-visible: var(--xh-tour-close-fg-hover, var(--xh-_action-variant-fg-focus-visible));
341
+ /* 作者塞进按钮的图标随档取字形尺(sm = 16px),与皮肤画的兜底字形同一把尺 */
342
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-_action-profile-glyph-size));
343
+
302
344
  position: absolute;
303
- inset-block-start: var(--xh-space-2);
304
- inset-inline-end: var(--xh-space-2);
305
- display: inline-flex;
306
- align-items: center;
307
- justify-content: center;
308
- block-size: var(--xh-tour-close-size, var(--xh-control-h-sm));
309
- inline-size: var(--xh-tour-close-size, var(--xh-control-h-sm));
310
- border: 0;
311
- border-radius: var(--xh-tour-close-radius, var(--xh-shape-control));
312
- background: transparent;
313
- color: var(--xh-fg-muted);
314
- cursor: pointer;
315
- transition:
316
- background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
317
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
345
+ inset-block-start: var(--xh-surface-action-inset);
346
+ inset-inline-end: var(--xh-surface-action-inset);
318
347
  }
319
348
 
320
349
  [data-scope='tour'][data-part='close-trigger'][hidden] {
321
350
  display: none;
322
351
  }
323
352
 
324
- [data-scope='tour'][data-part='close-trigger']:hover {
325
- background: var(--xh-tour-close-bg-hover, var(--xh-bg-subtle-hover));
326
- color: var(--xh-fg-default);
327
- }
328
-
329
- [data-scope='tour'][data-part='close-trigger']:active {
330
- background: var(--xh-tour-close-bg-active, var(--xh-bg-subtle-active));
331
- scale: var(--xh-motion-scale-press);
332
- }
333
-
334
- [data-scope='tour'][data-part='prev-trigger']:focus-visible,
335
- [data-scope='tour'][data-part='next-trigger']:focus-visible,
336
- [data-scope='tour'][data-part='skip-trigger']:focus-visible,
337
- [data-scope='tour'][data-part='close-trigger']:focus-visible {
338
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
339
- outline-offset: var(--xh-ring-offset);
340
- }
341
-
342
353
  /* 箭头的底色与描边色,几何在 overlay-arrow.css。
343
354
  交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中 */
344
355
  [data-scope='tour'][data-part='arrow'] {
@@ -348,8 +359,8 @@
348
359
  --xh-_overlay-arrow-x: var(--xh-_tour-arrow-x);
349
360
  --xh-_overlay-arrow-y: var(--xh-_tour-arrow-y);
350
361
 
351
- background: var(--xh-tour-bg, var(--xh-bg-surface));
352
- border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-border-default));
362
+ background: var(--xh-tour-bg, var(--xh-material-elevated-bg));
363
+ border: var(--xh-stroke-thin) solid var(--xh-tour-border, var(--xh-material-elevated-border));
353
364
  }
354
365
 
355
366
  /* 居中步没有锚点,连接层会给箭头发 hidden */
@@ -371,10 +382,30 @@
371
382
  }
372
383
 
373
384
  @layer xihan.components {
374
- /* 气泡限高之后只让正文让步:标题与上下步按钮滚出视线就点不到了 */
385
+ /* 气泡限高之后只让正文让步:标题与上下步按钮滚出视线就点不到了。
386
+ 模态气泡里的原生细条滚动面(§6.6):细条由 reset 层统一给,滚到头不把页面一起带走;内容高度不动态变化,不写 gutter */
375
387
  [data-scope='tour'][data-part='description'] {
376
388
  flex: 1 1 auto;
377
389
  min-block-size: 0;
378
390
  overflow-y: auto;
391
+ overscroll-behavior: contain;
392
+ }
393
+
394
+ @media (forced-colors: active) {
395
+ /* 这一档丢掉底色:走过的那几颗改由一圈描边表出,当前那颗仍靠宽度分辨 */
396
+ [data-scope='tour'][data-part='progress-dot'][data-complete] {
397
+ outline: var(--xh-stroke-thin) solid CanvasText;
398
+ }
399
+ }
400
+
401
+ @media print {
402
+ /* 打印:定位层与遮罩是交互期才存在的东西,落到纸上只会盖住底下的正文。
403
+ 收起写在这份皮肤里而不是 reset:reset 层排在组件层之前,组件层里任何一条 display 都压得住它。
404
+ 居中那一档的选择器多带一个属性、权重高一级,所以把它一并列出来,靠同权重下的书写顺序压回去。 */
405
+ [data-scope='tour'][data-part='backdrop'],
406
+ [data-scope='tour'][data-part='positioner'],
407
+ [data-scope='tour'][data-part='positioner'][data-position='center'] {
408
+ display: none;
409
+ }
379
410
  }
380
411
  }