@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/kbd.css ADDED
@@ -0,0 +1,72 @@
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
+ /* 定义 kbd 样式。 */
7
+
8
+ @layer xihan.components {
9
+ [data-scope='kbd'] {
10
+ --xh-kbd-skin: 1;
11
+ }
12
+
13
+ /* 单键和组合键共用一个整体表面,不模拟按钮按下状态。 */
14
+ [data-scope='kbd'][data-part='root'] {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ gap: var(--xh-kbd-gap, var(--xh-space-1));
19
+ box-sizing: border-box;
20
+ block-size: var(--xh-kbd-h, var(--xh-space-6));
21
+ min-inline-size: var(--xh-kbd-min-w, var(--xh-space-6));
22
+ padding-inline: var(--xh-kbd-px, var(--xh-space-2));
23
+ border: var(--xh-stroke-thin) solid var(--xh-kbd-border, transparent);
24
+ border-radius: var(--xh-kbd-radius, var(--xh-shape-control));
25
+ background: var(--xh-kbd-bg, var(--xh-bg-subtle));
26
+ color: var(--xh-kbd-fg, var(--xh-fg-muted));
27
+ font-family: var(--xh-kbd-font, inherit);
28
+ /* 快捷键是次级标注,字号取 caption 档(§6.4) */
29
+ font-size: var(--xh-kbd-font-size, var(--xh-text-caption-size));
30
+ font-weight: var(--xh-kbd-font-weight, var(--xh-font-weight-medium));
31
+ line-height: var(--xh-leading-none);
32
+ text-align: center;
33
+ text-decoration: none;
34
+ white-space: nowrap;
35
+ direction: ltr;
36
+ unicode-bidi: isolate;
37
+ }
38
+
39
+ [data-scope='kbd'][data-part='root'][data-variant='light'] {
40
+ background: transparent;
41
+ }
42
+
43
+ [data-scope='kbd'][data-part='key'] {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ min-inline-size: 0;
48
+ padding: 0;
49
+ border: 0;
50
+ background: transparent;
51
+ color: inherit;
52
+ font: inherit;
53
+ line-height: inherit;
54
+ }
55
+
56
+ [data-scope='kbd'][data-part='root'][data-disabled] {
57
+ color: var(--xh-kbd-fg-disabled, var(--xh-fg-disabled));
58
+ }
59
+
60
+ [data-scope='kbd'][data-part='root'][hidden],
61
+ [data-scope='kbd'][data-part='key'][hidden] {
62
+ display: none;
63
+ }
64
+
65
+ @media (forced-colors: active) {
66
+ [data-scope='kbd'][data-part='root']:not([data-variant='light']) {
67
+ border-color: ButtonText;
68
+ background: Canvas;
69
+ color: CanvasText;
70
+ }
71
+ }
72
+ }
package/css/label.css ADDED
@@ -0,0 +1,78 @@
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
+ * 字段族标签的公共层,按 [data-part='label'] 匹配下面逐个列出的 scope。
8
+ *
9
+ * 收在这里的是逐值相同的四条:行距取 --xh-leading-none,禁用档字色取 --xh-fg-subtle,
10
+ * 必填星号取 --xh-glyph-mark-required + --xh-space-1 + --xh-fg-danger,无效档字色取 --xh-fg-danger。
11
+ * 字色、字号、字重三条留在各组件皮肤——它们挂着 --xh-<组件>-label-* 覆盖槽,
12
+ * 槽名里带组件名,写不进一条共享规则。
13
+ *
14
+ * scope 逐个列出,不写成 [data-scope][data-part='label']:label 这个部件名在标签、
15
+ * 统计、进度、推理、说明列表上指的是另一种文字(行内省略的标签正文、环内居中的数字、
16
+ * 描述项的名字),通配规则会把行距按到它们头上。要接进来的组件把 scope 加进列表。
17
+ *
18
+ * 选择器停在两个属性(0,2,0)或三个属性(0,3,0),与组件皮肤同级;引入顺序排在全部组件皮肤之前,
19
+ * 要另写行距的组件照写即可压过。
20
+ */
21
+ @layer xihan.components {
22
+ /* 标签是单行短文,行距不留额外的行间空白,标签与控件之间只剩容器给的那一道间距。 */
23
+ [data-scope='checkbox'][data-part='label'],
24
+ [data-scope='checkbox-group'][data-part='label'],
25
+ [data-scope='color-picker'][data-part='label'],
26
+ [data-scope='date-field'][data-part='label'],
27
+ [data-scope='editable'][data-part='label'],
28
+ [data-scope='field'][data-part='label'],
29
+ [data-scope='file-upload'][data-part='label'],
30
+ [data-scope='number-field'][data-part='label'],
31
+ [data-scope='password-input'][data-part='label'],
32
+ [data-scope='pin-input'][data-part='label'],
33
+ [data-scope='radio-group'][data-part='label'],
34
+ [data-scope='rating'][data-part='label'],
35
+ [data-scope='signature-pad'][data-part='label'],
36
+ [data-scope='slider'][data-part='label'],
37
+ [data-scope='switch'][data-part='label'],
38
+ [data-scope='tags-input'][data-part='label'],
39
+ [data-scope='text-field'][data-part='label'],
40
+ [data-scope='time-field'][data-part='label'] {
41
+ line-height: var(--xh-leading-none);
42
+ }
43
+
44
+ /*
45
+ * 禁用档的字色:公共层默认统一 --xh-fg-subtle。这四家没有 --xh-<组件>-label-fg-disabled 覆盖槽,
46
+ * 取值只有这一处;挂了那个槽的组件在各自皮肤里另写一条,排在本份之后,压过这里。
47
+ */
48
+ [data-scope='color-picker'][data-part='label'][data-disabled],
49
+ [data-scope='rating'][data-part='label'][data-disabled],
50
+ [data-scope='signature-pad'][data-part='label'][data-disabled],
51
+ [data-scope='slider'][data-part='label'][data-disabled] {
52
+ color: var(--xh-fg-subtle);
53
+ }
54
+
55
+ /*
56
+ * 必填星号:跟着标签自己的 data-required 亮,选填不标。字形、间距、颜色是公共层规则,
57
+ * 自带标签的字段不得各画一套。
58
+ *
59
+ * 接入 = connect 在标签部件投影 data-required + 把 scope 加进这张列表;控件本体不画。
60
+ * 有 --xh-<组件>-label-star 覆盖槽的组件在各自皮肤里只另写一条 color 压过这里(field 的
61
+ * --xh-field-label-star、fieldset 的 --xh-fieldset-legend-star),content 与间距不再重写。
62
+ */
63
+ [data-scope='field'][data-part='label'][data-required]::after,
64
+ [data-scope='fieldset'][data-part='legend'][data-required]::after {
65
+ content: var(--xh-glyph-mark-required);
66
+ margin-inline-start: var(--xh-space-1);
67
+ color: var(--xh-fg-danger);
68
+ }
69
+
70
+ /*
71
+ * 无效档的字色:标签跟着自己的 data-invalid 转警示色,没渲染错误文案的字段上这是唯一变化的东西。
72
+ * 有 --xh-<组件>-label-fg-invalid 覆盖槽的组件在各自皮肤里另写一条 color 压过这里。
73
+ */
74
+ [data-scope='field'][data-part='label'][data-invalid],
75
+ [data-scope='fieldset'][data-part='legend'][data-invalid] {
76
+ color: var(--xh-fg-danger);
77
+ }
78
+ }
package/css/layers.css CHANGED
@@ -1,2 +1,7 @@
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
+
1
6
  /* 库层序单一真源:级联顺序由首次声明决定,与 @import 顺序解耦。 */
2
7
  @layer xihan.reset, xihan.tokens, xihan.motion, xihan.components, xihan.overrides;
package/css/layout.css CHANGED
@@ -1,3 +1,13 @@
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
+ /* 定义 layout 样式。 */
7
+
8
+ /* 独立皮肤传递引入折叠把手的动作控件配方,full bundle 递归去重。 */
9
+ @import '../family/action-control.css';
10
+
1
11
  @layer xihan.components {
2
12
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
13
  [data-scope='layout'] {
@@ -8,6 +18,7 @@
8
18
  缺哪一段,对应的行/列就没有条目,宽高自动收成 0,不必为"少写一段"另立规则。
9
19
 
10
20
  侧栏两档宽度与头的高度声明在根上:各段自己读这些槽,换档只改这里。
21
+ 宽度槽用 -w 缩写,与同处的 --xh-layout-header-h 一致。
11
22
  头的高度之所以也归到根上:头吸顶时头这一行的轨道要按同一个值定高,两处必须同源。 */
12
23
  [data-scope='layout'][data-part='root'] {
13
24
  display: grid;
@@ -17,15 +28,49 @@
17
28
  'footer footer';
18
29
  grid-template-columns: auto minmax(0, 1fr);
19
30
  grid-template-rows: auto minmax(0, 1fr) auto;
20
- background: var(--xh-layout-bg, var(--xh-bg-canvas));
31
+ background: var(--xh-layout-bg, var(--xh-bg-page));
21
32
  color: var(--xh-layout-fg, var(--xh-fg-default));
22
- --xh-_layout-sider-w: var(--xh-layout-sider-width, 15rem);
23
- --xh-_layout-sider-collapsed-w: var(--xh-layout-sider-collapsed-width, 4rem);
33
+ --xh-_layout-sider-expanded-w: var(--xh-layout-sider-w, 15rem);
34
+ --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
35
+ --xh-_layout-sider-collapsed-w: var(--xh-layout-sider-collapsed-w, 4rem);
24
36
  --xh-_layout-header-h: var(--xh-layout-header-h, 3.5rem);
25
37
  /* 侧栏吸附时钉在哪条线上:缺省贴滚动容器上沿,头也吸顶时改成让开头的高度 */
26
38
  --xh-_layout-sider-offset: 0px;
27
39
  }
28
40
 
41
+ /* —— 侧栏断点 —— */
42
+ /* 写了断点档就先按窄屏排(折叠宽),视口宽到那一档再还原成展开宽。
43
+ 移动优先、四档只用 min-width:媒体查询不改选择器权重,同时命中好几档时由源码序决定谁生效。
44
+ 宽度写字面量:自定义属性在 @media 条件里不参与求值,令牌变量写在这里等于没写条件。
45
+ 换的只是宽度,折叠态不动——那条通道归 siderCollapsed。 */
46
+ [data-scope='layout'][data-part='root'][data-sider-breakpoint] {
47
+ --xh-_layout-sider-w: var(--xh-_layout-sider-collapsed-w);
48
+ }
49
+
50
+ @media (min-width: 640px) {
51
+ [data-scope='layout'][data-part='root'][data-sider-breakpoint='sm'] {
52
+ --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
53
+ }
54
+ }
55
+
56
+ @media (min-width: 768px) {
57
+ [data-scope='layout'][data-part='root'][data-sider-breakpoint='md'] {
58
+ --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
59
+ }
60
+ }
61
+
62
+ @media (min-width: 1024px) {
63
+ [data-scope='layout'][data-part='root'][data-sider-breakpoint='lg'] {
64
+ --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
65
+ }
66
+ }
67
+
68
+ @media (min-width: 1280px) {
69
+ [data-scope='layout'][data-part='root'][data-sider-breakpoint='xl'] {
70
+ --xh-_layout-sider-w: var(--xh-_layout-sider-expanded-w);
71
+ }
72
+ }
73
+
29
74
  /* 侧栏挂到行尾:两列对调,内容在前 */
30
75
  [data-scope='layout'][data-part='root'][data-sider-placement='end'] {
31
76
  grid-template-areas:
@@ -46,14 +91,19 @@
46
91
  background: var(--xh-layout-header-bg, var(--xh-bg-surface));
47
92
  }
48
93
 
49
- /* 宽度过渡在这里声明一次,展开与折叠两档、以及 props 直接写进内联的宽度,走的都是这一条 */
94
+ /* 宽度过渡在这里声明一次,展开与折叠两档、以及 props 直接写进内联的宽度,走的都是这一条。
95
+ 占位档的侧栏是淡底承载面:把手摆进来时由它下发 hover 200 → pressed 300(§7.2);
96
+ 覆盖档换成 elevated 白底,那一档的规则把阶梯写回 100 → 200 */
50
97
  [data-scope='layout'][data-part='sider'] {
98
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
99
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
100
+
51
101
  grid-area: sider;
52
102
  inline-size: var(--xh-_layout-sider-w);
53
103
  overflow: hidden;
54
104
  padding: var(--xh-layout-sider-padding, var(--xh-space-3));
55
105
  background: var(--xh-layout-sider-bg, var(--xh-bg-subtle));
56
- transition: inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
106
+ transition: inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous);
57
107
  }
58
108
 
59
109
  /* 折起来时不换行:窄到放不下的那几个字直接被 overflow 裁掉,不会挤成一列竖排 */
@@ -78,47 +128,38 @@
78
128
  }
79
129
 
80
130
  /* —— 折叠把手 —— */
131
+ /* 一枚小档文字按钮:盒型、悬停 / 按下面与按压缩放由 Action Control 的 text 档给(ghost 形态,sm 档:
132
+ 摆在顶栏等白底上按画布承载 hover 100 → pressed 200,摆进占位档侧栏时由侧栏下发 host 槽 200 → 300,
133
+ 覆盖档侧栏是 elevated 白底、仍是 100 → 200);
134
+ 这里只把使用者槽映射到桥接槽(-gap / -px / -radius / -bg / -bg-hover / -bg-active / -fg 保留为第一参数) */
81
135
  [data-scope='layout'][data-part='sider-trigger'] {
82
- display: inline-flex;
83
- align-items: center;
84
- justify-content: center;
85
- gap: var(--xh-layout-sider-trigger-gap, var(--xh-control-gap-sm));
86
- block-size: var(--xh-control-h-sm);
87
- padding-inline: var(--xh-layout-sider-trigger-px, var(--xh-control-px-sm));
88
- border: 0;
89
- border-radius: var(--xh-layout-sider-trigger-radius, var(--xh-shape-control));
90
- background: var(--xh-layout-sider-trigger-bg, transparent);
91
- color: var(--xh-layout-sider-trigger-fg, var(--xh-fg-default));
92
- font-size: var(--xh-text-secondary-size);
93
- line-height: var(--xh-leading-none);
94
- cursor: pointer;
95
- }
96
-
97
- [data-scope='layout'][data-part='sider-trigger']:hover {
98
- background: var(--xh-layout-sider-trigger-bg-hover, var(--xh-bg-subtle-hover));
99
- }
100
-
101
- [data-scope='layout'][data-part='sider-trigger']:focus-visible {
102
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
103
- outline-offset: var(--xh-ring-offset);
136
+ --xh-action-gap: var(--xh-layout-sider-trigger-gap, var(--xh-_action-profile-gap));
137
+ --xh-action-padding-inline: var(--xh-layout-sider-trigger-px, var(--xh-_action-profile-padding-inline));
138
+ --xh-action-radius: var(--xh-layout-sider-trigger-radius, var(--xh-_action-profile-radius));
139
+ --xh-action-bg-rest: var(--xh-layout-sider-trigger-bg, var(--xh-_action-variant-bg-rest));
140
+ --xh-action-bg-hover: var(--xh-layout-sider-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
141
+ --xh-action-bg-pressed: var(--xh-layout-sider-trigger-bg-active, var(--xh-_action-variant-bg-pressed));
142
+ --xh-action-fg-rest: var(--xh-layout-sider-trigger-fg, var(--xh-_action-variant-fg-rest));
143
+ --xh-action-fg-hover: var(--xh-layout-sider-trigger-fg, var(--xh-_action-variant-fg-hover));
144
+ --xh-action-fg-pressed: var(--xh-layout-sider-trigger-fg, var(--xh-_action-variant-fg-pressed));
104
145
  }
105
146
 
106
147
  /* —— 分隔线 —— */
107
148
  /* 后代选择器带上 data-scope:骨架里装着整页内容,光凭 data-part 会连里面别的组件同名段一起画上线 */
108
- [data-scope='layout'][data-part='root'][data-bordered] [data-scope='layout'][data-part='header'] {
149
+ [data-scope='layout'][data-part='root'][data-split] [data-scope='layout'][data-part='header'] {
109
150
  border-block-end: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-border-default));
110
151
  }
111
152
 
112
- [data-scope='layout'][data-part='root'][data-bordered] [data-scope='layout'][data-part='footer'] {
153
+ [data-scope='layout'][data-part='root'][data-split] [data-scope='layout'][data-part='footer'] {
113
154
  border-block-start: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-border-default));
114
155
  }
115
156
 
116
157
  /* 侧栏只在挨着内容的那一边画线,另一边贴着骨架外沿,画了就是一条多出来的边框 */
117
- [data-scope='layout'][data-part='root'][data-bordered] [data-scope='layout'][data-part='sider'][data-placement='start'] {
158
+ [data-scope='layout'][data-part='root'][data-split] [data-scope='layout'][data-part='sider'][data-placement='start'] {
118
159
  border-inline-end: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-border-default));
119
160
  }
120
161
 
121
- [data-scope='layout'][data-part='root'][data-bordered] [data-scope='layout'][data-part='sider'][data-placement='end'] {
162
+ [data-scope='layout'][data-part='root'][data-split] [data-scope='layout'][data-part='sider'][data-placement='end'] {
122
163
  border-inline-start: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-border-default));
123
164
  }
124
165
 
@@ -168,6 +209,109 @@
168
209
  overflow-y: auto;
169
210
  }
170
211
 
212
+ /* —— 侧栏覆盖档 —— */
213
+ /* 侧栏移出画外、盖在内容之上:面板脱离网格,侧栏那一列于是收成零宽,内容占满整行。
214
+ 排在固定定位那一节之后:两处特指度相同,覆盖档要盖住 sticky 那一档。
215
+ 参照的是视口,与上面 sticky 那条同一个注意事项:整副骨架装进带 transform / filter 的祖先里时,
216
+ 固定定位的包含块会换成那个祖先,面板跟着一起滚。 */
217
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet'] {
218
+ /* 位移方向的私有槽位:默认按行首 + LTR,行尾与 RTL 在下面翻符号。
219
+ 写成槽位而不是写死 ±100%:贴边用的是逻辑 inset,RTL 下行首落在物理右边,
220
+ 位移若写死物理方向就会出现「贴在右边、却从左边滑进来」 */
221
+ --xh-_layout-sheet-shift: -100%;
222
+ /* 这一档的底是 elevated 白底:交互阶梯按承载面走(§7.2),把上面占位档下发的 200 → 300 写回
223
+ 白底的 hover 100 → pressed 200 */
224
+ --xh-action-host-bg-hover: var(--xh-bg-subtle);
225
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-hover);
226
+
227
+ position: fixed;
228
+ z-index: var(--xh-layout-sider-layer, var(--xh-layer-drawer));
229
+ inset-block: 0;
230
+ inset-inline-start: 0;
231
+ inset-inline-end: auto;
232
+ inline-size: var(--xh-_layout-sider-expanded-w);
233
+ /* 面板贴死上下两条边,高度上限就是滚动容器可视区那么高——上面 sticky 那一档的
234
+ 「减去顶栏偏移」在这一档不作数:覆盖档从视口顶铺到底。
235
+ 不认 dvh 的引擎由级联回落到前一条的 vh */
236
+ max-block-size: var(--xh-layout-scrollport-h, 100vh);
237
+ max-block-size: var(--xh-layout-scrollport-h, 100dvh);
238
+ /* 贴死视口的那一档,内衬与安全区取大的一头:刘海、圆角与底部横条压住的那一段由系统给出。
239
+ 桌面上 env() 恒为 0,取值与内衬槽完全一致。安全区只有物理方向的四个名字,
240
+ 行内轴上两侧同取较宽的那一段,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));
243
+ padding-inline: max(
244
+ var(--xh-layout-sider-padding, var(--xh-space-3)),
245
+ env(safe-area-inset-left),
246
+ env(safe-area-inset-right)
247
+ );
248
+ /* 盖在内容之上、带遮罩的一面走 sheet 三件套(§8.4:--xh-material-elevated-bg / -border / -shadow),
249
+ 贴着内容那一侧描一条边;占位档的侧栏不画投影 */
250
+ border-inline-end: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-material-elevated-border));
251
+ background: var(--xh-layout-sider-bg, var(--xh-material-elevated-bg));
252
+ box-shadow: var(--xh-layout-sider-shadow, var(--xh-material-elevated-shadow));
253
+ translate: 0 0;
254
+ visibility: visible;
255
+ /* 条目多到装不下时在面板内部滚:这一档的高度就是视口那么高。
256
+ overscroll 不在这里写 contain:这一面与占位档共用同一个部件,scroll-surface-registry 把侧栏整体登记为
257
+ 页内结构容器(overscroll=false),门禁按整个部件核,不按档分 */
258
+ overflow-y: auto;
259
+ /* 推出来与收进去是同一段行程,视口尺度的位移走 slide 档。
260
+ visibility 与它同拍:收起那一路等位移播完才真正藏起来,展开那一路立刻露出来 */
261
+ transition:
262
+ translate var(--xh-motion-duration-slide) var(--xh-motion-ease-slide),
263
+ visibility var(--xh-motion-duration-slide) var(--xh-motion-ease-slide);
264
+ }
265
+
266
+ /* 挂在行尾:贴另一条边,位移随之反向,描边也换到贴着内容的那一侧 */
267
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-placement='end'] {
268
+ --xh-_layout-sheet-shift: 100%;
269
+
270
+ inset-inline-start: auto;
271
+ inset-inline-end: 0;
272
+ border-inline-end: 0;
273
+ border-inline-start: var(--xh-stroke-thin) solid var(--xh-layout-border, var(--xh-material-elevated-border));
274
+ }
275
+
276
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet']:dir(rtl) {
277
+ --xh-_layout-sheet-shift: 100%;
278
+ }
279
+
280
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-placement='end']:dir(rtl) {
281
+ --xh-_layout-sheet-shift: -100%;
282
+ }
283
+
284
+ /* 收起:推出画外并让出无障碍树与 Tab 序列。位移量按面板自身宽度的百分比算,
285
+ 宽度换成任何一档都正好推到画外 */
286
+ [data-scope='layout'][data-part='sider'][data-presentation='sheet'][data-collapsed] {
287
+ translate: var(--xh-_layout-sheet-shift) 0;
288
+ visibility: hidden;
289
+ }
290
+
291
+ /* 覆盖档的遮罩:与面板同一个层号,谁盖谁看文档序——遮罩写在侧栏之前。
292
+ 占位档下连接层给它打 hidden,这里不必再管 */
293
+ [data-scope='layout'][data-part='sider-backdrop'] {
294
+ position: fixed;
295
+ z-index: var(--xh-layout-sider-backdrop-layer, var(--xh-layer-drawer));
296
+ inset: 0;
297
+ background: var(--xh-layout-sider-backdrop-bg, var(--xh-bg-overlay));
298
+ opacity: 1;
299
+ transition: opacity var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
300
+ }
301
+
302
+ /* 收起态:淡出并让开指针,底下的内容照常点得到 */
303
+ [data-scope='layout'][data-part='sider-backdrop'][data-collapsed] {
304
+ opacity: 0;
305
+ pointer-events: none;
306
+ }
307
+
308
+ /* 纸上没有覆盖这回事:遮罩印出来就是盖住正文的一片灰 */
309
+ @media print {
310
+ [data-scope='layout'][data-part='sider-backdrop'] {
311
+ display: none;
312
+ }
313
+ }
314
+
171
315
  /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
172
316
  写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
173
317
  [data-scope='layout'][data-part='root'][hidden],
package/css/list.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
+ /* 定义 list 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='list'] {
@@ -12,6 +19,8 @@
12
19
  --xh-_list-item-gap: var(--xh-space-3);
13
20
  --xh-_list-title-size: var(--xh-control-font-md);
14
21
  --xh-_list-description-size: var(--xh-control-caption-md);
22
+ /* 条目悬停换到的面:坐在白底上是 100,淡底档的根把它抬到 200(§7.2 按承载面的阶梯) */
23
+ --xh-_list-item-bg-hover: var(--xh-bg-subtle);
15
24
 
16
25
  display: flex;
17
26
  flex-direction: column;
@@ -41,10 +50,11 @@
41
50
  --xh-_list-item-px: var(--xh-list-item-px-lg);
42
51
  --xh-_list-item-gap: var(--xh-space-4);
43
52
  --xh-_list-title-size: var(--xh-control-font-lg);
53
+ --xh-_list-description-size: var(--xh-control-caption-lg);
44
54
  }
45
55
 
46
- /* —— 外框 —— */
47
- [data-scope='list'][data-part='root'][data-bordered] {
56
+ /* —— 形态:ghost 即基础规则,不画壳 —— */
57
+ [data-scope='list'][data-part='root'][data-variant='outline'] {
48
58
  border: var(--xh-stroke-thin) solid var(--xh-list-border, var(--xh-border-default));
49
59
  border-radius: var(--xh-list-radius, var(--xh-shape-surface));
50
60
  background: var(--xh-list-bg, var(--xh-bg-surface));
@@ -52,6 +62,17 @@
52
62
  overflow: hidden;
53
63
  }
54
64
 
65
+ /* 淡底档:底换成 subtle,描边留一圈透明边位,与 outline 同一几何;
66
+ 条目坐在淡底上,悬停面抬一档 */
67
+ [data-scope='list'][data-part='root'][data-variant='subtle'] {
68
+ --xh-_list-item-bg-hover: var(--xh-bg-subtle-hover);
69
+
70
+ border: var(--xh-stroke-thin) solid transparent;
71
+ border-radius: var(--xh-list-radius, var(--xh-shape-surface));
72
+ background: var(--xh-list-bg, var(--xh-bg-subtle));
73
+ overflow: hidden;
74
+ }
75
+
55
76
  /* —— 条目 —— */
56
77
  [data-scope='list'][data-part='item'] {
57
78
  display: flex;
@@ -76,7 +97,7 @@
76
97
  /* 悬停换底色:只在能用指针的设备上生效,触摸端不留一个按不掉的悬停态 */
77
98
  @media (hover: hover) {
78
99
  [data-scope='list'][data-part='root'][data-hoverable] > [data-scope='list'][data-part='item']:hover {
79
- background: var(--xh-list-item-bg-hover, var(--xh-bg-subtle-hover));
100
+ background: var(--xh-list-item-bg-hover, var(--xh-_list-item-bg-hover));
80
101
  }
81
102
  }
82
103