@xihan-ui/styles 1.0.0-alpha.3 → 1.1.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 (99) hide show
  1. package/CHANGELOG.md +1922 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +25 -2
  4. package/css/alert.css +13 -9
  5. package/css/anchor.css +1 -1
  6. package/css/avatar-group.css +5 -1
  7. package/css/avatar.css +6 -0
  8. package/css/back-top.css +6 -0
  9. package/css/badge.css +94 -36
  10. package/css/breadcrumb.css +1 -1
  11. package/css/button-group.css +4 -0
  12. package/css/button.css +6 -0
  13. package/css/calendar.css +39 -13
  14. package/css/card.css +15 -6
  15. package/css/cascader.css +29 -23
  16. package/css/checkbox-group.css +38 -10
  17. package/css/checkbox.css +21 -10
  18. package/css/collapsible.css +7 -1
  19. package/css/color-picker.css +22 -2
  20. package/css/combobox.css +18 -7
  21. package/css/context-menu.css +17 -6
  22. package/css/date-field.css +2 -2
  23. package/css/date-picker.css +27 -17
  24. package/css/descriptions.css +9 -3
  25. package/css/dialog.css +7 -1
  26. package/css/drawer.css +15 -5
  27. package/css/dynamic-input.css +7 -0
  28. package/css/ellipsis.css +6 -0
  29. package/css/empty-state.css +16 -6
  30. package/css/field.css +7 -0
  31. package/css/file-upload.css +1 -1
  32. package/css/flex.css +13 -7
  33. package/css/float-button.css +7 -0
  34. package/css/floating-panel.css +6 -0
  35. package/css/grid.css +11 -5
  36. package/css/heatmap.css +3 -2
  37. package/css/highlight.css +1 -1
  38. package/css/hotkeys.css +1 -1
  39. package/css/hover-card.css +3 -0
  40. package/css/image-cropper.css +4 -2
  41. package/css/image-viewer.css +18 -5
  42. package/css/json-viewer.css +34 -1
  43. package/css/layout.css +15 -7
  44. package/css/list.css +14 -5
  45. package/css/listbox.css +4 -2
  46. package/css/loading-bar.css +5 -4
  47. package/css/log.css +6 -2
  48. package/css/masonry.css +5 -5
  49. package/css/mention.css +13 -3
  50. package/css/menu.css +16 -5
  51. package/css/menubar.css +14 -6
  52. package/css/navigation-menu.css +2 -2
  53. package/css/notification.css +377 -0
  54. package/css/number-field.css +9 -3
  55. package/css/page-header.css +7 -0
  56. package/css/pagination.css +158 -1
  57. package/css/password-input.css +4 -4
  58. package/css/pin-input.css +2 -2
  59. package/css/popconfirm.css +9 -2
  60. package/css/popover.css +3 -0
  61. package/css/popselect.css +24 -4
  62. package/css/progress.css +8 -2
  63. package/css/radio-group.css +17 -6
  64. package/css/rating.css +2 -2
  65. package/css/resizable.css +113 -0
  66. package/css/result.css +15 -5
  67. package/css/scrollbar.css +3 -0
  68. package/css/segmented.css +1 -1
  69. package/css/select.css +25 -7
  70. package/css/side-nav.css +16 -5
  71. package/css/slider.css +4 -2
  72. package/css/sortable.css +103 -0
  73. package/css/space.css +6 -6
  74. package/css/steps.css +6 -6
  75. package/css/switch.css +9 -2
  76. package/css/table.css +309 -10
  77. package/css/tabs.css +148 -1
  78. package/css/tag.css +3 -1
  79. package/css/tags-input.css +3 -3
  80. package/css/text-field.css +3 -3
  81. package/css/thread.css +10 -2
  82. package/css/time-field.css +2 -2
  83. package/css/time-picker.css +6 -6
  84. package/css/timeline.css +7 -7
  85. package/css/toast.css +103 -53
  86. package/css/toggle-group.css +30 -4
  87. package/css/toggle.css +6 -0
  88. package/css/tone.css +47 -17
  89. package/css/tooltip.css +7 -1
  90. package/css/tour.css +9 -3
  91. package/css/transfer.css +38 -12
  92. package/css/tree-select.css +30 -5
  93. package/css/tree.css +175 -4
  94. package/css/typography.css +1 -1
  95. package/css/undefined.css +1 -0
  96. package/index.css +3 -1
  97. package/index.unlayered.css +2650 -634
  98. package/package.json +5 -3
  99. package/css/toaster.css +0 -74
@@ -0,0 +1,377 @@
1
+ @layer xihan.motion {
2
+ /*
3
+ * 九个位共用同一条进出场,位移不跟着落位走:要按位置分方向,就得从 group 的
4
+ * data-placement 反向选到卡片上,落位一改名整条动效静默失效。
5
+ * 竖向一小段位移在九个位上都说得通。
6
+ */
7
+ @keyframes xh-notification-in {
8
+ from {
9
+ opacity: 0;
10
+ translate: 0 var(--xh-motion-distance-md);
11
+ scale: var(--xh-motion-scale-enter);
12
+ }
13
+
14
+ to {
15
+ opacity: 1;
16
+ translate: 0 0;
17
+ scale: 1;
18
+ }
19
+ }
20
+
21
+ /* loading 那枚字形自己转。逐皮肤自带一份:跨皮肤共用动画名,
22
+ 引用方那份皮肤不在场时动画就静默不跑 */
23
+ @keyframes xh-notification-spin {
24
+ to {
25
+ rotate: 360deg;
26
+ }
27
+ }
28
+
29
+ @keyframes xh-notification-out {
30
+ from {
31
+ opacity: 1;
32
+ translate: 0 0;
33
+ scale: 1;
34
+ }
35
+
36
+ to {
37
+ opacity: 0;
38
+ translate: 0 var(--xh-motion-distance-md);
39
+ scale: var(--xh-motion-scale-enter);
40
+ }
41
+ }
42
+ }
43
+
44
+ @layer xihan.components {
45
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
46
+ [data-scope='notification'] {
47
+ --xh-notification-skin: 1;
48
+ }
49
+
50
+ /* 作用域包装不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
51
+ root 只是把队列的作用域圈起来(地标挂在那一摞上,不在这里)。
52
+ 它若留下一个块盒,写在页面中段的用法(按钮和队列摆在一起)就会凭空多出一行空白。
53
+ 另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
54
+ transform / filter / backdrop-filter / contain,包含块就被抢走,整摞通知立刻贴错位置——
55
+ 所以这里连 position 都不碰,也别往覆盖钩子里加这几个属性。 */
56
+ [data-scope='notification'][data-part='root'] {
57
+ display: contents;
58
+ }
59
+
60
+ /* 只要声明过 display,就盖掉了 UA 的 [hidden]{display:none},收起态得自己补回来 */
61
+ [data-scope='notification'][data-part='root'][hidden] {
62
+ display: none;
63
+ }
64
+
65
+ /*
66
+ * 一摞 = 一整面视口大小的定位面:贴边靠 padding,九个位靠 justify/align 表达。
67
+ * 不用四角 inset 逐个摆,是因为 column flex 的 align-items 走的是行内轴,
68
+ * RTL 下 start/end 自动跟着翻;写死 inset-inline-start 的话居中那三个位
69
+ * 还得再配一次 translate,方向一变就错。
70
+ * 条目次序按队列原样(旧的在前):贴底那三个位于是新的离屏幕边最近,符合直觉。
71
+ */
72
+ [data-scope='notification'][data-part='group'] {
73
+ position: fixed;
74
+ inset-block: 0;
75
+ inset-inline: 0;
76
+ z-index: var(--xh-notification-layer, var(--xh-layer-toast));
77
+ display: flex;
78
+ flex-direction: column;
79
+ /* 基线按默认落位 bottom-end 写,下面只覆盖跟它不同的那几个位 */
80
+ justify-content: flex-end;
81
+ align-items: center;
82
+ padding-block: var(--xh-notification-inset, var(--xh-space-6));
83
+ padding-inline: var(--xh-notification-inset, var(--xh-space-6));
84
+ /* 摞内间距由连接层写进内联 style(两个适配器共用同一份),这里绝不重复写:
85
+ 写了也会被内联盖掉,只会让人误以为间距归样式层管 */
86
+ /* 整面铺开就等于罩住了整块视口。面本身不吃指针,只有卡片吃(见下),
87
+ 否则九个位一叠,底下的页面就再也点不动了 */
88
+ pointer-events: none;
89
+ }
90
+
91
+ [data-scope='notification'][data-part='group'][hidden] {
92
+ display: none;
93
+ }
94
+
95
+ /* 空摞直接撤掉:九个位同时挂九张全屏定位面,白白多九个合成层 */
96
+ [data-scope='notification'][data-part='group'][data-empty] {
97
+ display: none;
98
+ }
99
+
100
+ /* 块轴落位:^= 一次吃掉某一行的三个位(top / top-start / top-end) */
101
+ [data-scope='notification'][data-part='group'][data-placement^='top'] {
102
+ justify-content: flex-start;
103
+ }
104
+
105
+ [data-scope='notification'][data-part='group'][data-placement^='middle'] {
106
+ justify-content: center;
107
+ }
108
+
109
+ /* 行内轴落位:不带后缀的 top / middle / bottom 用基线的居中 */
110
+ [data-scope='notification'][data-part='group'][data-placement$='-start'] {
111
+ align-items: flex-start;
112
+ }
113
+
114
+ [data-scope='notification'][data-part='group'][data-placement$='-end'] {
115
+ align-items: flex-end;
116
+ }
117
+
118
+ /*
119
+ * 一张通知卡:左列一枚类型字形,右列「标题 + 说明 + 操作」竖着排,叉钉在右上角。
120
+ * 用网格而不是竖排 flex:叉要脱离文档流钉到角上,正文要在字形右边成一列——
121
+ * 竖排 flex 里这两件事都做不到(叉会变成第三行)。
122
+ * 底与描边一律中性,语气只由左列那枚字形承载:整片兑色是轻提示那条的做法,
123
+ * 一张有标题有正文的卡片全片染色会把两层文字都压在同一片语气色上。
124
+ */
125
+ [data-scope='notification'][data-part='item'] {
126
+ /* 叉与操作钮的兜底字形按控件指示符那一档走;左列那枚类型字形另有自己的尺寸 */
127
+ --xh-icon-size: var(--xh-notification-icon-size, var(--xh-control-indicator-size));
128
+
129
+ position: relative;
130
+ display: grid;
131
+ /* 左列宽度由字形自己决定,作者不放指示符时它就是 0,正文自然贴到左内衬 */
132
+ grid-template-columns: auto 1fr;
133
+ align-items: start;
134
+ column-gap: var(--xh-notification-gap, var(--xh-space-3));
135
+ row-gap: var(--xh-notification-row-gap, var(--xh-space-2));
136
+ inline-size: var(--xh-notification-w, var(--xh-overlay-max-w-lg));
137
+ /* 摞是整面视口宽的定位面且带内边距,取 100% 就等于自动让出两侧留白,
138
+ 窄屏上不必再算一遍 viewport 减法 */
139
+ max-inline-size: 100%;
140
+ padding-block: var(--xh-notification-py, var(--xh-space-4));
141
+ padding-inline: var(--xh-notification-px, var(--xh-space-4));
142
+ border: var(--xh-stroke-thin) solid var(--xh-notification-border, var(--xh-border-default));
143
+ border-radius: var(--xh-notification-radius, var(--xh-shape-surface));
144
+ background: var(--xh-notification-bg, var(--xh-bg-surface-raised));
145
+ color: var(--xh-notification-fg, var(--xh-fg-default));
146
+ box-shadow: var(--xh-notification-shadow, var(--xh-elevation-sheet));
147
+ font-size: var(--xh-notification-font-size, var(--xh-text-body-size));
148
+ line-height: var(--xh-notification-leading, var(--xh-text-body-leading));
149
+ /* 摞的定位面整面铺开且不吃指针,卡片必须自己吃回来:
150
+ 悬停按住计时、按钮可点、焦点进出,全指着这一条 */
151
+ pointer-events: auto;
152
+ }
153
+
154
+ /* 除指示符外一律落第二列:作者往卡片里塞的任何东西都跟着正文走 */
155
+ [data-scope='notification'][data-part='item'] > *:not([data-part='item-indicator']) {
156
+ grid-column: 2;
157
+ }
158
+
159
+ /* 退场窗口走完连接层给的是 hidden 属性,而上面声明了 display——
160
+ 漏掉这条,已经"卸载"的通知会一直杵在屏幕上,且再也没人来收 */
161
+ [data-scope='notification'][data-part='item'][hidden] {
162
+ display: none;
163
+ }
164
+
165
+ /* 生命周期只有三段,unmounted 那段由上面的 [hidden] 收走,这里只管前两段 */
166
+ [data-scope='notification'][data-part='item'][data-state='visible'] {
167
+ animation: xh-notification-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
168
+ }
169
+
170
+ /* forwards 不能省:退场窗口(removeDelay 默认 200ms)比退场动画长,
171
+ 不定住末帧的话动画跑完会弹回全不透明,卡片在被收起前先闪一下 */
172
+ [data-scope='notification'][data-part='item'][data-state='dismissing'] {
173
+ animation: xh-notification-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
174
+ }
175
+
176
+ /* 独占第一列第一行,并与标题首行顶对齐:盒高取一行标题的行高,
177
+ 字形在盒里居中,标题字号改了也不会错位 */
178
+ [data-scope='notification'][data-part='item-indicator'] {
179
+ --xh-icon-size: var(--xh-notification-indicator-size, var(--xh-glyph-size-md));
180
+
181
+ grid-column: 1;
182
+ grid-row: 1;
183
+ display: inline-flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ block-size: calc(var(--xh-notification-title-font-size, var(--xh-text-label-size)) * var(--xh-leading-tight));
187
+ inline-size: var(--xh-notification-indicator-size, var(--xh-glyph-size-md));
188
+ color: var(--xh-notification-indicator-fg, var(--xh-_tone-fg));
189
+ }
190
+
191
+ [data-scope='notification'][data-part='item-indicator'][hidden] {
192
+ display: none;
193
+ }
194
+
195
+ /* 作者没往指示符里写内容就由皮肤画兜底字形,按语气各画一枚;
196
+ 塞了自己的图形这几条即不命中 */
197
+ [data-scope='notification'][data-part='item-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-info) center / contain no-repeat;
205
+ mask: var(--xh-glyph-mark-info) center / contain no-repeat;
206
+ }
207
+
208
+ [data-scope='notification'][data-part='item'][data-type='success'] [data-part='item-indicator']:empty::before {
209
+ -webkit-mask-image: var(--xh-glyph-mark-check);
210
+ mask-image: var(--xh-glyph-mark-check);
211
+ }
212
+
213
+ [data-scope='notification'][data-part='item'][data-type='warning'] [data-part='item-indicator']:empty::before {
214
+ -webkit-mask-image: var(--xh-glyph-mark-warning);
215
+ mask-image: var(--xh-glyph-mark-warning);
216
+ }
217
+
218
+ [data-scope='notification'][data-part='item'][data-type='error'] [data-part='item-indicator']:empty::before {
219
+ -webkit-mask-image: var(--xh-glyph-mark-close);
220
+ mask-image: var(--xh-glyph-mark-close);
221
+ }
222
+
223
+ /* loading 说的是「事情还没完」,不是好消息也不是坏消息:走中性前景档而不是语气色 */
224
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator'] {
225
+ color: var(--xh-notification-indicator-fg, var(--xh-fg-muted));
226
+ }
227
+
228
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
229
+ -webkit-mask-image: var(--xh-glyph-mark-rotate-right);
230
+ mask-image: var(--xh-glyph-mark-rotate-right);
231
+ animation: xh-notification-spin var(--xh-spin-duration) linear infinite;
232
+ }
233
+
234
+ /* 减少动效:转圈停下,静止的箭头仍然读得出「还没好」;
235
+ "在等什么"由卡片上的 role=status 与可见文案继续承担。
236
+ 两组规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
237
+ @media (prefers-reduced-motion: reduce) {
238
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
239
+ animation: none;
240
+ }
241
+ }
242
+
243
+ :where([data-motion='reduce']) [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
244
+ animation: none;
245
+ }
246
+
247
+ [data-scope='notification'][data-part='item-title'] {
248
+ /* 作者可能把它写成 h2/p,外边距得先归零,否则卡片内的行距对不上 */
249
+ margin: 0;
250
+ color: var(--xh-notification-title-fg, var(--xh-fg-default));
251
+ font-size: var(--xh-notification-title-font-size, var(--xh-text-label-size));
252
+ font-weight: var(--xh-notification-title-font-weight, var(--xh-font-weight-semibold));
253
+ line-height: var(--xh-notification-title-leading, var(--xh-leading-tight));
254
+ }
255
+
256
+ /* 叉钉在右上角,标题得给它让位;说明与操作在第二行往下,不受影响 */
257
+ [data-scope='notification'][data-part='item']:has([data-part='item-close-trigger']) [data-part='item-title'] {
258
+ padding-inline-end: calc(var(--xh-notification-close-size, var(--xh-control-h-sm)) + var(--xh-space-2));
259
+ }
260
+
261
+ [data-scope='notification'][data-part='item-description'] {
262
+ margin: 0;
263
+ color: var(--xh-notification-description-fg, var(--xh-fg-muted));
264
+ font-size: var(--xh-notification-description-font-size, var(--xh-text-secondary-size));
265
+ }
266
+
267
+ /* 没给文案的那一个仍然要留在 DOM 里(aria-labelledby / aria-describedby 指着它),
268
+ 但空盒子会照吃一份 gap,卡片看着就多出一截莫名的留白 */
269
+ [data-scope='notification'][data-part='item-title']:empty,
270
+ [data-scope='notification'][data-part='item-description']:empty {
271
+ display: none;
272
+ }
273
+
274
+ [data-scope='notification'][data-part='item-title'][hidden],
275
+ [data-scope='notification'][data-part='item-description'][hidden] {
276
+ display: none;
277
+ }
278
+
279
+ [data-scope='notification'][data-part='item-action-trigger'] {
280
+ /* 网格列默认拉满,按钮要贴着起始侧收成自己的宽度 */
281
+ justify-self: start;
282
+ display: inline-flex;
283
+ align-items: center;
284
+ justify-content: center;
285
+ block-size: var(--xh-notification-action-h, var(--xh-control-h-sm));
286
+ padding-inline: var(--xh-notification-action-px, var(--xh-control-px-sm));
287
+ border: var(--xh-stroke-thin) solid var(--xh-notification-action-border, var(--xh-border-default));
288
+ border-radius: var(--xh-notification-action-radius, var(--xh-shape-control));
289
+ background: var(--xh-notification-action-bg, var(--xh-bg-subtle));
290
+ color: var(--xh-notification-action-fg, var(--xh-fg-default));
291
+ /* 按钮不继承字族字号,不接回来的话卡片里会突然冒出一段系统 UI 字体 */
292
+ font: inherit;
293
+ font-weight: var(--xh-notification-action-font-weight, var(--xh-font-weight-medium));
294
+ line-height: var(--xh-leading-none);
295
+ cursor: pointer;
296
+ }
297
+
298
+ [data-scope='notification'][data-part='item-action-trigger'][hidden] {
299
+ display: none;
300
+ }
301
+
302
+ [data-scope='notification'][data-part='item-action-trigger']:hover:not(:disabled) {
303
+ background: var(--xh-notification-action-bg-hover, var(--xh-bg-subtle-hover));
304
+ }
305
+
306
+ [data-scope='notification'][data-part='item-action-trigger']:active:not(:disabled) {
307
+ background: var(--xh-notification-action-bg-active, var(--xh-bg-subtle-active));
308
+ }
309
+
310
+ [data-scope='notification'][data-part='item-action-trigger']:focus-visible {
311
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
312
+ outline-offset: var(--xh-ring-offset);
313
+ }
314
+
315
+ /* 钉在右上角的内衬处,不参与网格排布——留在流里它会变成正文下面的第三行 */
316
+ [data-scope='notification'][data-part='item-close-trigger'] {
317
+ position: absolute;
318
+ inset-block-start: var(--xh-notification-close-inset, var(--xh-space-3));
319
+ inset-inline-end: var(--xh-notification-close-inset, var(--xh-space-3));
320
+ display: inline-flex;
321
+ align-items: center;
322
+ justify-content: center;
323
+ block-size: var(--xh-notification-close-size, var(--xh-control-h-sm));
324
+ inline-size: var(--xh-notification-close-size, var(--xh-control-h-sm));
325
+ border: 0;
326
+ border-radius: var(--xh-notification-close-radius, var(--xh-shape-control));
327
+ background: transparent;
328
+ color: var(--xh-notification-close-fg, var(--xh-fg-muted));
329
+ font: inherit;
330
+ line-height: var(--xh-leading-none);
331
+ cursor: pointer;
332
+ transition:
333
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
334
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
335
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
336
+ }
337
+
338
+ /* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半:
339
+ 上面声明了 display,不补回来就会留下一个按不动的叉,比压根没有叉更让人困惑 */
340
+ [data-scope='notification'][data-part='item-close-trigger'][hidden] {
341
+ display: none;
342
+ }
343
+
344
+ [data-scope='notification'][data-part='item-close-trigger']:hover:not(:disabled) {
345
+ background: var(--xh-notification-close-bg-hover, var(--xh-bg-subtle-hover));
346
+ color: var(--xh-notification-close-fg-hover, var(--xh-fg-default));
347
+ }
348
+
349
+ [data-scope='notification'][data-part='item-close-trigger']:active {
350
+ background: var(--xh-notification-close-bg-active, var(--xh-bg-subtle-active));
351
+ scale: var(--xh-motion-scale-press);
352
+ }
353
+
354
+ /* 单体控件用原生 disabled。常规路径下它与 hidden 同时出现看不见,
355
+ 但作者若在覆盖层把收起改了回来,至少还能看出这颗叉是按不动的 */
356
+ [data-scope='notification'][data-part='item-close-trigger']:disabled {
357
+ color: var(--xh-fg-disabled);
358
+ cursor: not-allowed;
359
+ }
360
+
361
+ [data-scope='notification'][data-part='item-close-trigger']:focus-visible {
362
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
363
+ outline-offset: var(--xh-ring-offset);
364
+ }
365
+
366
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
367
+ [data-scope='notification'][data-part='item-close-trigger']:empty::before {
368
+ content: '';
369
+ display: inline-block;
370
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
371
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
372
+ vertical-align: var(--xh-glyph-baseline-shift);
373
+ background-color: currentColor;
374
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
375
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
376
+ }
377
+ }
@@ -17,9 +17,9 @@
17
17
  --xh-_number-field-h: var(--xh-control-h-md);
18
18
  --xh-_number-field-px: var(--xh-control-px-md);
19
19
  --xh-_number-field-gap: var(--xh-control-gap-md);
20
- --xh-_number-field-font-size: var(--xh-text-body-size);
21
- --xh-_number-field-label-font-size: var(--xh-text-label-size);
22
- --xh-_number-field-trigger-font-size: var(--xh-text-body-size);
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
23
 
24
24
  /* 盒子的圆角 */
25
25
  --xh-_number-field-radius: var(--xh-number-field-input-radius, var(--xh-shape-control));
@@ -378,4 +378,10 @@
378
378
  -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
379
379
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
380
380
  }
381
+
382
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
383
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
384
+ [data-scope='number-field'][data-part='control'][hidden] {
385
+ display: none;
386
+ }
381
387
  }
@@ -87,4 +87,11 @@
87
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
44
  --xh-_pagination-item-px: var(--xh-control-px-md);
15
- --xh-_pagination-font-size: var(--xh-text-label-size);
45
+ --xh-_pagination-font-size: var(--xh-control-font-md);
16
46
 
17
47
  /* 当前页的选中态随语气走。没写 data-tone 时这几个 --xh-_tone-* 都没被声明,
18
48
  退回原来的品牌底与其配色。聚焦环不在其列,它恒是 --xh-ring-focus */
@@ -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
  }
@@ -17,11 +17,11 @@
17
17
  --xh-_password-input-h: var(--xh-control-h-md);
18
18
  --xh-_password-input-px: var(--xh-control-px-md);
19
19
  --xh-_password-input-gap: var(--xh-control-gap-md);
20
- --xh-_password-input-font-size: var(--xh-text-body-size);
21
- --xh-_password-input-label-font-size: var(--xh-text-label-size);
20
+ --xh-_password-input-font-size: var(--xh-control-font-md);
21
+ --xh-_password-input-label-font-size: var(--xh-control-font-md);
22
22
  /* 提示与切换钮里的字形都比正文小一档,三个尺寸档各自换过,不是一个恒等的中转 */
23
- --xh-_password-input-hint-font-size: var(--xh-text-secondary-size);
24
- --xh-_password-input-trigger-font-size: var(--xh-text-secondary-size);
23
+ --xh-_password-input-hint-font-size: var(--xh-control-caption-md);
24
+ --xh-_password-input-trigger-font-size: var(--xh-control-caption-md);
25
25
 
26
26
  /* 盒子的圆角 */
27
27
  --xh-_password-input-radius: var(--xh-password-input-input-radius, var(--xh-shape-control));
package/css/pin-input.css CHANGED
@@ -8,9 +8,9 @@
8
8
  [data-scope='pin-input'][data-part='root'] {
9
9
  /* 尺寸档只换这四个私有槽,标题与格子都从 root 继承它们,换档不必给每个部件各写一条选择器 */
10
10
  --xh-_pin-input-box-size: var(--xh-control-box-md);
11
- --xh-_pin-input-box-gap: var(--xh-space-2);
11
+ --xh-_pin-input-box-gap: var(--xh-control-gap-md);
12
12
  --xh-_pin-input-box-font-size: var(--xh-text-heading-3-size);
13
- --xh-_pin-input-label-font-size: var(--xh-text-label-size);
13
+ --xh-_pin-input-label-font-size: var(--xh-control-font-md);
14
14
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
15
15
  --xh-_pin-input-box-bg: var(--xh-bg-canvas);
16
16
  --xh-_pin-input-box-border: var(--xh-border-control);
@@ -141,9 +141,9 @@
141
141
  align-items: center;
142
142
  justify-content: center;
143
143
  block-size: var(--xh-control-h-sm);
144
- padding-inline: var(--xh-control-px-sm);
144
+ padding-inline: var(--xh-popconfirm-cancel-trigger-px, var(--xh-control-px-sm));
145
145
  border: var(--xh-stroke-thin) solid transparent;
146
- border-radius: var(--xh-shape-control);
146
+ border-radius: var(--xh-popconfirm-action-radius, var(--xh-shape-control));
147
147
  font-size: var(--xh-text-secondary-size);
148
148
  font-weight: var(--xh-text-label-weight);
149
149
  line-height: var(--xh-leading-none);
@@ -227,4 +227,11 @@
227
227
  border-color: currentColor;
228
228
  animation: none;
229
229
  }
230
+
231
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
232
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
233
+ [data-scope='popconfirm'][data-part='root'][hidden],
234
+ [data-scope='popconfirm'][data-part='cancel-trigger'][hidden] {
235
+ display: none;
236
+ }
230
237
  }
package/css/popover.css CHANGED
@@ -38,6 +38,9 @@
38
38
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
39
39
  --xh-_popover-available-h: 100vh;
40
40
 
41
+ /* 面板内容的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊一条竖灰带 */
42
+ --xh-scrollbar-track-bg: transparent;
43
+
41
44
  position: fixed;
42
45
  z-index: var(--xh-popover-layer, var(--xh-layer-popover));
43
46
  /* 空壳不吃指针,交互只发生在 content 上 */