@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/anchor.css CHANGED
@@ -1,3 +1,15 @@
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
+ */
5
+
6
+ /* 定义 anchor 样式。 */
7
+
8
+ /* 链接归 Collection Item 导航当前(nav 语境):面、字色、字重、光标与按压时间线由家族配方按投影的家族角色给,
9
+ 本皮肤只映射桥接槽。2px 指示线由本皮肤画:目录里放了 indicator 部件就由部件在轨道上滑动,
10
+ 没放则当前那一节的链接自画一条静态线 */
11
+ @import '../family/collection-item.css';
12
+
1
13
  @layer xihan.components {
2
14
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
15
  [data-scope='anchor'] {
@@ -10,11 +22,12 @@
10
22
  /* 尺寸档只换这两个私有槽,链接从 root 继承它们,换档不必给每个部件各写一条选择器 */
11
23
  --xh-_anchor-font-size: var(--xh-control-font-md);
12
24
  --xh-_anchor-link-px: var(--xh-control-px-md);
13
- /* 当前那一节的指示条与文字随语气走。没写 data-tone 时这两个槽都没被声明,退回原来的品牌色。
14
- 指示条是装饰性的色条,取柔和档;文字要压在普通背景上读,取语气的文字档。
25
+ /* 当前那一节的指示条与文字随语气走。没写 data-tone 时这两个槽都没被声明,退回品牌色。
26
+ 指示条是装饰性的色条,取柔和档;文字要压在普通背景上读,取语气的文字档——
27
+ 导航当前页(§7.3)缺省是 --xh-fg-brand-strong,比指示条深一档。
15
28
  聚焦环不在其列,它恒是 --xh-ring-focus */
16
29
  --xh-_anchor-accent: var(--xh-_tone-soft, var(--xh-fg-brand));
17
- --xh-_anchor-accent-text: var(--xh-_tone-fg, var(--xh-fg-brand));
30
+ --xh-_anchor-accent-text: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
18
31
 
19
32
  color: var(--xh-anchor-fg, var(--xh-fg-muted));
20
33
  font-size: var(--xh-anchor-font-size, var(--xh-_anchor-font-size));
@@ -72,44 +85,51 @@
72
85
  display: none;
73
86
  }
74
87
 
88
+ /* 链接的几何、字号与面全经家族桥接槽:静息 muted / regular,悬停走白底承载 hover 100 + default 字,
89
+ 按下 pressed 200 只换面(§7.2 / §9.2);当前那一节(§7.3 导航当前页)brand-strong 字色(随语气的
90
+ --xh-_anchor-accent-text)+ medium 字重都跟着变,2px 指示线放了 indicator 部件由部件滑动、没放则由
91
+ 下面的静态线规则画在当前链接自己身上。本条 (0,2,0) 压过家族基础块 (0,1,0),不能再写 color / background。
92
+ position: relative 是静态线的定位参照 */
75
93
  [data-scope='anchor'][data-part='link'] {
94
+ --xh-collection-block-padding: var(--xh-anchor-link-py, var(--xh-space-1));
95
+ --xh-collection-inline-padding: var(--xh-anchor-link-px, var(--xh-_anchor-link-px));
96
+ --xh-collection-radius: var(--xh-anchor-link-radius, var(--xh-shape-control));
97
+ --xh-collection-font-size: var(--xh-anchor-font-size, var(--xh-_anchor-font-size));
98
+ --xh-collection-fg-rest: var(--xh-anchor-fg, var(--xh-fg-muted));
99
+ --xh-collection-bg-hover: var(--xh-anchor-link-bg-hover, var(--xh-bg-subtle));
100
+ --xh-collection-fg-hover: var(--xh-anchor-link-fg-hover, var(--xh-fg-default));
101
+ --xh-collection-bg-pressed: var(--xh-anchor-link-bg-pressed, var(--xh-bg-subtle-hover));
102
+ --xh-collection-fg-current: var(--xh-anchor-link-fg-current, var(--xh-_anchor-accent-text));
103
+ --xh-collection-font-weight-current: var(--xh-anchor-link-font-weight-current, var(--xh-font-weight-medium));
104
+
105
+ position: relative;
76
106
  display: inline-flex;
77
107
  align-items: center;
78
108
  /* 一节的标题可能很长,压不住会把整列撑开 */
79
109
  max-inline-size: var(--xh-anchor-link-max-w, var(--xh-nav-link-max-w));
80
- padding-block: var(--xh-anchor-link-py, var(--xh-space-1));
81
- padding-inline: var(--xh-anchor-link-px, var(--xh-_anchor-link-px));
82
- border-radius: var(--xh-anchor-link-radius, var(--xh-shape-control));
83
- color: inherit;
110
+ /* 行高随 root 的行距槽:家族基础块给条目写了 leading-normal,这里接回 root 那一支 */
111
+ line-height: var(--xh-anchor-leading, var(--xh-leading-normal));
84
112
  white-space: nowrap;
85
113
  text-decoration: none;
86
114
  text-overflow: ellipsis;
87
115
  overflow: hidden;
88
- transition: color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
89
116
  }
90
117
 
91
118
  [data-scope='anchor'][data-part='link'][hidden] {
92
119
  display: none;
93
120
  }
94
121
 
95
- [data-scope='anchor'][data-part='link']:hover {
96
- color: var(--xh-anchor-link-fg-hover, var(--xh-fg-default));
97
- }
98
-
99
- [data-scope='anchor'][data-part='link']:focus-visible {
100
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
101
- outline-offset: var(--xh-ring-offset);
102
- }
103
-
104
- /* 当前那一节:颜色与字重都跟着变,不只靠指示条——
105
- 指示条是可选部件,作者不渲染它时"当前在哪"仍然要看得出来 */
106
- [data-scope='anchor'][data-part='link'][data-current] {
107
- color: var(--xh-anchor-link-fg-active, var(--xh-_anchor-accent-text));
108
- font-weight: var(--xh-anchor-link-font-weight-active, var(--xh-font-weight-medium));
122
+ /* 链接里另有图标时,省略号只裁这一段文字 */
123
+ [data-scope='anchor'][data-part='link-text'] {
124
+ min-inline-size: 0;
125
+ white-space: nowrap;
126
+ text-overflow: ellipsis;
127
+ overflow: hidden;
109
128
  }
110
129
 
111
130
  /* 主轴上的位置与长度由连接层写成内联样式(它量得到,样式表量不到);
112
- 这里只管交叉轴的贴边与粗细,以及长什么样 */
131
+ 这里只管交叉轴的贴边与粗细,以及长什么样。它是可选部件——不渲染它时,
132
+ 当前那一节的链接自画一条同规格的静态线(见下) */
113
133
  [data-scope='anchor'][data-part='indicator'] {
114
134
  position: absolute;
115
135
  display: block;
@@ -120,8 +140,8 @@
120
140
  border-radius: var(--xh-anchor-indicator-radius, var(--xh-shape-pill));
121
141
  background: var(--xh-anchor-indicator-color, var(--xh-_anchor-accent));
122
142
  transition:
123
- inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
124
- block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
143
+ inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
144
+ block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous);
125
145
  }
126
146
 
127
147
  /* display 会盖掉 hidden 属性的 UA 规则,无激活项时显式让位 */
@@ -136,7 +156,59 @@
136
156
  inline-size: auto;
137
157
  block-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
138
158
  transition:
139
- inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
140
- inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
159
+ inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
160
+ inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous);
161
+ }
162
+
163
+ /* 目录里没放 indicator 部件时,当前那一节的链接自画一条静态指示线(§7.3 导航当前页):
164
+ 与 Tabs line 档同一取法,作者不必为了这条线多放一个部件。
165
+ 线画在当前链接的 ::after 上,以链接盒为定位参照(上面已给 position: relative),
166
+ 厚度 / 颜色 / 圆角与 indicator 部件读同一组槽与缺省——作者改一处,部件与静态线一起改。
167
+ 不做动画:它随 data-current 在链接间跳,滑动只有部件做得到。
168
+ 线贴在链接盒内的那条缘:链接为了省略号收着 overflow,画不到盒外;部件骑在 list 的轨道上(盒外一线宽),
169
+ 两者同侧、差一线宽。主轴两端各退一格 --xh-space-1 避开链接的圆角(overflow 连圆角一起裁,贴满会被
170
+ 切掉两个角),与家族 page 语境的起始侧指示条同一取法。嵌套目录里子级链接随自己的缩进走,部件则始终在
171
+ 外层轨道上。
172
+ 目录里一旦放了 indicator 部件,这条线就收起、位置交给部件滑动,不重复画两条:
173
+ 由 list 按 :has 探一次,把私有槽写成 none,线的 content 读它;链接自己不必再各带一段 :has */
174
+ [data-scope='anchor'][data-part='list']:has([data-scope='anchor'][data-part='indicator']) {
175
+ --xh-_anchor-static-line: none;
176
+ }
177
+
178
+ [data-scope='anchor'][data-part='link'][data-current]::after {
179
+ content: var(--xh-_anchor-static-line, '');
180
+ position: absolute;
181
+ pointer-events: none;
182
+ border-radius: var(--xh-anchor-indicator-radius, var(--xh-shape-pill));
183
+ background: var(--xh-anchor-indicator-color, var(--xh-_anchor-accent));
184
+ }
185
+
186
+ /* 竖排(缺省):贴链接的行向起始缘(与 indicator 部件同一侧,rtl 随逻辑属性镜像) */
187
+ [data-scope='anchor'][data-part='list'][data-orientation='vertical']
188
+ [data-scope='anchor'][data-part='link'][data-current]::after {
189
+ inset-inline-start: 0;
190
+ inset-block: var(--xh-space-1);
191
+ inline-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
192
+ }
193
+
194
+ /* 横排:贴链接的块向末端(底边) */
195
+ [data-scope='anchor'][data-part='list'][data-orientation='horizontal']
196
+ [data-scope='anchor'][data-part='link'][data-current]::after {
197
+ inset-block-end: 0;
198
+ inset-inline: var(--xh-space-1);
199
+ block-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
200
+ }
201
+
202
+ @media (forced-colors: active) {
203
+ /* 指示条画的是一块纯底色,这一档里底色被统一换成 Canvas,条子整根消失,
204
+ "读到哪一节"就只剩链接自己的字重。换成系统高亮色画回来 */
205
+ [data-scope='anchor'][data-part='indicator'] {
206
+ background: Highlight;
207
+ }
208
+
209
+ /* 没放部件时当前链接自画的那条静态线同样是一块纯底色,同一档换成系统高亮色 */
210
+ [data-scope='anchor'][data-part='link'][data-current]::after {
211
+ background: Highlight;
212
+ }
141
213
  }
142
214
  }
@@ -0,0 +1,461 @@
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
+ */
5
+
6
+ /* 定义 approval 样式。 */
7
+
8
+ /* 独立皮肤同时传递引入授权行与两颗钮的动作控件配方,full bundle 递归去重。 */
9
+ @import '../family/action-control.css';
10
+
11
+ @layer xihan.motion {
12
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
13
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
14
+
15
+ /* 幅度走令牌,减弱动效时由令牌层归零;位移用独立属性而非 transform 简写 */
16
+ @keyframes xh-approval-in {
17
+ from {
18
+ opacity: 0;
19
+ translate: 0 var(--xh-motion-distance-md);
20
+ }
21
+
22
+ to {
23
+ opacity: 1;
24
+ translate: 0 0;
25
+ }
26
+ }
27
+
28
+ @keyframes xh-approval-result-in {
29
+ from {
30
+ opacity: 0;
31
+ scale: var(--xh-motion-scale-enter);
32
+ }
33
+
34
+ to {
35
+ opacity: 1;
36
+ scale: 1;
37
+ }
38
+ }
39
+
40
+ @keyframes xh-approval-rotate {
41
+ to {
42
+ rotate: 360deg;
43
+ }
44
+ }
45
+ }
46
+
47
+ @layer xihan.components {
48
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
49
+ [data-scope='approval'] {
50
+ --xh-approval-skin: 1;
51
+ }
52
+
53
+ /* 一块要人做决定的静态内容面:--xh-border-default 描边 + surface 底 + 无影(§5.3 边界只由描边承担),
54
+ 作者打了语气时描边染成语气色作强调(下面那条),判定落定后描边退回中性 */
55
+ [data-scope='approval'][data-part='root'] {
56
+ /* 作者塞进标题 / 说明 / 结果条里的图标按档取尺(§6.5),缺省 md;勾选记号另按盒比例量 */
57
+ --xh-_approval-icon-size: var(--xh-glyph-size-md);
58
+ --xh-icon-size: var(--xh-approval-icon-size, var(--xh-_approval-icon-size));
59
+
60
+ /* 尺寸缺省档:不写 data-size 时的取值。三档都只写这批私有槽,
61
+ 公开槽留在读处当首选,作者在祖先上设的覆盖才赢得过档位声明 */
62
+ --xh-_approval-gap: var(--xh-space-3);
63
+ --xh-_approval-p: var(--xh-space-4);
64
+ --xh-_approval-action-h: var(--xh-control-h-md);
65
+ --xh-_approval-action-px: var(--xh-control-px-md);
66
+ --xh-_approval-item-font-size: var(--xh-control-font-md);
67
+ --xh-_approval-note-font-size: var(--xh-control-font-md);
68
+
69
+ display: flex;
70
+ flex-direction: column;
71
+ gap: var(--xh-approval-gap, var(--xh-_approval-gap));
72
+ padding: var(--xh-approval-p, var(--xh-_approval-p));
73
+ border: var(--xh-stroke-thin) solid var(--xh-approval-border, var(--xh-border-default));
74
+ border-radius: var(--xh-approval-radius, var(--xh-shape-surface));
75
+ background: var(--xh-approval-bg, var(--xh-bg-surface));
76
+ box-shadow: var(--xh-approval-shadow, none);
77
+ transition: border-color var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
78
+ animation: xh-approval-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
79
+ }
80
+
81
+ /* 上面声明的 display 会盖掉 UA 的 [hidden]{display:none},这里补回 */
82
+ [data-scope='approval'][data-part='root'][hidden] {
83
+ display: none;
84
+ }
85
+
86
+ /* 语气只染描边:作者定的强调,待决时把这块面从正文里提出来 */
87
+ [data-scope='approval'][data-part='root'][data-tone] {
88
+ border-color: var(--xh-approval-border, var(--xh-_tone, var(--xh-border-default)));
89
+ }
90
+
91
+ /* 判过了就不再抢注意力:语气色边退回中性描边(根面外边不取 subtle,§5.3)。
92
+ 排在语气那条之后:同等特指度,落定要盖得过语气 */
93
+ [data-scope='approval'][data-part='root']:not([data-state='pending']) {
94
+ border-color: var(--xh-approval-border-settled, var(--xh-border-default));
95
+ }
96
+
97
+ /* —— 形态 —— */
98
+ /* 缺省档即 outline,写在上面那条基础规则里。
99
+ 两档排在落定那条之后:它们把描边整个撤掉,排在前面会被落定那条按同等特指度盖回来 */
100
+ /* 底色分区:描边让位给底色,闸门嵌在别人的面里时不再多一圈线;
101
+ 淡底承载面向授权行与拒绝钮下发 hover 200 → pressed 300(§7.2) */
102
+ [data-scope='approval'][data-part='root'][data-variant='subtle'] {
103
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
104
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
105
+
106
+ border-color: transparent;
107
+ background: var(--xh-approval-bg, var(--xh-bg-subtle));
108
+ }
109
+
110
+ /* 无壳内联:卡中卡时不再自带一张面,跟着外层的底走 */
111
+ [data-scope='approval'][data-part='root'][data-variant='ghost'] {
112
+ border-color: transparent;
113
+ background: none;
114
+ box-shadow: none;
115
+ }
116
+
117
+ /* 标题走 Surface 标题档 14/600(§6.4) */
118
+ [data-scope='approval'][data-part='title'] {
119
+ display: block;
120
+ margin: 0;
121
+ color: var(--xh-approval-title-fg, var(--xh-fg-default));
122
+ font-size: var(--xh-approval-title-font-size, var(--xh-text-label-size));
123
+ font-weight: var(--xh-approval-title-font-weight, var(--xh-font-weight-semibold));
124
+ line-height: var(--xh-leading-tight);
125
+ }
126
+
127
+ [data-scope='approval'][data-part='title'][hidden] {
128
+ display: none;
129
+ }
130
+
131
+ [data-scope='approval'][data-part='description'] {
132
+ display: block;
133
+ margin: 0;
134
+ color: var(--xh-approval-description-fg, var(--xh-fg-muted));
135
+ font-size: var(--xh-approval-description-font-size, var(--xh-text-secondary-size));
136
+ line-height: var(--xh-leading-normal);
137
+ }
138
+
139
+ [data-scope='approval'][data-part='description'][hidden] {
140
+ display: none;
141
+ }
142
+
143
+ /* 视觉隐藏的播报区:不能 display:none,那样读屏就取不到它了 */
144
+ [data-scope='approval'][data-part='live-region'] {
145
+ position: absolute;
146
+ inline-size: 1px;
147
+ block-size: 1px;
148
+ padding: 0;
149
+ margin: -1px;
150
+ border: 0;
151
+ overflow: hidden;
152
+ clip-path: inset(50%);
153
+ white-space: nowrap;
154
+ }
155
+
156
+ [data-scope='approval'][data-part='group'] {
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: var(--xh-approval-group-gap, var(--xh-space-1));
160
+ }
161
+
162
+ [data-scope='approval'][data-part='group'][hidden] {
163
+ display: none;
164
+ }
165
+
166
+ /* 一项授权:整行可点、可聚焦,勾选记号在左。盒型、悬停 / 按下 / 禁用面由 Action Control 的 row 档给
167
+ (ghost 形态:白底承载 hover 100 → pressed 200,按下只换面不缩放,§9.2;禁用守卫认 data-disabled),
168
+ 这里只把使用者槽映射到桥接槽,内衬与间距沿用本组件的档位。
169
+ 行高不吃家族的单行档:row 档允许换行、高度随内容,一条会折行的授权文案走正文行高(§6.4) */
170
+ [data-scope='approval'][data-part='item'] {
171
+ --xh-action-gap: var(--xh-approval-item-gap, var(--xh-space-1_5));
172
+ --xh-action-padding-inline: var(--xh-approval-item-px, var(--xh-space-2));
173
+ --xh-action-padding-block: var(--xh-approval-item-py, var(--xh-space-1));
174
+ --xh-action-radius: var(--xh-approval-item-radius, var(--xh-_action-profile-radius));
175
+ --xh-action-font-size: var(--xh-approval-item-font-size, var(--xh-_approval-item-font-size));
176
+ --xh-action-bg-hover: var(--xh-approval-item-bg-hover, var(--xh-_action-variant-bg-hover));
177
+
178
+ line-height: var(--xh-leading-normal);
179
+ }
180
+
181
+ [data-scope='approval'][data-part='item'][hidden] {
182
+ display: none;
183
+ }
184
+
185
+ /* 勾选记号:方框 + 选中态填色,纯装饰不进可访问名。
186
+ 勾按盒比例量(与 Checkbox 同一比例),作者塞进来的图标读同一把尺,不随根上的整档图标放大撑破盒 */
187
+ [data-scope='approval'][data-part='item-indicator'] {
188
+ --xh-_approval-indicator-glyph: calc(var(--xh-approval-indicator-size, var(--xh-control-indicator-size)) * 0.75);
189
+ --xh-icon-size: var(--xh-approval-indicator-icon-size, var(--xh-_approval-indicator-glyph));
190
+
191
+ display: inline-flex;
192
+ flex: none;
193
+ align-items: center;
194
+ justify-content: center;
195
+ border: var(--xh-stroke-thin) solid var(--xh-approval-indicator-border, var(--xh-border-control));
196
+ border-radius: var(--xh-approval-indicator-radius, var(--xh-shape-inset));
197
+ color: var(--xh-approval-indicator-fg, var(--xh-fg-on-brand));
198
+ inline-size: var(--xh-approval-indicator-size, var(--xh-control-indicator-size));
199
+ block-size: var(--xh-approval-indicator-size, var(--xh-control-indicator-size));
200
+ transition:
201
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
202
+ border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
203
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
204
+ }
205
+
206
+ [data-scope='approval'][data-part='item-indicator'][hidden] {
207
+ display: none;
208
+ }
209
+
210
+ /* 没写内容就由皮肤画勾;作者往部件里塞了自己的图形,这条规则即不命中 */
211
+ [data-scope='approval'][data-part='item-indicator']:empty::before {
212
+ content: '';
213
+ display: inline-block;
214
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
215
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
216
+ vertical-align: var(--xh-glyph-baseline-shift);
217
+ background-color: currentColor;
218
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
219
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
220
+ }
221
+
222
+ [data-scope='approval'][data-part='item-indicator'][data-state='checked'] {
223
+ border-color: var(--xh-approval-indicator-border-checked, var(--xh-bg-brand));
224
+ background: var(--xh-approval-indicator-bg-checked, var(--xh-bg-brand));
225
+ }
226
+
227
+ /* 没勾上时把勾隐去而不是撤掉:盒子留在原位,翻面时整行不跳 */
228
+ [data-scope='approval'][data-part='item-indicator'][data-state='unchecked'] {
229
+ color: transparent;
230
+ }
231
+
232
+ /* 勾上的那条读起来更重一档 */
233
+ [data-scope='approval'][data-part='item-text'] {
234
+ display: block;
235
+ flex: 1 1 auto;
236
+ color: var(--xh-approval-item-text-fg, var(--xh-fg-muted));
237
+ }
238
+
239
+ [data-scope='approval'][data-part='item'][data-state='checked'] [data-part='item-text'] {
240
+ color: var(--xh-approval-item-text-fg-checked, var(--xh-fg-default));
241
+ }
242
+
243
+ /* 排在勾选档之后:禁用项无论勾没勾都是禁用色 */
244
+ [data-scope='approval'][data-part='item'][data-disabled] [data-part='item-text'] {
245
+ color: var(--xh-fg-disabled);
246
+ }
247
+
248
+ [data-scope='approval'][data-part='item-text'][hidden] {
249
+ display: none;
250
+ }
251
+
252
+ /* 备注:附在判定上的一句自由文本,占满整行 */
253
+ [data-scope='approval'][data-part='note'] {
254
+ display: block;
255
+ inline-size: 100%;
256
+ padding-inline: var(--xh-approval-note-px, var(--xh-space-2));
257
+ padding-block: var(--xh-approval-note-py, var(--xh-space-1_5));
258
+ border: var(--xh-stroke-thin) solid var(--xh-approval-note-border, var(--xh-border-control));
259
+ border-radius: var(--xh-approval-note-radius, var(--xh-shape-control));
260
+ background: var(--xh-approval-note-bg, var(--xh-bg-surface));
261
+ color: var(--xh-approval-note-fg, var(--xh-fg-default));
262
+ font-family: inherit;
263
+ font-size: var(--xh-approval-note-font-size, var(--xh-_approval-note-font-size));
264
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
265
+ }
266
+
267
+ [data-scope='approval'][data-part='note'][hidden] {
268
+ display: none;
269
+ }
270
+
271
+ [data-scope='approval'][data-part='note']:disabled {
272
+ color: var(--xh-fg-disabled);
273
+ }
274
+
275
+ /* 剩余时间:等宽数字,逐秒跳字时不左右晃 */
276
+ [data-scope='approval'][data-part='timer'] {
277
+ display: block;
278
+ color: var(--xh-approval-timer-fg, var(--xh-fg-muted));
279
+ font-size: var(--xh-approval-timer-font-size, var(--xh-text-caption-size));
280
+ font-variant-numeric: tabular-nums;
281
+ }
282
+
283
+ [data-scope='approval'][data-part='timer'][hidden] {
284
+ display: none;
285
+ }
286
+
287
+ /* 判定结果条:判过了才露出,语气随判定走 */
288
+ [data-scope='approval'][data-part='result'] {
289
+ display: inline-flex;
290
+ align-self: flex-start;
291
+ align-items: center;
292
+ gap: var(--xh-approval-result-gap, var(--xh-space-1_5));
293
+ padding-inline: var(--xh-approval-result-px, var(--xh-space-2));
294
+ padding-block: var(--xh-approval-result-py, var(--xh-space-1));
295
+ border-radius: var(--xh-approval-result-radius, var(--xh-shape-pill));
296
+ background: var(--xh-approval-result-bg, color-mix(in oklab, var(--xh-fg-success) 12%, var(--xh-bg-surface)));
297
+ color: var(--xh-approval-result-fg, var(--xh-fg-success));
298
+ font-size: var(--xh-approval-result-font-size, var(--xh-text-caption-size));
299
+ font-weight: var(--xh-approval-result-font-weight, var(--xh-text-label-weight));
300
+ animation: xh-approval-result-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
301
+ }
302
+
303
+ [data-scope='approval'][data-part='result'][hidden] {
304
+ display: none;
305
+ }
306
+
307
+ /* 超时按拒绝收口,两者同档:视觉上不该看着像第三种结果 */
308
+ [data-scope='approval'][data-part='result']:is([data-state='denied'], [data-state='expired']) {
309
+ background: var(--xh-approval-result-bg-denied, color-mix(in oklab, var(--xh-fg-danger) 12%, var(--xh-bg-surface)));
310
+ color: var(--xh-approval-result-fg-denied, var(--xh-fg-danger));
311
+ }
312
+
313
+ /* 动作行:两颗按钮靠右排,间距归库管。
314
+ 一行排不下就折行:两颗钮的文案都不折行,靠右排的行溢出时是往行首那侧漫出去,
315
+ 漫出去的那截既不产生横滚也回不来,折行是这一行唯一取得回来的形态。 */
316
+ [data-scope='approval'][data-part='footer'] {
317
+ display: flex;
318
+ flex-wrap: wrap;
319
+ align-items: center;
320
+ justify-content: flex-end;
321
+ gap: var(--xh-approval-footer-gap, var(--xh-space-2));
322
+ }
323
+
324
+ [data-scope='approval'][data-part='footer'][hidden] {
325
+ display: none;
326
+ }
327
+
328
+ /* 两颗按钮是离散动作控件:盒几何、悬停 / 按下与 0.97 按压、焦点环、禁用与在途面全由 Action Control 的
329
+ text 档给,组件只映射既有使用者槽。批准走 solid 档:判定闸门里的主要动作,与 Button 缺省同为品牌实心;
330
+ 拒绝走 outline 档:非 Button 的触发器缺省中性描边(§7.2.2)。
331
+ 三档守卫由连接层投影:判定在途是 data-loading + aria-disabled(保住可聚焦,家族给在途面:底色不置灰、
332
+ 指针 progress),必选项没勾满与落定是 data-disabled(家族给禁用面:置灰底、置灰字、not-allowed)。
333
+ 两颗共用的几何与字号写在一起 */
334
+ [data-scope='approval'][data-part='approve-trigger'],
335
+ [data-scope='approval'][data-part='deny-trigger'] {
336
+ --xh-action-visual-size: var(--xh-approval-action-h, var(--xh-_approval-action-h));
337
+ --xh-action-padding-inline: var(--xh-approval-action-px, var(--xh-_approval-action-px));
338
+ --xh-action-radius: var(--xh-approval-action-radius, var(--xh-shape-control));
339
+ --xh-action-font-size: var(--xh-approval-action-font-size, var(--xh-text-label-size));
340
+
341
+ font-weight: var(--xh-approval-action-font-weight, var(--xh-text-label-weight));
342
+ }
343
+
344
+ /* 家族那条 display 会把 UA 的 [hidden]{display:none} 盖掉 */
345
+ [data-scope='approval'][data-part='approve-trigger'][hidden],
346
+ [data-scope='approval'][data-part='deny-trigger'][hidden] {
347
+ display: none;
348
+ }
349
+
350
+ /* 批准钮:品牌实心,内顶高光把实心块顶出一道边,与拒绝那颗的描边同一档厚度(三态与在途同一支,
351
+ 禁用面由家族收掉);底 / 字与禁用底映到 solid 档的桥接槽 */
352
+ [data-scope='approval'][data-part='approve-trigger'] {
353
+ --xh-action-bg-rest: var(--xh-approval-approve-bg, var(--xh-_action-variant-bg-rest));
354
+ --xh-action-bg-hover: var(--xh-approval-approve-bg-hover, var(--xh-_action-variant-bg-hover));
355
+ --xh-action-bg-loading: var(--xh-approval-approve-bg, var(--xh-_action-variant-bg-loading));
356
+ --xh-action-bg-disabled: var(--xh-approval-approve-bg-off, var(--xh-_action-variant-bg-disabled));
357
+ --xh-action-fg-rest: var(--xh-approval-approve-fg, var(--xh-_action-variant-fg-rest));
358
+ --xh-action-fg-hover: var(--xh-approval-approve-fg, var(--xh-_action-variant-fg-hover));
359
+ --xh-action-fg-pressed: var(--xh-approval-approve-fg, var(--xh-_action-variant-fg-pressed));
360
+ --xh-action-fg-loading: var(--xh-approval-approve-fg, var(--xh-_action-variant-fg-loading));
361
+ --xh-action-highlight-rest: transparent;
362
+ --xh-action-shadow-rest: var(--xh-approval-approve-shadow, var(--xh-_highlight-tone));
363
+ --xh-action-shadow-hover: var(--xh-approval-approve-shadow, var(--xh-_highlight-tone));
364
+ --xh-action-shadow-pressed: var(--xh-approval-approve-shadow, var(--xh-_highlight-tone));
365
+ --xh-action-shadow-loading: var(--xh-approval-approve-shadow, var(--xh-_highlight-tone));
366
+ }
367
+
368
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
369
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的。
370
+ 只对着还铺着实心底的那两档:按得动的常态,与判定在途那一档;
371
+ 禁用档的底换成置灰底、字换成置灰色,环取过来就跟底一起糊了,那一档走公共层的环 */
372
+ [data-scope='approval'][data-part='approve-trigger']:not([data-disabled]) {
373
+ --xh-action-ring-color-focus-visible: currentColor;
374
+ }
375
+
376
+ /* 拒绝钮:中性描边,底 / 边 / 字与禁用面映到 outline 档的桥接槽(透明底 → 100 → 200;
377
+ 落定后描边退回中性,不再像个能按的出口) */
378
+ [data-scope='approval'][data-part='deny-trigger'] {
379
+ --xh-action-bg-rest: var(--xh-approval-deny-bg, var(--xh-_action-variant-bg-rest));
380
+ --xh-action-bg-hover: var(--xh-approval-deny-bg-hover, var(--xh-_action-variant-bg-hover));
381
+ --xh-action-bg-disabled: var(--xh-approval-deny-bg-off, var(--xh-_action-variant-bg-disabled));
382
+ --xh-action-fg-rest: var(--xh-approval-deny-fg, var(--xh-_action-variant-fg-rest));
383
+ --xh-action-fg-hover: var(--xh-approval-deny-fg, var(--xh-_action-variant-fg-hover));
384
+ --xh-action-fg-pressed: var(--xh-approval-deny-fg, var(--xh-_action-variant-fg-pressed));
385
+ --xh-action-border-rest: var(--xh-approval-deny-border, var(--xh-_action-variant-border-rest));
386
+ --xh-action-border-disabled: var(--xh-approval-deny-border-off, var(--xh-_action-variant-border-disabled));
387
+ --xh-action-highlight-rest: transparent;
388
+ --xh-action-shadow-rest: none;
389
+ --xh-action-shadow-hover: none;
390
+ --xh-action-shadow-pressed: none;
391
+ }
392
+
393
+ /* 判定在途:两颗钮那一行里转一枚圆环(指针 progress 由家族的在途面给)。
394
+ 两颗钮此刻确实按不动,但按不动的理由是「你按的那一下正在走」,与「必选项没勾满」
395
+ 的那档灰不是一回事;只留灰的话两种情形长得一模一样,用户读不出系统正在想。
396
+ 所以在途这一档不置灰:颜色与对比度都保持原样,锁住只由圆环与指针说。
397
+ 圆环挂在这一行上而不是某一颗钮上:连接层只拿到「有一条判定在途」,
398
+ 拿不到是哪一颗按下的,画在两颗钮上会有一颗在说假话 */
399
+
400
+ [data-scope='approval'][data-part='root'][data-loading] [data-scope='approval'][data-part='footer']::before {
401
+ content: '';
402
+ flex: none;
403
+
404
+ /* 圆环那一枚跟着两颗钮的字号走,不跟页面的:download-trigger 与 clipboard 的圆环
405
+ 1em 量的都是它所在那颗钮,这里的宿主是整行,不锁字号就会比按钮上的大一圈 */
406
+ font-size: var(--xh-approval-action-font-size, var(--xh-text-label-size));
407
+ inline-size: 1em;
408
+ block-size: 1em;
409
+ border: var(--xh-stroke-thin) solid transparent;
410
+ border-block-start-color: currentColor;
411
+ border-radius: var(--xh-shape-circle);
412
+ animation: xh-approval-rotate var(--xh-approval-loading-duration, var(--xh-spin-duration)) var(--xh-motion-ease-loop) infinite;
413
+ }
414
+
415
+ /* 减少动效:圆环停下并整圈换成虚线,静止的形状仍然读得出"还没好"。
416
+ 两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
417
+ @media (prefers-reduced-motion: reduce) {
418
+ [data-scope='approval'][data-part='root'][data-loading] [data-scope='approval'][data-part='footer']::before {
419
+ border-style: dotted;
420
+ border-color: currentColor;
421
+ animation: none;
422
+ }
423
+ }
424
+
425
+ :where([data-motion='reduce']) [data-scope='approval'][data-part='root'][data-loading] [data-scope='approval'][data-part='footer']::before {
426
+ border-style: dotted;
427
+ border-color: currentColor;
428
+ animation: none;
429
+ }
430
+
431
+ /* 尺寸档改内衬、间距、按钮高度、行内字号与图标档 */
432
+ [data-scope='approval'][data-part='root'][data-size='sm'] {
433
+ --xh-_approval-icon-size: var(--xh-glyph-size-sm);
434
+ --xh-_approval-p: var(--xh-space-3);
435
+ --xh-_approval-gap: var(--xh-space-2);
436
+ --xh-_approval-action-h: var(--xh-control-h-sm);
437
+ --xh-_approval-action-px: var(--xh-control-px-sm);
438
+ --xh-_approval-item-font-size: var(--xh-control-font-sm);
439
+ --xh-_approval-note-font-size: var(--xh-control-font-sm);
440
+ }
441
+
442
+ [data-scope='approval'][data-part='root'][data-size='md'] {
443
+ --xh-_approval-icon-size: var(--xh-glyph-size-md);
444
+ --xh-_approval-p: var(--xh-space-4);
445
+ --xh-_approval-gap: var(--xh-space-3);
446
+ --xh-_approval-action-h: var(--xh-control-h-md);
447
+ --xh-_approval-action-px: var(--xh-control-px-md);
448
+ --xh-_approval-item-font-size: var(--xh-control-font-md);
449
+ --xh-_approval-note-font-size: var(--xh-control-font-md);
450
+ }
451
+
452
+ [data-scope='approval'][data-part='root'][data-size='lg'] {
453
+ --xh-_approval-icon-size: var(--xh-glyph-size-lg);
454
+ --xh-_approval-p: var(--xh-space-5);
455
+ --xh-_approval-gap: var(--xh-space-4);
456
+ --xh-_approval-action-h: var(--xh-control-h-lg);
457
+ --xh-_approval-action-px: var(--xh-control-px-lg);
458
+ --xh-_approval-item-font-size: var(--xh-control-font-lg);
459
+ --xh-_approval-note-font-size: var(--xh-control-font-lg);
460
+ }
461
+ }