@xihan-ui/styles 1.0.0-alpha.2 → 1.0.0-alpha.3

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 (118) hide show
  1. package/CHANGELOG.md +447 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +56 -5
  4. package/css/alert.css +30 -5
  5. package/css/anchor.css +7 -7
  6. package/css/avatar-group.css +3 -3
  7. package/css/avatar.css +3 -3
  8. package/css/back-top.css +16 -1
  9. package/css/badge.css +16 -2
  10. package/css/breadcrumb.css +24 -4
  11. package/css/button-group.css +14 -13
  12. package/css/button.css +42 -11
  13. package/css/calendar.css +119 -2
  14. package/css/card.css +5 -5
  15. package/css/carousel.css +36 -5
  16. package/css/cascader.css +183 -102
  17. package/css/checkbox-group.css +41 -19
  18. package/css/checkbox.css +54 -8
  19. package/css/clipboard.css +2 -1
  20. package/css/code-block.css +12 -7
  21. package/css/collapsible.css +42 -2
  22. package/css/color-picker.css +111 -45
  23. package/css/combobox.css +114 -53
  24. package/css/composer.css +5 -3
  25. package/css/context-menu.css +97 -69
  26. package/css/date-field.css +91 -14
  27. package/css/date-picker.css +276 -65
  28. package/css/descriptions.css +2 -2
  29. package/css/dialog.css +40 -13
  30. package/css/download-trigger.css +76 -0
  31. package/css/drawer.css +45 -14
  32. package/css/dynamic-input.css +68 -17
  33. package/css/editable.css +12 -10
  34. package/css/ellipsis.css +1 -1
  35. package/css/empty-state.css +7 -7
  36. package/css/field.css +9 -6
  37. package/css/fieldset.css +69 -0
  38. package/css/file-upload.css +45 -7
  39. package/css/float-button.css +16 -1
  40. package/css/floating-panel.css +310 -0
  41. package/css/form.css +4 -4
  42. package/css/heatmap.css +410 -0
  43. package/css/highlight.css +1 -1
  44. package/css/hotkeys.css +90 -0
  45. package/css/hover-card.css +40 -45
  46. package/css/image-cropper.css +231 -0
  47. package/css/image-viewer.css +137 -12
  48. package/css/image.css +2 -2
  49. package/css/infinite-scroll.css +1 -1
  50. package/css/json-viewer.css +241 -0
  51. package/css/layout.css +6 -10
  52. package/css/list.css +8 -8
  53. package/css/listbox.css +20 -4
  54. package/css/loading-bar.css +7 -1
  55. package/css/log.css +1 -1
  56. package/css/marquee.css +9 -0
  57. package/css/masonry.css +63 -0
  58. package/css/mention.css +87 -33
  59. package/css/menu.css +113 -47
  60. package/css/menubar.css +146 -60
  61. package/css/navigation-menu.css +54 -29
  62. package/css/number-animation.css +3 -3
  63. package/css/number-field.css +173 -16
  64. package/css/overlay-arrow.css +51 -0
  65. package/css/page-header.css +5 -5
  66. package/css/pagination.css +13 -13
  67. package/css/password-input.css +356 -0
  68. package/css/pin-input.css +13 -10
  69. package/css/popconfirm.css +46 -10
  70. package/css/popover.css +70 -45
  71. package/css/popselect.css +183 -53
  72. package/css/progress.css +47 -7
  73. package/css/qr-code.css +1 -1
  74. package/css/radio-group.css +14 -8
  75. package/css/rating.css +2 -2
  76. package/css/reset.css +17 -0
  77. package/css/result.css +6 -6
  78. package/css/scroll-area.css +61 -89
  79. package/css/scrollbar.css +167 -0
  80. package/css/segmented.css +215 -0
  81. package/css/select.css +274 -125
  82. package/css/separator.css +2 -2
  83. package/css/side-nav.css +111 -19
  84. package/css/signature-pad.css +144 -0
  85. package/css/skeleton.css +7 -1
  86. package/css/slider.css +10 -10
  87. package/css/space.css +117 -0
  88. package/css/spinner.css +22 -10
  89. package/css/statistic.css +9 -9
  90. package/css/steps.css +25 -8
  91. package/css/switch.css +48 -6
  92. package/css/table.css +131 -37
  93. package/css/tabs.css +4 -4
  94. package/css/tag.css +177 -0
  95. package/css/tags-input.css +78 -40
  96. package/css/text-field.css +149 -36
  97. package/css/thread.css +1 -1
  98. package/css/time-field.css +97 -16
  99. package/css/time-picker.css +259 -69
  100. package/css/timeline.css +10 -10
  101. package/css/timer.css +119 -0
  102. package/css/toast.css +34 -10
  103. package/css/toaster.css +1 -1
  104. package/css/toggle.css +6 -6
  105. package/css/tone.css +10 -5
  106. package/css/toolbar.css +1 -1
  107. package/css/tooltip.css +36 -33
  108. package/css/tour.css +103 -58
  109. package/css/transfer.css +68 -17
  110. package/css/tree-select.css +185 -84
  111. package/css/tree.css +85 -1
  112. package/css/typography.css +4 -4
  113. package/css/undefined.css +11 -1
  114. package/css/virtualizer.css +3 -1
  115. package/css/watermark.css +1 -2
  116. package/index.css +17 -0
  117. package/index.unlayered.css +8659 -2799
  118. package/package.json +19 -3
@@ -0,0 +1,241 @@
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-text-secondary-size);
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
+ display: block;
24
+ color: var(--xh-json-viewer-fg, var(--xh-fg-default));
25
+ font-family: var(--xh-json-viewer-font, var(--xh-font-family-mono));
26
+ font-size: var(--xh-json-viewer-font-size, var(--xh-_json-viewer-font-size));
27
+ line-height: var(--xh-leading-normal);
28
+ }
29
+
30
+ /* 写了 display 就会盖掉 UA 的 [hidden]{display:none},这里补回 */
31
+ [data-scope='json-viewer'][data-part='root'][hidden] {
32
+ display: none;
33
+ }
34
+
35
+ /* 尺寸轴只换私有槽,部件从 root 继承 */
36
+ [data-scope='json-viewer'][data-part='root'][data-size='sm'] {
37
+ --xh-_json-viewer-font-size: var(--xh-control-caption-sm);
38
+ --xh-_json-viewer-row-py: var(--xh-space-0);
39
+ --xh-_json-viewer-indent: var(--xh-space-3);
40
+ }
41
+
42
+ [data-scope='json-viewer'][data-part='root'][data-size='lg'] {
43
+ --xh-_json-viewer-font-size: var(--xh-control-caption-lg);
44
+ --xh-_json-viewer-row-py: var(--xh-space-1);
45
+ --xh-_json-viewer-indent: var(--xh-space-5);
46
+ }
47
+
48
+ /* 常驻容器不是浮层:两轴都可能溢出——深层缩进往行首方向推、长字符串往行尾伸 */
49
+ [data-scope='json-viewer'][data-part='tree'] {
50
+ display: flex;
51
+ flex-direction: column;
52
+ max-block-size: var(--xh-json-viewer-max-h, var(--xh-viewport-max-h));
53
+ padding-block: var(--xh-json-viewer-py, var(--xh-space-2));
54
+ padding-inline: var(--xh-json-viewer-px, var(--xh-space-2));
55
+ border: var(--xh-stroke-thin) solid var(--xh-json-viewer-border, var(--xh-border-default));
56
+ border-radius: var(--xh-json-viewer-radius, var(--xh-shape-surface));
57
+ background: var(--xh-json-viewer-bg, var(--xh-bg-surface));
58
+ overflow: auto;
59
+ }
60
+
61
+ [data-scope='json-viewer'][data-part='tree'][hidden] {
62
+ display: none;
63
+ }
64
+
65
+ /* 焦点在树外时容器自己进 Tab 序列兜底,落焦不画环:环永远长在行上 */
66
+ [data-scope='json-viewer'][data-part='tree']:focus-visible {
67
+ outline: none;
68
+ }
69
+
70
+ /* 焦点落在 branch 上(它才是 treeitem),但环画在它自己那一行上:
71
+ 整棵子层套一圈描边会把展开的层级全框进去 */
72
+ [data-scope='json-viewer'][data-part='branch']:focus-visible {
73
+ outline: none;
74
+ }
75
+
76
+ [data-scope='json-viewer'][data-part='branch']:focus-visible > [data-scope='json-viewer'][data-part='branch-control'] {
77
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
78
+ /* 往内收:行是撑满宽度的,环画在外沿会被容器裁掉 */
79
+ outline-offset: calc(-1 * var(--xh-ring-width));
80
+ }
81
+
82
+ /* 行:标量与分支共用同一套盒子,两种行在视觉上必须齐平 */
83
+ [data-scope='json-viewer'][data-part='item'],
84
+ [data-scope='json-viewer'][data-part='branch-control'] {
85
+ display: flex;
86
+ align-items: baseline;
87
+ gap: var(--xh-json-viewer-row-gap, var(--xh-space-1));
88
+ padding-block: var(--xh-json-viewer-row-py, var(--xh-_json-viewer-row-py));
89
+ padding-inline: var(--xh-json-viewer-row-px, var(--xh-space-1));
90
+ border-radius: var(--xh-json-viewer-row-radius, var(--xh-shape-inset));
91
+ white-space: nowrap;
92
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
93
+ }
94
+
95
+ [data-scope='json-viewer'][data-part='item'][hidden],
96
+ [data-scope='json-viewer'][data-part='branch-control'][hidden] {
97
+ display: none;
98
+ }
99
+
100
+ /* 悬停与键盘锚点共用中性灰轻档:data-highlighted 跟的是连接层记的焦点行,
101
+ 键盘落焦另有聚焦环标记位置 */
102
+ [data-scope='json-viewer'][data-part='item']:is(:hover, [data-highlighted]),
103
+ [data-scope='json-viewer'][data-part='branch-control']:is(:hover, [data-highlighted]) {
104
+ background: var(--xh-json-viewer-row-bg-hover, var(--xh-bg-subtle));
105
+ }
106
+
107
+ /* 分支那一行是唯一的点击目标:点它切换展开态 */
108
+ [data-scope='json-viewer'][data-part='branch-control'] {
109
+ cursor: pointer;
110
+ user-select: none;
111
+ }
112
+
113
+ /* 标量行的焦点环直接画在行上:它自己就是 treeitem */
114
+ [data-scope='json-viewer'][data-part='item']:focus-visible {
115
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
116
+ outline-offset: calc(-1 * var(--xh-ring-width));
117
+ }
118
+
119
+ /* 键名不参与压缩:它短且必须完整可读,被挤掉的应该是值 */
120
+ [data-scope='json-viewer'][data-part='item-key'],
121
+ [data-scope='json-viewer'][data-part='branch-text'] {
122
+ flex: none;
123
+ color: var(--xh-json-viewer-key-fg);
124
+ font-weight: var(--xh-json-viewer-key-font-weight, var(--xh-font-weight-medium));
125
+ }
126
+
127
+ /* 键名与值之间的冒号由皮肤画:它是排版符号,进不了可及名字反而更清爽 */
128
+ [data-scope='json-viewer'][data-part='item-key']::after,
129
+ [data-scope='json-viewer'][data-part='branch-text']::after {
130
+ content: ':';
131
+ color: var(--xh-json-viewer-punctuation-fg);
132
+ }
133
+
134
+ /* 弹性子项默认最小尺寸是内容尺寸,不归零则长字符串把行撑破、省略号轮不上 */
135
+ [data-scope='json-viewer'][data-part='item-value'] {
136
+ flex: 1 1 auto;
137
+ min-inline-size: 0;
138
+ overflow: hidden;
139
+ white-space: nowrap;
140
+ text-overflow: ellipsis;
141
+ }
142
+
143
+ [data-scope='json-viewer'][data-part='item-value'][data-type='string'] {
144
+ color: var(--xh-json-viewer-string-fg);
145
+ }
146
+
147
+ [data-scope='json-viewer'][data-part='item-value'][data-type='number'] {
148
+ color: var(--xh-json-viewer-number-fg);
149
+ }
150
+
151
+ [data-scope='json-viewer'][data-part='item-value'][data-type='boolean'] {
152
+ color: var(--xh-json-viewer-boolean-fg);
153
+ }
154
+
155
+ [data-scope='json-viewer'][data-part='item-value'][data-type='null'] {
156
+ color: var(--xh-json-viewer-null-fg);
157
+ }
158
+
159
+ /* 空对象与空数组只剩一对括号,跟标点同色 */
160
+ [data-scope='json-viewer'][data-part='item-value'][data-type='array'],
161
+ [data-scope='json-viewer'][data-part='item-value'][data-type='object'] {
162
+ color: var(--xh-json-viewer-punctuation-fg);
163
+ }
164
+
165
+ /* 循环引用与截断占位不是真数据,排在语气之外用弱化字重表达 */
166
+ [data-scope='json-viewer'][data-part='item-value'][data-circular],
167
+ [data-scope='json-viewer'][data-part='item-value'][data-truncated] {
168
+ color: var(--xh-fg-muted);
169
+ font-style: italic;
170
+ }
171
+
172
+ /* 展开箭头与勾选标记同宽,两种行的文字起点才对得齐 */
173
+ [data-scope='json-viewer'][data-part='branch-trigger'] {
174
+ display: inline-flex;
175
+ flex: none;
176
+ align-items: center;
177
+ justify-content: center;
178
+ inline-size: var(--xh-json-viewer-indicator-size, var(--xh-control-indicator-size));
179
+ color: var(--xh-json-viewer-indicator-fg, var(--xh-fg-subtle));
180
+ }
181
+
182
+ [data-scope='json-viewer'][data-part='branch-trigger'][hidden] {
183
+ display: none;
184
+ }
185
+
186
+ [data-scope='json-viewer'][data-part='branch-indicator'] {
187
+ display: inline-block;
188
+ line-height: var(--xh-leading-none);
189
+ transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
190
+ }
191
+
192
+ [data-scope='json-viewer'][data-part='branch-indicator'][hidden] {
193
+ display: none;
194
+ }
195
+
196
+ /* 没写内容就由皮肤画;作者往部件里塞了自己的图形,这条规则即不命中 */
197
+ [data-scope='json-viewer'][data-part='branch-indicator']:empty::before {
198
+ content: '';
199
+ display: inline-block;
200
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
201
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
202
+ vertical-align: var(--xh-glyph-baseline-shift);
203
+ background-color: currentColor;
204
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
205
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
206
+ }
207
+
208
+ /* 收起时朝向行首、展开时转向下方,与逻辑书写方向一致:
209
+ rtl 下 inline-start 在右侧,箭头因此要反着转 */
210
+ [data-scope='json-viewer'][data-part='branch-indicator'][data-state='open'] {
211
+ rotate: 90deg;
212
+ }
213
+
214
+ [dir='rtl'] [data-scope='json-viewer'][data-part='branch-indicator'] {
215
+ rotate: 180deg;
216
+ }
217
+
218
+ [dir='rtl'] [data-scope='json-viewer'][data-part='branch-indicator'][data-state='open'] {
219
+ rotate: 90deg;
220
+ }
221
+
222
+ /* 收起摘要不参与选中:框选整块 JSON 时不该把它一起复制走 */
223
+ [data-scope='json-viewer'][data-part='preview'] {
224
+ flex: none;
225
+ color: var(--xh-json-viewer-preview-fg, var(--xh-fg-muted));
226
+ font-size: var(--xh-json-viewer-preview-font-size, var(--xh-text-caption-size));
227
+ user-select: none;
228
+ }
229
+
230
+ /* 层级缩进靠子层容器自己顶:分支物理嵌套着子层,每深一层就多缩一格,
231
+ 无需把层级号写进内联样式,也就不必在两个适配器里各写一遍 */
232
+ [data-scope='json-viewer'][data-part='branch-content'] {
233
+ display: flex;
234
+ flex-direction: column;
235
+ padding-inline-start: var(--xh-json-viewer-indent, var(--xh-_json-viewer-indent));
236
+ }
237
+
238
+ [data-scope='json-viewer'][data-part='branch-content'][hidden] {
239
+ display: none;
240
+ }
241
+ }
package/css/layout.css CHANGED
@@ -57,7 +57,7 @@
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
  }
@@ -74,7 +74,7 @@
74
74
  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
  /* —— 折叠把手 —— */
@@ -89,7 +89,7 @@
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,15 @@
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
-
169
- @media (prefers-reduced-motion: reduce) {
170
- [data-scope='layout'][data-part='sider'] {
171
- transition: none;
172
- }
173
- }
174
170
  }
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);
10
+ --xh-_list-item-py: var(--xh-list-item-py-md);
11
11
  --xh-_list-item-px: var(--xh-space-4);
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);
32
+ --xh-_list-item-py: var(--xh-list-item-py-sm);
33
33
  --xh-_list-item-px: var(--xh-space-3);
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);
40
+ --xh-_list-item-py: var(--xh-list-item-py-lg);
41
41
  --xh-_list-item-px: var(--xh-space-5);
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
  /* —— 外框 —— */
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,7 @@
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
+ max-block-size: var(--xh-listbox-content-max-h, var(--xh-viewport-h-md));
35
38
  padding-block: var(--xh-listbox-content-py, var(--xh-space-1));
36
39
  padding-inline: var(--xh-listbox-content-px, var(--xh-space-1));
37
40
  border: var(--xh-stroke-thin) solid var(--xh-listbox-content-border, var(--xh-border-default));
@@ -81,7 +84,7 @@
81
84
  padding-block: var(--xh-listbox-group-label-py, var(--xh-space-1));
82
85
  padding-inline: var(--xh-listbox-group-label-px, var(--xh-control-px-md));
83
86
  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));
87
+ font-size: var(--xh-listbox-group-label-font-size, var(--xh-text-caption-size));
85
88
  font-weight: var(--xh-listbox-group-label-font-weight, var(--xh-font-weight-medium));
86
89
  line-height: var(--xh-leading-none);
87
90
  user-select: none;
@@ -132,7 +135,13 @@
132
135
  font-weight: var(--xh-listbox-item-font-weight-selected, var(--xh-font-weight-medium));
133
136
  }
134
137
 
135
- [data-scope='listbox'][data-part='item']:focus {
138
+ /* 键盘落焦的条目画内收环;指针触发的聚焦不画 */
139
+ [data-scope='listbox'][data-part='item']:focus-visible {
140
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
141
+ outline-offset: calc(-1 * var(--xh-ring-width));
142
+ }
143
+
144
+ [data-scope='listbox'][data-part='item']:focus:not(:focus-visible) {
136
145
  outline: none;
137
146
  }
138
147
 
@@ -169,7 +178,14 @@
169
178
 
170
179
  /* 没写内容就由皮肤画勾;作者往部件里塞了自己的图形,这条规则即不命中 */
171
180
  [data-scope='listbox'][data-part='item-indicator']:empty::before {
172
- content: '✓';
181
+ content: '';
182
+ display: inline-block;
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
+ vertical-align: var(--xh-glyph-baseline-shift);
186
+ background-color: currentColor;
187
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
188
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
173
189
  }
174
190
 
175
191
  [data-scope='listbox'][data-part='item-indicator'][data-state='checked'] {
@@ -61,11 +61,17 @@
61
61
  }
62
62
 
63
63
  /* 减少动效:宽度与淡出都立刻到位。进度本身照常推进,只是不再有过渡的过程——
64
- 一条按 200ms 一拍持续变宽的带子正是最容易引发不适的那种动效 */
64
+ 一条按 200ms 一拍持续变宽的带子正是最容易引发不适的那种动效。
65
+ 两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
65
66
  @media (prefers-reduced-motion: reduce) {
66
67
  [data-scope='loading-bar'][data-part='root'],
67
68
  [data-scope='loading-bar'][data-part='range'] {
68
69
  transition: none;
69
70
  }
70
71
  }
72
+
73
+ :where([data-motion='reduce']) [data-scope='loading-bar'][data-part='root'],
74
+ :where([data-motion='reduce']) [data-scope='loading-bar'][data-part='range'] {
75
+ transition: none;
76
+ }
71
77
  }
package/css/log.css CHANGED
@@ -55,7 +55,7 @@
55
55
  display: block;
56
56
  padding-inline: var(--xh-log-content-px, var(--xh-space-3));
57
57
  font-family: var(--xh-log-font, var(--xh-font-family-mono));
58
- font-size: var(--xh-log-font-size, var(--xh-font-size-sm));
58
+ font-size: var(--xh-log-font-size, var(--xh-text-secondary-size));
59
59
  }
60
60
 
61
61
  [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
  }
@@ -0,0 +1,63 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='masonry'] {
4
+ --xh-masonry-skin: 1;
5
+ }
6
+
7
+ [data-scope='masonry'][data-part='root'] {
8
+ display: flex;
9
+ /* 各列按自己的内容收高,不被最高的那列拉平——列不等高正是瀑布流的样子 */
10
+ align-items: flex-start;
11
+ gap: var(--xh-_masonry-gap);
12
+
13
+ /* 列间距与列内的项间距共用这一份取值,声明在根上、由列继承下去;
14
+ 不写 gap 档位就不留间距。使用者槽位排在档位之前,写死一个值即盖过所有档 */
15
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-0));
16
+ }
17
+
18
+ /* 声明了 display 就盖掉了 UA 的 [hidden] 规则,这里还回去 */
19
+ [data-scope='masonry'][data-part='root'][hidden] {
20
+ display: none;
21
+ }
22
+
23
+ [data-scope='masonry'][data-part='column'] {
24
+ display: flex;
25
+ flex-direction: column;
26
+ /* 各列等宽;下限写 0 而不是 auto,一段长内容才不会把自己那列撑宽 */
27
+ flex: 1 1 0;
28
+ min-inline-size: 0;
29
+ gap: var(--xh-_masonry-gap);
30
+ }
31
+
32
+ /* 当前档位用不上的那几列由适配器收起;这条兜住作者自己写 hidden 的情形 */
33
+ [data-scope='masonry'][data-part='column'][hidden] {
34
+ display: none;
35
+ }
36
+
37
+ /* 项不发话,高度由内容定;只兜住一件事——不被列的弹性压缩,压缩了量到的高度就不是它真实的高度 */
38
+ [data-scope='masonry'][data-part='item'] {
39
+ flex: none;
40
+ }
41
+
42
+ /* —— 间距档位 —— */
43
+ /* 每一档指向一个间距令牌,列之间与列内项之间吃同一份间距 */
44
+ [data-scope='masonry'][data-part='root'][data-gap='xs'] {
45
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-1));
46
+ }
47
+
48
+ [data-scope='masonry'][data-part='root'][data-gap='sm'] {
49
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-2));
50
+ }
51
+
52
+ [data-scope='masonry'][data-part='root'][data-gap='md'] {
53
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-3));
54
+ }
55
+
56
+ [data-scope='masonry'][data-part='root'][data-gap='lg'] {
57
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-4));
58
+ }
59
+
60
+ [data-scope='masonry'][data-part='root'][data-gap='xl'] {
61
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-6));
62
+ }
63
+ }