@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
package/css/timeline.css CHANGED
@@ -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
+ /* 定义 timeline 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='timeline'] {
@@ -34,8 +41,11 @@
34
41
  flex-direction: column;
35
42
  }
36
43
 
44
+ /* 横排排成一行、允许折行:窄档里每条占满整行,于是一条一行地堆下来。
45
+ 朝向两档都是 row,换档换的是下面每条的 flex 基准 */
37
46
  [data-scope='timeline'][data-part='root'][data-orientation='horizontal'] {
38
47
  flex-direction: row;
48
+ flex-wrap: wrap;
39
49
  }
40
50
 
41
51
  /* —— 尺寸 —— */
@@ -57,10 +67,13 @@
57
67
  }
58
68
 
59
69
  /* —— 条目 —— */
60
- /* 圆点与连线占一列(横排时占一行),内容占另一列,用 grid 而不是再包一层节点:
61
- 解剖里没有那个包裹层,作者也不该被逼着多写一个 div */
70
+ /* 圆点与连线占一列,内容占另一列,用 grid 而不是再包一层节点:
71
+ 解剖里没有那个包裹层,作者也不该被逼着多写一个 div
72
+ 这份两列的摆法是两个朝向共同的窄档,横排在下面的宽档里改写它 */
62
73
  [data-scope='timeline'][data-part='item'] {
63
74
  display: grid;
75
+ grid-template-columns: auto minmax(0, 1fr);
76
+ grid-template-rows: auto minmax(0, 1fr);
64
77
  column-gap: var(--xh-timeline-gutter, var(--xh-_timeline-gutter));
65
78
  /* 库里没有全局 preflight,列表项的外边距在这里自己抹平 */
66
79
  margin: 0;
@@ -72,16 +85,9 @@
72
85
  display: none;
73
86
  }
74
87
 
75
- [data-scope='timeline'][data-part='item'][data-orientation='vertical'] {
76
- grid-template-columns: auto minmax(0, 1fr);
77
- grid-template-rows: auto minmax(0, 1fr);
78
- }
79
-
80
- /* 横排时每条等分整行 */
88
+ /* 横排的窄档:每条占满整行,一条一行地堆下来 */
81
89
  [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] {
82
- grid-template-columns: auto minmax(0, 1fr);
83
- grid-template-rows: auto minmax(0, 1fr);
84
- flex: 1;
90
+ flex: 0 0 100%;
85
91
  }
86
92
 
87
93
  /* —— 圆点 —— */
@@ -92,19 +98,24 @@
92
98
  justify-content: center;
93
99
  inline-size: var(--xh-timeline-indicator-size, var(--xh-_timeline-dot-size));
94
100
  block-size: var(--xh-timeline-indicator-size, var(--xh-_timeline-dot-size));
95
- border-radius: var(--xh-timeline-indicator-radius, var(--xh-shape-pill));
101
+ border-radius: var(--xh-timeline-indicator-radius, var(--xh-shape-circle));
96
102
  /* 使用者令牌排在语气之前;两者都没有时退回一个中性的实心点 */
97
103
  background: var(--xh-timeline-indicator-bg, var(--xh-_tone-soft, var(--xh-fg-muted)));
98
104
  color: var(--xh-timeline-indicator-fg, var(--xh-_tone-on, var(--xh-fg-on-brand)));
99
105
  font-size: var(--xh-timeline-indicator-font-size, var(--xh-_timeline-caption-font-size));
100
106
  line-height: var(--xh-leading-none);
107
+ /* 语气色由每条自己的数据给,同一条的语气改了(事情办成了、出错了)走一遍过渡,
108
+ 整列圆点不在数据回来的那一帧集体跳色 */
109
+ transition:
110
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
111
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
101
112
  }
102
113
 
103
114
  [data-scope='timeline'][data-part='indicator'][hidden] {
104
115
  display: none;
105
116
  }
106
117
 
107
- [data-scope='timeline'][data-part='item'][data-orientation='vertical'] [data-scope='timeline'][data-part='indicator'] {
118
+ [data-scope='timeline'][data-part='item'] [data-scope='timeline'][data-part='indicator'] {
108
119
  grid-column: 1;
109
120
  grid-row: 1;
110
121
  /* 行高减去直径的一半:calc 里的除法要写成乘 0.5,除号在这儿是无效语法 */
@@ -113,11 +124,6 @@
113
124
  );
114
125
  }
115
126
 
116
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='indicator'] {
117
- grid-column: 1;
118
- grid-row: 1;
119
- }
120
-
121
127
  /* —— 连线 —— */
122
128
  [data-scope='timeline'][data-part='connector'] {
123
129
  border-radius: var(--xh-timeline-connector-radius, var(--xh-shape-pill));
@@ -128,9 +134,9 @@
128
134
  display: none;
129
135
  }
130
136
 
131
- /* 竖排:从圆点下沿一直伸到条目底边,接上下一条的圆点。
137
+ /* 堆叠时:从圆点下沿一直伸到条目底边,接上下一条的圆点。
132
138
  min-block-size 兜住内容极短的条目,那时也还看得见一截线 */
133
- [data-scope='timeline'][data-part='item'][data-orientation='vertical'] [data-scope='timeline'][data-part='connector'] {
139
+ [data-scope='timeline'][data-part='item'] [data-scope='timeline'][data-part='connector'] {
134
140
  grid-column: 1;
135
141
  grid-row: 2;
136
142
  justify-self: center;
@@ -139,16 +145,6 @@
139
145
  margin-block-start: var(--xh-space-1);
140
146
  }
141
147
 
142
- /* 横排:线转成横的一条,与圆点同一行 */
143
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='connector'] {
144
- grid-column: 2;
145
- grid-row: 1;
146
- align-self: center;
147
- min-inline-size: var(--xh-timeline-connector-min-length, var(--xh-space-4));
148
- block-size: var(--xh-timeline-connector-thickness, var(--xh-stroke-thick));
149
- margin-inline-start: var(--xh-space-1);
150
- }
151
-
152
148
  /* 末条后面没有下一件事,那截线不该占地方;作者不写它也一样,写了就替他收掉 */
153
149
  [data-scope='timeline'][data-part='item']:last-child [data-scope='timeline'][data-part='connector'] {
154
150
  display: none;
@@ -167,28 +163,17 @@
167
163
  }
168
164
 
169
165
  /* 条目之间的留白由内容自己的边距撑出来,连线的那一列因此能一路连到下一条 */
170
- [data-scope='timeline'][data-part='item'][data-orientation='vertical'] [data-scope='timeline'][data-part='content'] {
166
+ [data-scope='timeline'][data-part='item'] [data-scope='timeline'][data-part='content'] {
171
167
  grid-column: 2;
172
168
  grid-row: 1 / -1;
173
169
  padding-block-end: var(--xh-timeline-item-gap, var(--xh-_timeline-item-gap));
174
170
  }
175
171
 
176
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='content'] {
177
- grid-column: 1 / -1;
178
- grid-row: 2;
179
- padding-block-start: var(--xh-timeline-content-pt, var(--xh-space-2));
180
- padding-inline-end: var(--xh-timeline-item-gap, var(--xh-_timeline-item-gap));
181
- }
182
-
183
172
  /* 末条的留白同样收掉:它后面已经没有要隔开的东西 */
184
- [data-scope='timeline'][data-part='item'][data-orientation='vertical']:last-child [data-scope='timeline'][data-part='content'] {
173
+ [data-scope='timeline'][data-part='item']:last-child [data-scope='timeline'][data-part='content'] {
185
174
  padding-block-end: 0;
186
175
  }
187
176
 
188
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:last-child [data-scope='timeline'][data-part='content'] {
189
- padding-inline-end: 0;
190
- }
191
-
192
177
  /* —— 侧别 —— */
193
178
  /* 不写 placement 时内容落在结束侧,即上面那几条基础规则。
194
179
  start 把线挪到结束侧、内容挪到起始侧,文字一并靠向线 */
@@ -227,45 +212,179 @@
227
212
  text-align: end;
228
213
  }
229
214
 
230
- /* 横排的 start 是把内容挪到线的上方,内容贴着线的那一边对齐 */
231
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] {
232
- grid-template-rows: minmax(0, 1fr) auto;
215
+ /* —— 坐标 —— */
216
+ /* 与内容对置的那一列。竖排三种侧别各给它一条轨道,横排不单开轨道、按流排在末尾 */
217
+ [data-scope='timeline'][data-part='label'] {
218
+ grid-column: var(--xh-_timeline-label-col, auto);
219
+ grid-row: var(--xh-_timeline-label-row, auto);
220
+ align-self: start;
221
+ min-inline-size: 0;
222
+ color: var(--xh-timeline-label-fg, var(--xh-fg-subtle));
223
+ font-size: var(--xh-timeline-label-font-size, var(--xh-_timeline-caption-font-size));
224
+ /* 等宽数字:日期里的 1 与 7 在比例字体里宽度不同,不定住会让整列坐标左右抖一格 */
225
+ font-variant-numeric: tabular-nums;
226
+ line-height: var(--xh-leading-tight);
227
+ text-align: var(--xh-_timeline-label-align, end);
233
228
  }
234
229
 
235
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='indicator'],
236
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='connector'] {
237
- grid-row: 2;
230
+ /* 内容落在结束侧时坐标占线之前的那一列,圆点与连线让到第二列 */
231
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical']:where(:not([data-placement]), [data-placement='end']):has(> [data-scope='timeline'][data-part='label']) {
232
+ --xh-_timeline-label-col: 1;
233
+ --xh-_timeline-label-row: 1;
234
+
235
+ grid-template-columns: auto auto minmax(0, 1fr);
238
236
  }
239
237
 
240
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='content'] {
241
- grid-row: 1;
242
- align-self: end;
243
- padding-block-start: 0;
244
- padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
238
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical']:where(:not([data-placement]), [data-placement='end']):has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='indicator'],
239
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical']:where(:not([data-placement]), [data-placement='end']):has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='connector'] {
240
+ grid-column: 2;
245
241
  }
246
242
 
247
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] {
248
- grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
243
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical']:where(:not([data-placement]), [data-placement='end']):has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='content'] {
244
+ grid-column: 3;
249
245
  }
250
246
 
251
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='indicator'],
252
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='connector'] {
253
- grid-row: 2;
247
+ /* 横排的窄档摆成上下两格,坐标照竖排那样占线之前的一列。
248
+ 不给这条轨道的话坐标会自动落进圆点那一列,把它撑宽,圆点与连线因此错开 */
249
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) {
250
+ --xh-_timeline-label-col: 1;
251
+ --xh-_timeline-label-row: 1;
252
+
253
+ grid-template-columns: auto auto minmax(0, 1fr);
254
254
  }
255
255
 
256
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='content'] {
257
- grid-row: 3;
258
- align-self: start;
256
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='indicator'],
257
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='connector'] {
258
+ grid-column: 2;
259
259
  }
260
260
 
261
- [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate']:nth-child(even) [data-scope='timeline'][data-part='content'] {
262
- grid-row: 1;
263
- align-self: end;
264
- padding-block-start: 0;
265
- padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
261
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='content'] {
262
+ grid-column: 3;
263
+ }
264
+
265
+ /* 内容落在起始侧时坐标占线之后的那一列 */
266
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical'][data-placement='start']:has(> [data-scope='timeline'][data-part='label']) {
267
+ --xh-_timeline-label-col: 3;
268
+ --xh-_timeline-label-row: 1;
269
+ --xh-_timeline-label-align: start;
270
+
271
+ grid-template-columns: minmax(0, 1fr) auto auto;
272
+ }
273
+
274
+ /* 逐条交替时坐标恒在内容的对面,时间戳因此不跟着内容左右横跳 */
275
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical'][data-placement='alternate'] {
276
+ --xh-_timeline-label-col: 1;
277
+ --xh-_timeline-label-row: 1;
278
+ }
279
+
280
+ [data-scope='timeline'][data-part='item'][data-orientation='vertical'][data-placement='alternate']:nth-child(even) {
281
+ --xh-_timeline-label-col: 3;
282
+ --xh-_timeline-label-align: start;
283
+ }
284
+
285
+ /* —— 横排的宽档 —— */
286
+ /* 上面那份两列的摆法是两个朝向共同的窄档。视口宽到放得下一行事件时,
287
+ 横排在这里把圆点与连线转回同一行、内容落到下一行。
288
+ 手机档停在窄档:一条一行,事件仍逐条读得完 */
289
+ @media (min-width: 768px) {
290
+ /* 每条等分整行 */
291
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] {
292
+ flex: 1;
293
+ }
294
+
295
+ /* 每条规则都带一条 :has(坐标) 的分支:窄档那条坐标轨道的选择器更重,
296
+ 不把它写进来的话带坐标的那些条目会停在窄档的摆法上 */
297
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='indicator'],
298
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='indicator'] {
299
+ grid-column: 1;
300
+ grid-row: 1;
301
+ /* 圆点与内容不再上下对位,窄档那半行的下移收掉 */
302
+ margin-block-start: 0;
303
+ }
304
+
305
+ /* 线转成横的一条,与圆点同一行;窄档那几条竖着走的取值一并收掉 */
306
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='connector'],
307
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='connector'] {
308
+ grid-column: 2;
309
+ grid-row: 1;
310
+ align-self: center;
311
+ justify-self: stretch;
312
+ inline-size: auto;
313
+ min-inline-size: var(--xh-timeline-connector-min-length, var(--xh-space-4));
314
+ block-size: var(--xh-timeline-connector-thickness, var(--xh-stroke-thick));
315
+ min-block-size: 0;
316
+ margin-block-start: 0;
317
+ margin-inline-start: var(--xh-space-1);
318
+ }
319
+
320
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='content'],
321
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) > [data-scope='timeline'][data-part='content'] {
322
+ grid-column: 1 / -1;
323
+ grid-row: 2;
324
+ padding-block-start: var(--xh-timeline-content-pt, var(--xh-space-2));
325
+ padding-block-end: 0;
326
+ padding-inline-end: var(--xh-timeline-item-gap, var(--xh-_timeline-item-gap));
327
+ }
328
+
329
+ /* 末条的留白同样收掉:它后面已经没有要隔开的东西 */
330
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:last-child [data-scope='timeline'][data-part='content'] {
331
+ padding-inline-end: 0;
332
+ }
333
+
334
+ /* 宽档不给坐标单开轨道,它按流排在末尾;窄档那条轨道在这里收掉 */
335
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal']:has(> [data-scope='timeline'][data-part='label']) {
336
+ --xh-_timeline-label-col: auto;
337
+ --xh-_timeline-label-row: auto;
338
+
339
+ grid-template-columns: auto minmax(0, 1fr);
340
+ }
341
+
342
+ /* 横排的 start 是把内容挪到线的上方,内容贴着线的那一边对齐 */
343
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] {
344
+ grid-template-rows: minmax(0, 1fr) auto;
345
+ }
346
+
347
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='indicator'],
348
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='connector'] {
349
+ grid-row: 2;
350
+ }
351
+
352
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='start'] [data-scope='timeline'][data-part='content'] {
353
+ grid-row: 1;
354
+ align-self: end;
355
+ padding-block-start: 0;
356
+ padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
357
+ }
358
+
359
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] {
360
+ grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
361
+ }
362
+
363
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='indicator'],
364
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='connector'] {
365
+ grid-row: 2;
366
+ }
367
+
368
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] [data-scope='timeline'][data-part='content'] {
369
+ grid-row: 3;
370
+ align-self: start;
371
+ }
372
+
373
+ [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate']:nth-child(even) [data-scope='timeline'][data-part='content'] {
374
+ grid-row: 1;
375
+ align-self: end;
376
+ padding-block-start: 0;
377
+ padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
378
+ }
266
379
  }
267
380
 
268
381
  /* —— 文字 —— */
382
+ /* 中间没有断点的长串——单号、路径、无空格的标识——在框内断开。
383
+ 每条的宽度由内容的最小宽度定,断不开就会把整条轴顶出容器 */
384
+ [data-scope='timeline']:is([data-part='title'], [data-part='description'], [data-part='time'], [data-part='label']) {
385
+ overflow-wrap: anywhere;
386
+ }
387
+
269
388
  [data-scope='timeline'][data-part='title'] {
270
389
  color: var(--xh-timeline-title-fg, var(--xh-fg-default));
271
390
  font-size: var(--xh-timeline-title-font-size, var(--xh-_timeline-title-font-size));
@@ -275,7 +394,7 @@
275
394
 
276
395
  [data-scope='timeline'][data-part='description'] {
277
396
  color: var(--xh-timeline-description-fg, var(--xh-fg-muted));
278
- font-size: var(--xh-timeline-description-font-size, var(--xh-text-body-size));
397
+ font-size: var(--xh-timeline-description-font-size, var(--xh-text-secondary-size));
279
398
  line-height: var(--xh-leading-normal);
280
399
  }
281
400
 
@@ -286,4 +405,19 @@
286
405
  font-variant-numeric: tabular-nums;
287
406
  line-height: var(--xh-leading-normal);
288
407
  }
408
+
409
+ /*
410
+ * 打印:底色被丢掉,圆点与连线整个是底色画出来的,纸上这条轴的骨架就此不见,
411
+ * 只剩几段没有次序的文字。两处都改由描边承载:圆点成一个空心圈,
412
+ * 连线的两条边合起来就是那条线(线本身只有一个描边厚,两边各画一半正好填满)。
413
+ */
414
+ @media print {
415
+ [data-scope='timeline'][data-part='indicator'] {
416
+ border: var(--xh-stroke-thick) solid currentColor;
417
+ }
418
+
419
+ [data-scope='timeline'][data-part='connector'] {
420
+ border: var(--xh-stroke-thin) solid currentColor;
421
+ }
422
+ }
289
423
  }
package/css/timer.css CHANGED
@@ -1,16 +1,24 @@
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
+ /* 定义 timer 样式。 */
7
+
8
+ /* Timer 独立皮肤同时传递引入起停钮的动作控件配方;full bundle 递归去重。 */
9
+ @import '../family/action-control.css';
10
+
1
11
  @layer xihan.components {
2
12
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
13
  [data-scope='timer'] {
4
14
  --xh-timer-skin: 1;
5
15
  }
6
16
 
7
- /* 三个尺寸档只换这几个私有槽,各部件从 root 继承它们,换档不必给每个部件各写一条选择器 */
17
+ /* 三个尺寸档只换这两个私有槽,各部件从 root 继承它们,换档不必给每个部件各写一条选择器;
18
+ 起停钮的档位由连接层直接投给家族,这里不再中转 */
8
19
  [data-scope='timer'][data-part='root'] {
9
20
  --xh-_timer-digit-size: var(--xh-text-heading-2-size);
10
21
  --xh-_timer-gap: var(--xh-space-3);
11
- --xh-_timer-control-h: var(--xh-control-h-md);
12
- --xh-_timer-control-px: var(--xh-control-px-md);
13
- --xh-_timer-control-gap: var(--xh-control-gap-md);
14
22
 
15
23
  display: inline-flex;
16
24
  align-items: center;
@@ -27,43 +35,48 @@
27
35
  [data-scope='timer'][data-part='root'][data-size='sm'] {
28
36
  --xh-_timer-digit-size: var(--xh-text-heading-3-size);
29
37
  --xh-_timer-gap: var(--xh-space-2);
30
- --xh-_timer-control-h: var(--xh-control-h-sm);
31
- --xh-_timer-control-px: var(--xh-control-px-sm);
32
- --xh-_timer-control-gap: var(--xh-control-gap-sm);
33
38
  }
34
39
 
35
40
  [data-scope='timer'][data-part='root'][data-size='lg'] {
36
41
  --xh-_timer-digit-size: var(--xh-text-heading-1-size);
37
42
  --xh-_timer-gap: var(--xh-space-4);
38
- --xh-_timer-control-h: var(--xh-control-h-lg);
39
- --xh-_timer-control-px: var(--xh-control-px-lg);
40
- --xh-_timer-control-gap: var(--xh-control-gap-lg);
41
43
  }
42
44
 
43
45
  /* —— 时间区 —— */
44
46
  /* 等宽数字:逐位宽度一致,秒数换位时分隔符与后面的段都不会左右挪动。
45
47
  direction 钉成 ltr:每段是一个独立的 flex 项,主轴方向跟着文字方向走,
46
48
  不钉住的话 rtl 页面上时分秒会整体倒过来排——时间串的读序两个方向都一样。 */
47
- [data-scope='timer'][data-part='area'] {
49
+ [data-scope='timer'][data-part='display'] {
48
50
  display: inline-flex;
49
51
  align-items: baseline;
50
52
  direction: ltr;
51
- color: var(--xh-timer-area-fg, var(--xh-fg-default));
53
+ color: var(--xh-timer-display-fg, var(--xh-fg-default));
54
+ /* 嵌在一句话里或摆在别人的数值槽里时把 --xh-timer-digit-font-size 写成 inherit,
55
+ 数字就跟着上下文的字号走,不再自带展示档字号 */
52
56
  font-size: var(--xh-timer-digit-font-size, var(--xh-_timer-digit-size));
53
57
  font-variant-numeric: tabular-nums;
54
58
  font-weight: var(--xh-font-weight-semibold);
55
59
  line-height: var(--xh-leading-tight);
60
+ /* 走到点那一刻前景退一档,这里让它淡过去而不是硬跳 */
61
+ transition: color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
56
62
  }
57
63
 
58
- [data-scope='timer'][data-part='area'][hidden] {
64
+ [data-scope='timer'][data-part='display'][hidden] {
59
65
  display: none;
60
66
  }
61
67
 
62
68
  /* 走完之后这串数字不再是活的信息,退一档;暂停在半路的仍是要盯着看的数,不退 */
63
- [data-scope='timer'][data-part='area'][data-state='completed'] {
69
+ [data-scope='timer'][data-part='display'][data-state='completed'] {
64
70
  color: var(--xh-timer-completed-fg, var(--xh-fg-muted));
65
71
  }
66
72
 
73
+ /* 数字段自己一个前景槽,与记号那个成对。
74
+ 缺省是 inherit 而不是某个具体前景:时间区走完会整体退一档,
75
+ 数字段照着继承下来才跟得上,写死取值就跟不动了 */
76
+ [data-scope='timer'][data-part='item'] {
77
+ color: var(--xh-timer-item-fg, inherit);
78
+ }
79
+
67
80
  /* 记号只是排版,比数字弱一档、两侧留一点气口 */
68
81
  [data-scope='timer'][data-part='separator'] {
69
82
  padding-inline: var(--xh-timer-separator-px, var(--xh-space-0_5));
@@ -71,49 +84,40 @@
71
84
  font-weight: var(--xh-font-weight-regular);
72
85
  }
73
86
 
74
- /* —— 起停按钮 —— */
87
+ /* —— 起停按钮 ——
88
+ 带文案(或图标)的离散动作钮:盒几何、悬停 / 按下与 0.97 按压、粗指针热区、焦点环、禁用面全由
89
+ Action Control 的 text outline 档给(连接层按 size 投档,缺省 md 一个控件高),组件只映射既有使用者槽。
90
+ 中性描边、透明底;白底承载 hover 100 → pressed 200,不抬升;焦点边由家族给,不随语气 */
75
91
  [data-scope='timer'][data-part='control'] {
76
- display: inline-flex;
77
- align-items: center;
78
- justify-content: center;
79
- gap: var(--xh-timer-control-gap, var(--xh-_timer-control-gap));
80
- block-size: var(--xh-timer-control-h, var(--xh-_timer-control-h));
81
- padding-inline: var(--xh-timer-control-px, var(--xh-_timer-control-px));
82
- border: var(--xh-stroke-thin) solid var(--xh-timer-control-border, var(--xh-border-control));
83
- border-radius: var(--xh-timer-control-radius, var(--xh-shape-control));
84
- background: var(--xh-timer-control-bg, var(--xh-bg-surface));
85
- color: var(--xh-timer-control-fg, var(--xh-fg-default));
86
- font-size: var(--xh-text-label-size);
92
+ --xh-action-visual-size: var(--xh-timer-control-h, var(--xh-_action-profile-visual-size));
93
+ --xh-action-padding-inline: var(--xh-timer-control-px, var(--xh-_action-profile-padding-inline));
94
+ --xh-action-gap: var(--xh-timer-control-gap, var(--xh-_action-profile-gap));
95
+ --xh-action-radius: var(--xh-timer-control-radius, var(--xh-shape-control));
96
+ --xh-action-bg-rest: var(--xh-timer-control-bg, var(--xh-_action-variant-bg-rest));
97
+ --xh-action-bg-hover: var(--xh-timer-control-bg-hover, var(--xh-_action-variant-bg-hover));
98
+ --xh-action-bg-pressed: var(--xh-timer-control-bg-active, var(--xh-_action-variant-bg-pressed));
99
+ --xh-action-bg-disabled: var(--xh-timer-control-bg-disabled, var(--xh-_action-variant-bg-disabled));
100
+ --xh-action-fg-rest: var(--xh-timer-control-fg, var(--xh-_action-variant-fg-rest));
101
+ --xh-action-fg-hover: var(--xh-timer-control-fg, var(--xh-_action-variant-fg-hover));
102
+ --xh-action-fg-pressed: var(--xh-timer-control-fg, var(--xh-_action-variant-fg-pressed));
103
+ --xh-action-border-rest: var(--xh-timer-control-border, var(--xh-_action-variant-border-rest));
104
+ --xh-action-border-hover: var(--xh-timer-control-border-hover, var(--xh-_action-variant-border-hover));
105
+ --xh-action-border-pressed: var(--xh-timer-control-border-hover, var(--xh-_action-variant-border-pressed));
106
+ --xh-action-border-focus-visible: var(--xh-timer-control-border-focus, var(--xh-_action-variant-border-focus-visible));
107
+ --xh-action-border-disabled: var(--xh-timer-control-border-disabled, var(--xh-_action-variant-border-disabled));
108
+ --xh-action-highlight-rest: transparent;
109
+ --xh-action-shadow-rest: none;
110
+ --xh-action-shadow-hover: var(--xh-timer-control-shadow-hover, none);
111
+ --xh-action-shadow-pressed: var(--xh-timer-control-shadow-active, none);
112
+ --xh-action-font-size: var(--xh-text-label-size);
113
+ /* 作者塞进钮里的图标按档取字形尺寸,与文案同一把尺 */
114
+ --xh-icon-size: var(--xh-timer-icon-size, var(--xh-_action-profile-glyph-size));
115
+
87
116
  font-weight: var(--xh-text-label-weight);
88
- line-height: var(--xh-leading-none);
89
- cursor: pointer;
90
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
91
117
  }
92
118
 
119
+ /* 家族那条 display 会把 UA 的 [hidden]{display:none} 盖掉,作者收起它时要的是这一条 */
93
120
  [data-scope='timer'][data-part='control'][hidden] {
94
121
  display: none;
95
122
  }
96
-
97
- [data-scope='timer'][data-part='control']:hover {
98
- border-color: var(--xh-timer-control-border-hover, var(--xh-border-control-hover));
99
- background: var(--xh-timer-control-bg-hover, var(--xh-bg-subtle-hover));
100
- }
101
-
102
- [data-scope='timer'][data-part='control']:active {
103
- background: var(--xh-timer-control-bg-active, var(--xh-bg-subtle-active));
104
- }
105
-
106
- [data-scope='timer'][data-part='control']:focus-visible {
107
- border-color: var(--xh-timer-control-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
108
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
109
- outline-offset: var(--xh-ring-offset);
110
- }
111
-
112
- /* 作者把按钮禁掉时的样子。文字改用 fg-disabled 就不再叠 opacity,两条一起上会掉到读不出来 */
113
- [data-scope='timer'][data-part='control']:disabled {
114
- border-color: var(--xh-timer-control-border-disabled, var(--xh-border-subtle));
115
- background: var(--xh-timer-control-bg-disabled, var(--xh-bg-muted));
116
- color: var(--xh-fg-disabled);
117
- cursor: not-allowed;
118
- }
119
123
  }
@@ -0,0 +1,34 @@
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
+ /* 定义 timestamp 样式。 */
7
+
8
+ @layer xihan.components {
9
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
10
+ [data-scope='timestamp'] {
11
+ --xh-timestamp-skin: 1;
12
+ }
13
+
14
+ [data-scope='timestamp'][data-part='root'] {
15
+ color: var(--xh-timestamp-fg, var(--xh-fg-default));
16
+ /* 等宽数字:秒数跳动时后面的字符不会左右挪 */
17
+ font-variant-numeric: tabular-nums;
18
+ /* 一个时间戳不该被拆到两行去 */
19
+ white-space: nowrap;
20
+ /* 时刻换成认不出的值时前景要换档,这里让它淡过去而不是硬跳 */
21
+ transition: color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
22
+ }
23
+
24
+ /* 相对说法是一句话不是一串数字,等宽数字反而把字距拉开 */
25
+ [data-scope='timestamp'][data-part='root'][data-relative] {
26
+ font-variant-numeric: normal;
27
+ }
28
+
29
+ /* 没给时刻、或给了认不出的时刻:这时显示的是作者写在节点里的兜底文案,退成弱前景 */
30
+ [data-scope='timestamp'][data-part='root'][data-state='empty'],
31
+ [data-scope='timestamp'][data-part='root'][data-state='invalid'] {
32
+ color: var(--xh-timestamp-placeholder-fg, var(--xh-fg-muted));
33
+ }
34
+ }