@xihan-ui/styles 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CHANGELOG.md +5146 -6
  2. package/README.md +22 -2
  3. package/component-tokens.d.ts +4212 -0
  4. package/component-tokens.js +2 -0
  5. package/components.tokens.json +80116 -0
  6. package/css/accordion.css +131 -75
  7. package/css/affix.css +16 -1
  8. package/css/alert.css +114 -67
  9. package/css/anchor.css +99 -27
  10. package/css/approval.css +461 -0
  11. package/css/avatar-group.css +14 -6
  12. package/css/avatar.css +33 -9
  13. package/css/back-top.css +103 -48
  14. package/css/badge.css +42 -14
  15. package/css/bar-code.css +62 -0
  16. package/css/breadcrumb.css +40 -21
  17. package/css/button-group.css +146 -24
  18. package/css/button.css +116 -99
  19. package/css/calendar-picker.css +448 -0
  20. package/css/calendar-range-picker.css +517 -0
  21. package/css/card.css +54 -77
  22. package/css/carousel.css +412 -68
  23. package/css/cascader.css +429 -246
  24. package/css/checkbox-group.css +225 -77
  25. package/css/checkbox.css +174 -37
  26. package/css/clipboard.css +266 -47
  27. package/css/code-view.css +279 -0
  28. package/css/collapsible.css +108 -63
  29. package/css/color-field.css +158 -0
  30. package/css/color-picker.css +172 -184
  31. package/css/color-slider.css +274 -0
  32. package/css/color-swatch-picker.css +243 -0
  33. package/css/color-swatch.css +35 -0
  34. package/css/combobox.css +267 -273
  35. package/css/command.css +399 -0
  36. package/css/context-menu.css +183 -108
  37. package/css/date-field.css +94 -121
  38. package/css/date-picker.css +486 -249
  39. package/css/date-range-picker.css +559 -0
  40. package/css/description.css +51 -0
  41. package/css/descriptions.css +133 -87
  42. package/css/dialog.css +247 -68
  43. package/css/diff-view.css +428 -0
  44. package/css/download-trigger.css +155 -46
  45. package/css/drawer.css +194 -111
  46. package/css/editable.css +172 -152
  47. package/css/empty-state.css +80 -11
  48. package/css/field-array.css +190 -0
  49. package/css/field.css +84 -31
  50. package/css/fieldset.css +51 -18
  51. package/css/file-upload.css +134 -36
  52. package/css/flex.css +20 -1
  53. package/css/float-button.css +238 -57
  54. package/css/floating-panel.css +173 -92
  55. package/css/focus.css +46 -0
  56. package/css/forced-colors.css +93 -0
  57. package/css/form.css +254 -77
  58. package/css/gradient-text.css +34 -10
  59. package/css/grid.css +516 -5
  60. package/css/heatmap.css +87 -29
  61. package/css/highlight.css +20 -5
  62. package/css/hover-card.css +97 -47
  63. package/css/icon-wrapper.css +15 -3
  64. package/css/icon.css +74 -8
  65. package/css/image-cropper.css +143 -29
  66. package/css/image-viewer.css +150 -89
  67. package/css/image.css +30 -1
  68. package/css/infinite-scroll.css +51 -1
  69. package/css/input-group.css +277 -0
  70. package/css/json-viewer.css +102 -45
  71. package/css/kbd.css +72 -0
  72. package/css/label.css +78 -0
  73. package/css/layers.css +5 -0
  74. package/css/layout.css +175 -31
  75. package/css/list.css +24 -3
  76. package/css/listbox.css +208 -67
  77. package/css/loading-bar.css +52 -3
  78. package/css/log.css +144 -9
  79. package/css/markdown-stream.css +149 -0
  80. package/css/marquee.css +27 -1
  81. package/css/masonry.css +7 -0
  82. package/css/matrix-code.css +67 -0
  83. package/css/mention.css +234 -152
  84. package/css/menu.css +180 -83
  85. package/css/menubar.css +204 -136
  86. package/css/message-feed.css +197 -0
  87. package/css/navigation-menu.css +144 -90
  88. package/css/notification.css +178 -100
  89. package/css/number-animation.css +7 -0
  90. package/css/number-field.css +120 -277
  91. package/css/overlay-arrow.css +12 -7
  92. package/css/page-header.css +99 -14
  93. package/css/pagination.css +175 -135
  94. package/css/password-input.css +222 -219
  95. package/css/pin-input.css +101 -67
  96. package/css/pointer.css +36 -0
  97. package/css/popconfirm.css +185 -94
  98. package/css/popover.css +121 -77
  99. package/css/progress.css +60 -12
  100. package/css/prompt-input.css +224 -0
  101. package/css/question-flow.css +513 -0
  102. package/css/radio-group.css +147 -30
  103. package/css/rating.css +193 -43
  104. package/css/reasoning.css +336 -0
  105. package/css/reset.css +84 -6
  106. package/css/resizable.css +237 -0
  107. package/css/scroll-area.css +68 -7
  108. package/css/scrollbar.css +47 -13
  109. package/css/segmented.css +94 -29
  110. package/css/select.css +288 -274
  111. package/css/separator.css +101 -1
  112. package/css/side-nav.css +133 -75
  113. package/css/signature-pad.css +74 -54
  114. package/css/skeleton.css +84 -11
  115. package/css/slider.css +132 -39
  116. package/css/sortable.css +198 -0
  117. package/css/spinner.css +126 -12
  118. package/css/splitter.css +29 -8
  119. package/css/statistic.css +55 -0
  120. package/css/steps.css +206 -72
  121. package/css/switch.css +268 -36
  122. package/css/table.css +695 -118
  123. package/css/tabs.css +604 -42
  124. package/css/tag-group.css +219 -0
  125. package/css/tag.css +118 -28
  126. package/css/tags-input.css +156 -274
  127. package/css/text-field.css +101 -249
  128. package/css/time-field.css +100 -128
  129. package/css/time-picker.css +323 -252
  130. package/css/time-range-picker.css +719 -0
  131. package/css/timeline.css +202 -68
  132. package/css/timer.css +56 -52
  133. package/css/timestamp.css +34 -0
  134. package/css/toast.css +373 -144
  135. package/css/toggle-group.css +309 -76
  136. package/css/toggle.css +116 -85
  137. package/css/tone.css +47 -0
  138. package/css/tool-call.css +421 -0
  139. package/css/toolbar.css +181 -33
  140. package/css/tooltip.css +107 -36
  141. package/css/tour.css +183 -152
  142. package/css/transfer.css +351 -138
  143. package/css/tree-select.css +323 -216
  144. package/css/tree.css +294 -62
  145. package/css/truncate.css +65 -0
  146. package/css/typography.css +228 -5
  147. package/css/undefined.css +10 -1
  148. package/css/virtualizer.css +9 -10
  149. package/css/visually-hidden.css +7 -0
  150. package/css/watermark.css +7 -0
  151. package/family/action-control.css +487 -0
  152. package/family/collection-item.css +721 -0
  153. package/family/field-chrome.css +298 -0
  154. package/family/motion.css +166 -0
  155. package/family/swatch.css +59 -0
  156. package/index.css +41705 -126
  157. package/index.unlayered.css +33692 -17339
  158. package/package.json +51 -17
  159. package/css/calendar.css +0 -367
  160. package/css/code-block.css +0 -91
  161. package/css/composer.css +0 -134
  162. package/css/countdown.css +0 -26
  163. package/css/dynamic-input.css +0 -220
  164. package/css/ellipsis.css +0 -52
  165. package/css/hotkeys.css +0 -90
  166. package/css/popselect.css +0 -391
  167. package/css/qr-code.css +0 -55
  168. package/css/result.css +0 -119
  169. package/css/space.css +0 -117
  170. package/css/thread.css +0 -120
  171. package/css/time.css +0 -25
@@ -1,3 +1,10 @@
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
5
+
6
+ /* 定义 page header 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='page-header'] {
@@ -9,14 +16,19 @@
9
16
  --xh-_page-header-py: var(--xh-space-4);
10
17
  --xh-_page-header-row-gap: var(--xh-space-2);
11
18
  --xh-_page-header-title-size: var(--xh-text-heading-3-size);
19
+ /* 形态档只换这两个:不画面的那一档左右不留内衬、也不切圆角 */
20
+ --xh-_page-header-px: 0;
21
+ --xh-_page-header-radius: 0;
12
22
 
13
- /* 一行排不下就折行;返回位、标题、副标题排在同一行,操作贴到行尾,页脚整行另起 */
14
- display: flex;
15
- flex-wrap: wrap;
23
+ /* 返回、媒体、标题区与操作区分列;标题与说明上下排列。 */
24
+ display: grid;
25
+ grid-auto-flow: dense;
26
+ grid-template-columns: auto auto minmax(0, 1fr) auto;
16
27
  align-items: center;
17
- column-gap: var(--xh-page-header-column-gap, var(--xh-space-3));
18
28
  row-gap: var(--xh-page-header-row-gap, var(--xh-_page-header-row-gap));
19
29
  padding-block: var(--xh-page-header-py, var(--xh-_page-header-py));
30
+ padding-inline: var(--xh-page-header-px, var(--xh-_page-header-px));
31
+ border-radius: var(--xh-page-header-radius, var(--xh-_page-header-radius));
20
32
  color: var(--xh-page-header-fg, var(--xh-fg-default));
21
33
  }
22
34
 
@@ -39,58 +51,131 @@
39
51
  }
40
52
 
41
53
  /* —— 分隔线 —— */
42
- [data-scope='page-header'][data-part='root'][data-bordered] {
54
+ /* 只有贴底的 ghost 画这条下边线:一块切了圆角的面底下横一条直线,两头会露在圆角外面,
55
+ 有面的两档由自己的边界接手同一件事——把页头与下面的内容分开 */
56
+ [data-scope='page-header'][data-part='root'][data-variant='ghost'][data-split] {
43
57
  border-block-end: var(--xh-stroke-thin) solid var(--xh-page-header-border, var(--xh-border-subtle));
44
58
  }
45
59
 
60
+ /* —— 形态 —— */
61
+ /* ghost 不在这儿:它就是上面那套基础取值,贴在页面底色上不画面。
62
+ 画了面的两档左右补上与上下同档的内衬,否则内容会贴着那块面的边 */
63
+ [data-scope='page-header'][data-part='root']:is([data-variant='outline'], [data-variant='subtle']) {
64
+ --xh-_page-header-px: var(--xh-_page-header-py);
65
+ --xh-_page-header-radius: var(--xh-shape-surface);
66
+ }
67
+
68
+ /* outline 是一张静态内容面:--xh-border-default 描边撑住这块面的边界 + surface 底,不叠投影(§5.3);
69
+ --xh-border-subtle 只作 ghost 贴底那条分隔线用,不当根面外边 */
70
+ [data-scope='page-header'][data-part='root'][data-variant='outline'] {
71
+ border: var(--xh-stroke-thin) solid var(--xh-page-header-border, var(--xh-border-default));
72
+ background: var(--xh-page-header-bg, var(--xh-bg-surface));
73
+ }
74
+
75
+ /* subtle 用淡底当边界:描边让位给底色但留住 1px 边位(与 outline 同一几何)、无影 */
76
+ [data-scope='page-header'][data-part='root'][data-variant='subtle'] {
77
+ border: var(--xh-stroke-thin) solid transparent;
78
+ background: var(--xh-page-header-bg, var(--xh-bg-subtle));
79
+ }
80
+
46
81
  /* —— 各段 —— */
82
+ /* 面包屑占满一整行排在标题之上:它写在标记的最前面,整行铺开就把标题挤到了下一行 */
83
+ [data-scope='page-header'][data-part='breadcrumb'] {
84
+ grid-column: 1 / -1;
85
+ color: var(--xh-page-header-breadcrumb-fg, var(--xh-fg-muted));
86
+ font-size: var(--xh-page-header-breadcrumb-font-size, var(--xh-text-secondary-size));
87
+ line-height: var(--xh-leading-normal);
88
+ }
89
+
90
+ /* 头像 / 图标位:不参与伸缩,图形本身多大由作者定 */
91
+ [data-scope='page-header'][data-part='media'] {
92
+ grid-column: 2;
93
+ margin-inline-end: var(--xh-page-header-column-gap, var(--xh-space-3));
94
+ display: inline-flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ }
98
+
47
99
  /* 返回位只摆位置与对齐,外观归作者自己的按钮 */
48
100
  [data-scope='page-header'][data-part='back-trigger'] {
101
+ grid-column: 1;
102
+ margin-inline-end: var(--xh-page-header-column-gap, var(--xh-space-3));
49
103
  display: inline-flex;
50
- flex: none;
51
104
  align-items: center;
52
105
  justify-content: center;
53
106
  }
54
107
 
55
108
  [data-scope='page-header'][data-part='title'] {
109
+ grid-column: 3;
56
110
  margin: 0;
57
- flex: none;
111
+ /* 标题不参与伸缩,长过整行时收到行宽为止,中间没有断点的长串在行尾断开,
112
+ 不把整条页头撑出容器 */
113
+ max-inline-size: 100%;
114
+ overflow-wrap: anywhere;
58
115
  color: var(--xh-page-header-title-fg, var(--xh-fg-default));
59
116
  font-size: var(--xh-page-header-title-font-size, var(--xh-_page-header-title-size));
60
- font-weight: var(--xh-page-header-title-font-weight, var(--xh-font-weight-semibold));
117
+ /* 页面级标题:字重走标题档令牌,不直接下探字重原语 */
118
+ font-weight: var(--xh-page-header-title-font-weight, var(--xh-text-heading-3-weight));
61
119
  line-height: var(--xh-leading-tight);
62
120
  }
63
121
 
64
122
  /* 副标题吃掉标题与操作之间的剩余宽度,长文本在这里收窄换行 */
65
- [data-scope='page-header'][data-part='subtitle'] {
123
+ [data-scope='page-header'][data-part='description'] {
124
+ grid-column: 3;
66
125
  margin: 0;
67
- flex: 1 1 auto;
68
126
  min-inline-size: 0;
69
- color: var(--xh-page-header-subtitle-fg, var(--xh-fg-muted));
70
- font-size: var(--xh-page-header-subtitle-font-size, var(--xh-text-secondary-size));
127
+ color: var(--xh-page-header-description-fg, var(--xh-fg-muted));
128
+ font-size: var(--xh-page-header-description-font-size, var(--xh-text-secondary-size));
71
129
  line-height: var(--xh-leading-normal);
72
130
  }
73
131
 
74
132
  /* 操作区贴到行尾,没有副标题占位时也一样靠边 */
75
133
  [data-scope='page-header'][data-part='extra'] {
134
+ grid-column: 4;
76
135
  display: flex;
77
136
  flex-wrap: wrap;
78
137
  align-items: center;
79
138
  gap: var(--xh-page-header-extra-gap, var(--xh-space-2));
80
- margin-inline-start: auto;
139
+ margin-inline-start: var(--xh-page-header-column-gap, var(--xh-space-3));
140
+ justify-self: end;
81
141
  }
82
142
 
83
143
  /* 页脚占满一整行,前面有内容时自然被挤到下一行 */
84
144
  [data-scope='page-header'][data-part='footer'] {
85
- flex: 1 0 100%;
145
+ grid-column: 1 / -1;
86
146
  color: var(--xh-page-header-footer-fg, var(--xh-fg-muted));
87
147
  font-size: var(--xh-page-header-footer-font-size, var(--xh-text-secondary-size));
88
148
  line-height: var(--xh-leading-normal);
89
149
  }
90
150
 
151
+ [data-scope='page-header'][data-part='root']:has(> [data-part='description'])
152
+ > :is([data-part='back-trigger'], [data-part='media'], [data-part='extra']) {
153
+ grid-row: span 2;
154
+ }
155
+
156
+ @media (max-width: 640px) {
157
+ [data-scope='page-header'][data-part='root'] {
158
+ grid-template-columns: auto minmax(0, 1fr);
159
+ }
160
+
161
+ [data-scope='page-header'][data-part='media'],
162
+ [data-scope='page-header'][data-part='title'],
163
+ [data-scope='page-header'][data-part='description'] {
164
+ grid-column: 2;
165
+ }
166
+
167
+ [data-scope='page-header'][data-part='root'] > [data-part='extra'] {
168
+ grid-column: 1 / -1;
169
+ grid-row: auto;
170
+ margin-inline-start: 0;
171
+ justify-self: start;
172
+ }
173
+ }
174
+
91
175
  /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
92
176
  写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
93
177
  [data-scope='page-header'][data-part='back-trigger'][hidden],
178
+ [data-scope='page-header'][data-part='media'][hidden],
94
179
  [data-scope='page-header'][data-part='extra'][hidden] {
95
180
  display: none;
96
181
  }
@@ -1,29 +1,13 @@
1
- @layer xihan.motion {
2
- /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
- 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
- @keyframes xh-pop-in {
5
- from {
6
- opacity: 0;
7
- scale: var(--xh-motion-scale-enter);
8
- }
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
9
5
 
10
- to {
11
- opacity: 1;
12
- scale: 1;
13
- }
14
- }
15
- @keyframes xh-pop-out {
16
- from {
17
- opacity: 1;
18
- scale: 1;
19
- }
6
+ /* 定义 pagination 样式。 */
20
7
 
21
- to {
22
- opacity: 0;
23
- scale: var(--xh-motion-scale-enter);
24
- }
25
- }
26
- }
8
+ /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立;四类格子接 Action Control 配方,同理 */
9
+ @import '../family/motion.css';
10
+ @import '../family/action-control.css';
27
11
 
28
12
  @layer xihan.components {
29
13
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
@@ -31,14 +15,13 @@
31
15
  --xh-pagination-skin: 1;
32
16
  }
33
17
 
34
- /* 根节点是 nav 地标,只负责把上一页 / 页码 / 下一页排成一行。
35
- 页数为 0 时连接层会打 data-empty,这里不拿它做隐藏:作者常把「第 x-y 条」这类
36
- 区间回显也写在 nav 里,整块藏掉会连那行字一起吞了,是否隐藏交给作者决定 */
37
- [data-scope='pagination'][data-part='root'] {
38
- /* 作者塞进上一页/下一页的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
39
- --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-text));
18
+ /* 私有槽同时声明在根与 positioner 上:摊开的页码面板被搬到 portal 落点,
19
+ 不是根的后代,继承不过去。面板里的页码格子与主区那排消费的是同一批槽 */
20
+ [data-scope='pagination']:is([data-part='root'], [data-part='positioner']) {
21
+ /* 作者塞进面板或分页行里的图标按档取字形尺(§6.5);四类格子上另按家族档位取同一把尺 */
22
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-md));
40
23
 
41
- /* 尺寸档只换这三个私有槽,上一页/下一页、页码与省略号都从 root 继承它们,
24
+ /* 尺寸档只换这三个私有槽,上一页/下一页、页码与省略号都从这两处继承它们,
42
25
  换档不必给每个部件各写一条选择器 */
43
26
  --xh-_pagination-item-size: var(--xh-control-h-md);
44
27
  --xh-_pagination-item-px: var(--xh-control-px-md);
@@ -50,7 +33,14 @@
50
33
  --xh-_pagination-selected-bg-hover: var(--xh-_tone-hover, var(--xh-bg-brand-hover));
51
34
  --xh-_pagination-selected-bg-active: var(--xh-_tone-active, var(--xh-bg-brand-active));
52
35
  --xh-_pagination-selected-fg: var(--xh-_tone-on, var(--xh-fg-on-brand));
36
+ /* 当前页那一格是实心底,顶边画一条极浅的内高光把它衬出厚度(solid 面允许顶高光,经家族的 highlight 槽画) */
37
+ --xh-_pagination-highlight: var(--xh-_highlight-tone);
38
+ }
53
39
 
40
+ /* 根节点是 nav 地标,只负责把上一页 / 页码 / 下一页排成一行。
41
+ 页数为 0 时连接层会打 data-empty,这里不拿它做隐藏:作者常把「第 x-y 条」这类
42
+ 区间回显也写在 nav 里,整块藏掉会连那行字一起吞了,是否隐藏交给作者决定 */
43
+ [data-scope='pagination'][data-part='root'] {
54
44
  display: flex;
55
45
  align-items: center;
56
46
  /* 页码多到一行放不下就换行,宁可折行也不要把按钮压扁或撑出横向滚动 */
@@ -61,13 +51,15 @@
61
51
  /* —— 尺寸 —— */
62
52
  /* 缺省档写在上面的基础规则里。格子高度、内边距、字号三者各走控件尺的同一档;
63
53
  页码格子靠最小宽度撑等宽,内边距只在页码超出最小宽度时才起作用 */
64
- [data-scope='pagination'][data-part='root'][data-size='sm'] {
54
+ [data-scope='pagination']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
55
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-sm));
65
56
  --xh-_pagination-item-size: var(--xh-control-h-sm);
66
57
  --xh-_pagination-item-px: var(--xh-control-px-sm);
67
58
  --xh-_pagination-font-size: var(--xh-control-font-sm);
68
59
  }
69
60
 
70
- [data-scope='pagination'][data-part='root'][data-size='lg'] {
61
+ [data-scope='pagination']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
62
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-lg));
71
63
  --xh-_pagination-item-size: var(--xh-control-h-lg);
72
64
  --xh-_pagination-item-px: var(--xh-control-px-lg);
73
65
  --xh-_pagination-font-size: var(--xh-control-font-lg);
@@ -77,142 +69,137 @@
77
69
  display: none;
78
70
  }
79
71
 
80
- /* 三类格子共用同一副骨架,行高与间距一致,切页时基线不会跳 */
72
+ /* 四类格子接 Action Control 的 text 档,缺省中性的 ghost 形态(§7.2 只有 Button 品牌实心):盒型、三档几何、
73
+ 透明描边(省略号也占一条,两者内容盒等高,一行里对得齐)、悬停 100 → 按下 200(画布承载)、禁用面、按压缩放与
74
+ 过渡都由家族给;这里只把使用者槽映射到桥接槽并保留分页自己的排版。
75
+ 等宽的关键:1 与 10 的内容宽度不同,靠最小宽度把它们撑到同一格,行宽才不会随当前页左右抖动 */
81
76
  [data-scope='pagination'][data-part='prev-trigger'],
82
77
  [data-scope='pagination'][data-part='next-trigger'],
83
78
  [data-scope='pagination'][data-part='item'],
84
- [data-scope='pagination'][data-part='ellipsis'] {
85
- display: inline-flex;
79
+ [data-scope='pagination'][data-part='ellipsis-trigger'] {
80
+ --xh-action-min-inline-size: var(--xh-pagination-item-min-size, var(--xh-_pagination-item-size));
81
+ --xh-action-visual-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
82
+ --xh-action-padding-inline: var(--xh-pagination-item-px, var(--xh-_pagination-item-px));
83
+ --xh-action-radius: var(--xh-pagination-item-radius, var(--xh-shape-control));
84
+ --xh-action-font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
85
+ --xh-action-bg-rest: var(--xh-pagination-item-bg, var(--xh-_action-variant-bg-rest));
86
+ --xh-action-bg-hover: var(--xh-pagination-item-bg-hover, var(--xh-_action-variant-bg-hover));
87
+ --xh-action-bg-pressed: var(--xh-pagination-item-bg-active, var(--xh-_action-variant-bg-pressed));
88
+ --xh-action-fg-rest: var(--xh-pagination-item-fg, var(--xh-_action-variant-fg-rest));
89
+ --xh-action-fg-hover: var(--xh-pagination-item-fg, var(--xh-_action-variant-fg-hover));
90
+ --xh-action-fg-pressed: var(--xh-pagination-item-fg, var(--xh-_action-variant-fg-pressed));
91
+ /* 作者塞进上一页/下一页的图标按档取字形尺(§6.5),与皮肤画的兜底字形同一把尺 */
92
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-_action-profile-glyph-size));
93
+
86
94
  flex: none;
87
- align-items: center;
88
- justify-content: center;
89
- /* 等宽的关键:1 与 10 的内容宽度不同,靠最小宽度把它们撑到同一格,
90
- 行宽才不会随当前页左右抖动。三位数超过最小宽度时才自然变宽 */
91
- min-inline-size: var(--xh-pagination-item-min-size, var(--xh-_pagination-item-size));
92
- block-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
93
- padding-inline: var(--xh-pagination-item-px, var(--xh-_pagination-item-px));
94
- /* 省略号也占一条透明描边:只给按钮描边的话两者内容盒不等高,一行里就对不齐 */
95
- border: var(--xh-stroke-thin) solid transparent;
96
- border-radius: var(--xh-pagination-item-radius, var(--xh-shape-control));
97
- font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
98
- line-height: var(--xh-leading-none);
95
+ font-weight: var(--xh-pagination-item-font-weight, var(--xh-text-label-weight));
99
96
  /* 等宽数字:1 与 7 的字形宽度在比例字体里并不相同,不定住会让同位数页码抖一格 */
100
97
  font-variant-numeric: tabular-nums;
101
- white-space: nowrap;
102
- user-select: none;
103
98
  }
104
99
 
105
100
  [data-scope='pagination'][data-part='prev-trigger'][hidden],
106
101
  [data-scope='pagination'][data-part='next-trigger'][hidden],
107
102
  [data-scope='pagination'][data-part='item'][hidden],
108
- [data-scope='pagination'][data-part='ellipsis'][hidden] {
103
+ [data-scope='pagination'][data-part='ellipsis-trigger'][hidden] {
109
104
  display: none;
110
105
  }
111
106
 
112
- /* 三个按钮共用的可点观感:默认透明底,只有交互与当前页才上色 */
113
- [data-scope='pagination'][data-part='prev-trigger'],
114
- [data-scope='pagination'][data-part='next-trigger'],
115
- [data-scope='pagination'][data-part='item'] {
116
- background: var(--xh-pagination-item-bg, transparent);
117
- color: var(--xh-pagination-item-fg, var(--xh-fg-default));
118
- font-weight: var(--xh-pagination-item-font-weight, var(--xh-text-label-weight));
119
- cursor: pointer;
120
- transition:
121
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
122
- color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
123
- border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
124
- }
125
-
126
- /* 悬停这条选择器比当前页那条多一节(:hover),同层里权重更高、会反过来压住它,
127
- 所以悬停一路显式把当前页排除:指针停在当前页上不该把品牌底色洗成灰底。
128
- 页码条目从不禁用(连接层只给上一页/下一页发原生 disabled),故这边不必再排除 :disabled */
129
- [data-scope='pagination'][data-part='prev-trigger']:hover:not(:disabled),
130
- [data-scope='pagination'][data-part='next-trigger']:hover:not(:disabled),
131
- [data-scope='pagination'][data-part='item']:not([data-current]):hover {
132
- background: var(--xh-pagination-item-bg-hover, var(--xh-bg-subtle-hover));
133
- }
107
+ /* 首末页的上一页 / 下一页是原生 disabled(不可聚焦、进不了 Tab 序列),连接层同时给 data-disabled,
108
+ 家族按 data-disabled 画禁用面(透明底 + --xh-fg-disabled);分页条目从不禁用 */
134
109
 
135
- [data-scope='pagination'][data-part='prev-trigger']:active:not(:disabled),
136
- [data-scope='pagination'][data-part='next-trigger']:active:not(:disabled),
137
- [data-scope='pagination'][data-part='item']:not([data-current]):active {
138
- background: var(--xh-pagination-item-bg-active, var(--xh-bg-subtle-active));
110
+ /* 当前页(§7.3 格状当前):data-current 与 aria-current='page' 由连接层成对给出,样式挂在 data 钩子上,
111
+ 无障碍语义留给 aria。实心品牌面 + 配对前景、不加粗——字重一变字形就变宽,页码格子会跟着长一点,
112
+ 正是这里要避免的抖动;悬停 / 按下沿 brand → brand-hover → brand-active 走,三态都经桥接槽交给家族画,
113
+ solid 面允许一条顶高光,环色改取面自己的前景 */
114
+ [data-scope='pagination'][data-part='item'][data-current] {
115
+ --xh-action-bg-rest: var(--xh-pagination-item-bg-selected, var(--xh-_pagination-selected-bg));
116
+ --xh-action-bg-hover: var(--xh-pagination-item-bg-selected-hover, var(--xh-_pagination-selected-bg-hover));
117
+ --xh-action-bg-pressed: var(--xh-pagination-item-bg-selected-active, var(--xh-_pagination-selected-bg-active));
118
+ --xh-action-bg-focus-visible: var(--xh-pagination-item-bg-selected, var(--xh-_pagination-selected-bg));
119
+ --xh-action-fg-rest: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
120
+ --xh-action-fg-hover: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
121
+ --xh-action-fg-pressed: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
122
+ --xh-action-fg-focus-visible: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
123
+ --xh-action-border-rest: var(--xh-pagination-item-border-selected, var(--xh-_pagination-selected-bg));
124
+ --xh-action-border-hover: var(--xh-pagination-item-border-selected-hover, var(--xh-_pagination-selected-bg-hover));
125
+ --xh-action-border-pressed: var(--xh-pagination-item-border-selected-active, var(--xh-_pagination-selected-bg-active));
126
+ --xh-action-border-focus-visible: var(--xh-pagination-item-border-selected, var(--xh-_pagination-selected-bg));
127
+ --xh-action-highlight-rest: var(--xh-_pagination-highlight);
128
+ --xh-action-highlight-hover: var(--xh-_pagination-highlight);
129
+ --xh-action-highlight-pressed: var(--xh-_pagination-highlight);
130
+ --xh-action-highlight-focus-visible: var(--xh-_pagination-highlight);
131
+ --xh-action-shadow-rest: var(--xh-pagination-item-shadow, none);
132
+ --xh-action-shadow-hover: var(--xh-pagination-item-shadow, none);
133
+ --xh-action-shadow-pressed: var(--xh-pagination-item-shadow, none);
134
+ --xh-action-shadow-focus-visible: var(--xh-pagination-item-shadow, none);
135
+ --xh-action-ring-color-focus-visible: currentColor;
139
136
  }
140
137
 
141
- [data-scope='pagination'][data-part='prev-trigger']:focus-visible,
142
- [data-scope='pagination'][data-part='next-trigger']:focus-visible,
143
- [data-scope='pagination'][data-part='item']:focus-visible {
144
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
145
- outline-offset: var(--xh-ring-offset);
138
+ /* 省略位是可展开的按钮:折进去的那几页只有它一个入口,指针与键盘都得点得到,
139
+ 所以它与页码同一副骨架、同一条阶梯。这里只把字色压淡一档与页码区分开,三态都压——
140
+ 家族的悬停 / 按下规则比基础块特定,只映射静息那一支会在悬停时被换回缺省字色 */
141
+ [data-scope='pagination'][data-part='ellipsis-trigger'] {
142
+ --xh-action-fg-rest: var(--xh-pagination-ellipsis-trigger-fg, var(--xh-fg-subtle));
143
+ --xh-action-fg-hover: var(--xh-pagination-ellipsis-trigger-fg, var(--xh-fg-subtle));
144
+ --xh-action-fg-pressed: var(--xh-pagination-ellipsis-trigger-fg, var(--xh-fg-subtle));
146
145
  }
147
-
148
- /* 首末页的上一页 / 下一页是原生 disabled(不可聚焦、进不了 Tab 序列),
149
- 所以这里必须用 :disabled;连接层同时给的 data-disabled 只是留给作者的钩子。
150
- 分页条目从不禁用,那边也就没有对应规则 */
151
- [data-scope='pagination'][data-part='prev-trigger']:disabled,
152
- [data-scope='pagination'][data-part='next-trigger']:disabled {
153
- color: var(--xh-fg-disabled);
154
- cursor: not-allowed;
146
+ /* 每页条数控制器的挂载点:里头装的是库里的 select,控件本身的描边、底色、聚焦环与
147
+ 浮层都归 select 那份皮肤,这一格只把它摆进分页行 */
148
+ [data-scope='pagination'][data-part='page-size-select'] {
149
+ display: inline-flex;
150
+ flex: none;
151
+ align-items: center;
155
152
  }
156
153
 
157
- /* 当前页:data-current 与 aria-current='page' 由连接层成对给出,
158
- 样式挂在 data 钩子上,无障碍语义留给 aria,两边各司其职。
159
- 只换底色不加粗——字重一变字形就变宽,页码格子会跟着长一点,正是这里要避免的抖动 */
160
- [data-scope='pagination'][data-part='item'][data-current] {
161
- border-color: var(--xh-pagination-item-border-selected, var(--xh-_pagination-selected-bg));
162
- background: var(--xh-pagination-item-bg-selected, var(--xh-_pagination-selected-bg));
163
- color: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
154
+ [data-scope='pagination'][data-part='page-size-select'][hidden] {
155
+ display: none;
164
156
  }
165
157
 
166
- [data-scope='pagination'][data-part='item'][data-current]:hover {
167
- border-color: var(--xh-pagination-item-border-selected-hover, var(--xh-_pagination-selected-bg-hover));
168
- background: var(--xh-pagination-item-bg-selected-hover, var(--xh-_pagination-selected-bg-hover));
158
+ /* 信息区:一段次要文字,与页码格子同一条基线 */
159
+ [data-scope='pagination'][data-part='summary'] {
160
+ display: inline-flex;
161
+ flex: none;
162
+ align-items: center;
163
+ block-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
164
+ color: var(--xh-pagination-summary-fg, var(--xh-fg-muted));
165
+ font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
166
+ line-height: var(--xh-leading-none);
167
+ white-space: nowrap;
169
168
  }
170
169
 
171
- [data-scope='pagination'][data-part='item'][data-current]:active {
172
- border-color: var(--xh-pagination-item-border-selected-active, var(--xh-_pagination-selected-bg-active));
173
- background: var(--xh-pagination-item-bg-selected-active, var(--xh-_pagination-selected-bg-active));
170
+ [data-scope='pagination'][data-part='summary'][hidden] {
171
+ display: none;
174
172
  }
175
173
 
176
- /* 省略号是纯视觉占位,读屏那边已被 aria-hidden 摘掉:
177
- 吞掉指针事件,免得它出现悬停反馈、看起来像一颗点得动的按钮 */
178
- [data-scope='pagination'][data-part='ellipsis'] {
179
- color: var(--xh-pagination-ellipsis-fg, var(--xh-fg-subtle));
180
- cursor: default;
181
- pointer-events: none;
182
- }
183
- /* 每页条数控制器:原生 select,抹掉系统外观后与页码格子共用同一副骨架。
184
- 箭头用背景图而非伪元素——原生 select 不生成 ::before */
185
- [data-scope='pagination'][data-part='page-size-select'] {
174
+ /* 跳页输入框:与每页条数控制器同一副外观,宽度按页码位数留够 */
175
+ [data-scope='pagination'][data-part='jumper'] {
186
176
  flex: none;
177
+ inline-size: var(--xh-pagination-jumper-w, calc(var(--xh-space-8) * 2));
187
178
  block-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
188
179
  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));
180
+ border: var(--xh-stroke-thin) solid var(--xh-pagination-jumper-border, var(--xh-border-default));
195
181
  border-radius: var(--xh-pagination-item-radius, var(--xh-shape-control));
196
- background: var(--xh-pagination-page-size-bg, var(--xh-bg-surface));
182
+ background: var(--xh-pagination-jumper-bg, var(--xh-bg-surface));
197
183
  color: var(--xh-pagination-item-fg, var(--xh-fg-default));
198
184
  font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
199
185
  line-height: var(--xh-leading-none);
200
186
  appearance: none;
201
- cursor: pointer;
187
+ transition:
188
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
189
+ border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
202
190
  }
203
191
 
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));
192
+ [data-scope='pagination'][data-part='jumper'][hidden] {
193
+ display: none;
206
194
  }
207
195
 
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);
196
+ [data-scope='pagination'][data-part='jumper']:hover:not(:disabled) {
197
+ border-color: var(--xh-pagination-jumper-border-hover, var(--xh-border-strong));
198
+ background: var(--xh-pagination-jumper-bg-hover, var(--xh-bg-subtle-hover));
211
199
  }
212
200
 
213
- [data-scope='pagination'][data-part='page-size-select']:disabled {
201
+ [data-scope='pagination'][data-part='jumper']:disabled {
214
202
  color: var(--xh-fg-disabled);
215
- cursor: not-allowed;
216
203
  }
217
204
 
218
205
  /* 摊开省略位的定位层。三处坐标系必须同为 fixed:机器交给引擎的 strategy、
@@ -221,12 +208,15 @@
221
208
  /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,面板继承它限高;
222
209
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
223
210
  --xh-_pagination-available-h: 100vh;
211
+ /* 落定那一侧的可用宽度,同样由定位引擎经内联自定义属性写进来,行内轴据此夹取;
212
+ 引擎没算(尚未落位 / 无引擎 / 贴边归零)时退到视口宽 */
213
+ --xh-_pagination-available-w: 100vw;
224
214
 
225
215
  /* 页码面板的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊一条竖灰带 */
226
216
  --xh-scrollbar-track-bg: transparent;
227
217
 
228
218
  position: fixed;
229
- z-index: var(--xh-pagination-layer, var(--xh-layer-popover));
219
+ z-index: var(--xh-pagination-layer, var(--xh-_layer, var(--xh-layer-popover)));
230
220
  /* 空壳不吃指针:省略位与面板之间那段间隙要能点得穿 */
231
221
  pointer-events: none;
232
222
  }
@@ -238,30 +228,32 @@
238
228
 
239
229
  /* 摊开的页码面板:一串页码格子,横着排、必要时折行 */
240
230
  [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
231
  display: flex;
245
232
  flex-flow: row wrap;
246
233
  gap: var(--xh-pagination-gap, var(--xh-space-1));
247
234
  /* 页码不可预知有多少:不限高就整块伸出视口且滚不到 */
248
- max-inline-size: var(--xh-pagination-content-max-w, var(--xh-overlay-max-w));
235
+ /* 静态档与落位后的可用宽度取小:窄视口下面板伸出去,最右侧的内容就点不到了 */
236
+ max-inline-size: min(var(--xh-pagination-content-max-w, var(--xh-overlay-max-w)), var(--xh-_pagination-available-w));
249
237
  max-block-size: min(
250
238
  var(--xh-pagination-content-max-h, var(--xh-overlay-max-h)),
251
239
  var(--xh-_pagination-available-h)
252
240
  );
253
241
  overflow-y: auto;
242
+ /* 浮层滚动面:滚到底不把滚动量交给页面(§6.6 只给 Overlay 家族滚动面) */
243
+ overscroll-behavior: contain;
254
244
  padding: var(--xh-pagination-content-p, var(--xh-space-1));
255
245
  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));
246
+ border-radius: var(--xh-pagination-content-radius, var(--xh-shape-overlay));
257
247
  background: var(--xh-pagination-content-bg, var(--xh-bg-surface));
258
248
  box-shadow: var(--xh-pagination-content-shadow, var(--xh-elevation-floating));
259
249
  /* 定位层不吃指针,面板本体必须吃:里面的页码要点得到 */
260
250
  pointer-events: auto;
261
251
  }
262
252
 
253
+ /* 在场那一档才提前备好合成层:属性随 data-state 一起消失,收起后不长期占着 */
263
254
  [data-scope='pagination'][data-part='content'][data-state='open'] {
264
- animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
255
+ will-change: opacity, scale;
256
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
265
257
  }
266
258
 
267
259
  /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
@@ -297,6 +289,18 @@
297
289
  mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
298
290
  }
299
291
 
292
+ /* 省略位不写内容时画三点:折进去那几页的入口,空着就是一格看不出能点的空白 */
293
+ [data-scope='pagination'][data-part='ellipsis-trigger']:empty::before {
294
+ content: '';
295
+ display: inline-block;
296
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
297
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
298
+ vertical-align: var(--xh-glyph-baseline-shift);
299
+ background-color: currentColor;
300
+ -webkit-mask: var(--xh-glyph-mark-ellipsis) center / contain no-repeat;
301
+ mask: var(--xh-glyph-mark-ellipsis) center / contain no-repeat;
302
+ }
303
+
300
304
  /* rtl 下页序从右往左走,箭头跟着指向行进方向 */
301
305
  [dir='rtl'] [data-scope='pagination'][data-part='prev-trigger']:empty::before {
302
306
  -webkit-mask-image: var(--xh-glyph-mark-chevron-right);
@@ -307,4 +311,40 @@
307
311
  -webkit-mask-image: var(--xh-glyph-mark-chevron-left);
308
312
  mask-image: var(--xh-glyph-mark-chevron-left);
309
313
  }
314
+
315
+ /* 手指落点:命中区由绝对定位的伪元素向块轴两侧外扩,格子的盒一点不动——
316
+ 加高格子会把整条 nav 撑高,行宽也会跟着当前页抖。
317
+ 只扩块轴:格与格在行内轴上只隔一格间距,往两侧扩会与相邻格的命中区叠上。
318
+ 取 8px 是按最矮的 sm 档算的(28 + 8 × 2 = 44),md 与 lg 档更宽裕。
319
+ 用 ::after:::before 已经被两枚箭头的兜底字形占着 */
320
+ @media (pointer: coarse) {
321
+ [data-scope='pagination'][data-part='prev-trigger'],
322
+ [data-scope='pagination'][data-part='next-trigger'],
323
+ [data-scope='pagination'][data-part='item'] {
324
+ position: relative;
325
+ }
326
+
327
+ [data-scope='pagination'][data-part='prev-trigger']::after,
328
+ [data-scope='pagination'][data-part='next-trigger']::after,
329
+ [data-scope='pagination'][data-part='item']::after {
330
+ content: '';
331
+ position: absolute;
332
+ inset-block: -8px;
333
+ inset-inline: 0;
334
+ }
335
+ }
336
+
337
+ @media print {
338
+ /* 打印:定位层与遮罩是交互期才存在的东西,落到纸上只会盖住底下的正文。
339
+ 收起写在这份皮肤里而不是 reset:reset 层排在组件层之前,组件层里任何一条 display 都压得住它。 */
340
+ [data-scope='pagination'][data-part='positioner'] {
341
+ display: none;
342
+ }
343
+
344
+ /* 打印默认丢背景:当前页那格的实心底印不出来,一排页码看上去完全一样。
345
+ 改用字重表达同一件事——常态之所以不加粗是怕格子变宽、行宽跟着抖,纸上没有这回事 */
346
+ [data-scope='pagination'][data-part='item'][data-current] {
347
+ font-weight: var(--xh-font-weight-semibold);
348
+ }
349
+ }
310
350
  }