@xihan-ui/styles 1.0.0-alpha.2 → 1.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 (122) hide show
  1. package/CHANGELOG.md +2177 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +80 -6
  4. package/css/alert.css +43 -14
  5. package/css/anchor.css +8 -8
  6. package/css/avatar-group.css +7 -3
  7. package/css/avatar.css +9 -3
  8. package/css/back-top.css +22 -1
  9. package/css/badge.css +104 -32
  10. package/css/breadcrumb.css +25 -5
  11. package/css/button-group.css +18 -13
  12. package/css/button.css +48 -11
  13. package/css/calendar.css +150 -7
  14. package/css/card.css +20 -11
  15. package/css/carousel.css +36 -5
  16. package/css/cascader.css +211 -124
  17. package/css/checkbox-group.css +72 -22
  18. package/css/checkbox.css +70 -13
  19. package/css/clipboard.css +2 -1
  20. package/css/code-block.css +12 -7
  21. package/css/collapsible.css +49 -3
  22. package/css/color-picker.css +132 -46
  23. package/css/combobox.css +132 -60
  24. package/css/composer.css +5 -3
  25. package/css/context-menu.css +113 -74
  26. package/css/date-field.css +93 -16
  27. package/css/date-picker.css +293 -72
  28. package/css/descriptions.css +11 -5
  29. package/css/dialog.css +47 -14
  30. package/css/download-trigger.css +76 -0
  31. package/css/drawer.css +57 -16
  32. package/css/dynamic-input.css +75 -17
  33. package/css/editable.css +12 -10
  34. package/css/ellipsis.css +7 -1
  35. package/css/empty-state.css +22 -12
  36. package/css/field.css +16 -6
  37. package/css/fieldset.css +69 -0
  38. package/css/file-upload.css +46 -8
  39. package/css/flex.css +13 -7
  40. package/css/float-button.css +23 -1
  41. package/css/floating-panel.css +316 -0
  42. package/css/form.css +4 -4
  43. package/css/grid.css +11 -5
  44. package/css/heatmap.css +411 -0
  45. package/css/highlight.css +2 -2
  46. package/css/hotkeys.css +90 -0
  47. package/css/hover-card.css +43 -45
  48. package/css/image-cropper.css +233 -0
  49. package/css/image-viewer.css +155 -17
  50. package/css/image.css +2 -2
  51. package/css/infinite-scroll.css +1 -1
  52. package/css/json-viewer.css +274 -0
  53. package/css/layout.css +19 -15
  54. package/css/list.css +22 -13
  55. package/css/listbox.css +24 -6
  56. package/css/loading-bar.css +12 -5
  57. package/css/log.css +7 -3
  58. package/css/marquee.css +9 -0
  59. package/css/masonry.css +63 -0
  60. package/css/mention.css +100 -36
  61. package/css/menu.css +127 -50
  62. package/css/menubar.css +155 -61
  63. package/css/navigation-menu.css +56 -31
  64. package/css/notification.css +377 -0
  65. package/css/number-animation.css +3 -3
  66. package/css/number-field.css +182 -19
  67. package/css/overlay-arrow.css +51 -0
  68. package/css/page-header.css +12 -5
  69. package/css/pagination.css +171 -14
  70. package/css/password-input.css +356 -0
  71. package/css/pin-input.css +15 -12
  72. package/css/popconfirm.css +55 -12
  73. package/css/popover.css +73 -45
  74. package/css/popselect.css +207 -57
  75. package/css/progress.css +54 -8
  76. package/css/qr-code.css +1 -1
  77. package/css/radio-group.css +27 -10
  78. package/css/rating.css +4 -4
  79. package/css/reset.css +17 -0
  80. package/css/result.css +21 -11
  81. package/css/scroll-area.css +61 -89
  82. package/css/scrollbar.css +170 -0
  83. package/css/segmented.css +215 -0
  84. package/css/select.css +298 -131
  85. package/css/separator.css +2 -2
  86. package/css/side-nav.css +127 -24
  87. package/css/signature-pad.css +144 -0
  88. package/css/skeleton.css +7 -1
  89. package/css/slider.css +14 -12
  90. package/css/space.css +117 -0
  91. package/css/spinner.css +22 -10
  92. package/css/statistic.css +9 -9
  93. package/css/steps.css +29 -12
  94. package/css/switch.css +57 -8
  95. package/css/table.css +146 -44
  96. package/css/tabs.css +13 -5
  97. package/css/tag.css +179 -0
  98. package/css/tags-input.css +80 -42
  99. package/css/text-field.css +151 -38
  100. package/css/thread.css +11 -3
  101. package/css/time-field.css +99 -18
  102. package/css/time-picker.css +261 -71
  103. package/css/timeline.css +15 -15
  104. package/css/timer.css +119 -0
  105. package/css/toast.css +129 -55
  106. package/css/toggle-group.css +30 -4
  107. package/css/toggle.css +12 -6
  108. package/css/tone.css +57 -22
  109. package/css/toolbar.css +1 -1
  110. package/css/tooltip.css +40 -31
  111. package/css/tour.css +112 -61
  112. package/css/transfer.css +98 -21
  113. package/css/tree-select.css +215 -89
  114. package/css/tree.css +131 -5
  115. package/css/typography.css +5 -5
  116. package/css/undefined.css +12 -1
  117. package/css/virtualizer.css +3 -1
  118. package/css/watermark.css +1 -2
  119. package/index.css +18 -1
  120. package/index.unlayered.css +10356 -3255
  121. package/package.json +20 -4
  122. package/css/toaster.css +0 -74
@@ -0,0 +1,274 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='json-viewer'] {
4
+ --xh-json-viewer-skin: 1;
5
+ }
6
+
7
+ /* 缺省态(md 档)。等宽字体让层级缩进与值的长度对得齐。
8
+ 逐类型配色走 --xh-syntax-* 语法令牌,与代码块的记号色同源、随主题明暗切换。 */
9
+ [data-scope='json-viewer'][data-part='root'] {
10
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
11
+ --xh-icon-size: var(--xh-json-viewer-icon-size, var(--xh-glyph-size-text));
12
+
13
+ --xh-_json-viewer-font-size: var(--xh-control-caption-md);
14
+ --xh-_json-viewer-row-py: var(--xh-space-0_5);
15
+ --xh-_json-viewer-indent: var(--xh-space-4);
16
+ --xh-json-viewer-key-fg: var(--xh-fg-brand-strong);
17
+ --xh-json-viewer-punctuation-fg: var(--xh-fg-subtle);
18
+ --xh-json-viewer-null-fg: var(--xh-fg-subtle);
19
+ --xh-json-viewer-string-fg: var(--xh-syntax-string);
20
+ --xh-json-viewer-number-fg: var(--xh-syntax-number);
21
+ --xh-json-viewer-boolean-fg: var(--xh-syntax-keyword);
22
+
23
+ /* 两档的自绘条浮在内容之上:轨道不上底色,实色轨道会沿容器边缘糊出一条灰带 */
24
+ --xh-scrollbar-track-bg: transparent;
25
+
26
+ /* 自绘条绝对定位贴这一层的内边距盒,它得是定位盒 */
27
+ position: relative;
28
+ display: block;
29
+ color: var(--xh-json-viewer-fg, var(--xh-fg-default));
30
+ font-family: var(--xh-json-viewer-font, var(--xh-font-family-mono));
31
+ font-size: var(--xh-json-viewer-font-size, var(--xh-_json-viewer-font-size));
32
+ line-height: var(--xh-leading-normal);
33
+ }
34
+
35
+ /* 写了 display 就会盖掉 UA 的 [hidden]{display:none},这里补回 */
36
+ [data-scope='json-viewer'][data-part='root'][hidden] {
37
+ display: none;
38
+ }
39
+
40
+ /* 尺寸轴只换私有槽,部件从 root 继承 */
41
+ [data-scope='json-viewer'][data-part='root'][data-size='sm'] {
42
+ --xh-_json-viewer-font-size: var(--xh-control-caption-sm);
43
+ --xh-_json-viewer-row-py: var(--xh-space-0);
44
+ --xh-_json-viewer-indent: var(--xh-space-3);
45
+ }
46
+
47
+ [data-scope='json-viewer'][data-part='root'][data-size='lg'] {
48
+ --xh-_json-viewer-font-size: var(--xh-control-caption-lg);
49
+ --xh-_json-viewer-row-py: var(--xh-space-1);
50
+ --xh-_json-viewer-indent: var(--xh-space-5);
51
+ }
52
+
53
+ /* 常驻容器不是浮层:两轴都可能溢出——深层缩进往行首方向推、长字符串往行尾伸 */
54
+ [data-scope='json-viewer'][data-part='tree'] {
55
+ display: flex;
56
+ flex-direction: column;
57
+ max-block-size: var(--xh-json-viewer-max-h, var(--xh-viewport-max-h));
58
+ padding-block: var(--xh-json-viewer-py, var(--xh-space-2));
59
+ padding-inline: var(--xh-json-viewer-px, var(--xh-space-2));
60
+ border: var(--xh-stroke-thin) solid var(--xh-json-viewer-border, var(--xh-border-default));
61
+ border-radius: var(--xh-json-viewer-radius, var(--xh-shape-surface));
62
+ background: var(--xh-json-viewer-bg, var(--xh-bg-surface));
63
+ overflow: auto;
64
+ }
65
+
66
+ /* 原文档:与树档共用同一套边框、内衬与高度令牌,两档切过去盒子不跳。
67
+ 整块可框选——这一档存在的理由就是把与后端一字不差的那份原文交到手上 */
68
+ [data-scope='json-viewer'][data-part='text'] {
69
+ margin: 0;
70
+ max-block-size: var(--xh-json-viewer-max-h, var(--xh-viewport-max-h));
71
+ padding-block: var(--xh-json-viewer-py, var(--xh-space-2));
72
+ padding-inline: var(--xh-json-viewer-px, var(--xh-space-2));
73
+ border: var(--xh-stroke-thin) solid var(--xh-json-viewer-border, var(--xh-border-default));
74
+ border-radius: var(--xh-json-viewer-radius, var(--xh-shape-surface));
75
+ background: var(--xh-json-viewer-bg, var(--xh-bg-surface));
76
+ color: var(--xh-json-viewer-text-fg, var(--xh-fg-default));
77
+ font-family: var(--xh-json-viewer-font, var(--xh-font-family-mono));
78
+ /* 缩进靠空格,行不折:折行会把层级读乱,横向给滚动条 */
79
+ white-space: pre;
80
+ tab-size: 2;
81
+ overflow: auto;
82
+ user-select: text;
83
+ }
84
+
85
+ [data-scope='json-viewer'][data-part='text'][hidden] {
86
+ display: none;
87
+ }
88
+
89
+ /* 这一档没有行可落焦,环画在整块上 */
90
+ [data-scope='json-viewer'][data-part='text']:focus-visible {
91
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
92
+ outline-offset: calc(-1 * var(--xh-ring-width));
93
+ }
94
+ [data-scope='json-viewer'][data-part='tree'][hidden] {
95
+ display: none;
96
+ }
97
+
98
+ /* 焦点在树外时容器自己进 Tab 序列兜底,落焦不画环:环永远长在行上 */
99
+ [data-scope='json-viewer'][data-part='tree']:focus-visible {
100
+ outline: none;
101
+ }
102
+
103
+ /* 焦点落在 branch 上(它才是 treeitem),但环画在它自己那一行上:
104
+ 整棵子层套一圈描边会把展开的层级全框进去 */
105
+ [data-scope='json-viewer'][data-part='branch']:focus-visible {
106
+ outline: none;
107
+ }
108
+
109
+ [data-scope='json-viewer'][data-part='branch']:focus-visible > [data-scope='json-viewer'][data-part='branch-control'] {
110
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
111
+ /* 往内收:行是撑满宽度的,环画在外沿会被容器裁掉 */
112
+ outline-offset: calc(-1 * var(--xh-ring-width));
113
+ }
114
+
115
+ /* 行:标量与分支共用同一套盒子,两种行在视觉上必须齐平 */
116
+ [data-scope='json-viewer'][data-part='item'],
117
+ [data-scope='json-viewer'][data-part='branch-control'] {
118
+ display: flex;
119
+ align-items: baseline;
120
+ gap: var(--xh-json-viewer-row-gap, var(--xh-space-1));
121
+ padding-block: var(--xh-json-viewer-row-py, var(--xh-_json-viewer-row-py));
122
+ padding-inline: var(--xh-json-viewer-row-px, var(--xh-space-1));
123
+ border-radius: var(--xh-json-viewer-row-radius, var(--xh-shape-inset));
124
+ white-space: nowrap;
125
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
126
+ }
127
+
128
+ [data-scope='json-viewer'][data-part='item'][hidden],
129
+ [data-scope='json-viewer'][data-part='branch-control'][hidden] {
130
+ display: none;
131
+ }
132
+
133
+ /* 悬停与键盘锚点共用中性灰轻档:data-highlighted 跟的是连接层记的焦点行,
134
+ 键盘落焦另有聚焦环标记位置 */
135
+ [data-scope='json-viewer'][data-part='item']:is(:hover, [data-highlighted]),
136
+ [data-scope='json-viewer'][data-part='branch-control']:is(:hover, [data-highlighted]) {
137
+ background: var(--xh-json-viewer-row-bg-hover, var(--xh-bg-subtle));
138
+ }
139
+
140
+ /* 分支那一行是唯一的点击目标:点它切换展开态 */
141
+ [data-scope='json-viewer'][data-part='branch-control'] {
142
+ cursor: pointer;
143
+ user-select: none;
144
+ }
145
+
146
+ /* 标量行的焦点环直接画在行上:它自己就是 treeitem */
147
+ [data-scope='json-viewer'][data-part='item']:focus-visible {
148
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
149
+ outline-offset: calc(-1 * var(--xh-ring-width));
150
+ }
151
+
152
+ /* 键名不参与压缩:它短且必须完整可读,被挤掉的应该是值 */
153
+ [data-scope='json-viewer'][data-part='item-key'],
154
+ [data-scope='json-viewer'][data-part='branch-text'] {
155
+ flex: none;
156
+ color: var(--xh-json-viewer-key-fg);
157
+ font-weight: var(--xh-json-viewer-key-font-weight, var(--xh-font-weight-medium));
158
+ }
159
+
160
+ /* 键名与值之间的冒号由皮肤画:它是排版符号,进不了可及名字反而更清爽 */
161
+ [data-scope='json-viewer'][data-part='item-key']::after,
162
+ [data-scope='json-viewer'][data-part='branch-text']::after {
163
+ content: ':';
164
+ color: var(--xh-json-viewer-punctuation-fg);
165
+ }
166
+
167
+ /* 弹性子项默认最小尺寸是内容尺寸,不归零则长字符串把行撑破、省略号轮不上 */
168
+ [data-scope='json-viewer'][data-part='item-value'] {
169
+ flex: 1 1 auto;
170
+ min-inline-size: 0;
171
+ overflow: hidden;
172
+ white-space: nowrap;
173
+ text-overflow: ellipsis;
174
+ }
175
+
176
+ [data-scope='json-viewer'][data-part='item-value'][data-type='string'] {
177
+ color: var(--xh-json-viewer-string-fg);
178
+ }
179
+
180
+ [data-scope='json-viewer'][data-part='item-value'][data-type='number'] {
181
+ color: var(--xh-json-viewer-number-fg);
182
+ }
183
+
184
+ [data-scope='json-viewer'][data-part='item-value'][data-type='boolean'] {
185
+ color: var(--xh-json-viewer-boolean-fg);
186
+ }
187
+
188
+ [data-scope='json-viewer'][data-part='item-value'][data-type='null'] {
189
+ color: var(--xh-json-viewer-null-fg);
190
+ }
191
+
192
+ /* 空对象与空数组只剩一对括号,跟标点同色 */
193
+ [data-scope='json-viewer'][data-part='item-value'][data-type='array'],
194
+ [data-scope='json-viewer'][data-part='item-value'][data-type='object'] {
195
+ color: var(--xh-json-viewer-punctuation-fg);
196
+ }
197
+
198
+ /* 循环引用与截断占位不是真数据,排在语气之外用弱化字重表达 */
199
+ [data-scope='json-viewer'][data-part='item-value'][data-circular],
200
+ [data-scope='json-viewer'][data-part='item-value'][data-truncated] {
201
+ color: var(--xh-fg-muted);
202
+ font-style: italic;
203
+ }
204
+
205
+ /* 展开箭头与勾选标记同宽,两种行的文字起点才对得齐 */
206
+ [data-scope='json-viewer'][data-part='branch-trigger'] {
207
+ display: inline-flex;
208
+ flex: none;
209
+ align-items: center;
210
+ justify-content: center;
211
+ inline-size: var(--xh-json-viewer-indicator-size, var(--xh-control-indicator-size));
212
+ color: var(--xh-json-viewer-indicator-fg, var(--xh-fg-subtle));
213
+ }
214
+
215
+ [data-scope='json-viewer'][data-part='branch-trigger'][hidden] {
216
+ display: none;
217
+ }
218
+
219
+ [data-scope='json-viewer'][data-part='branch-indicator'] {
220
+ display: inline-block;
221
+ line-height: var(--xh-leading-none);
222
+ transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
223
+ }
224
+
225
+ [data-scope='json-viewer'][data-part='branch-indicator'][hidden] {
226
+ display: none;
227
+ }
228
+
229
+ /* 没写内容就由皮肤画;作者往部件里塞了自己的图形,这条规则即不命中 */
230
+ [data-scope='json-viewer'][data-part='branch-indicator']:empty::before {
231
+ content: '';
232
+ display: inline-block;
233
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
234
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
235
+ vertical-align: var(--xh-glyph-baseline-shift);
236
+ background-color: currentColor;
237
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
238
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
239
+ }
240
+
241
+ /* 收起时朝向行首、展开时转向下方,与逻辑书写方向一致:
242
+ rtl 下 inline-start 在右侧,箭头因此要反着转 */
243
+ [data-scope='json-viewer'][data-part='branch-indicator'][data-state='open'] {
244
+ rotate: 90deg;
245
+ }
246
+
247
+ [dir='rtl'] [data-scope='json-viewer'][data-part='branch-indicator'] {
248
+ rotate: 180deg;
249
+ }
250
+
251
+ [dir='rtl'] [data-scope='json-viewer'][data-part='branch-indicator'][data-state='open'] {
252
+ rotate: 90deg;
253
+ }
254
+
255
+ /* 收起摘要不参与选中:框选整块 JSON 时不该把它一起复制走 */
256
+ [data-scope='json-viewer'][data-part='preview'] {
257
+ flex: none;
258
+ color: var(--xh-json-viewer-preview-fg, var(--xh-fg-muted));
259
+ font-size: var(--xh-json-viewer-preview-font-size, var(--xh-text-caption-size));
260
+ user-select: none;
261
+ }
262
+
263
+ /* 层级缩进靠子层容器自己顶:分支物理嵌套着子层,每深一层就多缩一格,
264
+ 无需把层级号写进内联样式,也就不必在两个适配器里各写一遍 */
265
+ [data-scope='json-viewer'][data-part='branch-content'] {
266
+ display: flex;
267
+ flex-direction: column;
268
+ padding-inline-start: var(--xh-json-viewer-indent, var(--xh-_json-viewer-indent));
269
+ }
270
+
271
+ [data-scope='json-viewer'][data-part='branch-content'][hidden] {
272
+ display: none;
273
+ }
274
+ }
package/css/layout.css CHANGED
@@ -40,9 +40,9 @@
40
40
  display: flex;
41
41
  grid-area: header;
42
42
  align-items: center;
43
- gap: var(--xh-space-3);
43
+ gap: var(--xh-layout-header-gap, var(--xh-space-3));
44
44
  block-size: var(--xh-_layout-header-h);
45
- padding-inline: var(--xh-space-4);
45
+ padding-inline: var(--xh-layout-header-px, var(--xh-space-4));
46
46
  background: var(--xh-layout-header-bg, var(--xh-bg-surface));
47
47
  }
48
48
 
@@ -51,13 +51,13 @@
51
51
  grid-area: sider;
52
52
  inline-size: var(--xh-_layout-sider-w);
53
53
  overflow: hidden;
54
- padding: var(--xh-space-3);
54
+ padding: var(--xh-layout-sider-padding, var(--xh-space-3));
55
55
  background: var(--xh-layout-sider-bg, var(--xh-bg-subtle));
56
56
  transition: inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
57
57
  }
58
58
 
59
59
  /* 折起来时不换行:窄到放不下的那几个字直接被 overflow 裁掉,不会挤成一列竖排 */
60
- [data-scope='layout'][data-part='sider'][data-state='collapsed'] {
60
+ [data-scope='layout'][data-part='sider'][data-collapsed] {
61
61
  inline-size: var(--xh-_layout-sider-collapsed-w);
62
62
  white-space: nowrap;
63
63
  }
@@ -66,15 +66,15 @@
66
66
  grid-area: content;
67
67
  /* 内容列已是 minmax(0, 1fr),这里再声明一次,宽表格与长串文本才撑不破列 */
68
68
  min-inline-size: 0;
69
- padding: var(--xh-space-4);
69
+ padding: var(--xh-layout-content-padding, var(--xh-space-4));
70
70
  }
71
71
 
72
72
  [data-scope='layout'][data-part='footer'] {
73
73
  grid-area: footer;
74
- padding: var(--xh-space-3) var(--xh-space-4);
74
+ padding: var(--xh-layout-footer-padding, var(--xh-space-3) var(--xh-space-4));
75
75
  background: var(--xh-layout-footer-bg, var(--xh-bg-surface));
76
76
  color: var(--xh-fg-muted);
77
- font-size: var(--xh-font-size-sm);
77
+ font-size: var(--xh-text-secondary-size);
78
78
  }
79
79
 
80
80
  /* —— 折叠把手 —— */
@@ -82,14 +82,14 @@
82
82
  display: inline-flex;
83
83
  align-items: center;
84
84
  justify-content: center;
85
- gap: var(--xh-control-gap-sm);
85
+ gap: var(--xh-layout-sider-trigger-gap, var(--xh-control-gap-sm));
86
86
  block-size: var(--xh-control-h-sm);
87
- padding-inline: var(--xh-control-px-sm);
87
+ padding-inline: var(--xh-layout-sider-trigger-px, var(--xh-control-px-sm));
88
88
  border: 0;
89
89
  border-radius: var(--xh-layout-sider-trigger-radius, var(--xh-shape-control));
90
90
  background: var(--xh-layout-sider-trigger-bg, transparent);
91
91
  color: var(--xh-layout-sider-trigger-fg, var(--xh-fg-default));
92
- font-size: var(--xh-font-size-sm);
92
+ font-size: var(--xh-text-secondary-size);
93
93
  line-height: var(--xh-leading-none);
94
94
  cursor: pointer;
95
95
  }
@@ -156,19 +156,23 @@
156
156
  /* 侧栏保持默认的拉伸对齐,只加一道高度上限:内容短时它照旧填满整列,内容长过一屏时它收成
157
157
  可视区那么高,短出来的那一段就是 sticky 的行程。
158
158
  上限量的是滚动容器可视区的高度,缺省按视口算;滚动容器不是视口时由作者把那个高度写进
159
- --xh-layout-scrollport-h。视口取 dvh:移动端地址栏收放会改变可视高度,dvh 跟着变。
159
+ --xh-layout-scrollport-h。视口取 dvh:移动端地址栏收放会改变可视高度,dvh 跟着变;
160
+ 不认 dvh 的引擎由级联回落到前一条的 vh。
160
161
  侧栏自己的条目多到装不下时在内部滚,横轴仍归上面那条 overflow: hidden 裁,
161
162
  折叠态靠它把放不下的字裁掉;逻辑属性 overflow-block 尚无可用实现,写物理轴。 */
162
163
  [data-scope='layout'][data-part='sider'][data-fixed] {
163
164
  position: sticky;
164
165
  inset-block-start: var(--xh-_layout-sider-offset);
166
+ max-block-size: calc(var(--xh-layout-scrollport-h, 100vh) - var(--xh-_layout-sider-offset));
165
167
  max-block-size: calc(var(--xh-layout-scrollport-h, 100dvh) - var(--xh-_layout-sider-offset));
166
168
  overflow-y: auto;
167
169
  }
168
170
 
169
- @media (prefers-reduced-motion: reduce) {
170
- [data-scope='layout'][data-part='sider'] {
171
- transition: none;
172
- }
171
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
172
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
173
+ [data-scope='layout'][data-part='root'][hidden],
174
+ [data-scope='layout'][data-part='header'][hidden],
175
+ [data-scope='layout'][data-part='sider-trigger'][hidden] {
176
+ display: none;
173
177
  }
174
178
  }
package/css/list.css CHANGED
@@ -7,11 +7,11 @@
7
7
  [data-scope='list'][data-part='root'] {
8
8
  /* 一个尺寸档只换这几个私有槽,条目与两行文字都从根上继承它们,
9
9
  换档不必给每个部件各写一条选择器 */
10
- --xh-_list-item-py: var(--xh-space-3);
11
- --xh-_list-item-px: var(--xh-space-4);
10
+ --xh-_list-item-py: var(--xh-list-item-py-md);
11
+ --xh-_list-item-px: var(--xh-list-item-px-md);
12
12
  --xh-_list-item-gap: var(--xh-space-3);
13
- --xh-_list-title-size: var(--xh-font-size-md);
14
- --xh-_list-description-size: var(--xh-font-size-sm);
13
+ --xh-_list-title-size: var(--xh-control-font-md);
14
+ --xh-_list-description-size: var(--xh-control-caption-md);
15
15
 
16
16
  display: flex;
17
17
  flex-direction: column;
@@ -29,18 +29,18 @@
29
29
 
30
30
  /* —— 尺寸 —— */
31
31
  [data-scope='list'][data-part='root'][data-size='sm'] {
32
- --xh-_list-item-py: var(--xh-space-2);
33
- --xh-_list-item-px: var(--xh-space-3);
32
+ --xh-_list-item-py: var(--xh-list-item-py-sm);
33
+ --xh-_list-item-px: var(--xh-list-item-px-sm);
34
34
  --xh-_list-item-gap: var(--xh-space-2);
35
- --xh-_list-title-size: var(--xh-font-size-sm);
36
- --xh-_list-description-size: var(--xh-font-size-xs);
35
+ --xh-_list-title-size: var(--xh-control-font-sm);
36
+ --xh-_list-description-size: var(--xh-control-caption-sm);
37
37
  }
38
38
 
39
39
  [data-scope='list'][data-part='root'][data-size='lg'] {
40
- --xh-_list-item-py: var(--xh-space-4);
41
- --xh-_list-item-px: var(--xh-space-5);
40
+ --xh-_list-item-py: var(--xh-list-item-py-lg);
41
+ --xh-_list-item-px: var(--xh-list-item-px-lg);
42
42
  --xh-_list-item-gap: var(--xh-space-4);
43
- --xh-_list-title-size: var(--xh-font-size-lg);
43
+ --xh-_list-title-size: var(--xh-control-font-lg);
44
44
  }
45
45
 
46
46
  /* —— 外框 —— */
@@ -66,11 +66,11 @@
66
66
  [data-scope='list'][data-part='root'][data-split]
67
67
  > [data-scope='list'][data-part='item']
68
68
  + [data-scope='list'][data-part='item'] {
69
- border-block-start: var(--xh-stroke-thin) solid var(--xh-list-border, var(--xh-border-subtle));
69
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-list-divider, var(--xh-border-subtle));
70
70
  }
71
71
 
72
72
  [data-scope='list'][data-part='root'][data-hoverable] > [data-scope='list'][data-part='item'] {
73
- transition: background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
73
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
74
74
  }
75
75
 
76
76
  /* 悬停换底色:只在能用指针的设备上生效,触摸端不留一个按不掉的悬停态 */
@@ -119,4 +119,13 @@
119
119
  gap: var(--xh-list-action-gap, var(--xh-space-2));
120
120
  margin-inline-start: auto;
121
121
  }
122
+
123
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
124
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
125
+ [data-scope='list'][data-part='item'][hidden],
126
+ [data-scope='list'][data-part='item-media'][hidden],
127
+ [data-scope='list'][data-part='item-content'][hidden],
128
+ [data-scope='list'][data-part='item-action'][hidden] {
129
+ display: none;
130
+ }
122
131
  }
package/css/listbox.css CHANGED
@@ -5,6 +5,9 @@
5
5
  }
6
6
 
7
7
  [data-scope='listbox'][data-part='root'] {
8
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
9
+ --xh-icon-size: var(--xh-listbox-icon-size, var(--xh-glyph-size-text));
10
+
8
11
  display: flex;
9
12
  flex-direction: column;
10
13
  gap: var(--xh-listbox-gap, var(--xh-space-2));
@@ -31,7 +34,8 @@
31
34
  [data-scope='listbox'][data-part='content'] {
32
35
  display: flex;
33
36
  flex-direction: column;
34
- max-block-size: var(--xh-listbox-content-max-h, var(--xh-overlay-max-h));
37
+ gap: var(--xh-listbox-content-gap, var(--xh-list-option-gap));
38
+ max-block-size: var(--xh-listbox-content-max-h, var(--xh-viewport-h-md));
35
39
  padding-block: var(--xh-listbox-content-py, var(--xh-space-1));
36
40
  padding-inline: var(--xh-listbox-content-px, var(--xh-space-1));
37
41
  border: var(--xh-stroke-thin) solid var(--xh-listbox-content-border, var(--xh-border-default));
@@ -63,6 +67,7 @@
63
67
  [data-scope='listbox'][data-part='item-group'] {
64
68
  display: flex;
65
69
  flex-direction: column;
70
+ gap: var(--xh-listbox-item-group-gap, var(--xh-list-option-gap));
66
71
  }
67
72
 
68
73
  [data-scope='listbox'][data-part='item-group'][hidden] {
@@ -71,7 +76,7 @@
71
76
 
72
77
  /* 组间留白只加在后继分组上:首组顶上已经有 content 的内边距,再加一层会显得头重 */
73
78
  [data-scope='listbox'][data-part='item-group'] + [data-scope='listbox'][data-part='item-group'] {
74
- margin-block-start: var(--xh-listbox-group-gap, var(--xh-space-2));
79
+ margin-block-start: var(--xh-listbox-group-gap, var(--xh-space-1_5));
75
80
  }
76
81
 
77
82
  /* 分组标题不是选项、进不了导航,画成小号次要文字,
@@ -81,7 +86,7 @@
81
86
  padding-block: var(--xh-listbox-group-label-py, var(--xh-space-1));
82
87
  padding-inline: var(--xh-listbox-group-label-px, var(--xh-control-px-md));
83
88
  color: var(--xh-listbox-group-label-fg, var(--xh-fg-subtle));
84
- font-size: var(--xh-listbox-group-label-font-size, var(--xh-font-size-xs));
89
+ font-size: var(--xh-listbox-group-label-font-size, var(--xh-text-caption-size));
85
90
  font-weight: var(--xh-listbox-group-label-font-weight, var(--xh-font-weight-medium));
86
91
  line-height: var(--xh-leading-none);
87
92
  user-select: none;
@@ -132,7 +137,13 @@
132
137
  font-weight: var(--xh-listbox-item-font-weight-selected, var(--xh-font-weight-medium));
133
138
  }
134
139
 
135
- [data-scope='listbox'][data-part='item']:focus {
140
+ /* 键盘落焦的条目画内收环;指针触发的聚焦不画 */
141
+ [data-scope='listbox'][data-part='item']:focus-visible {
142
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
143
+ outline-offset: calc(-1 * var(--xh-ring-width));
144
+ }
145
+
146
+ [data-scope='listbox'][data-part='item']:focus:not(:focus-visible) {
136
147
  outline: none;
137
148
  }
138
149
 
@@ -159,7 +170,7 @@
159
170
  align-items: center;
160
171
  justify-content: center;
161
172
  inline-size: var(--xh-listbox-item-indicator-size, var(--xh-control-indicator-size));
162
- color: var(--xh-listbox-item-indicator-fg, var(--xh-bg-brand));
173
+ color: var(--xh-listbox-item-indicator-fg, var(--xh-fg-brand));
163
174
  visibility: hidden;
164
175
  }
165
176
 
@@ -169,7 +180,14 @@
169
180
 
170
181
  /* 没写内容就由皮肤画勾;作者往部件里塞了自己的图形,这条规则即不命中 */
171
182
  [data-scope='listbox'][data-part='item-indicator']:empty::before {
172
- content: '';
183
+ content: '';
184
+ display: inline-block;
185
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
186
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
187
+ vertical-align: var(--xh-glyph-baseline-shift);
188
+ background-color: currentColor;
189
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
190
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
173
191
  }
174
192
 
175
193
  [data-scope='listbox'][data-part='item-indicator'][data-state='checked'] {
@@ -31,8 +31,9 @@
31
31
  display: none;
32
32
  }
33
33
 
34
- /* 冲到 100 之后进入淡出:机器会在淡出窗口走完之前一直停在 finishing
35
- 这段过渡才有时间跑完;窗口与时长两处默认值都是 200ms,改一处记得对齐另一处 */
34
+ /* 冲到 100 之后进入淡出:机器会在淡出窗口走完之前一直停在 finishing,这段过渡才有时间跑完。
35
+ 窗口(machine 的 LOADING_BAR_FADE_DURATION,200ms)比过渡本身(motion-duration-exit,120ms)
36
+ 宽出一截是有意的余量;两者不是同一个数,改窗口时只要保证它仍不短于过渡 */
36
37
  [data-scope='loading-bar'][data-part='root'][data-state='finishing'] {
37
38
  opacity: 0;
38
39
  }
@@ -50,8 +51,8 @@
50
51
  * 进度段。宽度那条轴(inline-size)由连接层写进内联样式,这里绝不重复写。
51
52
  * 背景色同理:给了 color 就走内联,盖过下面这条。
52
53
  *
53
- * 语气取柔和档 --xh-_tone-soft(500)而不是 --xh-_tone(600):600 是给实心底与
54
- * 文字用的强调档,压在这么一条细带上偏重。槽位由 root 上的 data-tone 声明,继承下来。
54
+ * 语气取装饰档 --xh-_tone-soft:那一档压在画布上够 3:1,细带才看得出来。
55
+ * 槽位由 root 上的 data-tone 声明,继承下来。
55
56
  * 没写 data-tone 时该槽没被声明,退回原来的品牌色。
56
57
  */
57
58
  [data-scope='loading-bar'][data-part='range'] {
@@ -61,11 +62,17 @@
61
62
  }
62
63
 
63
64
  /* 减少动效:宽度与淡出都立刻到位。进度本身照常推进,只是不再有过渡的过程——
64
- 一条按 200ms 一拍持续变宽的带子正是最容易引发不适的那种动效 */
65
+ 一条按 200ms 一拍持续变宽的带子正是最容易引发不适的那种动效。
66
+ 两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
65
67
  @media (prefers-reduced-motion: reduce) {
66
68
  [data-scope='loading-bar'][data-part='root'],
67
69
  [data-scope='loading-bar'][data-part='range'] {
68
70
  transition: none;
69
71
  }
70
72
  }
73
+
74
+ :where([data-motion='reduce']) [data-scope='loading-bar'][data-part='root'],
75
+ :where([data-motion='reduce']) [data-scope='loading-bar'][data-part='range'] {
76
+ transition: none;
77
+ }
71
78
  }
package/css/log.css CHANGED
@@ -28,14 +28,18 @@
28
28
  flex-basis 取 auto,连接层写的按行数高度才算数,同时外层给了高度时还能撑满;
29
29
  min-block-size: 0 让它在弹性父级里能被压缩从而真的溢出;
30
30
  两个轴都 auto:长行不折,横向也要能滚;
31
- overscroll-behavior: contain 阻止滚动量传给页面;
32
- scrollbar-gutter: stable 避免滚动条出现与消失时推动文字。 */
31
+ overscroll-behavior: contain 阻止滚动量传给页面。 */
33
32
  [data-scope='log'][data-part='viewport'] {
34
33
  flex: 1 1 auto;
35
34
  min-block-size: 0;
36
35
  block-size: calc(var(--xh-_log-line-h) * var(--xh-log-rows, 16));
37
36
  overflow: auto;
38
37
  overscroll-behavior: contain;
38
+ }
39
+
40
+ /* 还在用原生滚动条的视口留一条空道,滚动条出现与消失时不推动文字。
41
+ 带 data-xh-scrollbar 的容器已经把原生条藏成零宽,这条空道对它没有布局作用,排除掉 */
42
+ [data-scope='log'][data-part='viewport']:not([data-xh-scrollbar]) {
39
43
  scrollbar-gutter: stable;
40
44
  }
41
45
 
@@ -55,7 +59,7 @@
55
59
  display: block;
56
60
  padding-inline: var(--xh-log-content-px, var(--xh-space-3));
57
61
  font-family: var(--xh-log-font, var(--xh-font-family-mono));
58
- font-size: var(--xh-log-font-size, var(--xh-font-size-sm));
62
+ font-size: var(--xh-log-font-size, var(--xh-text-secondary-size));
59
63
  }
60
64
 
61
65
  [data-scope='log'][data-part='content'][hidden] {
package/css/marquee.css CHANGED
@@ -174,6 +174,7 @@
174
174
  * 减少动效:轨道停在起点不再走。一段自己动起来、不停到底的横移正是最容易引发不适的那一类,
175
175
  * 这里不能只把速度压到很慢——慢速横移仍然是横移。
176
176
  * 停下后窗口外那段就够不着了,故窗口同时改成可滚,内容仍然读得全。
177
+ * 两组规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion。
177
178
  */
178
179
  @media (prefers-reduced-motion: reduce) {
179
180
  [data-scope='marquee'][data-part='content'] {
@@ -184,4 +185,12 @@
184
185
  overflow: auto;
185
186
  }
186
187
  }
188
+
189
+ :where([data-motion='reduce']) [data-scope='marquee'][data-part='content'] {
190
+ animation: none;
191
+ }
192
+
193
+ :where([data-motion='reduce']) [data-scope='marquee'][data-part='root'] {
194
+ overflow: auto;
195
+ }
187
196
  }