@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
@@ -5,15 +5,24 @@
5
5
  }
6
6
 
7
7
  /* 与文本框同一套堆叠:标签一行、输入行一行。
8
- 加减钮与输入框中间那层包裹归作者,这里不碰,三者各自把高度对齐即可成一体 */
8
+ 输入框与加减钮放进 control 部件即得一体式:视觉盒画在 control 上,
9
+ 减在左、加在右、输入框居中,前后缀图标/文字可直接流式插在框内。
10
+ 不写 control 时退回旧式三件并排的观感(下方 input / 按钮的基础规则原样生效) */
9
11
  [data-scope='number-field'][data-part='root'] {
12
+ /* 作者塞进来的图标跟着控件的尺寸档走;它自己写了 size 时仍以作者的为准 */
13
+ --xh-icon-size: var(--xh-number-field-icon-size, var(--xh-glyph-size-md));
14
+
10
15
  /* 尺寸档只换这几个私有槽,标题、输入框与加减钮都从 root 继承它们,
11
16
  换档不必给每个部件各写一条选择器 */
12
17
  --xh-_number-field-h: var(--xh-control-h-md);
13
18
  --xh-_number-field-px: var(--xh-control-px-md);
14
- --xh-_number-field-font-size: var(--xh-text-body-size);
15
- --xh-_number-field-label-font-size: var(--xh-text-label-size);
16
- --xh-_number-field-trigger-font-size: var(--xh-text-body-size);
19
+ --xh-_number-field-gap: var(--xh-control-gap-md);
20
+ --xh-_number-field-font-size: var(--xh-control-font-md);
21
+ --xh-_number-field-label-font-size: var(--xh-control-font-md);
22
+ --xh-_number-field-trigger-font-size: var(--xh-control-font-md);
23
+
24
+ /* 盒子的圆角 */
25
+ --xh-_number-field-radius: var(--xh-number-field-input-radius, var(--xh-shape-control));
17
26
 
18
27
  /* 形态档只换这几个私有槽:输入框的底与描边,加减钮的底与描边 */
19
28
  --xh-_number-field-bg: var(--xh-bg-canvas);
@@ -28,7 +37,7 @@
28
37
  /* 语气只落在聚焦这一处:环与聚焦态描边。框里的数字不归它管。
29
38
  没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色与常态描边 */
30
39
  --xh-_number-field-ring: var(--xh-ring-focus);
31
- --xh-_number-field-border-focus: var(--xh-number-field-input-border, var(--xh-_tone, var(--xh-border-control)));
40
+ --xh-_number-field-border-focus: var(--xh-number-field-input-border, var(--xh-_tone, var(--xh-border-control-focus)));
32
41
 
33
42
  display: inline-flex;
34
43
  flex-direction: column;
@@ -43,19 +52,23 @@
43
52
  /* —— 尺寸 —— */
44
53
  /* 缺省档写在上面的基础规则里 */
45
54
  [data-scope='number-field'][data-part='root'][data-size='sm'] {
55
+ --xh-icon-size: var(--xh-number-field-icon-size, var(--xh-glyph-size-sm));
46
56
  --xh-_number-field-h: var(--xh-control-h-sm);
47
57
  --xh-_number-field-px: var(--xh-control-px-sm);
48
- --xh-_number-field-font-size: var(--xh-font-size-sm);
49
- --xh-_number-field-label-font-size: var(--xh-font-size-sm);
50
- --xh-_number-field-trigger-font-size: var(--xh-font-size-sm);
58
+ --xh-_number-field-gap: var(--xh-control-gap-sm);
59
+ --xh-_number-field-font-size: var(--xh-control-font-sm);
60
+ --xh-_number-field-label-font-size: var(--xh-control-font-sm);
61
+ --xh-_number-field-trigger-font-size: var(--xh-control-font-sm);
51
62
  }
52
63
 
53
64
  [data-scope='number-field'][data-part='root'][data-size='lg'] {
65
+ --xh-icon-size: var(--xh-number-field-icon-size, var(--xh-glyph-size-lg));
54
66
  --xh-_number-field-h: var(--xh-control-h-lg);
55
67
  --xh-_number-field-px: var(--xh-control-px-lg);
56
- --xh-_number-field-font-size: var(--xh-font-size-lg);
57
- --xh-_number-field-label-font-size: var(--xh-font-size-lg);
58
- --xh-_number-field-trigger-font-size: var(--xh-font-size-lg);
68
+ --xh-_number-field-gap: var(--xh-control-gap-lg);
69
+ --xh-_number-field-font-size: var(--xh-control-font-lg);
70
+ --xh-_number-field-label-font-size: var(--xh-control-font-lg);
71
+ --xh-_number-field-trigger-font-size: var(--xh-control-font-lg);
59
72
  }
60
73
 
61
74
  /* —— 形态 —— */
@@ -70,7 +83,7 @@
70
83
  --xh-_number-field-trigger-bg-active: var(--xh-bg-subtle-active);
71
84
  --xh-_number-field-trigger-border: var(--xh-border-control);
72
85
  --xh-_number-field-trigger-border-hover: var(--xh-border-control-hover);
73
- --xh-_number-field-border-focus: var(--xh-number-field-input-border, var(--xh-_tone, var(--xh-border-control)));
86
+ --xh-_number-field-border-focus: var(--xh-number-field-input-border, var(--xh-_tone, var(--xh-border-control-focus)));
74
87
  }
75
88
 
76
89
  /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
@@ -84,10 +97,10 @@
84
97
  --xh-_number-field-trigger-bg-active: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active));
85
98
  --xh-_number-field-trigger-border: transparent;
86
99
  --xh-_number-field-trigger-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
87
- --xh-_number-field-border-focus: var(--xh-_tone, var(--xh-border-control));
100
+ --xh-_number-field-border-focus: var(--xh-_tone, var(--xh-border-control-focus));
88
101
  }
89
102
 
90
- /* 无框:底与描边都透明,平时只看得见数字,悬停与聚焦才浮出边界 */
103
+ /* 无框:底与常态描边透明,悬停与聚焦浮出描边 */
91
104
  [data-scope='number-field'][data-part='root'][data-variant='ghost'] {
92
105
  --xh-_number-field-bg: transparent;
93
106
  --xh-_number-field-border: transparent;
@@ -97,7 +110,7 @@
97
110
  --xh-_number-field-trigger-bg-active: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active));
98
111
  --xh-_number-field-trigger-border: transparent;
99
112
  --xh-_number-field-trigger-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
100
- --xh-_number-field-border-focus: var(--xh-_tone, var(--xh-border-control));
113
+ --xh-_number-field-border-focus: var(--xh-_tone, var(--xh-border-control-focus));
101
114
  }
102
115
 
103
116
  [data-scope='number-field'][data-part='label'] {
@@ -111,12 +124,130 @@
111
124
  color: var(--xh-number-field-label-fg-disabled, var(--xh-fg-subtle));
112
125
  }
113
126
 
127
+ /* —— 一体式 control:输入框与加减钮同框 —— */
128
+ /* control 是唯一的视觉盒:描边、底色、圆角、聚焦环全画在它身上,盒内三件都退成透明分段,
129
+ 整枚控件从头到尾只有这一道描边。减钮在前、input 居中、加钮在后(作者在模板里的顺序决定),
130
+ 前后缀内容直接流式插在框里。
131
+ focus-within 而不是 :focus 上的聚焦态:按钮也能触发聚焦环 */
132
+ [data-scope='number-field'][data-part='control'] {
133
+ position: relative;
134
+ display: inline-flex;
135
+ /* 居中而不是拉伸:作者插在框里的前后缀是一行文字,被拉满整框高度后字会贴着框顶 */
136
+ align-items: center;
137
+ gap: var(--xh-number-field-control-gap, var(--xh-_number-field-gap));
138
+ min-inline-size: var(--xh-number-field-control-min-w, var(--xh-control-min-w));
139
+ block-size: var(--xh-number-field-control-h, var(--xh-_number-field-h));
140
+ padding-inline: var(--xh-number-field-control-px, var(--xh-_number-field-px));
141
+ border: var(--xh-stroke-thin) solid var(--xh-number-field-input-border, var(--xh-_number-field-border));
142
+ border-radius: var(--xh-_number-field-radius);
143
+ background: var(--xh-number-field-input-bg, var(--xh-_number-field-bg));
144
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
145
+ }
146
+
147
+ [data-scope='number-field'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
148
+ border-color: var(--xh-number-field-input-border-hover, var(--xh-_number-field-border-hover));
149
+ }
150
+
151
+ [data-scope='number-field'][data-part='control']:focus-within:not([data-disabled]) {
152
+ border-color: var(--xh-number-field-input-border-focus, var(--xh-_number-field-border-focus));
153
+ outline: var(--xh-ring-width) solid var(--xh-_number-field-ring);
154
+ outline-offset: var(--xh-ring-offset);
155
+ }
156
+
157
+ [data-scope='number-field'][data-part='control'][data-invalid] {
158
+ border-color: var(--xh-number-field-input-border-invalid, var(--xh-border-invalid));
159
+
160
+ /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
161
+ --xh-_number-field-ring: var(--xh-ring-invalid);
162
+ }
163
+
164
+ [data-scope='number-field'][data-part='control'][data-readonly] {
165
+ background: var(--xh-number-field-input-bg-readonly, var(--xh-bg-subtle));
166
+ }
167
+
168
+ [data-scope='number-field'][data-part='control'][data-disabled] {
169
+ background: var(--xh-number-field-input-bg-disabled, var(--xh-bg-subtle));
170
+ color: var(--xh-fg-disabled);
171
+ cursor: not-allowed;
172
+ }
173
+
174
+ /* 盒内 input:无边框无底无圆角,观感全归 control;行内内衬也归 control,
175
+ 这里再留一份就是框内套了一圈空白。数字居中排在两个按钮之间;
176
+ 前后缀图标/文字直接流式排在 input 两侧,不用再绝对定位 */
177
+ [data-scope='number-field'][data-part='control'] [data-part='input'] {
178
+ flex: 1 1 auto;
179
+ inline-size: var(--xh-number-field-input-w, 5em);
180
+ min-inline-size: 0;
181
+ block-size: 100%;
182
+ padding-inline: 0;
183
+ border: 0;
184
+ border-radius: 0;
185
+ background: transparent;
186
+ text-align: var(--xh-number-field-input-align, center);
187
+ }
188
+
189
+ /* 盒内 input 不再自己画各态,全部交还 control。hover 这条带上与基础规则同样的
190
+ :not 条件:基础 hover 的特异度里有它们,不带就打不过 */
191
+ [data-scope='number-field'][data-part='control'] [data-part='input']:hover:not(:disabled, [data-invalid]) {
192
+ border-color: transparent;
193
+ }
194
+
195
+ [data-scope='number-field'][data-part='control'] [data-part='input']:focus-visible {
196
+ border-color: transparent;
197
+ outline: none;
198
+ }
199
+
200
+ [data-scope='number-field'][data-part='control'] [data-part='input'][data-invalid] {
201
+ border-color: transparent;
202
+ }
203
+
204
+ [data-scope='number-field'][data-part='control'] [data-part='input']:disabled,
205
+ [data-scope='number-field'][data-part='control'] [data-part='input'][readonly] {
206
+ background: transparent;
207
+ }
208
+
209
+ /* 盒内按钮:尺寸与圆角走基础规则那枚行内动作方钮,这里只把底与描边交还 control——
210
+ 按钮自带一块底色就会把一个盒子读成三块拼起来的;
211
+ 常态只剩符号,符号取次级前景,悬停与按下才浮出底色 */
212
+ [data-scope='number-field'][data-part='control'] [data-part='increment-trigger'],
213
+ [data-scope='number-field'][data-part='control'] [data-part='decrement-trigger'] {
214
+ margin: 0;
215
+ border: 0;
216
+ background: transparent;
217
+ color: var(--xh-number-field-trigger-fg, var(--xh-fg-muted));
218
+ }
219
+
220
+ /* 悬停只在分段自己身上浮出一块底色与更实的符号,盒子的描边纹丝不动 */
221
+ [data-scope='number-field'][data-part='control'] [data-part='increment-trigger']:hover:not(:disabled),
222
+ [data-scope='number-field'][data-part='control'] [data-part='decrement-trigger']:hover:not(:disabled) {
223
+ background: var(--xh-number-field-trigger-bg-hover, var(--xh-_number-field-trigger-bg-hover));
224
+ color: var(--xh-number-field-trigger-fg-hover, var(--xh-fg-default));
225
+ }
226
+
227
+ [data-scope='number-field'][data-part='control'] [data-part='increment-trigger']:active:not(:disabled),
228
+ [data-scope='number-field'][data-part='control'] [data-part='decrement-trigger']:active:not(:disabled) {
229
+ background: var(--xh-number-field-trigger-bg-active, var(--xh-_number-field-trigger-bg-active));
230
+ }
231
+
232
+ /* 焦点落到盒内按钮时 control 已经 focus-within 起了环,按钮自己再画一圈就是框里套框 */
233
+ [data-scope='number-field'][data-part='control'] [data-part='increment-trigger']:focus-visible,
234
+ [data-scope='number-field'][data-part='control'] [data-part='decrement-trigger']:focus-visible {
235
+ outline: none;
236
+ }
237
+
238
+ /* 贴住 min / max 的那一侧只把符号压灰,不铺一块灰底:铺了底就又成了框上贴着的一个方块 */
239
+ [data-scope='number-field'][data-part='control'] [data-part='increment-trigger']:disabled,
240
+ [data-scope='number-field'][data-part='control'] [data-part='decrement-trigger']:disabled {
241
+ background: transparent;
242
+ color: var(--xh-fg-disabled);
243
+ }
244
+
114
245
  [data-scope='number-field'][data-part='input'] {
115
246
  block-size: var(--xh-number-field-input-h, var(--xh-_number-field-h));
116
247
  padding-inline: var(--xh-number-field-input-px, var(--xh-_number-field-px));
117
248
  padding-block: 0;
118
249
  border: var(--xh-stroke-thin) solid var(--xh-number-field-input-border, var(--xh-_number-field-border));
119
- border-radius: var(--xh-number-field-input-radius, var(--xh-shape-control));
250
+ border-radius: var(--xh-_number-field-radius);
120
251
  background: var(--xh-number-field-input-bg, var(--xh-_number-field-bg));
121
252
  color: var(--xh-number-field-input-fg, var(--xh-fg-default));
122
253
  /* 表单控件不继承页面字体,只给字号会让输入框用 UA 默认字族 */
@@ -146,7 +277,10 @@
146
277
  }
147
278
 
148
279
  [data-scope='number-field'][data-part='input'][data-invalid] {
149
- border-color: var(--xh-number-field-input-border-invalid, var(--xh-color-danger-500));
280
+ border-color: var(--xh-number-field-input-border-invalid, var(--xh-border-invalid));
281
+
282
+ /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
283
+ --xh-_number-field-ring: var(--xh-ring-invalid);
150
284
  }
151
285
 
152
286
  /* 只读仍可聚焦、可复制,不置灰,只把底色压下去表示"改不动" */
@@ -169,8 +303,8 @@
169
303
  flex: none;
170
304
  align-items: center;
171
305
  justify-content: center;
172
- inline-size: var(--xh-number-field-trigger-size, var(--xh-_number-field-h));
173
- block-size: var(--xh-number-field-trigger-size, var(--xh-_number-field-h));
306
+ inline-size: var(--xh-number-field-trigger-size, var(--xh-control-action-size));
307
+ block-size: var(--xh-number-field-trigger-size, var(--xh-control-action-size));
174
308
  padding: 0;
175
309
  border: var(--xh-stroke-thin) solid var(--xh-number-field-trigger-border, var(--xh-_number-field-trigger-border));
176
310
  border-radius: var(--xh-number-field-trigger-radius, var(--xh-shape-control));
@@ -221,4 +355,33 @@
221
355
  color: var(--xh-fg-disabled);
222
356
  cursor: not-allowed;
223
357
  }
358
+
359
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
360
+ [data-scope='number-field'][data-part='increment-trigger']:empty::before {
361
+ content: '';
362
+ display: inline-block;
363
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
364
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
365
+ vertical-align: var(--xh-glyph-baseline-shift);
366
+ background-color: currentColor;
367
+ -webkit-mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
368
+ mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
369
+ }
370
+
371
+ [data-scope='number-field'][data-part='decrement-trigger']:empty::before {
372
+ content: '';
373
+ display: inline-block;
374
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
375
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
376
+ vertical-align: var(--xh-glyph-baseline-shift);
377
+ background-color: currentColor;
378
+ -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
379
+ mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
380
+ }
381
+
382
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
383
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
384
+ [data-scope='number-field'][data-part='control'][hidden] {
385
+ display: none;
386
+ }
224
387
  }
@@ -0,0 +1,51 @@
1
+ /*
2
+ * 浮层箭头的几何,六份浮层皮肤共用一份,按 [data-part='arrow'] 匹配。
3
+ *
4
+ * 箭头是正方形转 45°,构成尖角的是哪两条物理边,所以贴边与摘边框都写物理属性。
5
+ * 行内轴上的中心点仍写逻辑属性:定位引擎在 RTL 下已把 arrow-x 镜像成逻辑量。
6
+ *
7
+ * 底色与描边色留在各组件皮肤,它们同时把自己的内联落点槽接到这里的统一名字上。
8
+ * 引入顺序排在六份浮层皮肤之后:摘边框那几条要压过各皮肤的 border 简写。
9
+ */
10
+ @layer xihan.components {
11
+ [data-part='arrow'] {
12
+ position: absolute;
13
+ inline-size: var(--xh-_overlay-arrow-size);
14
+ block-size: var(--xh-_overlay-arrow-size);
15
+ rotate: 45deg;
16
+ }
17
+
18
+ /* 浮层落在锚点下方:箭头贴 content 上缘,摘掉埋进 content 的下、右两条边 */
19
+ [data-part='arrow'][data-placement^='bottom'] {
20
+ top: calc(var(--xh-_overlay-arrow-size) / -2);
21
+ inset-inline-start: calc(var(--xh-_overlay-arrow-x) - var(--xh-_overlay-arrow-size) / 2);
22
+ border-right: 0;
23
+ border-bottom: 0;
24
+ }
25
+
26
+ /* 浮层落在锚点上方:箭头贴 content 下缘,摘掉上、左两条边 */
27
+ [data-part='arrow'][data-placement^='top'] {
28
+ bottom: calc(var(--xh-_overlay-arrow-size) / -2);
29
+ inset-inline-start: calc(var(--xh-_overlay-arrow-x) - var(--xh-_overlay-arrow-size) / 2);
30
+ border-top: 0;
31
+ border-left: 0;
32
+ }
33
+
34
+ /* 浮层落在锚点右侧:箭头贴 content 左缘,摘掉上、右两条边 */
35
+ [data-part='arrow'][data-placement^='right'] {
36
+ top: calc(var(--xh-_overlay-arrow-y) - var(--xh-_overlay-arrow-size) / 2);
37
+ /* stylelint-disable-next-line property-disallowed-list -- 旋转是物理的,贴边跟着物理走 */
38
+ left: calc(var(--xh-_overlay-arrow-size) / -2);
39
+ border-top: 0;
40
+ border-right: 0;
41
+ }
42
+
43
+ /* 浮层落在锚点左侧:箭头贴 content 右缘,摘掉下、左两条边 */
44
+ [data-part='arrow'][data-placement^='left'] {
45
+ top: calc(var(--xh-_overlay-arrow-y) - var(--xh-_overlay-arrow-size) / 2);
46
+ /* stylelint-disable-next-line property-disallowed-list -- 旋转是物理的,贴边跟着物理走 */
47
+ right: calc(var(--xh-_overlay-arrow-size) / -2);
48
+ border-bottom: 0;
49
+ border-left: 0;
50
+ }
51
+ }
@@ -8,7 +8,7 @@
8
8
  /* 尺寸档只换这三个私有槽,各段从根上继承它们,换档不必给每个部件各写一条选择器 */
9
9
  --xh-_page-header-py: var(--xh-space-4);
10
10
  --xh-_page-header-row-gap: var(--xh-space-2);
11
- --xh-_page-header-title-size: var(--xh-font-size-xl);
11
+ --xh-_page-header-title-size: var(--xh-text-heading-3-size);
12
12
 
13
13
  /* 一行排不下就折行;返回位、标题、副标题排在同一行,操作贴到行尾,页脚整行另起 */
14
14
  display: flex;
@@ -29,13 +29,13 @@
29
29
  [data-scope='page-header'][data-part='root'][data-size='sm'] {
30
30
  --xh-_page-header-py: var(--xh-space-3);
31
31
  --xh-_page-header-row-gap: var(--xh-space-1);
32
- --xh-_page-header-title-size: var(--xh-font-size-lg);
32
+ --xh-_page-header-title-size: var(--xh-control-font-lg);
33
33
  }
34
34
 
35
35
  [data-scope='page-header'][data-part='root'][data-size='lg'] {
36
36
  --xh-_page-header-py: var(--xh-space-6);
37
37
  --xh-_page-header-row-gap: var(--xh-space-3);
38
- --xh-_page-header-title-size: var(--xh-font-size-2xl);
38
+ --xh-_page-header-title-size: var(--xh-text-heading-2-size);
39
39
  }
40
40
 
41
41
  /* —— 分隔线 —— */
@@ -67,7 +67,7 @@
67
67
  flex: 1 1 auto;
68
68
  min-inline-size: 0;
69
69
  color: var(--xh-page-header-subtitle-fg, var(--xh-fg-muted));
70
- font-size: var(--xh-page-header-subtitle-font-size, var(--xh-font-size-sm));
70
+ font-size: var(--xh-page-header-subtitle-font-size, var(--xh-text-secondary-size));
71
71
  line-height: var(--xh-leading-normal);
72
72
  }
73
73
 
@@ -84,7 +84,14 @@
84
84
  [data-scope='page-header'][data-part='footer'] {
85
85
  flex: 1 0 100%;
86
86
  color: var(--xh-page-header-footer-fg, var(--xh-fg-muted));
87
- font-size: var(--xh-page-header-footer-font-size, var(--xh-font-size-sm));
87
+ font-size: var(--xh-page-header-footer-font-size, var(--xh-text-secondary-size));
88
88
  line-height: var(--xh-leading-normal);
89
89
  }
90
+
91
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
92
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
93
+ [data-scope='page-header'][data-part='back-trigger'][hidden],
94
+ [data-scope='page-header'][data-part='extra'][hidden] {
95
+ display: none;
96
+ }
90
97
  }
@@ -1,3 +1,30 @@
1
+ @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-pop-in {
5
+ from {
6
+ opacity: 0;
7
+ scale: var(--xh-motion-scale-enter);
8
+ }
9
+
10
+ to {
11
+ opacity: 1;
12
+ scale: 1;
13
+ }
14
+ }
15
+ @keyframes xh-pop-out {
16
+ from {
17
+ opacity: 1;
18
+ scale: 1;
19
+ }
20
+
21
+ to {
22
+ opacity: 0;
23
+ scale: var(--xh-motion-scale-enter);
24
+ }
25
+ }
26
+ }
27
+
1
28
  @layer xihan.components {
2
29
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
30
  [data-scope='pagination'] {
@@ -8,11 +35,14 @@
8
35
  页数为 0 时连接层会打 data-empty,这里不拿它做隐藏:作者常把「第 x-y 条」这类
9
36
  区间回显也写在 nav 里,整块藏掉会连那行字一起吞了,是否隐藏交给作者决定 */
10
37
  [data-scope='pagination'][data-part='root'] {
38
+ /* 作者塞进上一页/下一页的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
39
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-text));
40
+
11
41
  /* 尺寸档只换这三个私有槽,上一页/下一页、页码与省略号都从 root 继承它们,
12
42
  换档不必给每个部件各写一条选择器 */
13
43
  --xh-_pagination-item-size: var(--xh-control-h-md);
14
- --xh-_pagination-item-px: var(--xh-space-2);
15
- --xh-_pagination-font-size: var(--xh-text-label-size);
44
+ --xh-_pagination-item-px: var(--xh-control-px-md);
45
+ --xh-_pagination-font-size: var(--xh-control-font-md);
16
46
 
17
47
  /* 当前页的选中态随语气走。没写 data-tone 时这几个 --xh-_tone-* 都没被声明,
18
48
  退回原来的品牌底与其配色。聚焦环不在其列,它恒是 --xh-ring-focus */
@@ -29,18 +59,18 @@
29
59
  }
30
60
 
31
61
  /* —— 尺寸 —— */
32
- /* 缺省档写在上面的基础规则里。格子高度走控件高度尺;内边距不在控件内边距那把尺上
33
- (页码格子靠最小宽度撑等宽,内边距比同高的控件窄一档),三档一律取空间尺 */
62
+ /* 缺省档写在上面的基础规则里。格子高度、内边距、字号三者各走控件尺的同一档;
63
+ 页码格子靠最小宽度撑等宽,内边距只在页码超出最小宽度时才起作用 */
34
64
  [data-scope='pagination'][data-part='root'][data-size='sm'] {
35
65
  --xh-_pagination-item-size: var(--xh-control-h-sm);
36
- --xh-_pagination-item-px: var(--xh-space-1_5);
37
- --xh-_pagination-font-size: var(--xh-font-size-sm);
66
+ --xh-_pagination-item-px: var(--xh-control-px-sm);
67
+ --xh-_pagination-font-size: var(--xh-control-font-sm);
38
68
  }
39
69
 
40
70
  [data-scope='pagination'][data-part='root'][data-size='lg'] {
41
71
  --xh-_pagination-item-size: var(--xh-control-h-lg);
42
- --xh-_pagination-item-px: var(--xh-space-3);
43
- --xh-_pagination-font-size: var(--xh-font-size-lg);
72
+ --xh-_pagination-item-px: var(--xh-control-px-lg);
73
+ --xh-_pagination-font-size: var(--xh-control-font-lg);
44
74
  }
45
75
 
46
76
  [data-scope='pagination'][data-part='root'][hidden] {
@@ -98,13 +128,13 @@
98
128
  页码条目从不禁用(连接层只给上一页/下一页发原生 disabled),故这边不必再排除 :disabled */
99
129
  [data-scope='pagination'][data-part='prev-trigger']:hover:not(:disabled),
100
130
  [data-scope='pagination'][data-part='next-trigger']:hover:not(:disabled),
101
- [data-scope='pagination'][data-part='item']:not([data-selected]):hover {
131
+ [data-scope='pagination'][data-part='item']:not([data-current]):hover {
102
132
  background: var(--xh-pagination-item-bg-hover, var(--xh-bg-subtle-hover));
103
133
  }
104
134
 
105
135
  [data-scope='pagination'][data-part='prev-trigger']:active:not(:disabled),
106
136
  [data-scope='pagination'][data-part='next-trigger']:active:not(:disabled),
107
- [data-scope='pagination'][data-part='item']:not([data-selected]):active {
137
+ [data-scope='pagination'][data-part='item']:not([data-current]):active {
108
138
  background: var(--xh-pagination-item-bg-active, var(--xh-bg-subtle-active));
109
139
  }
110
140
 
@@ -124,21 +154,21 @@
124
154
  cursor: not-allowed;
125
155
  }
126
156
 
127
- /* 当前页:data-selected 与 aria-current='page' 由连接层成对给出,
157
+ /* 当前页:data-current 与 aria-current='page' 由连接层成对给出,
128
158
  样式挂在 data 钩子上,无障碍语义留给 aria,两边各司其职。
129
159
  只换底色不加粗——字重一变字形就变宽,页码格子会跟着长一点,正是这里要避免的抖动 */
130
- [data-scope='pagination'][data-part='item'][data-selected] {
160
+ [data-scope='pagination'][data-part='item'][data-current] {
131
161
  border-color: var(--xh-pagination-item-border-selected, var(--xh-_pagination-selected-bg));
132
162
  background: var(--xh-pagination-item-bg-selected, var(--xh-_pagination-selected-bg));
133
163
  color: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
134
164
  }
135
165
 
136
- [data-scope='pagination'][data-part='item'][data-selected]:hover {
166
+ [data-scope='pagination'][data-part='item'][data-current]:hover {
137
167
  border-color: var(--xh-pagination-item-border-selected-hover, var(--xh-_pagination-selected-bg-hover));
138
168
  background: var(--xh-pagination-item-bg-selected-hover, var(--xh-_pagination-selected-bg-hover));
139
169
  }
140
170
 
141
- [data-scope='pagination'][data-part='item'][data-selected]:active {
171
+ [data-scope='pagination'][data-part='item'][data-current]:active {
142
172
  border-color: var(--xh-pagination-item-border-selected-active, var(--xh-_pagination-selected-bg-active));
143
173
  background: var(--xh-pagination-item-bg-selected-active, var(--xh-_pagination-selected-bg-active));
144
174
  }
@@ -150,4 +180,131 @@
150
180
  cursor: default;
151
181
  pointer-events: none;
152
182
  }
183
+ /* 每页条数控制器:原生 select,抹掉系统外观后与页码格子共用同一副骨架。
184
+ 箭头用背景图而非伪元素——原生 select 不生成 ::before */
185
+ [data-scope='pagination'][data-part='page-size-select'] {
186
+ flex: none;
187
+ block-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
188
+ padding-inline: var(--xh-pagination-item-px, var(--xh-_pagination-item-px));
189
+ /* 右侧让开箭头 */
190
+ padding-inline-end: calc(
191
+ var(--xh-pagination-item-px, var(--xh-_pagination-item-px)) +
192
+ var(--xh-icon-size, var(--xh-glyph-size-text)) + var(--xh-space-1)
193
+ );
194
+ border: var(--xh-stroke-thin) solid var(--xh-pagination-page-size-border, var(--xh-border-default));
195
+ border-radius: var(--xh-pagination-item-radius, var(--xh-shape-control));
196
+ background: var(--xh-pagination-page-size-bg, var(--xh-bg-surface));
197
+ color: var(--xh-pagination-item-fg, var(--xh-fg-default));
198
+ font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
199
+ line-height: var(--xh-leading-none);
200
+ appearance: none;
201
+ cursor: pointer;
202
+ }
203
+
204
+ [data-scope='pagination'][data-part='page-size-select']:hover:not(:disabled) {
205
+ border-color: var(--xh-pagination-page-size-border-hover, var(--xh-border-strong));
206
+ }
207
+
208
+ [data-scope='pagination'][data-part='page-size-select']:focus-visible {
209
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
210
+ outline-offset: var(--xh-ring-offset);
211
+ }
212
+
213
+ [data-scope='pagination'][data-part='page-size-select']:disabled {
214
+ color: var(--xh-fg-disabled);
215
+ cursor: not-allowed;
216
+ }
217
+
218
+ /* 摊开省略位的定位层。三处坐标系必须同为 fixed:机器交给引擎的 strategy、
219
+ 连接层的内联 position、这里 —— 差一处就会算在错的坐标系里 */
220
+ [data-scope='pagination'][data-part='positioner'] {
221
+ /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,面板继承它限高;
222
+ 引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
223
+ --xh-_pagination-available-h: 100vh;
224
+
225
+ /* 页码面板的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊一条竖灰带 */
226
+ --xh-scrollbar-track-bg: transparent;
227
+
228
+ position: fixed;
229
+ z-index: var(--xh-pagination-layer, var(--xh-layer-popover));
230
+ /* 空壳不吃指针:省略位与面板之间那段间隙要能点得穿 */
231
+ pointer-events: none;
232
+ }
233
+
234
+ /* 锚点被滚出可视区:整个浮层随之收起 */
235
+ [data-scope='pagination'][data-part='positioner'][data-hidden] {
236
+ visibility: hidden;
237
+ }
238
+
239
+ /* 摊开的页码面板:一串页码格子,横着排、必要时折行 */
240
+ [data-scope='pagination'][data-part='content'] {
241
+ /* 浮层被搬到 portal 落点,继承不到 root 上那把尺,这里再声明一遍 */
242
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-text));
243
+
244
+ display: flex;
245
+ flex-flow: row wrap;
246
+ gap: var(--xh-pagination-gap, var(--xh-space-1));
247
+ /* 页码不可预知有多少:不限高就整块伸出视口且滚不到 */
248
+ max-inline-size: var(--xh-pagination-content-max-w, var(--xh-overlay-max-w));
249
+ max-block-size: min(
250
+ var(--xh-pagination-content-max-h, var(--xh-overlay-max-h)),
251
+ var(--xh-_pagination-available-h)
252
+ );
253
+ overflow-y: auto;
254
+ padding: var(--xh-pagination-content-p, var(--xh-space-1));
255
+ border: var(--xh-stroke-thin) solid var(--xh-pagination-content-border, var(--xh-border-default));
256
+ border-radius: var(--xh-pagination-content-radius, var(--xh-shape-surface));
257
+ background: var(--xh-pagination-content-bg, var(--xh-bg-surface));
258
+ box-shadow: var(--xh-pagination-content-shadow, var(--xh-elevation-floating));
259
+ /* 定位层不吃指针,面板本体必须吃:里面的页码要点得到 */
260
+ pointer-events: auto;
261
+ }
262
+
263
+ [data-scope='pagination'][data-part='content'][data-state='open'] {
264
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
265
+ }
266
+
267
+ /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
268
+ 免得动画结束到真收起之间闪一下原样 */
269
+ [data-scope='pagination'][data-part='content'][data-state='closed'] {
270
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
271
+ }
272
+
273
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none }:
274
+ 补了退场就一帧都播不出来,真正的收起由适配器落成内联 display */
275
+
276
+ /* 没写内容就由皮肤画兜底字形:上一页/下一页默认就是两枚箭头,
277
+ 作者往部件里塞了自己的图形或文字,这两条即不命中 */
278
+ [data-scope='pagination'][data-part='prev-trigger']:empty::before {
279
+ content: '';
280
+ display: inline-block;
281
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
282
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
283
+ vertical-align: var(--xh-glyph-baseline-shift);
284
+ background-color: currentColor;
285
+ -webkit-mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
286
+ mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
287
+ }
288
+
289
+ [data-scope='pagination'][data-part='next-trigger']:empty::before {
290
+ content: '';
291
+ display: inline-block;
292
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
293
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
294
+ vertical-align: var(--xh-glyph-baseline-shift);
295
+ background-color: currentColor;
296
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
297
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
298
+ }
299
+
300
+ /* rtl 下页序从右往左走,箭头跟着指向行进方向 */
301
+ [dir='rtl'] [data-scope='pagination'][data-part='prev-trigger']:empty::before {
302
+ -webkit-mask-image: var(--xh-glyph-mark-chevron-right);
303
+ mask-image: var(--xh-glyph-mark-chevron-right);
304
+ }
305
+
306
+ [dir='rtl'] [data-scope='pagination'][data-part='next-trigger']:empty::before {
307
+ -webkit-mask-image: var(--xh-glyph-mark-chevron-left);
308
+ mask-image: var(--xh-glyph-mark-chevron-left);
309
+ }
153
310
  }