@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
@@ -0,0 +1,219 @@
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
+ /* 定义 tag group 样式。 */
7
+
8
+ @layer xihan.components {
9
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10
+ [data-scope='tag-group'] {
11
+ --xh-tag-group-skin: 1;
12
+ }
13
+
14
+ [data-scope='tag-group'][data-part='root'] {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: var(--xh-tag-group-gap, var(--xh-space-2));
18
+ }
19
+
20
+ [data-scope='tag-group'][data-part='root'][hidden] {
21
+ display: none;
22
+ }
23
+
24
+ [data-scope='tag-group'][data-part='label'] {
25
+ color: var(--xh-tag-group-label-fg, var(--xh-fg-muted));
26
+ font-size: var(--xh-tag-group-label-font-size, var(--xh-text-label-size));
27
+ font-weight: var(--xh-tag-group-label-font-weight, var(--xh-text-label-weight));
28
+ line-height: var(--xh-leading-none);
29
+ }
30
+
31
+ [data-scope='tag-group'][data-part='label'][data-disabled] {
32
+ color: var(--xh-fg-subtle);
33
+ }
34
+
35
+ /* 一排标签横着排、放不下就换行:标签宽度由文字决定,硬撑一行会把整块版面挤破 */
36
+ [data-scope='tag-group'][data-part='list'] {
37
+ display: flex;
38
+ flex-wrap: wrap;
39
+ align-items: center;
40
+ gap: var(--xh-tag-group-list-gap, var(--xh-space-1_5));
41
+ }
42
+
43
+ [data-scope='tag-group'][data-part='list'][hidden] {
44
+ display: none;
45
+ }
46
+
47
+ /* 竖排时一枚一行,标签各自贴左,不跟着行宽拉长 */
48
+ [data-scope='tag-group'][data-part='list'][data-orientation='vertical'] {
49
+ flex-direction: column;
50
+ align-items: flex-start;
51
+ flex-wrap: nowrap;
52
+ }
53
+
54
+ /* 焦点在组外时容器自己进 Tab 序列兜底,落焦不画环:高亮永远长在标签上 */
55
+ [data-scope='tag-group'][data-part='list']:focus-visible {
56
+ outline: none;
57
+ }
58
+
59
+ /* 一枚标签就是 tag 的 root(data-scope="tag"):形态、语气、尺寸、置灰、截断、摘除钮的样子全归 tag.css。
60
+ 这里只管它在集合里的那几件事:可点、锚点、选中、只读。
61
+ 标签这时是拿焦点的那个节点,按下与松手之间要有回应;选中与锚点的过渡也挂在这一层 */
62
+ [data-scope='tag-group'][data-part='list'] > [data-scope='tag'][data-part='root'] {
63
+ user-select: none;
64
+ transition:
65
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
66
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
67
+ scale var(--xh-motion-duration-release) var(--xh-motion-ease-release);
68
+ }
69
+
70
+ /* 参与选中的标签才是点击目标,只是标记的那些不给手势暗示 */
71
+ [data-scope='tag-group'][data-part='list'] > [data-scope='tag'][data-part='root'][data-selectable] {
72
+ cursor: pointer;
73
+ }
74
+
75
+ /* 按下去要有回应:可选的芯片是一颗定尺的离散控件(§9.1),整枚轻微下压并同时换底
76
+ (白底承载 hover 100 → pressed 200),松手即弹回。置灰的不压;
77
+ 指针 :active 与 Headless 投影的 data-pressed 看见同一副按压面 */
78
+ [data-scope='tag-group'][data-part='list']
79
+ > [data-scope='tag'][data-part='root'][data-selectable]:not([data-disabled]):not([data-variant='solid']):is(:active, [data-pressed]) {
80
+ scale: var(--xh-motion-scale-press);
81
+ background: var(--xh-tag-group-item-bg-pressed, var(--xh-bg-subtle-hover));
82
+ transition-duration: var(--xh-motion-duration-press);
83
+ transition-timing-function: var(--xh-motion-ease-press);
84
+ }
85
+
86
+ /* 写了语气的淡底标签静息是 12% 语气淡底(tag.css),悬停 / 按下沿同一条语气曲线走 20% / 28%,
87
+ 不跳回中性阶梯把语气丢掉;与 tag.css 同样带 [data-tone] 限定,语气槽沿继承流下来不算 */
88
+ [data-scope='tag-group'][data-part='list']
89
+ > [data-scope='tag'][data-part='root'][data-selectable][data-tone]:not([data-disabled]):not([data-variant='solid']):is(:active, [data-pressed]) {
90
+ background: var(--xh-tag-group-item-bg-pressed, var(--xh-_tone-subtle-active, var(--xh-bg-subtle-hover)));
91
+ }
92
+
93
+ /* 实心档的面本身就是那族色,按下往同一族的 active 档走,字仍是实心底上配对的前景。
94
+ 语气那条与 tag.css 同样带 [data-tone] 限定:语气槽沿继承流下来,没写语气的实心标签落在带
95
+ data-tone 的组里,静息面与字仍是品牌那族,按下若读祖先的 --xh-_tone-active 就会跳成另一族 */
96
+ [data-scope='tag-group'][data-part='list']
97
+ > [data-scope='tag'][data-part='root'][data-selectable][data-variant='solid']:not([data-disabled]):is(:active, [data-pressed]) {
98
+ scale: var(--xh-motion-scale-press);
99
+ background: var(--xh-tag-group-item-bg-pressed-solid, var(--xh-bg-brand-active));
100
+ transition-duration: var(--xh-motion-duration-press);
101
+ transition-timing-function: var(--xh-motion-ease-press);
102
+ }
103
+
104
+ [data-scope='tag-group'][data-part='list']
105
+ > [data-scope='tag'][data-part='root'][data-selectable][data-variant='solid'][data-tone]:not([data-disabled]):is(:active, [data-pressed]) {
106
+ background: var(--xh-tag-group-item-bg-pressed-solid, var(--xh-_tone-active, var(--xh-bg-brand-active)));
107
+ }
108
+
109
+ /* 悬停与键盘锚点共用白底承载的 hover 档(§7.2:hover 100 → pressed 200):
110
+ data-highlighted 跟的是连接层记的焦点标签,与选中互相独立。
111
+ 实心标签不进这里:它的字是实心底上配对的那支前景色,换成灰底就读不出来了;
112
+ 实心档在这两档里面不换,回执落在按压缩放与聚焦环上 */
113
+ [data-scope='tag-group'][data-part='list']
114
+ > [data-scope='tag'][data-part='root']:not([data-disabled]):not([data-variant='solid']):is(:hover, [data-highlighted]) {
115
+ background: var(--xh-tag-group-item-bg-hover, var(--xh-bg-subtle));
116
+ }
117
+
118
+ [data-scope='tag-group'][data-part='list']
119
+ > [data-scope='tag'][data-part='root'][data-tone]:not([data-disabled]):not([data-variant='solid']):is(:hover, [data-highlighted]) {
120
+ background: var(--xh-tag-group-item-bg-hover, var(--xh-_tone-subtle-hover, var(--xh-bg-subtle)));
121
+ }
122
+
123
+ /* 只读整组都改不动,但不是禁用:颜色照常,只把「可点」这个暗示收回来。
124
+ 排掉禁用项是因为这条选择器权重高过 pointer 层那条,不排就会把 not-allowed 覆盖回 default */
125
+ [data-scope='tag-group'][data-part='root'][data-readonly]
126
+ [data-scope='tag-group'][data-part='list']
127
+ > [data-scope='tag'][data-part='root']:not([data-disabled]) {
128
+ cursor: default;
129
+ }
130
+
131
+ /* —— 选中 —— */
132
+ /* 页内持久集合的选中(§7.3):品牌淡底行面 + 配对前景 + 前导对号(item-indicator),描边退到透明边位;
133
+ 悬停与按下在淡底上派生 20% / 28%,键盘锚点同悬停档。
134
+ 标了语气的组从语气层取同一条曲线。置灰的标签不进这里:它的边与字都已退成置灰色。
135
+ 实心档另有一条:它的面本身就是那族色,淡底与配对前景压在上面都读不出来 */
136
+ [data-scope='tag-group'][data-part='list']
137
+ > [data-scope='tag'][data-part='root'][data-selected]:not([data-disabled]):not([data-variant='solid']) {
138
+ border-color: var(--xh-tag-group-item-border-selected, transparent);
139
+ background: var(--xh-tag-group-item-bg-selected, var(--xh-_tone-subtle, var(--xh-bg-brand-subtle)));
140
+ color: var(--xh-tag-group-item-fg-selected, var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle)));
141
+ }
142
+
143
+ [data-scope='tag-group'][data-part='list']
144
+ > [data-scope='tag'][data-part='root'][data-selected]:not([data-disabled]):not([data-variant='solid']):is(:hover, [data-highlighted]) {
145
+ background: var(--xh-tag-group-item-bg-selected-hover, var(--xh-_tone-subtle-hover, var(--xh-bg-brand-subtle-hover)));
146
+ }
147
+
148
+ [data-scope='tag-group'][data-part='list']
149
+ > [data-scope='tag'][data-part='root'][data-selected][data-selectable]:not([data-disabled]):not([data-variant='solid']):is(:active, [data-pressed]) {
150
+ background: var(--xh-tag-group-item-bg-selected-pressed, var(--xh-_tone-subtle-active, var(--xh-bg-brand-subtle-active)));
151
+ }
152
+
153
+ /* 实心标签选中:字不换(仍是 tag.css 给的面配对前景色,作者的 --xh-tag-fg 照旧生效),
154
+ 描边取字色,在实心底上描出一圈;环由 tag.css 取 currentColor,跟着字走 */
155
+ [data-scope='tag-group'][data-part='list'] > [data-scope='tag'][data-part='root'][data-variant='solid'][data-selected]:not([data-disabled]) {
156
+ border-color: var(--xh-tag-group-item-border-selected, currentColor);
157
+ }
158
+
159
+ /* 标签里那一格:文字与摘除钮排在一条线上。它是 tag 根与 tag 的 label / close-trigger 之间的一层,
160
+ 间距照抄所在标签的那一档,有它与没它标签长得一样 */
161
+ [data-scope='tag-group'][data-part='cell'] {
162
+ display: inline-flex;
163
+ align-items: center;
164
+ /* 弹性子项默认最小尺寸是内容尺寸,不归零则长文本把标签撑破、省略号轮不上 */
165
+ min-inline-size: 0;
166
+ gap: inherit;
167
+ }
168
+
169
+ [data-scope='tag-group'][data-part='cell'][hidden] {
170
+ display: none;
171
+ }
172
+
173
+ /* 选中标记:领在文字前面的一枚对号,与摘除钮的叉同一把随文尺(标签是纯行内文字组件);
174
+ 作者塞进来的图标读同一支 --xh-icon-size。连接层没选中时给 hidden,UA 的 display:none 被上面的 display 盖住,
175
+ 这里压回去 */
176
+ [data-scope='tag-group'][data-part='item-indicator'] {
177
+ --xh-icon-size: var(--xh-tag-group-item-indicator-size, var(--xh-glyph-size-text));
178
+
179
+ display: inline-flex;
180
+ flex: none;
181
+ align-items: center;
182
+ justify-content: center;
183
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
184
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
185
+ color: var(--xh-tag-group-item-indicator-fg, currentColor);
186
+ }
187
+
188
+ [data-scope='tag-group'][data-part='item-indicator'][hidden] {
189
+ display: none;
190
+ }
191
+
192
+ /* 没写内容就由皮肤画兜底对号;作者往部件里塞了自己的图形,这条即不命中 */
193
+ [data-scope='tag-group'][data-part='item-indicator']:empty::before {
194
+ content: '';
195
+ display: inline-block;
196
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
197
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
198
+ background-color: currentColor;
199
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
200
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
201
+ }
202
+
203
+ @media (forced-colors: active) {
204
+ /* 选中靠淡底与配对前景表出,这一档里两者都被统一换掉;用系统高亮反色画回,前导对号是字形节点、自己活得下来 */
205
+ [data-scope='tag-group'][data-part='list']
206
+ > [data-scope='tag'][data-part='root'][data-selected]:not([data-disabled]):not([data-variant='solid']) {
207
+ border-color: Highlight;
208
+ background: Highlight;
209
+ color: HighlightText;
210
+ }
211
+
212
+ /* 按下:常态靠底色深一档表出,这一档里底色被统一换成 Canvas;按住那一下用系统高亮反色画回来 */
213
+ [data-scope='tag-group'][data-part='list']
214
+ > [data-scope='tag'][data-part='root'][data-selectable]:not([data-disabled]):not([data-variant='solid']):is(:active, [data-pressed]) {
215
+ background: Highlight;
216
+ color: HighlightText;
217
+ }
218
+ }
219
+ }
package/css/tag.css CHANGED
@@ -1,3 +1,10 @@
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
+ /* 定义 tag 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='tag'] {
@@ -9,11 +16,12 @@
9
16
  /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
10
17
  --xh-icon-size: var(--xh-tag-icon-size, var(--xh-glyph-size-text));
11
18
 
12
- /* 尺寸档只换这四个私有槽,下面的声明从它们取值 */
19
+ /* 尺寸档只换这五个私有槽,下面的声明从它们取值;行框是标签里那一行的高,取指示符档 */
13
20
  --xh-_tag-gap: var(--xh-space-1);
14
21
  --xh-_tag-px: var(--xh-space-2);
15
- --xh-_tag-py: var(--xh-space-0_5);
16
- --xh-_tag-font-size: var(--xh-text-caption-size);
22
+ --xh-_tag-py: var(--xh-space-1);
23
+ --xh-_tag-font-size: var(--xh-text-secondary-size);
24
+ --xh-_tag-line-h: var(--xh-control-indicator-md);
17
25
 
18
26
  display: inline-flex;
19
27
  align-items: center;
@@ -22,13 +30,17 @@
22
30
  gap: var(--xh-tag-gap, var(--xh-_tag-gap));
23
31
  padding-inline: var(--xh-tag-px, var(--xh-_tag-px));
24
32
  padding-block: var(--xh-tag-py, var(--xh-_tag-py));
25
- border: var(--xh-stroke-thin) solid transparent;
26
- border-radius: var(--xh-tag-radius, var(--xh-shape-control));
27
- background: var(--xh-tag-bg, var(--xh-bg-subtle));
28
- color: var(--xh-tag-fg, var(--xh-fg-default));
33
+ border: var(--xh-stroke-thin) solid var(--xh-tag-border, var(--xh-material-soft-border));
34
+ /* 状态 chip 的身份是胶囊(§6.3 pill 只给状态 chip 与一维对象) */
35
+ border-radius: var(--xh-tag-radius, var(--xh-shape-pill));
36
+ background: var(--xh-tag-bg, var(--xh-material-soft-bg));
37
+ box-shadow: var(--xh-tag-shadow, var(--xh-material-soft-shadow));
38
+ color: var(--xh-tag-fg, var(--xh-material-soft-fg));
29
39
  font-size: var(--xh-tag-font-size, var(--xh-_tag-font-size));
30
40
  font-weight: var(--xh-tag-font-weight, var(--xh-font-weight-medium));
31
- line-height: var(--xh-leading-none);
41
+ /* 行框不低于关闭钮,有没有关闭钮同档标签一样高;
42
+ 作者把字调得比这一格还大时行框跟着字走,label 的截断不会剪掉字的上下沿 */
43
+ line-height: max(calc(var(--xh-leading-none) * 1em), var(--xh-_tag-line-h));
32
44
  /* 随文排时与正文基线对齐 */
33
45
  vertical-align: middle;
34
46
  }
@@ -51,13 +63,15 @@
51
63
  display: inline-flex;
52
64
  align-items: center;
53
65
  justify-content: center;
66
+ position: relative;
54
67
  flex: none;
55
- /* 命中区取标签内移除钮的指示符尺寸,不随标签档位缩小 */
68
+ /* 命中区:作者槽 → 不分档的指示符,三档同一个数,与库里其它标签内的移除钮同一把尺;行框比它高的档里钮居中 */
56
69
  block-size: var(--xh-tag-close-size, var(--xh-control-indicator-size));
57
70
  inline-size: var(--xh-tag-close-size, var(--xh-control-indicator-size));
58
71
  /* 命中区比字形大一圈,往内收一格才不会在标签右缘留出一块空白 */
59
72
  margin-inline-end: calc(-1 * var(--xh-space-1));
60
73
  border: 0;
74
+ /* 随文标记档的叉:16px 正方盒取 inset 4px,与 checkbox 系方框同档,嵌在胶囊里内层圆角不越过外层 */
61
75
  border-radius: var(--xh-tag-close-radius, var(--xh-shape-inset));
62
76
  background: transparent;
63
77
  /* 叉取标签自己的文字色:实心底上是浅字、淡底上是深字,不必逐形态各写一遍 */
@@ -68,7 +82,16 @@
68
82
  cursor: pointer;
69
83
  transition:
70
84
  background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
71
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
85
+ scale var(--xh-motion-duration-release) var(--xh-motion-ease-release);
86
+ }
87
+
88
+ /* 视觉盒保持 16px,透明命中层扩到随文动作的 24px,不把整枚标签撑高。 */
89
+ [data-scope='tag'][data-part='close-trigger']::after {
90
+ position: absolute;
91
+ inset: calc(
92
+ (var(--xh-control-action-size) - var(--xh-tag-close-size, var(--xh-control-indicator-size))) / -2
93
+ );
94
+ content: '';
72
95
  }
73
96
 
74
97
  /* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半 */
@@ -81,42 +104,67 @@
81
104
  background: var(--xh-tag-close-bg-hover, color-mix(in oklab, currentColor 14%, transparent));
82
105
  }
83
106
 
84
- [data-scope='tag'][data-part='close-trigger']:not(:disabled):active {
107
+ /* 指针 :active 与 Headless 投影的 data-pressed(Space / Enter 与触屏按住)看见同一副按压面 */
108
+ [data-scope='tag'][data-part='close-trigger']:not(:disabled):is(:active, [data-pressed]) {
85
109
  background: var(--xh-tag-close-bg-active, color-mix(in oklab, currentColor 22%, transparent));
86
110
  scale: var(--xh-motion-scale-press);
111
+ transition-duration: var(--xh-motion-duration-press);
112
+ transition-timing-function: var(--xh-motion-ease-press);
87
113
  }
88
114
 
89
- [data-scope='tag'][data-part='close-trigger']:disabled {
90
- color: var(--xh-fg-disabled);
91
- cursor: not-allowed;
115
+ /* 按住的叉落着焦点(§9.3 focus-visible + pressed 保留焦点环):按压面是从字色兑出的 22% 底,
116
+ 压在淡底 / 选中面上把面往字色那头带了一档,默认环与这块混色面在浅色档上只剩 2.2–2.9。
117
+ 环改取叉自己的字色:按压面正是从这支色兑出来的,字色压在它上面的对比与字压在标签面上同源,
118
+ 六族语气与深浅两态都过 3:1;实心档本来就取字色,这条与它同一口径 */
119
+ [data-scope='tag'][data-part='close-trigger']:not(:disabled):is(:active, [data-pressed]):focus-visible {
120
+ --xh-_ring-color: currentColor;
92
121
  }
93
122
 
94
- [data-scope='tag'][data-part='close-trigger']:focus-visible {
95
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
96
- /* 环往内收:命中区贴着标签内缘,往外画会被相邻标签压住 */
97
- outline-offset: calc(-1 * var(--xh-ring-offset));
123
+ [data-scope='tag'][data-part='close-trigger']:disabled {
124
+ color: var(--xh-fg-disabled);
98
125
  }
99
126
 
100
127
  /* —— 形态 —— */
101
128
  /* 形态只决定颜色怎么用。每个形态拆成两条:先是没写语气时的基线配色,
102
129
  再是写了语气时的覆盖。语气槽会沿继承流下来,覆盖那条必须带 [data-tone] 限定,
103
130
  否则一枚没写语气的标签只要落在带 data-tone 的容器里(警告提示、吐司、按钮内)
104
- 就会跟着染色 */
131
+ 就会跟着染色。
132
+ 实心档还在顶边画一条极浅的内高光,把整块底衬出厚度;语气那条同样从实心底上的前景色兑,
133
+ 换语气时高光跟着换 */
105
134
  [data-scope='tag'][data-part='root'][data-variant='solid'] {
135
+ --xh-_tag-highlight: var(--xh-_highlight-brand);
136
+
106
137
  border-color: transparent;
107
138
  background: var(--xh-tag-bg, var(--xh-bg-brand));
108
139
  color: var(--xh-tag-fg, var(--xh-fg-on-brand));
140
+ box-shadow: var(--xh-tag-shadow, var(--xh-_tag-highlight));
141
+ }
142
+
143
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
144
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的。
145
+ 置灰那档的底已换成静默色、字换成置灰色,不在其列:环退回默认那一支 */
146
+ [data-scope='tag'][data-part='root'][data-variant='solid']:not([data-disabled]):focus-visible {
147
+ --xh-_ring-color: currentColor;
148
+ }
149
+
150
+ /* 关闭钮自己的面是透空的,环压着的是标签那块实心底;它的字色就是那块底上的前景色,
151
+ 环跟着取过来 */
152
+ [data-scope='tag'][data-part='root'][data-variant='solid']:not([data-disabled])
153
+ [data-scope='tag'][data-part='close-trigger']:focus-visible {
154
+ --xh-_ring-color: currentColor;
109
155
  }
110
156
 
111
157
  [data-scope='tag'][data-part='root'][data-variant='solid'][data-tone] {
158
+ --xh-_tag-highlight: var(--xh-_highlight-tone);
159
+
112
160
  background: var(--xh-tag-bg, var(--xh-_tone, var(--xh-bg-brand)));
113
161
  color: var(--xh-tag-fg, var(--xh-_tone-on, var(--xh-fg-on-brand)));
114
162
  }
115
163
 
116
164
  [data-scope='tag'][data-part='root'][data-variant='subtle'] {
117
- border-color: transparent;
118
- background: var(--xh-tag-bg, var(--xh-bg-subtle));
119
- color: var(--xh-tag-fg, var(--xh-fg-default));
165
+ border-color: var(--xh-tag-border, var(--xh-material-soft-border));
166
+ background: var(--xh-tag-bg, var(--xh-material-soft-bg));
167
+ color: var(--xh-tag-fg, var(--xh-material-soft-fg));
120
168
  }
121
169
 
122
170
  [data-scope='tag'][data-part='root'][data-variant='subtle'][data-tone] {
@@ -127,6 +175,7 @@
127
175
  [data-scope='tag'][data-part='root'][data-variant='outline'] {
128
176
  border-color: var(--xh-tag-border, var(--xh-border-default));
129
177
  background: transparent;
178
+ box-shadow: none;
130
179
  color: var(--xh-tag-fg, var(--xh-fg-default));
131
180
  }
132
181
 
@@ -137,19 +186,32 @@
137
186
  color: var(--xh-tag-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
138
187
  }
139
188
 
189
+ [data-scope='tag'][data-part='root'][data-variant='ghost'] {
190
+ border-color: transparent;
191
+ background: transparent;
192
+ box-shadow: none;
193
+ color: var(--xh-tag-fg, var(--xh-fg-default));
194
+ }
195
+
196
+ [data-scope='tag'][data-part='root'][data-variant='ghost'][data-tone] {
197
+ color: var(--xh-tag-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
198
+ }
199
+
140
200
  /* —— 尺寸 —— */
141
- /* 标签是随文排的标记,不占控件行高,档位走间距与字号而不是 control-h */
201
+ /* 标签是随文排的标记,不占控件行高,档位走间距、字号与行框而不是 control-h */
142
202
  [data-scope='tag'][data-part='root'][data-size='sm'] {
143
203
  --xh-_tag-gap: var(--xh-space-0_5);
144
204
  --xh-_tag-px: var(--xh-space-1_5);
145
- --xh-_tag-py: var(--xh-space-0);
205
+ --xh-_tag-py: var(--xh-space-0_5);
206
+ --xh-_tag-font-size: var(--xh-text-caption-size);
146
207
  }
147
208
 
209
+ /* 行框上到指示符的大档,竖向内衬沿用中档;关闭钮不换档 */
148
210
  [data-scope='tag'][data-part='root'][data-size='lg'] {
149
211
  --xh-_tag-gap: var(--xh-space-1_5);
150
212
  --xh-_tag-px: var(--xh-space-3);
151
- --xh-_tag-py: var(--xh-space-1);
152
- --xh-_tag-font-size: var(--xh-text-secondary-size);
213
+ --xh-_tag-font-size: var(--xh-text-body-size);
214
+ --xh-_tag-line-h: var(--xh-control-indicator-lg);
153
215
  }
154
216
 
155
217
  /* —— 禁用 —— */
@@ -159,10 +221,38 @@
159
221
  用了 fg-disabled 就不再叠 opacity */
160
222
  [data-scope='tag'][data-part='root'][data-disabled],
161
223
  [data-scope='tag'][data-part='root'][data-tone][data-disabled] {
162
- border-color: var(--xh-tag-border-disabled, var(--xh-border-subtle));
224
+ border-color: var(--xh-tag-border-disabled, var(--xh-border-default));
163
225
  background: var(--xh-tag-bg-disabled, var(--xh-bg-muted));
164
226
  color: var(--xh-fg-disabled);
165
- cursor: not-allowed;
227
+ /* 底已经退成置灰色,实心档那条内高光跟着收掉 */
228
+ box-shadow: none;
229
+ }
230
+
231
+ /*
232
+ * 打印:底色被丢掉,实心与淡底两档的底一起没了。实心档配的是实心底上的前景色,
233
+ * 底一没那行字就落在白纸上——白字印在白纸上,整枚标签只剩一块空白。
234
+ * 两档在纸上都退成描边档:字色回到正文色,轮廓由边框接手,内高光跟着收掉。
235
+ * 两条选择器分别压过形态与语气这两层覆盖点;禁用档摘掉,它自己就是灰的。
236
+ */
237
+ @media print {
238
+ [data-scope='tag'][data-part='root']:not([data-disabled]),
239
+ [data-scope='tag'][data-part='root'][data-variant][data-tone]:not([data-disabled]) {
240
+ border-color: currentColor;
241
+ background: none;
242
+ color: var(--xh-fg-default);
243
+ box-shadow: none;
244
+ }
245
+ }
246
+
247
+ /*
248
+ * 高对比档:关闭钮的按压面常态靠从 currentColor 兑出来的底色表出,这一档里底色被统一换成 Canvas,
249
+ * 按住那一下与静息塌成同一个样子;用系统高亮反色画回来,兜底字形读 currentColor、自己跟着换
250
+ */
251
+ @media (forced-colors: active) {
252
+ [data-scope='tag'][data-part='close-trigger']:not(:disabled):is(:active, [data-pressed]) {
253
+ background: Highlight;
254
+ color: HighlightText;
255
+ }
166
256
  }
167
257
 
168
258
  /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */