@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,428 @@
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
+ /* 定义 diff view 样式。 */
7
+
8
+ /* 独立皮肤同时传递引入折叠格按钮的动作控件配方;full bundle 递归去重。 */
9
+ @import '../family/action-control.css';
10
+
11
+ @layer xihan.components {
12
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13
+ [data-scope='diff-view'] {
14
+ --xh-diff-view-skin: 1;
15
+ }
16
+
17
+ /* 一张静态内容面:--xh-border-default 描边 + surface 底 + 无影(§5.3 边界只由描边承担);
18
+ 头部、行号列与并排接缝的内部分隔线走另一支 --xh-diff-view-divider(subtle) */
19
+ [data-scope='diff-view'][data-part='root'] {
20
+ /* 作者塞进部件里的图标与皮肤画的兜底字形同一把尺:md 档,随 data-size 换档(§6.5) */
21
+ --xh-icon-size: var(--xh-diff-view-icon-size, var(--xh-glyph-size-md));
22
+
23
+ /* 尺寸缺省档:不写 data-size 时的取值。三档都只写这三个私有槽,
24
+ 公开槽留在读处当首选,作者在祖先上设的覆盖才赢得过档位声明 */
25
+ --xh-_diff-view-font-size: var(--xh-control-font-sm);
26
+ --xh-_diff-view-px: var(--xh-space-3);
27
+ --xh-_diff-view-py: var(--xh-space-2);
28
+
29
+ display: block;
30
+ overflow: hidden;
31
+ border: var(--xh-stroke-thin) solid var(--xh-diff-view-border, var(--xh-border-default));
32
+ border-radius: var(--xh-diff-view-radius, var(--xh-shape-surface));
33
+ background: var(--xh-diff-view-bg, var(--xh-bg-surface));
34
+ box-shadow: var(--xh-diff-view-shadow, none);
35
+ }
36
+
37
+ /* 上面声明的 display 会盖掉 UA 的 [hidden]{display:none},这里补回 */
38
+ [data-scope='diff-view'][data-part='root'][hidden] {
39
+ display: none;
40
+ }
41
+
42
+ [data-scope='diff-view'][data-part='header'] {
43
+ display: flex;
44
+ align-items: center;
45
+ gap: var(--xh-diff-view-header-gap, var(--xh-space-2));
46
+ padding-inline: var(--xh-diff-view-px, var(--xh-_diff-view-px));
47
+ padding-block: var(--xh-diff-view-py, var(--xh-_diff-view-py));
48
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-diff-view-divider, var(--xh-border-subtle));
49
+ color: var(--xh-diff-view-header-fg, var(--xh-fg-muted));
50
+ font-family: var(--xh-diff-view-font, var(--xh-font-family-mono));
51
+ font-size: var(--xh-diff-view-header-font-size, var(--xh-text-secondary-size));
52
+ }
53
+
54
+ [data-scope='diff-view'][data-part='header'][hidden] {
55
+ display: none;
56
+ }
57
+
58
+ /* 增删统计整组顶到右侧:头部是 flex,自动外边距吃掉中间的空当。
59
+ 第二个之后的不再顶,与前一个之间只留头部本来的间隙 */
60
+ [data-scope='diff-view'][data-part='summary'] {
61
+ margin-inline-start: auto;
62
+ }
63
+
64
+ [data-scope='diff-view'][data-part='summary'] ~ [data-scope='diff-view'][data-part='summary'] {
65
+ margin-inline-start: 0;
66
+ }
67
+
68
+ [data-scope='diff-view'][data-part='summary'][data-change='added'] {
69
+ color: var(--xh-diff-view-added-fg, var(--xh-diff-added-fg));
70
+ }
71
+
72
+ [data-scope='diff-view'][data-part='summary'][data-change='removed'] {
73
+ color: var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg));
74
+ }
75
+
76
+ /* 唯一的 Tab 停靠点;两轴都可能溢出 */
77
+ [data-scope='diff-view'][data-part='viewport'] {
78
+ overflow: auto;
79
+ max-block-size: var(--xh-diff-view-max-h, var(--xh-viewport-max-h));
80
+ }
81
+
82
+ [data-scope='diff-view'][data-part='body'] {
83
+ display: block;
84
+ font-family: var(--xh-diff-view-font, var(--xh-font-family-mono));
85
+ font-size: var(--xh-diff-view-font-size, var(--xh-_diff-view-font-size));
86
+ line-height: var(--xh-diff-view-line-height, var(--xh-text-code-leading));
87
+ min-inline-size: max-content;
88
+ }
89
+
90
+ [data-scope='diff-view'][data-part='body'][hidden] {
91
+ display: none;
92
+ }
93
+
94
+ /* 一行:行号与内容并排 */
95
+ [data-scope='diff-view'][data-part='row'],
96
+ [data-scope='diff-view'][data-part='gap'] {
97
+ display: flex;
98
+ min-block-size: var(--xh-diff-view-line-height, var(--xh-text-code-leading));
99
+ }
100
+
101
+ [data-scope='diff-view'][data-part='row'][hidden],
102
+ [data-scope='diff-view'][data-part='gap'][hidden] {
103
+ display: none;
104
+ }
105
+
106
+ /* 变更类型不只靠颜色:新增行画一条实心色条 */
107
+ [data-scope='diff-view'][data-part='row'][data-change='added'] {
108
+ background: var(--xh-diff-view-added-bg, var(--xh-diff-added-bg));
109
+ box-shadow: inset var(--xh-diff-view-change-bar, var(--xh-stroke-thick)) 0 0 0 var(--xh-diff-view-added-fg, var(--xh-diff-added-fg));
110
+ }
111
+
112
+ /* 删除行的色条改画斜纹:与新增行的实心条在灰度与高对比度下也分得开。
113
+ 45 度、1.5px 实 1.5px 空是纹理几何,不是设计尺度上的档位 */
114
+ [data-scope='diff-view'][data-part='row'][data-change='removed'] {
115
+ background:
116
+ repeating-linear-gradient(
117
+ 45deg,
118
+ var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg)) 0,
119
+ var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg)) 1.5px,
120
+ transparent 1.5px,
121
+ transparent 3px
122
+ )
123
+ left / var(--xh-diff-view-change-bar, var(--xh-stroke-thick)) 100% no-repeat,
124
+ var(--xh-diff-view-removed-bg, var(--xh-diff-removed-bg));
125
+ }
126
+
127
+ /* 点开折叠格才露出来的那几行播一次入场;收起是硬切,不占一段退场窗口 */
128
+ [data-scope='diff-view'][data-part='row'][data-revealed] {
129
+ animation: xh-diff-view-reveal var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
130
+ }
131
+
132
+ /* 行号是画上去的不是写上去的:复制差异不带它,读屏也不逐行念数字 */
133
+ [data-scope='diff-view'][data-part='line-number'] {
134
+ display: block;
135
+ box-sizing: content-box;
136
+ flex: 0 0 auto;
137
+ padding-inline: var(--xh-diff-view-px, var(--xh-_diff-view-px));
138
+ border-inline-end: var(--xh-stroke-thin) solid var(--xh-diff-view-divider, var(--xh-border-subtle));
139
+ color: var(--xh-diff-view-number-fg, var(--xh-fg-subtle));
140
+ inline-size: var(--xh-diff-view-gutter, 4ch);
141
+ text-align: end;
142
+ user-select: none;
143
+ }
144
+
145
+ [data-scope='diff-view'][data-part='line-number']::before {
146
+ content: attr(data-line-number);
147
+ }
148
+
149
+ [data-scope='diff-view'][data-part='line-number'][hidden] {
150
+ display: none;
151
+ }
152
+
153
+ /* 行号跟着行的变更类型走:一眼扫下来数字本身就分出了增删 */
154
+ [data-scope='diff-view'][data-part='line-number'][data-change='added'] {
155
+ color: var(--xh-diff-view-added-fg, var(--xh-diff-added-fg));
156
+ }
157
+
158
+ [data-scope='diff-view'][data-part='line-number'][data-change='removed'] {
159
+ color: var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg));
160
+ }
161
+
162
+ /* 窄档的并排视图:一行的两侧改成上下两段,旧行在上、新行在下。
163
+ 行由横排 flex 换成两列栅格——行号一列、正文一列,一行里的四个格按 DOM 次序
164
+ 自然落成两行,正文列因此只按单侧的最长行撑宽,不再是两侧之和 */
165
+ [data-scope='diff-view'][data-part='root'][data-view='split'] [data-part='row']:not([hidden]) {
166
+ display: grid;
167
+ grid-template-columns: auto minmax(0, 1fr);
168
+ }
169
+
170
+ /* white-space: pre 保留缩进;每一侧各占一半宽 */
171
+ [data-scope='diff-view'][data-part='line-content'] {
172
+ display: block;
173
+ flex: 1 1 0;
174
+ min-inline-size: 0;
175
+ padding-inline-end: var(--xh-diff-view-px, var(--xh-_diff-view-px));
176
+ white-space: pre;
177
+ }
178
+
179
+ [data-scope='diff-view'][data-part='line-content'][hidden] {
180
+ display: none;
181
+ }
182
+
183
+ [data-scope='diff-view'][data-part='line-content'][data-change='added'] {
184
+ color: var(--xh-diff-view-added-fg, var(--xh-diff-added-fg));
185
+ }
186
+
187
+ [data-scope='diff-view'][data-part='line-content'][data-change='removed'] {
188
+ color: var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg));
189
+ }
190
+
191
+ /* 并排视图里空的那一侧只有底色,没有内容 */
192
+ [data-scope='diff-view'][data-part='line-content'][data-empty] {
193
+ background: var(--xh-diff-view-empty-bg, var(--xh-bg-subtle));
194
+ }
195
+
196
+ /* 开了换行:pre-wrap 仍保留缩进与连续空白,只是允许行尾折下来;
197
+ anywhere 让没有空格的长串(url、base64)也能断 */
198
+ [data-scope='diff-view'][data-part='root'][data-wrap] [data-part='line-content'] {
199
+ white-space: pre-wrap;
200
+ overflow-wrap: anywhere;
201
+ }
202
+
203
+ /* 正文原本按最长行撑宽,不解除就折不下来 */
204
+ [data-scope='diff-view'][data-part='root'][data-wrap] [data-part='body'] {
205
+ min-inline-size: 0;
206
+ }
207
+
208
+ /* 变更类型的读屏文字:视觉隐藏,不能 display:none——那样读屏就取不到它了。
209
+ 变更不该只靠颜色传达 */
210
+ [data-scope='diff-view'][data-part='change-label'] {
211
+ position: absolute;
212
+ inline-size: 1px;
213
+ block-size: 1px;
214
+ padding: 0;
215
+ margin: -1px;
216
+ border: 0;
217
+ overflow: hidden;
218
+ clip-path: inset(50%);
219
+ white-space: nowrap;
220
+ }
221
+
222
+ /* 词级片段:只有真正动过的那几段上底色,其余段落是纯包裹。
223
+ 不给内衬——等宽列要逐字对齐,多一像素整份差异就错位 */
224
+ [data-scope='diff-view'][data-part='inline-change'][data-change] {
225
+ border-radius: var(--xh-diff-view-inline-change-radius, var(--xh-shape-inset));
226
+ /* 片段跨行时两半各自收边,否则圆角只画在整段的首尾。两条都写:WebKit 只认带前缀那条 */
227
+ -webkit-box-decoration-break: clone;
228
+ box-decoration-break: clone;
229
+ }
230
+
231
+ [data-scope='diff-view'][data-part='inline-change'][data-change='added'] {
232
+ background: color-mix(in oklab, var(--xh-diff-view-added-fg, var(--xh-diff-added-fg)) 18%, transparent);
233
+ }
234
+
235
+ [data-scope='diff-view'][data-part='inline-change'][data-change='removed'] {
236
+ background: color-mix(in oklab, var(--xh-diff-view-removed-fg, var(--xh-diff-removed-fg)) 18%, transparent);
237
+ }
238
+
239
+ [data-scope='diff-view'][data-part='token'][data-kind='comment'] {
240
+ color: var(--xh-diff-view-comment-fg, var(--xh-fg-muted));
241
+ font-style: italic;
242
+ }
243
+
244
+ [data-scope='diff-view'][data-part='token'][data-kind='string'] {
245
+ color: var(--xh-diff-view-string-fg, var(--xh-syntax-string));
246
+ }
247
+
248
+ [data-scope='diff-view'][data-part='token'][data-kind='number'] {
249
+ color: var(--xh-diff-view-number-token-fg, var(--xh-syntax-number));
250
+ }
251
+
252
+ [data-scope='diff-view'][data-part='token'][data-kind='keyword'] {
253
+ color: var(--xh-diff-view-keyword-fg, var(--xh-syntax-keyword));
254
+ font-weight: var(--xh-diff-view-keyword-weight, var(--xh-font-weight-semibold));
255
+ }
256
+
257
+ [data-scope='diff-view'][data-part='token'][data-kind='punctuation'] {
258
+ color: var(--xh-diff-view-punctuation-fg, var(--xh-fg-subtle));
259
+ }
260
+
261
+ /* 折起来的那一行:整行都是展开按钮。行是淡底承载面,向按钮下发 hover 200 → pressed 300(§7.2) */
262
+ [data-scope='diff-view'][data-part='gap'] {
263
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
264
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
265
+
266
+ background: var(--xh-diff-view-gap-bg, var(--xh-bg-subtle));
267
+ }
268
+
269
+ [data-scope='diff-view'][data-part='gap-cell'] {
270
+ display: block;
271
+ flex: 1 1 auto;
272
+ }
273
+
274
+ [data-scope='diff-view'][data-part='gap-cell'][hidden] {
275
+ display: none;
276
+ }
277
+
278
+ /* 展开按钮铺满折叠格,盒型、悬停与按下面由 Action Control 的 disclosure-trigger 档给(ghost 形态,
279
+ 按下只换面不缩放,§9.2);这里只把使用者槽映射到桥接槽:圆角归零贴住格边、纵向内衬归零、
280
+ 高度锚在代码行高上让折叠格与相邻代码行同高,字号跟着正文走 */
281
+ [data-scope='diff-view'][data-part='gap-trigger'] {
282
+ --xh-action-radius: 0;
283
+ --xh-action-visual-size: var(--xh-diff-view-line-height, var(--xh-text-code-leading));
284
+ --xh-action-padding-inline: var(--xh-diff-view-px, var(--xh-_diff-view-px));
285
+ --xh-action-padding-block: 0;
286
+ --xh-action-font-size: var(--xh-diff-view-font-size, var(--xh-_diff-view-font-size));
287
+ --xh-action-fg-rest: var(--xh-diff-view-gap-fg, var(--xh-fg-muted));
288
+ --xh-action-bg-hover: var(--xh-diff-view-gap-bg-hover, var(--xh-_action-variant-bg-hover));
289
+
290
+ border-width: 0;
291
+ }
292
+
293
+ [data-scope='diff-view'][data-part='gap-trigger'][hidden] {
294
+ display: none;
295
+ }
296
+
297
+ [data-scope='diff-view'][data-part='empty'] {
298
+ display: block;
299
+ padding-inline: var(--xh-diff-view-px, var(--xh-_diff-view-px));
300
+ padding-block: var(--xh-diff-view-py, var(--xh-_diff-view-py));
301
+ color: var(--xh-diff-view-empty-fg, var(--xh-fg-muted));
302
+ font-size: var(--xh-diff-view-header-font-size, var(--xh-text-secondary-size));
303
+ }
304
+
305
+ [data-scope='diff-view'][data-part='empty'][hidden] {
306
+ display: none;
307
+ }
308
+
309
+ /* 截断提示条:这份差异不完整。它比 empty 显眼一档——空差异只是没东西可看,
310
+ 被砍过的差异看着像完整的,读的人不主动往这儿看就不会知道 */
311
+ [data-scope='diff-view'][data-part='truncation'] {
312
+ display: flex;
313
+ align-items: center;
314
+ gap: var(--xh-diff-view-truncation-gap, var(--xh-space-2));
315
+ padding-inline: var(--xh-diff-view-px, var(--xh-_diff-view-px));
316
+ padding-block: var(--xh-diff-view-py, var(--xh-_diff-view-py));
317
+ border-block-start: var(--xh-stroke-thin) solid
318
+ var(--xh-diff-view-truncation-border, var(--xh-border-subtle));
319
+ background: var(--xh-diff-view-truncation-bg,
320
+ color-mix(in oklab, var(--xh-fg-warning) 12%, var(--xh-bg-surface)));
321
+ color: var(--xh-diff-view-truncation-fg,
322
+ color-mix(in oklab, var(--xh-fg-warning) 60%, var(--xh-fg-default)));
323
+ font-size: var(--xh-diff-view-header-font-size, var(--xh-text-secondary-size));
324
+ }
325
+
326
+ [data-scope='diff-view'][data-part='truncation'][hidden] {
327
+ display: none;
328
+ }
329
+
330
+ /* 提示条的文字由适配器填,所以字形不走 :empty 那条兜底路径,恒画一枚;
331
+ 不要它就把 --xh-glyph-mark-warning 在子树上置 none */
332
+ [data-scope='diff-view'][data-part='truncation']::before {
333
+ content: '';
334
+ flex: none;
335
+ display: inline-block;
336
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
337
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
338
+ vertical-align: var(--xh-glyph-baseline-shift);
339
+ background-color: currentColor;
340
+ -webkit-mask: var(--xh-glyph-mark-warning) center / contain no-repeat;
341
+ mask: var(--xh-glyph-mark-warning) center / contain no-repeat;
342
+ }
343
+
344
+ /* 尺寸档改字号、内衬与图标档 */
345
+ [data-scope='diff-view'][data-part='root'][data-size='sm'] {
346
+ --xh-icon-size: var(--xh-diff-view-icon-size, var(--xh-glyph-size-sm));
347
+ --xh-_diff-view-font-size: var(--xh-control-font-sm);
348
+ --xh-_diff-view-px: var(--xh-space-2);
349
+ --xh-_diff-view-py: var(--xh-space-1);
350
+ }
351
+
352
+ [data-scope='diff-view'][data-part='root'][data-size='md'] {
353
+ --xh-_diff-view-font-size: var(--xh-control-font-md);
354
+ --xh-_diff-view-px: var(--xh-space-3);
355
+ --xh-_diff-view-py: var(--xh-space-2);
356
+ }
357
+
358
+ [data-scope='diff-view'][data-part='root'][data-size='lg'] {
359
+ --xh-icon-size: var(--xh-diff-view-icon-size, var(--xh-glyph-size-lg));
360
+ --xh-_diff-view-font-size: var(--xh-control-font-lg);
361
+ --xh-_diff-view-px: var(--xh-space-4);
362
+ --xh-_diff-view-py: var(--xh-space-3);
363
+ }
364
+
365
+ /* 宽档:视口放得下两列,并排视图回到一行两侧 */
366
+ @media (min-width: 1024px) {
367
+ [data-scope='diff-view'][data-part='root'][data-view='split'] [data-part='row']:not([hidden]) {
368
+ display: flex;
369
+ }
370
+
371
+ /* 两列之间的接缝:新侧的行号槽再补一条左边线。只在并排时是接缝,
372
+ 堆叠时它落在段首,成了一条与任何东西都不相接的竖线 */
373
+ [data-scope='diff-view'][data-part='root'][data-view='split'] [data-part='line-number'][data-side='new'] {
374
+ border-inline-start: var(--xh-stroke-thin) solid var(--xh-diff-view-divider, var(--xh-border-subtle));
375
+ }
376
+ }
377
+
378
+ /*
379
+ * 高对比档:新增行那条实心色条写在 box-shadow 上、删除行那条斜纹写在渐变上,
380
+ * 这一档里两者一起被丢弃,只剩两个被系统换成同色的底。
381
+ * 改画两圈内收的环,实线对新增、虚线对删除,两档在纯系统色下仍分得开。
382
+ * 用 outline 不用 border:行是横排 flex,加边会把行号与内容一起往里推,
383
+ * 没有变更的行不加边,同一屏上的行首就对不齐了。
384
+ */
385
+ @media (forced-colors: active) {
386
+ [data-scope='diff-view'][data-part='row'][data-change='added'] {
387
+ outline: var(--xh-stroke-thick) solid CanvasText;
388
+ outline-offset: calc(-1 * var(--xh-stroke-thick));
389
+ }
390
+
391
+ [data-scope='diff-view'][data-part='row'][data-change='removed'] {
392
+ outline: var(--xh-stroke-thick) dashed CanvasText;
393
+ outline-offset: calc(-1 * var(--xh-stroke-thick));
394
+ }
395
+ }
396
+
397
+ /*
398
+ * 打印:底色与背景图一起被丢掉,新增行那条实心色条写在 box-shadow 上、
399
+ * 删除行那条斜纹写在渐变上,两者在纸上都不出现,两种变更就此糊成一样。
400
+ * 与高对比档同一套办法:实线环对新增、虚线环对删除,都是印得出来的通道。
401
+ */
402
+ @media print {
403
+ [data-scope='diff-view'][data-part='row'][data-change='added'] {
404
+ outline: var(--xh-stroke-thick) solid currentColor;
405
+ outline-offset: calc(-1 * var(--xh-stroke-thick));
406
+ }
407
+
408
+ [data-scope='diff-view'][data-part='row'][data-change='removed'] {
409
+ outline: var(--xh-stroke-thick) dashed currentColor;
410
+ outline-offset: calc(-1 * var(--xh-stroke-thick));
411
+ }
412
+ }
413
+ }
414
+
415
+ @layer xihan.motion {
416
+ /* 露出来的行从上一行底下推出来:位移走幅度令牌,减弱动效档把它归零 */
417
+ @keyframes xh-diff-view-reveal {
418
+ from {
419
+ opacity: 0;
420
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
421
+ }
422
+
423
+ to {
424
+ opacity: 1;
425
+ translate: 0 0;
426
+ }
427
+ }
428
+ }
@@ -1,3 +1,33 @@
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
+ /* 定义 download trigger 样式。 */
7
+
8
+ @import '../family/action-control.css';
9
+
10
+ @layer xihan.motion {
11
+ /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
12
+ @keyframes xh-download-trigger-rotate {
13
+ to {
14
+ rotate: 360deg;
15
+ }
16
+ }
17
+
18
+ @keyframes xh-download-trigger-loading-reveal {
19
+ to {
20
+ opacity: 1;
21
+ }
22
+ }
23
+
24
+ @keyframes xh-download-trigger-content-hide {
25
+ to {
26
+ color: transparent;
27
+ }
28
+ }
29
+ }
30
+
1
31
  @layer xihan.components {
2
32
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
33
  [data-scope='download-trigger'] {
@@ -5,35 +35,49 @@
5
35
  }
6
36
 
7
37
  /*
8
- * 触发器就是这一个原生按钮,两个适配器都由组件自己渲染它,
9
- * 所以外观得由设计系统给出一份完整的中性按钮:底色、描边、高度、字号都上令牌,
38
+ * 触发器就是这一个原生按钮,是定尺的独立动作按钮(§9.1):盒型、三档几何、四态面、0.97 按压与粗指针
39
+ * 命中区由家族配方按 data-xh-action-variant / -size 给出(缺省 subtle 由连接层显式投影,只有 solid 才品牌实心)。
40
+ * 这里只把公开槽桥接到矩阵之前(使用者槽 → 形态矩阵 → 家族缺省)与几何槽映射;
10
41
  * 要换成品牌样式的作者改 --xh-download-trigger-* 这一族槽位,或直接写自己的类名。
11
42
  */
12
43
  [data-scope='download-trigger'][data-part='root'] {
13
- display: inline-flex;
14
- align-items: center;
15
- justify-content: center;
16
- gap: var(--xh-download-trigger-gap, var(--xh-control-gap-md));
17
- block-size: var(--xh-download-trigger-h, var(--xh-control-h-md));
18
- padding-inline: var(--xh-download-trigger-px, var(--xh-control-px-md));
19
- padding-block: 0;
20
- border: var(--xh-stroke-thin) solid var(--xh-download-trigger-border, var(--xh-border-control));
21
- border-radius: var(--xh-download-trigger-radius, var(--xh-shape-control));
22
- background: var(--xh-download-trigger-bg, var(--xh-bg-canvas));
23
- color: var(--xh-download-trigger-fg, var(--xh-fg-default));
24
- /* 表单控件不继承页面字体,只给字号会让按钮用 UA 默认字族 */
25
- font-family: inherit;
26
- font-size: var(--xh-download-trigger-font-size, var(--xh-text-label-size));
44
+ --xh-action-bg-rest: var(--xh-download-trigger-bg, var(--xh-_action-variant-bg-rest));
45
+ --xh-action-bg-hover: var(--xh-download-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
46
+ --xh-action-bg-pressed: var(--xh-download-trigger-bg-active, var(--xh-_action-variant-bg-pressed));
47
+ --xh-action-bg-focus-visible: var(--xh-download-trigger-bg, var(--xh-_action-variant-bg-focus-visible));
48
+ --xh-action-bg-loading: var(--xh-download-trigger-bg, var(--xh-_action-variant-bg-loading));
49
+ --xh-action-bg-disabled: var(--xh-download-trigger-bg-disabled, var(--xh-_action-variant-bg-disabled));
50
+ --xh-action-fg-rest: var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-rest));
51
+ --xh-action-fg-hover: var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-hover));
52
+ --xh-action-fg-pressed: var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-pressed));
53
+ --xh-action-fg-focus-visible: var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-focus-visible));
54
+ --xh-action-fg-loading: var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-loading));
55
+ --xh-action-border-rest: var(--xh-download-trigger-border, var(--xh-_action-variant-border-rest));
56
+ --xh-action-border-hover: var(--xh-download-trigger-border-hover, var(--xh-_action-variant-border-hover));
57
+ --xh-action-border-pressed: var(--xh-download-trigger-border-hover, var(--xh-_action-variant-border-pressed));
58
+ --xh-action-border-focus-visible: var(--xh-download-trigger-border, var(--xh-_action-variant-border-focus-visible));
59
+ --xh-action-border-disabled: var(--xh-download-trigger-border-disabled, var(--xh-_action-variant-border-disabled));
60
+ /* 矩阵各态无影(§8.3 淡底与阴影互斥):solid 也不再悬停抬影,使用者槽仍可自行加 */
61
+ --xh-action-shadow-hover: var(--xh-download-trigger-shadow-hover, none);
62
+ --xh-action-radius: var(--xh-download-trigger-radius, var(--xh-shape-control));
63
+ --xh-action-visual-size: var(--xh-download-trigger-h, var(--xh-_action-profile-visual-size));
64
+ --xh-action-padding-inline: var(--xh-download-trigger-px, var(--xh-_action-profile-padding-inline));
65
+ --xh-action-gap: var(--xh-download-trigger-gap, var(--xh-_action-profile-gap));
66
+ --xh-action-font-size: var(--xh-download-trigger-font-size, var(--xh-_action-profile-font-size));
67
+ /* 作者塞进来的图标跟着尺寸档走,与皮肤画的兜底字形同一把尺 */
68
+ --xh-icon-size: var(--xh-download-trigger-icon-size, var(--xh-_action-profile-glyph-size));
69
+ /* 取数在途那枚圆环的颜色:字被 content-hide 关键帧压成透明,环不能跟着 currentColor 走,取加载态的前景 */
70
+ --xh-_download-trigger-loading-fg: var(--xh-download-trigger-loading-fg, var(--xh-download-trigger-fg, var(--xh-_action-variant-fg-loading)));
71
+
72
+ /* safe:文案放不下时居中改成靠行首排,裁掉的是末尾那截,开头仍然读得到 */
73
+ justify-content: safe center;
27
74
  font-weight: var(--xh-download-trigger-font-weight, var(--xh-text-label-weight));
28
- line-height: var(--xh-leading-none);
29
- white-space: nowrap;
30
- cursor: pointer;
75
+ /* 文案比所在那一栏还长时,按钮的盒收到栏宽为止,多出来的字在行内一轴裁掉,
76
+ 整颗按钮不再撑破侧栏。块轴留 visible:粗指针那一档的命中区是往块轴外扩的伪元素 */
77
+ max-inline-size: 100%;
78
+ overflow-x: clip;
31
79
  /* 导出键常被连点,触屏上默认会当成双击缩放 */
32
- user-select: none;
33
80
  touch-action: manipulation;
34
- transition:
35
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
36
- border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
37
81
  }
38
82
 
39
83
  /* 上面声明了 display,会盖掉 UA 的 [hidden] 规则,收起态要在这里接回来 */
@@ -41,36 +85,101 @@
41
85
  display: none;
42
86
  }
43
87
 
44
- [data-scope='download-trigger'][data-part='root']:hover {
45
- border-color: var(--xh-download-trigger-border-hover, var(--xh-border-control-hover));
46
- background: var(--xh-download-trigger-bg-hover, var(--xh-bg-subtle-hover));
88
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
89
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的 */
90
+ [data-scope='download-trigger'][data-part='root'][data-xh-action-variant='solid']:focus-visible {
91
+ --xh-action-ring-color-focus-visible: currentColor;
92
+ }
93
+
94
+ /* 没写内容就由皮肤画兜底字形;作者往按钮里塞了文字或自己的图形,这几条即不命中。
95
+ 字形另起一颗 ::after:::before 是转圈那枚圆环的方框,mask 会把描边裁成字形轮廓、圆环就此消失。
96
+ 取数在途那一档不画字形,那一格让给圆环 */
97
+ [data-scope='download-trigger'][data-part='root']:empty:not([aria-busy='true'])::after {
98
+ content: '';
99
+ display: inline-block;
100
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
101
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
102
+ vertical-align: var(--xh-glyph-baseline-shift);
103
+ background-color: currentColor;
104
+ -webkit-mask: var(--xh-glyph-mark-download) center / contain no-repeat;
105
+ mask: var(--xh-glyph-mark-download) center / contain no-repeat;
47
106
  }
48
107
 
49
- [data-scope='download-trigger'][data-part='root']:active {
50
- background: var(--xh-download-trigger-bg-active, var(--xh-bg-subtle-active));
108
+ /* 快速取数不显示瞬时圆环;超过一个 micro 周期后才在原位换成加载状态。 */
109
+ [data-scope='download-trigger'][data-part='root'][data-state='preparing'][aria-busy='true'] {
110
+ cursor: progress;
111
+ animation: xh-download-trigger-content-hide var(--xh-motion-duration-micro) var(--xh-motion-ease-enter)
112
+ var(--xh-motion-duration-micro) forwards;
51
113
  }
52
114
 
53
- [data-scope='download-trigger'][data-part='root']:focus-visible {
54
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
55
- outline-offset: var(--xh-ring-offset);
115
+ [data-scope='download-trigger'][data-part='root'][aria-busy='true']::before {
116
+ content: '';
117
+ position: absolute;
118
+ inset: 0;
119
+ inline-size: 1em;
120
+ block-size: 1em;
121
+ margin: auto;
122
+ border: var(--xh-stroke-thin) solid transparent;
123
+ border-block-start-color: var(--xh-_download-trigger-loading-fg);
124
+ /* 正圆的加载环:正方盒取 circle(§6.3) */
125
+ border-radius: var(--xh-shape-circle);
126
+ opacity: 0;
127
+ animation:
128
+ xh-download-trigger-rotate var(--xh-download-trigger-loading-duration, var(--xh-spin-duration)) var(--xh-motion-ease-loop) infinite,
129
+ xh-download-trigger-loading-reveal var(--xh-motion-duration-micro) var(--xh-motion-ease-enter) var(--xh-motion-duration-micro) forwards;
56
130
  }
57
131
 
58
- /* 取数在途:按钮留在原地不动,只换指针形状——位置一变,正要再点的人就点空了 */
59
- [data-scope='download-trigger'][data-part='root'][data-state='preparing'] {
60
- cursor: progress;
132
+ @media (prefers-reduced-motion: reduce) {
133
+ [data-scope='download-trigger'][data-part='root'][aria-busy='true'] {
134
+ color: transparent;
135
+ animation: none;
136
+ }
137
+
138
+ [data-scope='download-trigger'][data-part='root'][aria-busy='true']::before {
139
+ border-style: dotted;
140
+ border-color: var(--xh-_download-trigger-loading-fg);
141
+ opacity: 1;
142
+ animation: none;
143
+ }
61
144
  }
62
145
 
63
- /*
64
- * 单体原生控件的禁用走 :disabled。前景与底色一起换,禁用前后两侧都由令牌管着;
65
- * 用了 fg-disabled 就不再叠 opacity——两样一起用会压到读不出来。
66
- * 这条排在悬停与按下之后,特异度相同、后写的赢。
67
- * 描边仍按可操作区那一档:这是一颗独立按钮,四周没有别的结构标出它的位置,
68
- * 描边一压下去整颗按钮在页面上就没影了。
69
- */
70
- [data-scope='download-trigger'][data-part='root']:disabled {
71
- border-color: var(--xh-download-trigger-border-disabled, var(--xh-border-control));
72
- background: var(--xh-download-trigger-bg-disabled, var(--xh-bg-muted));
73
- color: var(--xh-fg-disabled);
74
- cursor: not-allowed;
146
+ :where([data-motion='reduce']) [data-scope='download-trigger'][data-part='root'][aria-busy='true'] {
147
+ color: transparent;
148
+ animation: none;
149
+ }
150
+
151
+ :where([data-motion='reduce']) [data-scope='download-trigger'][data-part='root'][aria-busy='true']::before {
152
+ border-style: dotted;
153
+ border-color: var(--xh-_download-trigger-loading-fg);
154
+ opacity: 1;
155
+ animation: none;
156
+ }
157
+
158
+ /* 手指落点:配方 text 档用 ::after 把块轴命中区扩到 44px;没写内容的按钮 ::after 已被兜底字形占着,
159
+ 这一档改用当时空着的 ::before 扩——取数在途时字形不画、::before 是圆环,配方的 ::after 又能落下来,
160
+ 两颗伪元素轮着用。字形那条只写了尺寸与 mask,配方的定位、44px 下限与 -50% 平移会从同一个
161
+ ::after 漏进来:字形被拎出行内流、盒撑到 44px 高,按钮随之收窄一格字形——这里逐项钉回 */
162
+ @media (pointer: coarse) {
163
+ [data-scope='download-trigger'][data-part='root']:empty:not([aria-busy='true'])::after {
164
+ position: static;
165
+ min-block-size: 0;
166
+ translate: none;
167
+ }
168
+
169
+ [data-scope='download-trigger'][data-part='root']:empty:not([aria-busy='true'])::before {
170
+ content: '';
171
+ position: absolute;
172
+ inset-block-start: 50%;
173
+ inset-inline-start: 50%;
174
+ min-block-size: 44px;
175
+ inline-size: 100%;
176
+ block-size: 100%;
177
+ translate: -50% -50%;
178
+ }
179
+
180
+ /* 与家族同一笔:起点是逻辑属性、平移是物理通道,rtl 下行内分量掉头,热区才落回按钮中心 */
181
+ [data-scope='download-trigger'][data-part='root']:empty:not([aria-busy='true']):dir(rtl)::before {
182
+ translate: 50% -50%;
183
+ }
75
184
  }
76
185
  }