@xihan-ui/styles 2.0.0 → 3.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 (156) hide show
  1. package/CHANGELOG.md +1328 -0
  2. package/README.md +6 -1
  3. package/component-tokens.d.ts +505 -111
  4. package/components.tokens.json +34750 -26291
  5. package/css/accordion.css +39 -13
  6. package/css/alert.css +61 -3
  7. package/css/anchor.css +49 -11
  8. package/css/approval.css +124 -84
  9. package/css/avatar-group.css +1 -1
  10. package/css/avatar.css +13 -5
  11. package/css/back-top.css +63 -44
  12. package/css/badge.css +63 -13
  13. package/css/bar-code.css +1 -1
  14. package/css/breadcrumb.css +63 -4
  15. package/css/button-group.css +5 -5
  16. package/css/button.css +69 -21
  17. package/css/calendar-picker.css +27 -8
  18. package/css/calendar-range-picker.css +48 -11
  19. package/css/card.css +116 -2
  20. package/css/carousel.css +153 -48
  21. package/css/cartesian-chart.css +830 -0
  22. package/css/cascader.css +184 -70
  23. package/css/checkbox-group.css +69 -99
  24. package/css/checkbox.css +21 -54
  25. package/css/citation.css +470 -0
  26. package/css/clipboard.css +23 -66
  27. package/css/code-view.css +103 -8
  28. package/css/collapsible.css +37 -11
  29. package/css/color-field.css +18 -0
  30. package/css/color-picker.css +57 -62
  31. package/css/color-slider.css +26 -19
  32. package/css/color-swatch-picker.css +8 -6
  33. package/css/combobox.css +82 -37
  34. package/css/command.css +48 -48
  35. package/css/context-menu.css +43 -28
  36. package/css/date-field.css +23 -0
  37. package/css/date-picker.css +57 -24
  38. package/css/date-range-picker.css +301 -14
  39. package/css/description.css +17 -1
  40. package/css/descriptions.css +43 -1
  41. package/css/dialog.css +99 -43
  42. package/css/diff-view.css +101 -16
  43. package/css/download-trigger.css +46 -80
  44. package/css/drawer.css +168 -133
  45. package/css/editable.css +19 -0
  46. package/css/empty-state.css +8 -7
  47. package/css/field-array.css +36 -0
  48. package/css/field.css +17 -19
  49. package/css/fieldset.css +1 -1
  50. package/css/file-upload.css +126 -136
  51. package/css/flex.css +324 -8
  52. package/css/float-button.css +168 -41
  53. package/css/floating-panel.css +59 -27
  54. package/css/form.css +26 -20
  55. package/css/funnel-chart.css +106 -0
  56. package/css/graph-chart.css +205 -0
  57. package/css/grid-list.css +235 -0
  58. package/css/grid.css +252 -1
  59. package/css/heatmap.css +119 -36
  60. package/css/hierarchy-chart.css +298 -0
  61. package/css/hover-card.css +33 -18
  62. package/css/icon.css +100 -0
  63. package/css/image-cropper.css +34 -8
  64. package/css/image-viewer.css +169 -26
  65. package/css/image.css +23 -4
  66. package/css/infinite-scroll.css +2 -2
  67. package/css/input-group.css +13 -15
  68. package/css/json-viewer.css +55 -7
  69. package/css/kbd.css +1 -1
  70. package/css/layout.css +71 -21
  71. package/css/liquid.css +106 -0
  72. package/css/list.css +2 -2
  73. package/css/listbox.css +72 -23
  74. package/css/loading-bar.css +27 -13
  75. package/css/log.css +131 -35
  76. package/css/markdown-stream.css +1 -1
  77. package/css/marquee.css +163 -7
  78. package/css/matrix-code.css +1 -1
  79. package/css/mention.css +35 -21
  80. package/css/menu.css +40 -28
  81. package/css/menubar.css +42 -28
  82. package/css/message-feed.css +174 -53
  83. package/css/navigation-menu.css +177 -18
  84. package/css/notification.css +431 -110
  85. package/css/number-field.css +22 -0
  86. package/css/page-header.css +4 -2
  87. package/css/pagination.css +129 -29
  88. package/css/password-input.css +40 -8
  89. package/css/pie-chart.css +247 -0
  90. package/css/popconfirm.css +50 -58
  91. package/css/popover.css +55 -21
  92. package/css/progress.css +308 -10
  93. package/css/prompt-input.css +37 -1
  94. package/css/question-flow.css +104 -64
  95. package/css/radar-chart.css +233 -0
  96. package/css/radio-group.css +372 -14
  97. package/css/rating.css +25 -27
  98. package/css/reasoning.css +62 -55
  99. package/css/reset.css +1 -1
  100. package/css/resizable.css +6 -1
  101. package/css/sankey-chart.css +174 -0
  102. package/css/scroll-area.css +32 -0
  103. package/css/scrollbar.css +1 -1
  104. package/css/select.css +76 -59
  105. package/css/side-nav.css +177 -30
  106. package/css/signature-pad.css +23 -8
  107. package/css/skeleton.css +13 -14
  108. package/css/slider.css +39 -17
  109. package/css/sortable.css +38 -8
  110. package/css/sparkline.css +164 -0
  111. package/css/spinner.css +50 -22
  112. package/css/splitter.css +8 -2
  113. package/css/statistic.css +10 -0
  114. package/css/steps.css +257 -38
  115. package/css/switch.css +30 -55
  116. package/css/table.css +168 -128
  117. package/css/tabs.css +243 -31
  118. package/css/tag-group.css +65 -37
  119. package/css/tag.css +55 -14
  120. package/css/tags-input.css +40 -3
  121. package/css/text-field.css +19 -0
  122. package/css/time-field.css +20 -1
  123. package/css/time-picker.css +44 -17
  124. package/css/time-range-picker.css +45 -18
  125. package/css/timeline.css +1 -1
  126. package/css/toggle-group.css +8 -8
  127. package/css/toggle.css +6 -5
  128. package/css/tool-call.css +64 -56
  129. package/css/toolbar.css +105 -7
  130. package/css/tooltip.css +18 -7
  131. package/css/tour.css +49 -21
  132. package/css/transfer.css +104 -81
  133. package/css/tree-select.css +235 -58
  134. package/css/tree.css +240 -147
  135. package/css/truncate.css +55 -12
  136. package/css/typography.css +93 -0
  137. package/css/virtualizer.css +57 -1
  138. package/css/watermark.css +23 -0
  139. package/family/action-control.css +14 -5
  140. package/family/chart.css +480 -0
  141. package/family/check-mark.css +94 -0
  142. package/family/choice-card.css +97 -0
  143. package/family/collection-item.css +70 -27
  144. package/family/field-chrome.css +1 -12
  145. package/family/loading-ring.css +95 -0
  146. package/family/material.css +72 -0
  147. package/family/menu-choice.css +56 -0
  148. package/family/motion.css +208 -11
  149. package/family/tag-list.css +59 -0
  150. package/index.css +23363 -14091
  151. package/index.unlayered.css +23198 -13922
  152. package/package.json +20 -8
  153. package/css/gradient-text.css +0 -91
  154. package/css/icon-wrapper.css +0 -81
  155. package/css/segmented.css +0 -280
  156. package/css/toast.css +0 -499
@@ -14,7 +14,7 @@
14
14
  /* 缺省态(md 档)。等宽字体让层级缩进与值的长度对得齐。
15
15
  逐类型配色走 --xh-syntax-* 语法令牌,与代码块的记号色同源、随主题明暗切换。 */
16
16
  [data-scope='json-viewer'][data-part='root'] {
17
- /* 作者放进空态格里的图标按档取尺,缺省 md,随 data-size 换档(§6.5)。
17
+ /* 作者放进空态格里的图标按档取尺,缺省 md,随 data-size 换档。
18
18
  查看器自绘的状态字形(分支行首的展开方向 chevron)不读这支:它是指示符,与所在的把手盒同走
19
19
  --xh-control-indicator-* 一族——branch-trigger 在自己身上把 --xh-icon-size 改接到盒的尺 */
20
20
  --xh-icon-size: var(--xh-json-viewer-icon-size, var(--xh-glyph-size-md));
@@ -35,7 +35,7 @@
35
35
  display: none;
36
36
  }
37
37
 
38
- /* 面画在两档容器与空态格上,root 只是壳。三档按 §8.3 边界三选一:outline 即基础规则
38
+ /* 面画在两档容器与空态格上,root 只是壳。三档按边界三选一:outline 即基础规则
39
39
  (--xh-border-default 描边 + surface 底 + 无影);淡底档描边透明、底换 subtle;
40
40
  无框档边框留着但透明——去掉外框不会让行的位置跳一格 */
41
41
  [data-scope='json-viewer'][data-part='root'][data-variant='subtle']
@@ -66,7 +66,7 @@
66
66
  }
67
67
 
68
68
  /* 常驻容器不是浮层:两轴都可能溢出——深层缩进往行首方向推、长字符串往行尾伸;
69
- 页内结构容器走 reset 层的原生细条(§6.6),不写 overscroll */
69
+ 页内结构容器走 reset 层的原生细条,不写 overscroll */
70
70
  [data-scope='json-viewer'][data-part='tree'] {
71
71
  display: flex;
72
72
  flex-direction: column;
@@ -133,7 +133,7 @@
133
133
  padding-inline: var(--xh-json-viewer-row-px, var(--xh-space-1));
134
134
  border-radius: var(--xh-json-viewer-row-radius, var(--xh-shape-inset));
135
135
  white-space: nowrap;
136
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
136
+ transition: background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
137
137
  }
138
138
 
139
139
  [data-scope='json-viewer'][data-part='item'][hidden],
@@ -154,7 +154,7 @@
154
154
  user-select: none;
155
155
  }
156
156
 
157
- /* 按下只换面不缩放:白底承载 hover 100 → pressed 200(§7.2 / §9.2 集合行不允许零反馈);
157
+ /* 按下只换面不缩放:白底承载 hover 100 → pressed 200(集合行不允许零反馈);
158
158
  指针按住由 :active 表出,Space / Enter 与触屏按住由 Headless 投影 data-pressed,三种输入同一副面 */
159
159
  [data-scope='json-viewer'][data-part='branch-control']:not([data-disabled]):is(:active, [data-pressed]) {
160
160
  background: var(--xh-json-viewer-row-bg-active, var(--xh-bg-subtle-hover));
@@ -214,7 +214,7 @@
214
214
  }
215
215
 
216
216
  /* 展开箭头与勾选标记同宽,两种行的文字起点才对得齐。
217
- 盒里的 chevron 是指示符(§6.5):与盒同边长,--xh-icon-size 在自己身上改接到盒的尺——
217
+ 盒里的 chevron 是指示符:与盒同边长,--xh-icon-size 在自己身上改接到盒的尺——
218
218
  root 那支只管作者图标的 --xh-json-viewer-icon-size 不流进来,按图标档取的 20px 会比 16px 的盒还大;
219
219
  branch-indicator 由适配器固定渲染在这颗把手里,继承即可 */
220
220
  [data-scope='json-viewer'][data-part='branch-trigger'] {
@@ -235,7 +235,7 @@
235
235
  [data-scope='json-viewer'][data-part='branch-indicator'] {
236
236
  display: inline-block;
237
237
  line-height: var(--xh-leading-none);
238
- transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter-strong);
238
+ transition: rotate var(--xh-motion-duration-nudge) var(--xh-motion-ease-enter-strong);
239
239
  }
240
240
 
241
241
  [data-scope='json-viewer'][data-part='branch-indicator'][hidden] {
@@ -311,6 +311,23 @@
311
311
  display: none;
312
312
  }
313
313
 
314
+ /*
315
+ * 搜索命中的那一段:与 Highlight 的命中片段同一身份(品牌淡底 + 品牌深字),浏览器给 mark 的固定亮黄不随主题走。
316
+ * 在命中之间逐个走时停住的那一行(data-current),片段换成品牌实心,一眼分得出「现在停在哪」。
317
+ */
318
+ [data-scope='json-viewer'][data-part='mark'] {
319
+ border-radius: var(--xh-json-viewer-mark-radius, var(--xh-shape-inset));
320
+ background: var(--xh-json-viewer-mark-bg, var(--xh-bg-brand-subtle));
321
+ color: var(--xh-json-viewer-mark-fg, var(--xh-fg-brand-strong));
322
+ }
323
+
324
+ [data-scope='json-viewer'][data-part='branch'][data-current] > [data-scope='json-viewer'][data-part='branch-control'] > [data-scope='json-viewer'][data-part='branch-text'] > [data-scope='json-viewer'][data-part='mark'],
325
+ [data-scope='json-viewer'][data-part='item'][data-current] > [data-scope='json-viewer'][data-part='item-key'] > [data-scope='json-viewer'][data-part='mark'],
326
+ [data-scope='json-viewer'][data-part='item'][data-current] > [data-scope='json-viewer'][data-part='item-value'] > [data-scope='json-viewer'][data-part='mark'] {
327
+ background: var(--xh-json-viewer-mark-bg-current, var(--xh-bg-brand));
328
+ color: var(--xh-json-viewer-mark-fg-current, var(--xh-fg-on-brand));
329
+ }
330
+
314
331
  /*
315
332
  * 高对比档:分支行的按压面常态靠底色深一档表出,这一档里底色被统一换成 Canvas,
316
333
  * 按住那一下与静息塌成同一个样子;用系统高亮反色画回来,行里的键名、摘要与箭头跟着换成反色前景
@@ -321,6 +338,18 @@
321
338
  color: HighlightText;
322
339
  }
323
340
 
341
+ /* 系统色下底色统一成 Canvas:命中片段改画一圈正文色的框,停住的那一条换成系统高亮 */
342
+ [data-scope='json-viewer'][data-part='mark'] {
343
+ outline: var(--xh-stroke-thin) solid CanvasText;
344
+ }
345
+
346
+ [data-scope='json-viewer'][data-part='branch'][data-current] > [data-scope='json-viewer'][data-part='branch-control'] > [data-scope='json-viewer'][data-part='branch-text'] > [data-scope='json-viewer'][data-part='mark'],
347
+ [data-scope='json-viewer'][data-part='item'][data-current] > [data-scope='json-viewer'][data-part='item-key'] > [data-scope='json-viewer'][data-part='mark'],
348
+ [data-scope='json-viewer'][data-part='item'][data-current] > [data-scope='json-viewer'][data-part='item-value'] > [data-scope='json-viewer'][data-part='mark'] {
349
+ background: Highlight;
350
+ color: HighlightText;
351
+ }
352
+
324
353
  [data-scope='json-viewer'][data-part='branch-control']:not([data-disabled]):is(:active, [data-pressed]) [data-scope='json-viewer'][data-part='branch-text'],
325
354
  [data-scope='json-viewer'][data-part='branch-control']:not([data-disabled]):is(:active, [data-pressed]) [data-scope='json-viewer'][data-part='branch-text']::after,
326
355
  [data-scope='json-viewer'][data-part='branch-control']:not([data-disabled]):is(:active, [data-pressed]) [data-scope='json-viewer'][data-part='preview'],
@@ -328,4 +357,23 @@
328
357
  color: HighlightText;
329
358
  }
330
359
  }
360
+
361
+ @media (forced-colors: active) {
362
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
363
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
364
+ 分支行上取 CanvasText,按下时整行涂成 Highlight、字形换 HighlightText;
365
+ 禁用取 GrayText */
366
+ [data-scope='json-viewer'][data-part='branch-indicator']:empty::before {
367
+ forced-color-adjust: none;
368
+ background-color: CanvasText;
369
+ }
370
+
371
+ [data-scope='json-viewer'][data-part='branch-control']:not([data-disabled]):is(:active, [data-pressed]) [data-scope='json-viewer'][data-part='branch-indicator']:empty::before {
372
+ background-color: HighlightText;
373
+ }
374
+
375
+ [data-scope='json-viewer'][data-part='branch-control'][data-disabled] [data-scope='json-viewer'][data-part='branch-indicator']:empty::before {
376
+ background-color: GrayText;
377
+ }
378
+ }
331
379
  }
package/css/kbd.css CHANGED
@@ -25,7 +25,7 @@
25
25
  background: var(--xh-kbd-bg, var(--xh-bg-subtle));
26
26
  color: var(--xh-kbd-fg, var(--xh-fg-muted));
27
27
  font-family: var(--xh-kbd-font, inherit);
28
- /* 快捷键是次级标注,字号取 caption 档(§6.4) */
28
+ /* 快捷键是次级标注,字号取 caption 档 */
29
29
  font-size: var(--xh-kbd-font-size, var(--xh-text-caption-size));
30
30
  font-weight: var(--xh-kbd-font-weight, var(--xh-font-weight-medium));
31
31
  line-height: var(--xh-leading-none);
package/css/layout.css CHANGED
@@ -18,7 +18,7 @@
18
18
  缺哪一段,对应的行/列就没有条目,宽高自动收成 0,不必为"少写一段"另立规则。
19
19
 
20
20
  侧栏两档宽度与头的高度声明在根上:各段自己读这些槽,换档只改这里。
21
- 宽度槽用 -w 缩写,与同处的 --xh-layout-header-h 一致。
21
+ 宽度槽用 -w 缩写,与同处的 --xh-layout-header-h 一致;两档宽度的缺省取侧栏令牌 --xh-sider-w / --xh-sider-collapsed-w。
22
22
  头的高度之所以也归到根上:头吸顶时头这一行的轨道要按同一个值定高,两处必须同源。 */
23
23
  [data-scope='layout'][data-part='root'] {
24
24
  display: grid;
@@ -30,9 +30,9 @@
30
30
  grid-template-rows: auto minmax(0, 1fr) auto;
31
31
  background: var(--xh-layout-bg, var(--xh-bg-page));
32
32
  color: var(--xh-layout-fg, var(--xh-fg-default));
33
- --xh-_layout-sider-expanded-w: var(--xh-layout-sider-w, 15rem);
33
+ --xh-_layout-sider-expanded-w: var(--xh-layout-sider-w, var(--xh-sider-w));
34
34
  --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
35
- --xh-_layout-sider-collapsed-w: var(--xh-layout-sider-collapsed-w, 4rem);
35
+ --xh-_layout-sider-collapsed-w: var(--xh-layout-sider-collapsed-w, var(--xh-sider-collapsed-w));
36
36
  --xh-_layout-header-h: var(--xh-layout-header-h, 3.5rem);
37
37
  /* 侧栏吸附时钉在哪条线上:缺省贴滚动容器上沿,头也吸顶时改成让开头的高度 */
38
38
  --xh-_layout-sider-offset: 0px;
@@ -92,18 +92,20 @@
92
92
  }
93
93
 
94
94
  /* 宽度过渡在这里声明一次,展开与折叠两档、以及 props 直接写进内联的宽度,走的都是这一条。
95
- 占位档的侧栏是淡底承载面:把手摆进来时由它下发 hover 200 → pressed 300(§7.2);
95
+ 占位档的侧栏是淡底承载面:把手摆进来时由它下发 hover 200 → pressed 300;
96
96
  覆盖档换成 elevated 白底,那一档的规则把阶梯写回 100 → 200 */
97
97
  [data-scope='layout'][data-part='sider'] {
98
98
  --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
99
99
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
100
+ /* 内衬缺省一档,装了 SideNav 的侧栏在下面归零;覆盖档与安全区取大时读的也是这一支 */
101
+ --xh-_layout-sider-padding: var(--xh-space-3);
100
102
 
101
103
  grid-area: sider;
102
104
  inline-size: var(--xh-_layout-sider-w);
103
105
  overflow: hidden;
104
- padding: var(--xh-layout-sider-padding, var(--xh-space-3));
106
+ padding: var(--xh-layout-sider-padding, var(--xh-_layout-sider-padding));
105
107
  background: var(--xh-layout-sider-bg, var(--xh-bg-subtle));
106
- transition: inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous);
108
+ transition: inline-size var(--xh-motion-duration-move) var(--xh-motion-ease-continuous);
107
109
  }
108
110
 
109
111
  /* 折起来时不换行:窄到放不下的那几个字直接被 overflow 裁掉,不会挤成一列竖排 */
@@ -112,6 +114,19 @@
112
114
  white-space: nowrap;
113
115
  }
114
116
 
117
+ /* 侧栏里装着 SideNav 时内衬缺省归零:SideNav 自带一圈内衬,宽度又与侧栏同取侧栏令牌,
118
+ 再叠一圈侧栏内衬,导航就比侧栏的内容盒宽出两侧内衬、右缘被裁掉。
119
+ 认后代而不是子代:Web Components 在侧栏与导航根之间隔着 <xh-side-nav> 宿主。
120
+ 不认 :has() 的引擎(Firefox 121 以前)照旧留内衬,导航右缘被裁,与改动前一致 */
121
+ [data-scope='layout'][data-part='sider']:has([data-scope='side-nav'][data-part='root']) {
122
+ --xh-_layout-sider-padding: 0;
123
+ }
124
+
125
+ /* 侧栏里的 SideNav 跟着侧栏收放:侧栏这一次开合直接落位(首帧、跨过断点)时,导航的宽度同样直接落位 */
126
+ [data-scope='layout'][data-part='sider'][data-instant] [data-scope='side-nav'][data-part='root'] {
127
+ transition: none;
128
+ }
129
+
115
130
  [data-scope='layout'][data-part='content'] {
116
131
  grid-area: content;
117
132
  /* 内容列已是 minmax(0, 1fr),这里再声明一次,宽表格与长串文本才撑不破列 */
@@ -189,6 +204,23 @@
189
204
  inset-block-start: 0;
190
205
  }
191
206
 
207
+ /* liquid 档:吸顶的顶栏是内容从下面滚过的导航层,换成液态面。贴边铺满的栏不取圆角,
208
+ 边界由下沿那条墨色细线承担。液态面是墨色域,前景在这里按域重取,子孙跟着继承。
209
+ 滚过深浅分界时色调翻转:底色、字色、细线与投影一起淡变,不在同一帧跳 */
210
+ :where([data-material='liquid']) [data-scope='layout'][data-part='header'][data-fixed][data-xh-liquid] {
211
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-material-liquid-border));
212
+ background: var(--xh-layout-header-bg, var(--xh-_liquid-bg));
213
+ color: var(--xh-material-liquid-fg);
214
+ box-shadow: var(--xh-_liquid-shadow);
215
+ -webkit-backdrop-filter: var(--xh-material-liquid-backdrop);
216
+ backdrop-filter: var(--xh-material-liquid-backdrop);
217
+ transition:
218
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
219
+ border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
220
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
221
+ box-shadow var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
222
+ }
223
+
192
224
  /* 头也吸顶时侧栏钉在头的下沿,两段不叠在一起 */
193
225
  [data-scope='layout'][data-part='root'][data-header-fixed][data-sider-fixed] {
194
226
  --xh-_layout-sider-offset: var(--xh-_layout-header-h);
@@ -215,11 +247,11 @@
215
247
  参照的是视口,与上面 sticky 那条同一个注意事项:整副骨架装进带 transform / filter 的祖先里时,
216
248
  固定定位的包含块会换成那个祖先,面板跟着一起滚。 */
217
249
  [data-scope='layout'][data-part='sider'][data-presentation='sheet'] {
218
- /* 位移方向的私有槽位:默认按行首 + LTR,行尾与 RTL 在下面翻符号。
219
- 写成槽位而不是写死 ±100%:贴边用的是逻辑 inset,RTL 下行首落在物理右边,
250
+ /* 位移方向的私有槽位:默认按行首 + LTR,行尾与 RTL 在下面翻符号。幅度取整幅位移令牌,
251
+ 减弱动效下归零。写成槽位而不是写死物理方向:贴边用的是逻辑 inset,RTL 下行首落在物理右边,
220
252
  位移若写死物理方向就会出现「贴在右边、却从左边滑进来」 */
221
- --xh-_layout-sheet-shift: -100%;
222
- /* 这一档的底是 elevated 白底:交互阶梯按承载面走(§7.2),把上面占位档下发的 200 → 300 写回
253
+ --xh-_layout-sheet-shift: calc(-1 * var(--xh-motion-travel));
254
+ /* 这一档的底是 elevated 白底:交互阶梯按承载面走,把上面占位档下发的 200 → 300 写回
223
255
  白底的 hover 100 → pressed 200 */
224
256
  --xh-action-host-bg-hover: var(--xh-bg-subtle);
225
257
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-hover);
@@ -238,14 +270,14 @@
238
270
  /* 贴死视口的那一档,内衬与安全区取大的一头:刘海、圆角与底部横条压住的那一段由系统给出。
239
271
  桌面上 env() 恒为 0,取值与内衬槽完全一致。安全区只有物理方向的四个名字,
240
272
  行内轴上两侧同取较宽的那一段,RTL 下不会翻错边 */
241
- padding-block-start: max(var(--xh-layout-sider-padding, var(--xh-space-3)), env(safe-area-inset-top));
242
- padding-block-end: max(var(--xh-layout-sider-padding, var(--xh-space-3)), env(safe-area-inset-bottom));
273
+ padding-block-start: max(var(--xh-layout-sider-padding, var(--xh-_layout-sider-padding)), env(safe-area-inset-top));
274
+ padding-block-end: max(var(--xh-layout-sider-padding, var(--xh-_layout-sider-padding)), env(safe-area-inset-bottom));
243
275
  padding-inline: max(
244
- var(--xh-layout-sider-padding, var(--xh-space-3)),
276
+ var(--xh-layout-sider-padding, var(--xh-_layout-sider-padding)),
245
277
  env(safe-area-inset-left),
246
278
  env(safe-area-inset-right)
247
279
  );
248
- /* 盖在内容之上、带遮罩的一面走 sheet 三件套(§8.4:--xh-material-elevated-bg / -border / -shadow),
280
+ /* 盖在内容之上、带遮罩的一面走 sheet 三件套(--xh-material-elevated-bg / -border / -shadow),
249
281
  贴着内容那一侧描一条边;占位档的侧栏不画投影 */
250
282
  border-inline-end: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-material-elevated-border));
251
283
  background: var(--xh-layout-sider-bg, var(--xh-material-elevated-bg));
@@ -256,16 +288,19 @@
256
288
  overscroll 不在这里写 contain:这一面与占位档共用同一个部件,scroll-surface-registry 把侧栏整体登记为
257
289
  页内结构容器(overscroll=false),门禁按整个部件核,不按档分 */
258
290
  overflow-y: auto;
259
- /* 推出来与收进去是同一段行程,视口尺度的位移走 slide 档。
260
- visibility 与它同拍:收起那一路等位移播完才真正藏起来,展开那一路立刻露出来 */
291
+ /* 推出来走 slide 档:视口尺度的位移。并列的不透明度取淡变档:
292
+ 缺省两端都是不透明、看不出来,减弱动效下整幅位移归零、由它表达进出。
293
+ visibility 展开那一路立刻露出来 */
294
+ opacity: 1;
261
295
  transition:
262
296
  translate var(--xh-motion-duration-slide) var(--xh-motion-ease-slide),
297
+ opacity var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
263
298
  visibility var(--xh-motion-duration-slide) var(--xh-motion-ease-slide);
264
299
  }
265
300
 
266
301
  /* 挂在行尾:贴另一条边,位移随之反向,描边也换到贴着内容的那一侧 */
267
302
  [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-placement='end'] {
268
- --xh-_layout-sheet-shift: 100%;
303
+ --xh-_layout-sheet-shift: var(--xh-motion-travel);
269
304
 
270
305
  inset-inline-start: auto;
271
306
  inset-inline-end: 0;
@@ -274,18 +309,24 @@
274
309
  }
275
310
 
276
311
  [data-scope='layout'][data-part='sider'][data-presentation='sheet']:dir(rtl) {
277
- --xh-_layout-sheet-shift: 100%;
312
+ --xh-_layout-sheet-shift: var(--xh-motion-travel);
278
313
  }
279
314
 
280
315
  [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-placement='end']:dir(rtl) {
281
- --xh-_layout-sheet-shift: -100%;
316
+ --xh-_layout-sheet-shift: calc(-1 * var(--xh-motion-travel));
282
317
  }
283
318
 
284
319
  /* 收起:推出画外并让出无障碍树与 Tab 序列。位移量按面板自身宽度的百分比算,
285
- 宽度换成任何一档都正好推到画外 */
320
+ 宽度换成任何一档都正好推到画外。收进去是退场,位移与淡出同走退场档,
321
+ visibility 等这一段播完才真正藏起来;减弱动效下位移归零,只剩淡出 */
286
322
  [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-collapsed] {
287
323
  translate: var(--xh-_layout-sheet-shift) 0;
324
+ opacity: var(--xh-motion-travel-opacity);
288
325
  visibility: hidden;
326
+ transition:
327
+ translate var(--xh-motion-duration-exit) var(--xh-motion-ease-exit),
328
+ opacity var(--xh-motion-duration-exit) var(--xh-motion-ease-exit),
329
+ visibility var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
289
330
  }
290
331
 
291
332
  /* 覆盖档的遮罩:与面板同一个层号,谁盖谁看文档序——遮罩写在侧栏之前。
@@ -299,10 +340,19 @@
299
340
  transition: opacity var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
300
341
  }
301
342
 
302
- /* 收起态:淡出并让开指针,底下的内容照常点得到 */
343
+ /* 收起态:淡出并让开指针,底下的内容照常点得到;淡出走退场档 */
303
344
  [data-scope='layout'][data-part='sider-backdrop'][data-collapsed] {
304
345
  opacity: 0;
305
346
  pointer-events: none;
347
+ transition: opacity var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
348
+ }
349
+
350
+ /* 侧栏与遮罩的过渡只给用户的开合:首帧与跨过断点这类环境引起的开合,连接层投影 data-instant,
351
+ 直接落位。三条各压过同一部件上带过渡的那一档(占位 / 覆盖展开、覆盖收起、遮罩收起) */
352
+ [data-scope='layout']:is([data-part='sider'], [data-part='sider-backdrop'])[data-instant],
353
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-collapsed][data-instant],
354
+ [data-scope='layout'][data-part='sider-backdrop'][data-collapsed][data-instant] {
355
+ transition: none;
306
356
  }
307
357
 
308
358
  /* 纸上没有覆盖这回事:遮罩印出来就是盖住正文的一片灰 */
package/css/liquid.css ADDED
@@ -0,0 +1,106 @@
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
+ /*
7
+ * 液态材质层:与组件无关,全库共用一份。
8
+ *
9
+ * data-material="liquid" 下,连接层投影了 data-xh-liquid 的导航层部件(浮动钮、回到顶部等浮在内容之上的控制面)
10
+ * 换成液态面。这里只声明私有槽,各组件皮肤在自己的部件上把 Action Control 的桥接槽指过来;standard 档下
11
+ * 这些槽没人读,部件保持原材质。
12
+ *
13
+ * 静态形态(服务端、挂载前,或液态面还没判定下层):色调随主题极性,不透明度取可读下限,这一档对任何
14
+ * 下层都保证标签 4.5:1。组件的状态机把部件挂进 core 的液态面,由它按下层在部件上写:
15
+ * data-xh-ink dark / light:部件成为黑墨或白墨域。墨色域本身是浅色 / 深色主题边界,
16
+ * 按主题取值的液态通道随之落到那一种色调
17
+ * data-xh-liquid-clarity clear:下层均匀且色调已知,换通透档
18
+ * --xh-_liquid-light-x / -y 光源方向的单位向量,决定 1px 亮边落在哪一侧
19
+ * --xh-_liquid-deform 按住时的形变(transform 串),松手弹回后撤掉
20
+ *
21
+ * 同一宿主里的几块可以结成液态组(core 的 trackLiquidGoo):宿主带 data-xh-liquid-goo,最前面多一层
22
+ * [data-xh-liquid-goo-layer] 色块层,沿整组的外形画底色、墨色细线、亮边与投影;组件皮肤在这一档把块自己的
23
+ * 面、细线、亮边与投影撤掉,只留磨砂。
24
+ */
25
+ @layer xihan.components {
26
+ :where([data-material='liquid']) [data-xh-liquid] {
27
+ /* 光源缺省在左上方 */
28
+ --xh-_liquid-light-x: -0.71;
29
+ --xh-_liquid-light-y: -0.71;
30
+ --xh-_liquid-bg: var(--xh-material-liquid-bg);
31
+ /* 1px 亮边是两层零模糊内阴影:阴影形状朝背光方向偏移,露出的一弯落在朝光源的一侧,
32
+ 另一层反过来偏移,在背光一侧留一道弱亮边。面内不加高光 */
33
+ --xh-_liquid-rim:
34
+ inset calc(var(--xh-_liquid-light-x) * var(--xh-stroke-thin) * -1) calc(var(--xh-_liquid-light-y) * var(--xh-stroke-thin) * -1) 0 0 var(--xh-material-liquid-highlight),
35
+ inset calc(var(--xh-_liquid-light-x) * var(--xh-stroke-thin)) calc(var(--xh-_liquid-light-y) * var(--xh-stroke-thin)) 0 0 var(--xh-material-liquid-rim-far);
36
+ --xh-_liquid-shadow: var(--xh-_liquid-rim), var(--xh-material-liquid-shadow);
37
+ /* 交互阶梯往部件自己的前景色兑:浅色调变深、深色调变浅 */
38
+ --xh-_liquid-bg-hover: color-mix(in oklab, var(--xh-_liquid-bg), var(--xh-material-liquid-fg) 8%);
39
+ --xh-_liquid-bg-pressed: color-mix(in oklab, var(--xh-_liquid-bg), var(--xh-material-liquid-fg) 14%);
40
+ /* 按住时的黏滞形变:液态面在手指按住期间逐帧写进来(朝手指鼓出、沿指向拉长、另一个方向压扁),
41
+ 松手由弹簧带回后撤掉;组件皮肤拿它当 transform。没按住时为 none */
42
+ --xh-_liquid-deform: none;
43
+ }
44
+
45
+ /* 通透档:下层均匀且色调已知时由液态面写上,着色按主题取值,已随墨色域落到对应色调 */
46
+ :where([data-material='liquid']) [data-xh-liquid][data-xh-liquid-clarity='clear'] {
47
+ --xh-_liquid-bg: color-mix(in oklab, var(--xh-material-liquid-tint) calc(var(--xh-material-liquid-alpha-clear) * 100%), transparent);
48
+ }
49
+
50
+ /* 液态组的色块层:core 在宿主最前面生成(aria-hidden、不接指针),压在各块之下,每块一个色块,
51
+ 跟着块的盒子、圆角与变换走。色块层套 core 放在它旁边的粘连滤镜(行内 filter),滤镜只取色块的轮廓,
52
+ 把靠得够近的连成一片,再沿整体外形画液态面:投影、底色、墨色细线、朝光亮边与背光弱亮边,颜色都在下面
53
+ 按段取液态令牌,投影由色块自己带着、滤镜只留外形之外的那部分。色调(墨色域)与通透档由 core 按源块的
54
+ 读数同步到色块层与装滤镜的 <svg> 上。
55
+ 色块层不设层号,靠排在宿主最前压在各块之下:宿主须是定位元素,组里的块须是定位元素(或装在定位容器里)。
56
+ 层往外多铺一圈,给模糊与投影留出余地。组件可以在自己的宿主上改写投影槽,把使用者的投影槽接进来 */
57
+ [data-xh-liquid-goo-layer] {
58
+ --xh-_liquid-goo-shadow: var(--xh-material-liquid-shadow);
59
+
60
+ position: absolute;
61
+ inset: calc(-1 * var(--xh-space-8));
62
+ pointer-events: none;
63
+ }
64
+
65
+ /* 色块提供轮廓与投影,底色由滤镜铺 */
66
+ [data-xh-liquid-goo-layer] > span {
67
+ position: absolute;
68
+ box-sizing: border-box;
69
+ background-color: var(--xh-material-liquid-tint);
70
+ box-shadow: var(--xh-_liquid-goo-shadow);
71
+ }
72
+
73
+ [data-xh-liquid-goo-filter] [data-xh-goo-paint='fill'] {
74
+ flood-color: var(--xh-material-liquid-tint);
75
+ flood-opacity: var(--xh-material-liquid-alpha-floor);
76
+ }
77
+
78
+ [data-xh-liquid-goo-filter][data-xh-liquid-clarity='clear'] [data-xh-goo-paint='fill'] {
79
+ flood-opacity: var(--xh-material-liquid-alpha-clear);
80
+ }
81
+
82
+ [data-xh-liquid-goo-filter] [data-xh-goo-paint='edge'] {
83
+ flood-color: var(--xh-material-liquid-border);
84
+ }
85
+
86
+ [data-xh-liquid-goo-filter] [data-xh-goo-paint='near'] {
87
+ flood-color: var(--xh-material-liquid-highlight);
88
+ }
89
+
90
+ [data-xh-liquid-goo-filter] [data-xh-goo-paint='far'] {
91
+ flood-color: var(--xh-material-liquid-rim-far);
92
+ }
93
+
94
+ /* 强制色:系统配色下只留块自己的边,装饰色块撤掉 */
95
+ @media (forced-colors: active) {
96
+ [data-xh-liquid-goo-layer] {
97
+ display: none;
98
+ }
99
+ }
100
+
101
+ /* 从右往左排版时光源缺省在右上方 */
102
+ :where([dir='rtl']) :where([data-material='liquid']) [data-xh-liquid],
103
+ :where([data-material='liquid']) :where([dir='rtl']) [data-xh-liquid] {
104
+ --xh-_liquid-light-x: 0.71;
105
+ }
106
+ }
package/css/list.css CHANGED
@@ -19,7 +19,7 @@
19
19
  --xh-_list-item-gap: var(--xh-space-3);
20
20
  --xh-_list-title-size: var(--xh-control-font-md);
21
21
  --xh-_list-description-size: var(--xh-control-caption-md);
22
- /* 条目悬停换到的面:坐在白底上是 100,淡底档的根把它抬到 200(§7.2 按承载面的阶梯) */
22
+ /* 条目悬停换到的面:坐在白底上是 100,淡底档的根把它抬到 200(按承载面的阶梯) */
23
23
  --xh-_list-item-bg-hover: var(--xh-bg-subtle);
24
24
 
25
25
  display: flex;
@@ -91,7 +91,7 @@
91
91
  }
92
92
 
93
93
  [data-scope='list'][data-part='root'][data-hoverable] > [data-scope='list'][data-part='item'] {
94
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
94
+ transition: background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
95
95
  }
96
96
 
97
97
  /* 悬停换底色:只在能用指针的设备上生效,触摸端不留一个按不掉的悬停态 */