@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/heatmap.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
+ /* 定义 heatmap 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='heatmap'] {
@@ -18,9 +25,8 @@
18
25
  不接控件高度那把尺——它是给可点可输的控件在一行里排齐用的,矩阵格子不可交互,
19
26
  接上去密度档一换矩阵就跟着变形 */
20
27
  --xh-_heatmap-row-h: var(--xh-heatmap-row-h, var(--xh-space-5));
21
- /* 格间距等于聚焦环占的宽度(偏移 + 环宽):环因此整圈落在格子之间的空当里,
22
- 不压到相邻的格子上(外缘与相邻格相接) */
23
- --xh-_heatmap-gap: calc(var(--xh-ring-offset) + var(--xh-ring-width));
28
+ /* 格与格之间的空当:格子按天铺满一年,靠这道缝把一格与相邻格分开 */
29
+ --xh-_heatmap-gap: var(--xh-space-1);
24
30
  --xh-_heatmap-gutter: var(--xh-heatmap-gutter, var(--xh-space-8));
25
31
  --xh-_heatmap-font-size: var(--xh-text-caption-size);
26
32
  /* 星期名隔行画:第 0/2/4/6 行那个字的颜色。缺省透明——只是字不上色,
@@ -43,9 +49,9 @@
43
49
  display: flex;
44
50
  flex-direction: column;
45
51
  gap: var(--xh-heatmap-gap, var(--xh-space-2));
46
- /* 一整年五十几列,一屏放不下就自己横着滚。横向滚动会把纵向也变成 auto,
47
- 上下留出一圈聚焦环的余量,最上一行与最下一行的环才不会被裁掉 */
48
- padding-block: var(--xh-heatmap-py, calc(var(--xh-ring-offset) + var(--xh-ring-width)));
52
+ /* 一整年五十几列,一屏放不下就自己横着滚。上下各留一道与格间距同宽的空当,
53
+ 最上一行与最下一行不贴着滚动容器的边 */
54
+ padding-block: var(--xh-heatmap-py, var(--xh-_heatmap-gap));
49
55
  overflow-x: auto;
50
56
  /* 键盘走到视口外的格子时 scrollIntoView 会把它滚进来,落点要让开钉住的那一列,
51
57
  否则往回走的那一格正好停在行首星期名底下 */
@@ -121,13 +127,6 @@
121
127
  gap: var(--xh-heatmap-grid-gap, var(--xh-_heatmap-gap));
122
128
  }
123
129
 
124
- /* 网格自己只在没有格子可落焦点时才占 Tab 位,那几帧里也该看得出焦点在哪。
125
- 环往内收:网格铺满 root,root 那层 overflow-x: auto 会把画在外沿的环裁掉 */
126
- [data-scope='heatmap'][data-part='grid']:focus-visible {
127
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
128
- outline-offset: calc(-1 * var(--xh-ring-width));
129
- }
130
-
131
130
  [data-scope='heatmap'][data-part='row'] {
132
131
  /* 行首空出的列数由连接层写进这个槽:日历形态是区间起点不在周首日时的错列,
133
132
  月历形态是这一周里 1 号之前的那几个星期几 */
@@ -152,7 +151,7 @@
152
151
  /* 行首的星期名。月份行行首那个占位也是它,宽度一样,月份才对得上列。
153
152
  一整年放不下时网格横着滚,这一列钉在滚动容器的起始缘:跟着滚走的话,
154
153
  滚过头一屏就再也认不出哪一行是星期几。底色必须实色,格子从它下面滚过去不能透出来 */
155
- [data-scope='heatmap'][data-part='week-day-label'] {
154
+ [data-scope='heatmap'][data-part='week-day'] {
156
155
  position: sticky;
157
156
  /* 层号收在 root 建的层叠上下文里,只跟组件内的兄弟比 */
158
157
  z-index: var(--xh-heatmap-sticky-layer, 1);
@@ -173,10 +172,10 @@
173
172
  一行只有 10px 高,七个 12px 的字挨着写会上下叠在一起;隔一行之后每个留下来的字
174
173
  有两行的高度(2 × 格高 + 格距)可用。哪一行是星期几由行自己的可及名字念出来,
175
174
  可见文字与可及名字是两件事,读屏这边一行都没少 */
176
- [data-scope='heatmap'][data-part='week-day-label'][data-week-day='0'],
177
- [data-scope='heatmap'][data-part='week-day-label'][data-week-day='2'],
178
- [data-scope='heatmap'][data-part='week-day-label'][data-week-day='4'],
179
- [data-scope='heatmap'][data-part='week-day-label'][data-week-day='6'] {
175
+ [data-scope='heatmap'][data-part='week-day'][data-week-day='0'],
176
+ [data-scope='heatmap'][data-part='week-day'][data-week-day='2'],
177
+ [data-scope='heatmap'][data-part='week-day'][data-week-day='4'],
178
+ [data-scope='heatmap'][data-part='week-day'][data-week-day='6'] {
180
179
  color: var(--xh-_heatmap-week-day-skip);
181
180
  }
182
181
 
@@ -217,17 +216,12 @@
217
216
  左侧那一列星期名就变成锯齿。两条选择器合起来正好是「本行第一个格子」,
218
217
  行里写不写星期名都成立 */
219
218
  [data-scope='heatmap'][data-part='row'] > [data-scope='heatmap'][data-part='cell']:first-child,
220
- [data-scope='heatmap'][data-part='week-day-label'] + [data-scope='heatmap'][data-part='cell'] {
219
+ [data-scope='heatmap'][data-part='week-day'] + [data-scope='heatmap'][data-part='cell'] {
221
220
  margin-inline-start: calc(
222
221
  var(--xh-_heatmap-row-offset) * (var(--xh-_heatmap-cell-size) + var(--xh-_heatmap-gap))
223
222
  );
224
223
  }
225
224
 
226
- [data-scope='heatmap'][data-part='cell']:focus-visible {
227
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
228
- outline-offset: var(--xh-ring-offset);
229
- }
230
-
231
225
  /* —— 月历形态:一个自然月一块,块内一行是一周、一列是一个星期几 —— */
232
226
  [data-scope='heatmap'][data-part='root'][data-variant='month'] [data-scope='heatmap'][data-part='grid'] {
233
227
  flex-flow: row wrap;
@@ -257,7 +251,7 @@
257
251
  /* 块里的星期名是一排列头,宽度改成格宽才对得上下面的格子,也不再钉住。
258
252
  字比一格宽,不裁:裁掉就是七个缺角的字,让它往两边的列间距里溢出去,
259
253
  相邻两个各溢出一点也还差着一段空白 */
260
- [data-scope='heatmap'][data-part='root'][data-variant='month'] [data-scope='heatmap'][data-part='week-day-label'] {
254
+ [data-scope='heatmap'][data-part='root'][data-variant='month'] [data-scope='heatmap'][data-part='week-day'] {
261
255
  position: static;
262
256
  inline-size: var(--xh-_heatmap-cell-size);
263
257
  overflow: visible;
@@ -329,12 +323,16 @@
329
323
  padding-block: var(--xh-heatmap-tooltip-py, var(--xh-space-1));
330
324
  padding-inline: var(--xh-heatmap-tooltip-px, var(--xh-space-2));
331
325
  border-radius: var(--xh-heatmap-tooltip-radius, var(--xh-shape-control));
326
+ /* 与 Tooltip 同一副反白气泡:任何浮层都得有一圈非透明描边(§8.4),描边从字色里兑两成,
327
+ 深浅主题与语气换色时跟着字色走;影走 frosted 紧凑档,与 Tooltip 的 content 同深 */
328
+ border: var(--xh-stroke-thin) solid var(--xh-heatmap-tooltip-border, color-mix(in oklab, var(--xh-heatmap-tooltip-fg, var(--xh-bg-surface)) 20%, transparent));
332
329
  background: var(--xh-heatmap-tooltip-bg, var(--xh-fg-default));
333
330
  color: var(--xh-heatmap-tooltip-fg, var(--xh-bg-surface));
334
- font-size: var(--xh-heatmap-tooltip-font-size, var(--xh-text-caption-size));
331
+ /* 字号与 Tooltip 缺省档同一把尺(次级标注档 13px) */
332
+ font-size: var(--xh-heatmap-tooltip-font-size, var(--xh-control-caption-md));
335
333
  line-height: var(--xh-leading-normal);
336
334
  white-space: nowrap;
337
- box-shadow: var(--xh-heatmap-tooltip-shadow, var(--xh-elevation-floating));
335
+ box-shadow: var(--xh-heatmap-tooltip-shadow, var(--xh-material-frosted-compact-shadow));
338
336
  /* 详情条不接指针:压在格子上时指针要能穿过去,否则一进条里就算离开了格子,
339
337
  详情自己把自己收起来,来回闪 */
340
338
  pointer-events: none;
@@ -392,14 +390,19 @@
392
390
  box-shadow: inset 0 0 0 var(--xh-stroke-thin) var(--xh-heatmap-cell-border, var(--xh-border-default));
393
391
  }
394
392
 
393
+ /* 详情条的收起态:没有哪一格是活的时候整条藏起来 */
394
+ [data-scope='heatmap'][data-part='tooltip'][data-state='hidden'] {
395
+ display: none;
396
+ }
397
+
395
398
  /* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
396
- 不补的话作者给节点加 hidden 后它照样显示。详情条收起靠的正是这一条。
399
+ 不补的话作者给节点加 hidden 后它照样显示。
397
400
  格子没有声明 display,UA 那条兜得住,不必列在这里 */
398
401
  [data-scope='heatmap'][data-part='root'][hidden],
399
402
  [data-scope='heatmap'][data-part='grid'][hidden],
400
403
  [data-scope='heatmap'][data-part='month-block'][hidden],
401
404
  [data-scope='heatmap'][data-part='row'][hidden],
402
- [data-scope='heatmap'][data-part='week-day-label'][hidden],
405
+ [data-scope='heatmap'][data-part='week-day'][hidden],
403
406
  [data-scope='heatmap'][data-part='month-label'][hidden],
404
407
  [data-scope='heatmap'][data-part='row-label'][hidden],
405
408
  [data-scope='heatmap'][data-part='column-label'][hidden],
@@ -408,4 +411,59 @@
408
411
  [data-scope='heatmap'][data-part='legend-item'][hidden] {
409
412
  display: none;
410
413
  }
414
+
415
+ /*
416
+ * 打印:格子的深浅只写在底色上,纸上多数丢背景,整张图印成一片空白。
417
+ * 这一档把档位改画成边框的粗细——0 档只有一圈发丝线,档位越高边越厚,
418
+ * 顶到一半格宽时整格填满。边算在尺寸里(reset 兜了 border-box),格子大小一点不变。
419
+ *
420
+ * 比例取 0.2 / 0.3 / 0.4 / 0.5:缺省格宽 10px 下正好落在 2 / 3 / 4 / 5 像素,
421
+ * 与 0 档那一像素合成五档整数宽——边宽在屏幕与纸上都取整,分数宽会有两档并到一起。
422
+ *
423
+ * 第一条给的是高档那一身,下面四条按档位逐个改薄:档数由作者定,
424
+ * 超出缺省五档的那些落在第一条上,一律按最高档画。
425
+ * 图例里那几个方块与格子同源,跟着走同一套。
426
+ */
427
+ @media print {
428
+ [data-scope='heatmap'][data-part='cell'],
429
+ [data-scope='heatmap'][data-part='legend-item'] {
430
+ --xh-_heatmap-ink-ring: calc(var(--xh-_heatmap-cell-size) * 0.5);
431
+
432
+ border: var(--xh-_heatmap-ink-ring) solid currentColor;
433
+ }
434
+
435
+ [data-scope='heatmap'][data-part='cell'][data-level='0'],
436
+ [data-scope='heatmap'][data-part='legend-item'][data-level='0'] {
437
+ --xh-_heatmap-ink-ring: var(--xh-stroke-thin);
438
+ }
439
+
440
+ [data-scope='heatmap'][data-part='cell'][data-level='1'],
441
+ [data-scope='heatmap'][data-part='legend-item'][data-level='1'] {
442
+ --xh-_heatmap-ink-ring: calc(var(--xh-_heatmap-cell-size) * 0.2);
443
+ }
444
+
445
+ [data-scope='heatmap'][data-part='cell'][data-level='2'],
446
+ [data-scope='heatmap'][data-part='legend-item'][data-level='2'] {
447
+ --xh-_heatmap-ink-ring: calc(var(--xh-_heatmap-cell-size) * 0.3);
448
+ }
449
+
450
+ [data-scope='heatmap'][data-part='cell'][data-level='3'],
451
+ [data-scope='heatmap'][data-part='legend-item'][data-level='3'] {
452
+ --xh-_heatmap-ink-ring: calc(var(--xh-_heatmap-cell-size) * 0.4);
453
+ }
454
+ }
455
+
456
+ /*
457
+ * 高对比档:格子画的就是色阶本身,被系统换成同一个底色之后整张图没有任何深浅。
458
+ * 这几处退出强制着色,自己保住色阶;退出之后不再跟系统底色走,
459
+ * 各补一圈系统描边把方格从背景里框出来(原来那圈发丝线写在 inset 阴影上,这一档里被丢弃)。
460
+ */
461
+ @media (forced-colors: active) {
462
+ [data-scope='heatmap'][data-part='cell'],
463
+ [data-scope='heatmap'][data-part='legend-item'] {
464
+ forced-color-adjust: none;
465
+ outline: var(--xh-stroke-thin) solid CanvasText;
466
+ outline-offset: calc(-1 * var(--xh-stroke-thin));
467
+ }
468
+ }
411
469
  }
package/css/highlight.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
+ /* 定义 highlight 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='highlight'] {
@@ -11,16 +18,24 @@
11
18
  }
12
19
 
13
20
  /* 浏览器给 mark 的默认底色是一个固定的亮黄,暗色主题下压在深底上刺眼、
14
- 配的黑字也不随主题走;这里整份换成随主题走的品牌淡底 */
21
+ 配的黑字也不随主题走;这里整份换成随主题走的品牌淡底。
22
+ 槽名带 mark 段与部件对上 */
15
23
  [data-scope='highlight'][data-part='mark'] {
16
24
  padding-inline: var(--xh-highlight-mark-px, var(--xh-space-0_5));
17
- border-radius: var(--xh-highlight-radius, var(--xh-shape-inset));
18
- background: var(--xh-highlight-bg, var(--xh-bg-brand-subtle));
19
- color: var(--xh-highlight-fg, var(--xh-fg-brand-strong));
20
- font-weight: var(--xh-font-weight-medium);
25
+ border-radius: var(--xh-highlight-mark-radius, var(--xh-shape-inset));
26
+ background: var(--xh-highlight-mark-bg, var(--xh-bg-brand-subtle));
27
+ color: var(--xh-highlight-mark-fg, var(--xh-fg-brand-strong));
28
+ font-weight: var(--xh-highlight-mark-font-weight, var(--xh-font-weight-medium));
21
29
  /* 命中片段跨行时两半各自收边,否则圆角与内边距只画在整段的首尾。
22
30
  两条都写:WebKit 只认带前缀那条 */
23
31
  -webkit-box-decoration-break: clone;
24
32
  box-decoration-break: clone;
25
33
  }
34
+
35
+ /* 语气落在根上而不是每个 mark 上:命中片段有好几个,用哪族颜色是整段的属性。
36
+ 使用者槽排在语气之前:写死了 mark 的底与字色,六族语气一并让位 */
37
+ [data-scope='highlight'][data-part='root'][data-tone] [data-part='mark'] {
38
+ background: var(--xh-highlight-mark-bg, var(--xh-_tone-subtle));
39
+ color: var(--xh-highlight-mark-fg, var(--xh-_tone-fg));
40
+ }
26
41
  }
@@ -1,29 +1,12 @@
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
+ /* 定义 hover card 样式。 */
20
7
 
21
- to {
22
- opacity: 0;
23
- scale: var(--xh-motion-scale-enter);
24
- }
25
- }
26
- }
8
+ /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立。 */
9
+ @import '../family/motion.css';
27
10
 
28
11
  @layer xihan.components {
29
12
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
@@ -56,9 +39,10 @@
56
39
  display: none;
57
40
  }
58
41
 
59
- [data-scope='hover-card'][data-part='trigger']:focus-visible {
60
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
61
- outline-offset: var(--xh-ring-offset);
42
+ /* 这里的 data-disabled 关掉的是卡片,不是宿主控件:光标仍旧交给宿主 */
43
+ [data-scope='hover-card'][data-part='root'][data-disabled],
44
+ [data-scope='hover-card'][data-part='trigger'][data-disabled] {
45
+ cursor: inherit;
62
46
  }
63
47
 
64
48
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
@@ -66,12 +50,15 @@
66
50
  /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,内容层继承它限高;
67
51
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
68
52
  --xh-_hover-card-available-h: 100vh;
53
+ /* 落定那一侧的可用宽度,同样由定位引擎经内联自定义属性写进来,行内轴据此夹取;
54
+ 引擎没算(尚未落位 / 无引擎 / 贴边归零)时退到视口宽 */
55
+ --xh-_hover-card-available-w: 100vw;
69
56
 
70
57
  /* 卡片内容的自绘条浮在内容之上:轨道不上底色,实色轨道会在卡片右缘糊一条竖灰带 */
71
58
  --xh-scrollbar-track-bg: transparent;
72
59
 
73
60
  position: fixed;
74
- z-index: var(--xh-hover-card-layer, var(--xh-layer-popover));
61
+ z-index: var(--xh-hover-card-layer, var(--xh-_layer, var(--xh-layer-popover)));
75
62
  /* 空壳不吃指针:trigger 与 content 之间那段间隙要能点得穿,
76
63
  指针穿行的判定全靠 content 自己的进出事件 */
77
64
  pointer-events: none;
@@ -82,13 +69,35 @@
82
69
  visibility: hidden;
83
70
  }
84
71
 
72
+ /* 缩放原点与进场位移按落定的那一侧给:卡片从贴着锚点的那条边涨开、沿主轴退让一小段。
73
+ 两个槽由 content 继承。placement 是物理方向(引擎按 top / right / bottom / left 出值),
74
+ origin 与 translate 也是物理量,两边同轴,不随书写方向翻 */
75
+ [data-scope='hover-card'][data-part='positioner'][data-placement^='top'] {
76
+ --xh-_overlay-origin-y: 100%;
77
+ --xh-_overlay-enter-down: 1;
78
+ }
79
+
80
+ [data-scope='hover-card'][data-part='positioner'][data-placement^='bottom'] {
81
+ --xh-_overlay-origin-y: 0;
82
+ --xh-_overlay-enter-up: 1;
83
+ }
84
+
85
+ [data-scope='hover-card'][data-part='positioner'][data-placement^='left'] {
86
+ --xh-_overlay-origin-x: 100%;
87
+ --xh-_overlay-enter-right: 1;
88
+ }
89
+
90
+ [data-scope='hover-card'][data-part='positioner'][data-placement^='right'] {
91
+ --xh-_overlay-origin-x: 0;
92
+ --xh-_overlay-enter-left: 1;
93
+ }
94
+
85
95
  /* 与 tooltip 不同:卡片本体承载交互,必须吃指针——
86
96
  指针停在卡片上就不该收起,里面的链接与按钮也要点得到 */
87
97
  [data-scope='hover-card'][data-part='content'] {
88
98
  /* 尺寸档只换这两个私有槽。size 落在 content 上而非 root:root 是可选部件,
89
99
  面板几何也长在 content 上。语气不接:卡片是内容容器,语气该由里面的内容表达 */
90
- --xh-_hover-card-py: var(--xh-space-3);
91
- --xh-_hover-card-px: var(--xh-control-px-md);
100
+ --xh-_hover-card-pad: var(--xh-surface-pad-md);
92
101
  --xh-_hover-card-max-w: var(--xh-overlay-max-w);
93
102
 
94
103
  position: relative;
@@ -96,18 +105,32 @@
96
105
  flex-direction: column;
97
106
  gap: var(--xh-hover-card-gap, var(--xh-space-2));
98
107
  inline-size: max-content;
99
- max-inline-size: var(--xh-hover-card-max-w, var(--xh-_hover-card-max-w));
108
+ /* 静态档与落位后的可用宽度取小:窄视口下面板伸出去,最右侧的内容就点不到了 */
109
+ max-inline-size: min(var(--xh-hover-card-max-w, var(--xh-_hover-card-max-w)), var(--xh-_hover-card-available-w));
100
110
  /* 内容由作者给,长度不可预知:不限高就整块伸出视口且滚不到 */
101
111
  max-block-size: min(var(--xh-hover-card-max-h, var(--xh-overlay-max-h)), var(--xh-_hover-card-available-h));
102
112
  overflow-y: auto;
103
- padding-block: var(--xh-hover-card-py, var(--xh-_hover-card-py));
104
- padding-inline: var(--xh-hover-card-px, var(--xh-_hover-card-px));
105
- border: var(--xh-stroke-thin) solid var(--xh-hover-card-border, var(--xh-border-default));
106
- border-radius: var(--xh-hover-card-radius, var(--xh-shape-surface));
107
- background: var(--xh-hover-card-bg, var(--xh-bg-surface));
108
- color: var(--xh-hover-card-fg, var(--xh-fg-default));
109
- box-shadow: var(--xh-hover-card-shadow, var(--xh-elevation-floating));
113
+ /* 浮在页面之上的 Overlay 滚动面(§6.6):滚到头不把页面一起带走 */
114
+ overscroll-behavior: contain;
115
+ padding-block: var(--xh-hover-card-py, var(--xh-_hover-card-pad));
116
+ padding-inline: var(--xh-hover-card-px, var(--xh-_hover-card-pad));
117
+ border: var(--xh-stroke-thin) solid var(--xh-hover-card-border, var(--xh-material-frosted-border));
118
+ border-radius: var(--xh-hover-card-radius, var(--xh-shape-overlay));
119
+ /* 与气泡族共用 M2:顶光只占一像素,正文保持实体,只在内容层采样一次背景。 */
120
+ background:
121
+ linear-gradient(
122
+ to bottom,
123
+ var(--xh-material-frosted-highlight) 0 var(--xh-stroke-thin),
124
+ transparent var(--xh-stroke-thin)
125
+ ),
126
+ var(--xh-hover-card-bg, var(--xh-material-frosted-bg));
127
+ color: var(--xh-hover-card-fg, var(--xh-material-frosted-fg));
128
+ box-shadow: var(--xh-hover-card-shadow, var(--xh-material-frosted-shadow));
129
+ -webkit-backdrop-filter: var(--xh-hover-card-backdrop, var(--xh-material-frosted-backdrop));
130
+ backdrop-filter: var(--xh-hover-card-backdrop, var(--xh-material-frosted-backdrop));
110
131
  pointer-events: auto;
132
+ /* 进退场的缩放锚在贴着锚点的那条边上;两个分量由 positioner 按 placement 写进私有槽 */
133
+ transform-origin: var(--xh-_overlay-origin-x, 50%) var(--xh-_overlay-origin-y, 50%);
111
134
  }
112
135
 
113
136
  /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 dialog 一致:
@@ -122,7 +145,9 @@
122
145
  }
123
146
 
124
147
  [data-scope='hover-card'][data-part='content'][data-state='open'] {
125
- animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
148
+ animation: xh-overlay-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
149
+ /* 只在开着的这一档挂:合成层随 data-state 一起收走,收起后不再占着 */
150
+ will-change: opacity, scale, translate;
126
151
  }
127
152
 
128
153
  /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
@@ -132,20 +157,31 @@
132
157
  }
133
158
 
134
159
  /* —— 尺寸 —— */
135
- /* 缺省档写在 content 的基础规则里;行内内缩本就取 control-px 那把尺,上下各挪一档,
136
- 纵向内缩按 space 档同步 */
160
+ /* 缺省档写在 content 的基础规则里;四边等宽的面板内衬三档取 surface-pad 那把尺 */
137
161
  [data-scope='hover-card'][data-part='content'][data-size='sm'] {
138
- --xh-_hover-card-py: var(--xh-space-2);
139
- --xh-_hover-card-px: var(--xh-control-px-sm);
162
+ --xh-_hover-card-pad: var(--xh-surface-pad-sm);
140
163
  --xh-_hover-card-max-w: var(--xh-overlay-max-w-sm);
141
164
  }
142
165
 
143
166
  [data-scope='hover-card'][data-part='content'][data-size='lg'] {
144
- --xh-_hover-card-py: var(--xh-space-4);
145
- --xh-_hover-card-px: var(--xh-control-px-lg);
167
+ --xh-_hover-card-pad: var(--xh-surface-pad-lg);
146
168
  --xh-_hover-card-max-w: var(--xh-overlay-max-w-lg);
147
169
  }
148
170
 
171
+ [data-scope='hover-card'][data-part='title'] {
172
+ margin: 0;
173
+ font-size: var(--xh-hover-card-title-font-size, var(--xh-text-label-size));
174
+ font-weight: var(--xh-hover-card-title-font-weight, var(--xh-font-weight-semibold));
175
+ color: var(--xh-hover-card-title-fg, var(--xh-fg-default));
176
+ }
177
+
178
+ /* 说明文字走说明档(§6.4):13px + fg-muted */
179
+ [data-scope='hover-card'][data-part='description'] {
180
+ margin: 0;
181
+ font-size: var(--xh-hover-card-description-font-size, var(--xh-text-secondary-size));
182
+ color: var(--xh-hover-card-description-fg, var(--xh-fg-muted));
183
+ }
184
+
149
185
  /* 箭头的底色与描边色,几何在 overlay-arrow.css。
150
186
  交叉轴落点由定位引擎经内联自定义属性写进来,没给时退回居中 */
151
187
  [data-scope='hover-card'][data-part='arrow'] {
@@ -155,7 +191,21 @@
155
191
  --xh-_overlay-arrow-x: var(--xh-_hover-card-arrow-x);
156
192
  --xh-_overlay-arrow-y: var(--xh-_hover-card-arrow-y);
157
193
 
158
- background: var(--xh-hover-card-bg, var(--xh-bg-surface));
159
- border: var(--xh-stroke-thin) solid var(--xh-hover-card-border, var(--xh-border-default));
194
+ background: var(--xh-hover-card-bg, var(--xh-material-frosted-bg));
195
+ border: var(--xh-stroke-thin) solid var(--xh-hover-card-border, var(--xh-material-frosted-border));
196
+ }
197
+
198
+ @media (forced-colors: active) {
199
+ [data-scope='hover-card'][data-part='content'] {
200
+ background-image: none;
201
+ }
202
+ }
203
+
204
+ @media print {
205
+ /* 打印:定位层与遮罩是交互期才存在的东西,落到纸上只会盖住底下的正文。
206
+ 收起写在这份皮肤里而不是 reset:reset 层排在组件层之前,组件层里任何一条 display 都压得住它。 */
207
+ [data-scope='hover-card'][data-part='positioner'] {
208
+ display: none;
209
+ }
160
210
  }
161
211
  }
@@ -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
+ /* 定义 icon wrapper 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='icon-wrapper'] {
@@ -10,7 +17,8 @@
10
17
  /* 私有槽位:底座直径与图元直径,换档只改这两个 */
11
18
  --xh-_icon-wrapper-size: var(--xh-icon-wrapper-size, var(--xh-control-h-md));
12
19
 
13
- /* 流给里面的图元;图元自己写了档位时仍按自己的档走 */
20
+ /* 流给里面的图元——包括自己写了档位的那一枚,它的档位取值也读这个槽,
21
+ 图元直径因此始终跟着底座换档 */
14
22
  --xh-icon-size: var(--xh-icon-wrapper-glyph-size, var(--xh-glyph-size-md));
15
23
 
16
24
  display: inline-flex;
@@ -20,7 +28,7 @@
20
28
  inline-size: var(--xh-_icon-wrapper-size);
21
29
  block-size: var(--xh-_icon-wrapper-size);
22
30
  border: var(--xh-stroke-thin) solid transparent;
23
- border-radius: var(--xh-icon-wrapper-radius, var(--xh-shape-pill));
31
+ border-radius: var(--xh-icon-wrapper-radius, var(--xh-shape-circle));
24
32
  background: var(--xh-icon-wrapper-bg, var(--xh-bg-subtle));
25
33
  color: var(--xh-icon-wrapper-fg, var(--xh-fg-default));
26
34
  line-height: var(--xh-leading-none);
@@ -33,10 +41,14 @@
33
41
  }
34
42
 
35
43
  /* —— 形态 —— */
36
- /* 形态只决定颜色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的品牌/中性配色 */
44
+ /* 形态只决定颜色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的品牌/中性配色。
45
+ 实心档还在顶边画一条极浅的内高光,把这块底座衬出厚度;另外三档面上没有实心底,不画 */
37
46
  [data-scope='icon-wrapper'][data-part='root'][data-variant='solid'] {
47
+ --xh-_icon-wrapper-highlight: var(--xh-_highlight-tone);
48
+
38
49
  background: var(--xh-_tone, var(--xh-bg-brand));
39
50
  color: var(--xh-_tone-on, var(--xh-fg-on-brand));
51
+ box-shadow: var(--xh-icon-wrapper-shadow, var(--xh-_icon-wrapper-highlight));
40
52
  }
41
53
 
42
54
  [data-scope='icon-wrapper'][data-part='root'][data-variant='subtle'] {
package/css/icon.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
+ /* 定义 icon 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='icon'] {
@@ -30,24 +37,56 @@
30
37
  display: none;
31
38
  }
32
39
 
33
- /* 三档直径,缺省档写在上面的基础规则里 */
40
+ /* 八档直径,缺省档 md 写在上面的基础规则里。
41
+ 每一档都把 --xh-icon-size 排在自己的档值前面:这个槽是外层统一图元直径的通道,
42
+ 档值直接写终值的话,写了 data-size 的那一枚就脱离外层控制,作者在祖先上的覆盖也改不动它 */
43
+ [data-scope='icon'][data-part='root'][data-size='text'] {
44
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
45
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
46
+ }
47
+
34
48
  [data-scope='icon'][data-part='root'][data-size='sm'] {
35
- inline-size: var(--xh-glyph-size-sm);
36
- block-size: var(--xh-glyph-size-sm);
49
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-sm));
50
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-sm));
51
+ }
52
+
53
+ [data-scope='icon'][data-part='root'][data-size='md'] {
54
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
55
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
37
56
  }
38
57
 
39
58
  [data-scope='icon'][data-part='root'][data-size='lg'] {
40
- inline-size: var(--xh-glyph-size-lg);
41
- block-size: var(--xh-glyph-size-lg);
59
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-lg));
60
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-lg));
61
+ }
62
+
63
+ [data-scope='icon'][data-part='root'][data-size='xl'] {
64
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-xl));
65
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-xl));
66
+ }
67
+
68
+ [data-scope='icon'][data-part='root'][data-size='2xl'] {
69
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-2xl));
70
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-2xl));
71
+ }
72
+
73
+ [data-scope='icon'][data-part='root'][data-size='3xl'] {
74
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-3xl));
75
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-3xl));
42
76
  }
43
77
 
44
- /* 三档描边,缺省档同样写在基础规则里 */
78
+ [data-scope='icon'][data-part='root'][data-size='4xl'] {
79
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-4xl));
80
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-4xl));
81
+ }
82
+
83
+ /* 三档描边,缺省档同样写在基础规则里;--xh-icon-stroke 同样排在档值前面 */
45
84
  [data-scope='icon'][data-part='root'][data-weight='light'] {
46
- stroke-width: var(--xh-glyph-stroke-light);
85
+ stroke-width: var(--xh-icon-stroke, var(--xh-glyph-stroke-light));
47
86
  }
48
87
 
49
88
  [data-scope='icon'][data-part='root'][data-weight='bold'] {
50
- stroke-width: var(--xh-glyph-stroke-bold);
89
+ stroke-width: var(--xh-icon-stroke, var(--xh-glyph-stroke-bold));
51
90
  }
52
91
 
53
92
  /* 语气:图标没有底色,语气只落在前景上,取普通背景上表达该语气的那档文字色。
@@ -56,4 +95,31 @@
56
95
  [data-scope='icon'][data-part='root'][data-tone] {
57
96
  color: var(--xh-icon-fg, var(--xh-_tone-fg, currentColor));
58
97
  }
98
+
99
+ /* 旋转:四分之一圈的整数倍,是把箭头指向别处的结构性角度,不是可调幅度。
100
+ 没有过渡也没有动画——转到位就停在那儿,减弱动效那一档碰不到它 */
101
+ [data-scope='icon'][data-part='root'][data-rotate='90'] {
102
+ rotate: 90deg;
103
+ }
104
+
105
+ [data-scope='icon'][data-part='root'][data-rotate='180'] {
106
+ rotate: 180deg;
107
+ }
108
+
109
+ [data-scope='icon'][data-part='root'][data-rotate='270'] {
110
+ rotate: 270deg;
111
+ }
112
+
113
+ /* 翻转:沿轴取反,同样是静态几何。与旋转是两个独立属性,同写时自然叠加 */
114
+ [data-scope='icon'][data-part='root'][data-flip='horizontal'] {
115
+ scale: -1 1;
116
+ }
117
+
118
+ [data-scope='icon'][data-part='root'][data-flip='vertical'] {
119
+ scale: 1 -1;
120
+ }
121
+
122
+ [data-scope='icon'][data-part='root'][data-flip='both'] {
123
+ scale: -1 -1;
124
+ }
59
125
  }