@xihan-ui/styles 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CHANGELOG.md +5146 -6
  2. package/README.md +22 -2
  3. package/component-tokens.d.ts +4212 -0
  4. package/component-tokens.js +2 -0
  5. package/components.tokens.json +80116 -0
  6. package/css/accordion.css +131 -75
  7. package/css/affix.css +16 -1
  8. package/css/alert.css +114 -67
  9. package/css/anchor.css +99 -27
  10. package/css/approval.css +461 -0
  11. package/css/avatar-group.css +14 -6
  12. package/css/avatar.css +33 -9
  13. package/css/back-top.css +103 -48
  14. package/css/badge.css +42 -14
  15. package/css/bar-code.css +62 -0
  16. package/css/breadcrumb.css +40 -21
  17. package/css/button-group.css +146 -24
  18. package/css/button.css +116 -99
  19. package/css/calendar-picker.css +448 -0
  20. package/css/calendar-range-picker.css +517 -0
  21. package/css/card.css +54 -77
  22. package/css/carousel.css +412 -68
  23. package/css/cascader.css +429 -246
  24. package/css/checkbox-group.css +225 -77
  25. package/css/checkbox.css +174 -37
  26. package/css/clipboard.css +266 -47
  27. package/css/code-view.css +279 -0
  28. package/css/collapsible.css +108 -63
  29. package/css/color-field.css +158 -0
  30. package/css/color-picker.css +172 -184
  31. package/css/color-slider.css +274 -0
  32. package/css/color-swatch-picker.css +243 -0
  33. package/css/color-swatch.css +35 -0
  34. package/css/combobox.css +267 -273
  35. package/css/command.css +399 -0
  36. package/css/context-menu.css +183 -108
  37. package/css/date-field.css +94 -121
  38. package/css/date-picker.css +486 -249
  39. package/css/date-range-picker.css +559 -0
  40. package/css/description.css +51 -0
  41. package/css/descriptions.css +133 -87
  42. package/css/dialog.css +247 -68
  43. package/css/diff-view.css +428 -0
  44. package/css/download-trigger.css +155 -46
  45. package/css/drawer.css +194 -111
  46. package/css/editable.css +172 -152
  47. package/css/empty-state.css +80 -11
  48. package/css/field-array.css +190 -0
  49. package/css/field.css +84 -31
  50. package/css/fieldset.css +51 -18
  51. package/css/file-upload.css +134 -36
  52. package/css/flex.css +20 -1
  53. package/css/float-button.css +238 -57
  54. package/css/floating-panel.css +173 -92
  55. package/css/focus.css +46 -0
  56. package/css/forced-colors.css +93 -0
  57. package/css/form.css +254 -77
  58. package/css/gradient-text.css +34 -10
  59. package/css/grid.css +516 -5
  60. package/css/heatmap.css +87 -29
  61. package/css/highlight.css +20 -5
  62. package/css/hover-card.css +97 -47
  63. package/css/icon-wrapper.css +15 -3
  64. package/css/icon.css +74 -8
  65. package/css/image-cropper.css +143 -29
  66. package/css/image-viewer.css +150 -89
  67. package/css/image.css +30 -1
  68. package/css/infinite-scroll.css +51 -1
  69. package/css/input-group.css +277 -0
  70. package/css/json-viewer.css +102 -45
  71. package/css/kbd.css +72 -0
  72. package/css/label.css +78 -0
  73. package/css/layers.css +5 -0
  74. package/css/layout.css +175 -31
  75. package/css/list.css +24 -3
  76. package/css/listbox.css +208 -67
  77. package/css/loading-bar.css +52 -3
  78. package/css/log.css +144 -9
  79. package/css/markdown-stream.css +149 -0
  80. package/css/marquee.css +27 -1
  81. package/css/masonry.css +7 -0
  82. package/css/matrix-code.css +67 -0
  83. package/css/mention.css +234 -152
  84. package/css/menu.css +180 -83
  85. package/css/menubar.css +204 -136
  86. package/css/message-feed.css +197 -0
  87. package/css/navigation-menu.css +144 -90
  88. package/css/notification.css +178 -100
  89. package/css/number-animation.css +7 -0
  90. package/css/number-field.css +120 -277
  91. package/css/overlay-arrow.css +12 -7
  92. package/css/page-header.css +99 -14
  93. package/css/pagination.css +175 -135
  94. package/css/password-input.css +222 -219
  95. package/css/pin-input.css +101 -67
  96. package/css/pointer.css +36 -0
  97. package/css/popconfirm.css +185 -94
  98. package/css/popover.css +121 -77
  99. package/css/progress.css +60 -12
  100. package/css/prompt-input.css +224 -0
  101. package/css/question-flow.css +513 -0
  102. package/css/radio-group.css +147 -30
  103. package/css/rating.css +193 -43
  104. package/css/reasoning.css +336 -0
  105. package/css/reset.css +84 -6
  106. package/css/resizable.css +237 -0
  107. package/css/scroll-area.css +68 -7
  108. package/css/scrollbar.css +47 -13
  109. package/css/segmented.css +94 -29
  110. package/css/select.css +288 -274
  111. package/css/separator.css +101 -1
  112. package/css/side-nav.css +133 -75
  113. package/css/signature-pad.css +74 -54
  114. package/css/skeleton.css +84 -11
  115. package/css/slider.css +132 -39
  116. package/css/sortable.css +198 -0
  117. package/css/spinner.css +126 -12
  118. package/css/splitter.css +29 -8
  119. package/css/statistic.css +55 -0
  120. package/css/steps.css +206 -72
  121. package/css/switch.css +268 -36
  122. package/css/table.css +695 -118
  123. package/css/tabs.css +604 -42
  124. package/css/tag-group.css +219 -0
  125. package/css/tag.css +118 -28
  126. package/css/tags-input.css +156 -274
  127. package/css/text-field.css +101 -249
  128. package/css/time-field.css +100 -128
  129. package/css/time-picker.css +323 -252
  130. package/css/time-range-picker.css +719 -0
  131. package/css/timeline.css +202 -68
  132. package/css/timer.css +56 -52
  133. package/css/timestamp.css +34 -0
  134. package/css/toast.css +373 -144
  135. package/css/toggle-group.css +309 -76
  136. package/css/toggle.css +116 -85
  137. package/css/tone.css +47 -0
  138. package/css/tool-call.css +421 -0
  139. package/css/toolbar.css +181 -33
  140. package/css/tooltip.css +107 -36
  141. package/css/tour.css +183 -152
  142. package/css/transfer.css +351 -138
  143. package/css/tree-select.css +323 -216
  144. package/css/tree.css +294 -62
  145. package/css/truncate.css +65 -0
  146. package/css/typography.css +228 -5
  147. package/css/undefined.css +10 -1
  148. package/css/virtualizer.css +9 -10
  149. package/css/visually-hidden.css +7 -0
  150. package/css/watermark.css +7 -0
  151. package/family/action-control.css +487 -0
  152. package/family/collection-item.css +721 -0
  153. package/family/field-chrome.css +298 -0
  154. package/family/motion.css +166 -0
  155. package/family/swatch.css +59 -0
  156. package/index.css +41705 -126
  157. package/index.unlayered.css +33692 -17339
  158. package/package.json +51 -17
  159. package/css/calendar.css +0 -367
  160. package/css/code-block.css +0 -91
  161. package/css/composer.css +0 -134
  162. package/css/countdown.css +0 -26
  163. package/css/dynamic-input.css +0 -220
  164. package/css/ellipsis.css +0 -52
  165. package/css/hotkeys.css +0 -90
  166. package/css/popselect.css +0 -391
  167. package/css/qr-code.css +0 -55
  168. package/css/result.css +0 -119
  169. package/css/space.css +0 -117
  170. package/css/thread.css +0 -120
  171. package/css/time.css +0 -25
@@ -1,3 +1,10 @@
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
5
+
6
+ /* 定义 scroll area 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='scroll-area'] {
@@ -58,13 +65,6 @@
58
65
  overflow-y: hidden;
59
66
  }
60
67
 
61
- /* 视口带 tabindex=0(滚动区里可能一个可聚焦元素都没有),因此要有焦点环。
62
- 偏移取负:环画在视口内侧,否则会被 root 的 overflow:hidden 裁掉半圈 */
63
- [data-scope='scroll-area'][data-part='viewport']:focus-visible {
64
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
65
- outline-offset: calc(-1 * var(--xh-ring-width));
66
- }
67
-
68
68
  /* 有滚动条要占道时,视口在那条轴上收窄一条道的宽度,末端内容不再被压在滚动条底下。
69
69
  缩视口而不是给视口加内边距:滚动容器末端缘的 padding 计不计进 scrollWidth,各引擎不一致。 */
70
70
  [data-scope='scroll-area'][data-part='viewport'][data-lane-vertical] {
@@ -75,6 +75,64 @@
75
75
  block-size: calc(100% - var(--xh-_scrollbar-thickness));
76
76
  }
77
77
 
78
+ /* —— 边缘渐隐 —— */
79
+ /* 两条轴各铺一层遮罩,取交集:还滚得动的那一侧把内容淡出,滚到头即收成 0。
80
+ 渐变没有逻辑方向,只能沿物理方向铺,横轴那一层的两端在 rtl 下对调(见下)。
81
+ 遮罩里的黑白画的是 alpha 的两端,不是设计色。
82
+ -webkit-* 那两条排在前面兜住只认前缀写法的引擎。
83
+ 画在视口上而不是根上:自绘滚动条是视口的兄弟节点,不会跟着一起淡掉 */
84
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade'] {
85
+ /* 渐隐带宽跟着尺寸档走,与滚动条厚度同一个 data-size */
86
+ --xh-_scroll-area-fade-size: var(--xh-scroll-area-fade-size, var(--xh-space-6));
87
+ /* 四条边各自的带宽:到头那一侧收成 0,没到头才铺开 */
88
+ --xh-_scroll-area-fade-block-start: 0px;
89
+ --xh-_scroll-area-fade-block-end: 0px;
90
+ --xh-_scroll-area-fade-inline-start: 0px;
91
+ --xh-_scroll-area-fade-inline-end: 0px;
92
+ --xh-_scroll-area-fade-left: var(--xh-_scroll-area-fade-inline-start);
93
+ --xh-_scroll-area-fade-right: var(--xh-_scroll-area-fade-inline-end);
94
+
95
+ -webkit-mask-image:
96
+ linear-gradient(to bottom, transparent 0, black var(--xh-_scroll-area-fade-block-start), black calc(100% - var(--xh-_scroll-area-fade-block-end)), transparent 100%),
97
+ linear-gradient(to right, transparent 0, black var(--xh-_scroll-area-fade-left), black calc(100% - var(--xh-_scroll-area-fade-right)), transparent 100%);
98
+ mask-image:
99
+ linear-gradient(to bottom, transparent 0, black var(--xh-_scroll-area-fade-block-start), black calc(100% - var(--xh-_scroll-area-fade-block-end)), transparent 100%),
100
+ linear-gradient(to right, transparent 0, black var(--xh-_scroll-area-fade-left), black calc(100% - var(--xh-_scroll-area-fade-right)), transparent 100%);
101
+ -webkit-mask-composite: source-in;
102
+ mask-composite: intersect;
103
+ }
104
+
105
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade'][data-size='sm'] {
106
+ --xh-_scroll-area-fade-size: var(--xh-scroll-area-fade-size, var(--xh-space-4));
107
+ }
108
+
109
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade'][data-size='lg'] {
110
+ --xh-_scroll-area-fade-size: var(--xh-scroll-area-fade-size, var(--xh-space-8));
111
+ }
112
+
113
+ /* 还回得去、还去得了的那一侧才铺带:贴着那一端时属性在场,规则不命中 */
114
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade']:not([data-at-min-vertical]) {
115
+ --xh-_scroll-area-fade-block-start: var(--xh-_scroll-area-fade-size);
116
+ }
117
+
118
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade']:not([data-at-max-vertical]) {
119
+ --xh-_scroll-area-fade-block-end: var(--xh-_scroll-area-fade-size);
120
+ }
121
+
122
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade']:not([data-at-min-horizontal]) {
123
+ --xh-_scroll-area-fade-inline-start: var(--xh-_scroll-area-fade-size);
124
+ }
125
+
126
+ [data-scope='scroll-area'][data-part='viewport'][data-variant='fade']:not([data-at-max-horizontal]) {
127
+ --xh-_scroll-area-fade-inline-end: var(--xh-_scroll-area-fade-size);
128
+ }
129
+
130
+ /* 从右往左排版时横轴的起始端在右:两端对调,逻辑那两支槽的取值不动 */
131
+ [dir='rtl'] [data-scope='scroll-area'][data-part='viewport'][data-variant='fade'] {
132
+ --xh-_scroll-area-fade-left: var(--xh-_scroll-area-fade-inline-end);
133
+ --xh-_scroll-area-fade-right: var(--xh-_scroll-area-fade-inline-start);
134
+ }
135
+
78
136
  /* 横向溢出全靠它撑:内容若跟着视口一起收成 100% 宽,横轴永远量不出溢出,
79
137
  横向滚动条也就永远不显形。 */
80
138
  [data-scope='scroll-area'][data-part='content'] {
@@ -86,6 +144,9 @@
86
144
  (轨道与滑块的皮仍归 scrollbar 那一份)。滑块主轴的起点与长度由连接层写进内联样式,这里不碰。 */
87
145
  [data-scope='scroll-area'][data-part='scrollbar'] {
88
146
  position: absolute;
147
+ /* 浮层的 positioner 一律 pointer-events: none,条子作为它的子节点会继承到,拖不动也点不着;
148
+ 收起态那条规则优先级更高,仍旧穿透 */
149
+ pointer-events: auto;
89
150
  /* touch-action 关掉浏览器自己的手势:不关的话手指一按滑块页面就跟着滚,
90
151
  指针随即被系统收走(pointercancel),拖到一半的滑块停在原地。
91
152
  user-select 同理——拖动时选中页面文字会让滑块"粘"住。 */
package/css/scrollbar.css CHANGED
@@ -1,11 +1,20 @@
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
+ /* 定义 scrollbar 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='scrollbar'] {
4
11
  --xh-scrollbar-skin: 1;
5
12
  }
6
13
 
7
- /* 挂了自绘滚动条的容器:原生滚动条只藏外观,滚动能力一点不动。
8
- 标记由机器挂监听时打上,最后一条滚动条拆走才撤。下面那条 ::-webkit-scrollbar 兜住还没实现 scrollbar-width 的引擎 */
14
+ /* 库内原生滚动面的细条规则住在 reset 层(reset.css),本文件只管自绘条本身。
15
+ 挂了自绘滚动条的容器:原生滚动条只藏外观,滚动能力一点不动。
16
+ 标记由机器挂监听时打上,最后一条滚动条拆走才撤。这条是 (0,1,0),压得过 reset 层的 thin;
17
+ 下面那条 ::-webkit-scrollbar 兜住还没实现 scrollbar-width 的引擎 */
9
18
  [data-xh-scrollbar] {
10
19
  scrollbar-width: none;
11
20
  }
@@ -70,6 +79,12 @@
70
79
  inset-inline-end: var(--xh-_scrollbar-thickness);
71
80
  }
72
81
 
82
+ /* 贴在滚动层上的根:位置由连接层按层在壳内的偏移盒写成内联几何(含让位),
83
+ 壳边的 inset 全部放开,交叉轴的厚度仍由上面的方向规则给 */
84
+ [data-scope='scrollbar'][data-part='root'][data-anchor='layer'] {
85
+ inset: auto;
86
+ }
87
+
73
88
  [data-scope='scrollbar'][data-part='root'][data-state='hidden'] {
74
89
  visibility: hidden;
75
90
  opacity: 0;
@@ -101,9 +116,16 @@
101
116
  [data-scope='scrollbar'][data-part='thumb'] {
102
117
  position: absolute;
103
118
  border-radius: var(--xh-scrollbar-thumb-radius, var(--xh-shape-pill));
104
- background: var(--xh-scrollbar-thumb-bg, var(--xh-fg-scrollbar-thumb));
119
+ background: var(
120
+ --xh-scrollbar-thumb-bg,
121
+ var(--xh-fg-scrollbar-thumb)
122
+ );
123
+ /* 滑块里没有字,这支墨色只给聚焦环用。 */
124
+ color: var(--xh-fg-default);
105
125
  cursor: default;
106
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
126
+ transition:
127
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
128
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
107
129
  }
108
130
 
109
131
  /* 交叉轴在轨道内两侧各收进一个间隙,与轨道那条 padding 共用同一个旋钮。
@@ -118,19 +140,24 @@
118
140
  inset-block: var(--xh-scrollbar-gutter);
119
141
  }
120
142
 
143
+ /* 这两档的面往另一头走(浅色主题更深、深色主题更亮),配对的墨色跟着翻到反色那一支 */
121
144
  [data-scope='scrollbar'][data-part='thumb']:hover {
122
- background: var(--xh-scrollbar-thumb-bg-hover, var(--xh-fg-scrollbar-thumb-hover));
145
+ background: var(
146
+ --xh-scrollbar-thumb-bg-hover,
147
+ var(--xh-fg-scrollbar-thumb-hover)
148
+ );
123
149
  }
124
150
 
125
151
  [data-scope='scrollbar'][data-part='thumb'][data-dragging] {
126
- background: var(--xh-scrollbar-thumb-bg-active, var(--xh-fg-scrollbar-thumb-active));
152
+ background: var(
153
+ --xh-scrollbar-thumb-bg-active,
154
+ var(--xh-fg-scrollbar-thumb-active)
155
+ );
127
156
  }
128
157
 
129
- /* 只有开了 focusable 的滑块进得了 Tab 序,环也就只画在它身上。
130
- 偏移取负:环画在轨道内侧,否则会被滚动容器的溢出边界裁掉半圈 */
131
- [data-scope='scrollbar'][data-part='thumb']:focus-visible {
132
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
133
- outline-offset: calc(-1 * var(--xh-ring-width));
158
+ /* 面是实心的中性色,环色与面同族,画在面里就看不出来;环改取这一档配对的墨色 */
159
+ [data-scope='scrollbar'][data-part='thumb']:not([data-disabled]):focus-visible {
160
+ --xh-_ring-color: currentColor;
134
161
  }
135
162
 
136
163
  /* 根与轨道都是纯容器,不承载焦点;作者若给它们加了 tabindex,也不该在这儿多画一圈 */
@@ -142,7 +169,6 @@
142
169
  /* 禁用:整条不显形,这里只兜住作者硬把它显出来的那一路 */
143
170
  [data-scope='scrollbar'][data-part='thumb'][data-disabled] {
144
171
  background: var(--xh-scrollbar-thumb-bg-disabled, var(--xh-border-subtle));
145
- cursor: not-allowed;
146
172
  }
147
173
 
148
174
  /* 交叉口补丁:贴在本条末端之外的那一格,与轨道同色,跟着本条淡入淡出 */
@@ -150,7 +176,7 @@
150
176
  position: absolute;
151
177
  inline-size: var(--xh-_scrollbar-thickness);
152
178
  block-size: var(--xh-_scrollbar-thickness);
153
- background: var(--xh-scrollbar-corner-bg, var(--xh-scrollbar-track-bg, var(--xh-bg-scrollbar-track)));
179
+ background: var(--xh-scrollbar-corner-bg, var(--xh-scrollbar-track-bg, transparent));
154
180
  }
155
181
 
156
182
  [data-scope='scrollbar'][data-part='corner'][data-orientation='vertical'] {
@@ -167,4 +193,12 @@
167
193
  [data-scope='scrollbar'][data-part='corner'][hidden] {
168
194
  display: none;
169
195
  }
196
+
197
+ @media print {
198
+ /* 打印:滚动条画的是「还能往下看多少」,纸上没有这回事,它只会在版心边上留一条灰带。 */
199
+ [data-scope='scrollbar'][data-part='root'],
200
+ [data-scope='scrollbar'][data-part='corner'] {
201
+ display: none;
202
+ }
203
+ }
170
204
  }
package/css/segmented.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
+ /* 定义 segmented 样式。 */
7
+
1
8
  @layer xihan.components {
2
9
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
10
  [data-scope='segmented'] {
@@ -12,32 +19,49 @@
12
19
  --xh-_segmented-px: var(--xh-control-px-md);
13
20
  --xh-_segmented-gap: var(--xh-control-gap-md);
14
21
  --xh-_segmented-font-size: var(--xh-control-font-md);
15
- /* 指示器底色与选中段的文字色;没写 data-tone 时就是这里的取值 */
16
- --xh-_segmented-indicator-bg: var(--xh-bg-surface);
22
+ /* 指示器(有滑块开关的白色抬起面,§7.3)的底、描边与选中段的文字色;没写 data-tone 时就是这里的取值 */
23
+ --xh-_segmented-indicator-bg: var(--xh-bg-surface-raised);
17
24
  --xh-_segmented-fg-selected: var(--xh-fg-default);
25
+ /* 轨道是淡底承载面:段坐在它上面,悬停 200 → 按下 300(§7.2),host 槽向内下发同一副阶梯 */
26
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
27
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
18
28
 
29
+ /* 一行排不下就折行:每个选项都必须看得见、点得到,硬撑一行会把末尾几段顶出容器。
30
+ 段各自带圆角,折行不会切角;不改成横向滚动是因为段离轨道内沿只有一格衬距,
31
+ 轨道一旦成为滚动容器,段的焦点环(画在段外侧 2px 处)会被裁掉。
32
+ 轨道是一块淡底面(§8.3):--xh-bg-subtle 底 + 同宽透明占位边 + 无影,边界由滑块的描边与轨道底色的落差承担 */
19
33
  position: relative;
20
34
  display: inline-flex;
35
+ flex-wrap: wrap;
21
36
  align-items: stretch;
22
37
  padding: var(--xh-segmented-track-padding, var(--xh-space-0_5));
23
- border: var(--xh-stroke-thin) solid var(--xh-segmented-border, var(--xh-border-subtle));
24
- border-radius: var(--xh-segmented-radius, var(--xh-shape-control));
38
+ border: var(--xh-stroke-thin) solid var(--xh-segmented-border, transparent);
39
+ border-radius: var(--xh-segmented-radius, var(--xh-shape-surface));
25
40
  background: var(--xh-segmented-bg, var(--xh-bg-subtle));
26
41
  font-size: var(--xh-segmented-font-size, var(--xh-_segmented-font-size));
27
42
  }
28
43
 
29
- /* 横排时外盒整体就是一档控件高:段被 align-items: stretch 撑满轨道内侧,与同行控件齐平 */
44
+ /* 横排时外盒整体就是一档控件高:段被 align-items: stretch 撑满轨道内侧,与同行控件齐平。
45
+ 写下限而非定值:排得下时两者逐值相同,排不下折了行才让轨道往下长 */
30
46
  [data-scope='segmented'][data-part='root'][data-orientation='horizontal'] {
31
47
  flex-direction: row;
32
- block-size: var(--xh-segmented-h, var(--xh-_segmented-h));
48
+ min-block-size: var(--xh-segmented-h, var(--xh-_segmented-h));
33
49
  }
34
50
 
51
+ /* 段的高度交给轨道:一行时被 stretch 撑满轨道内侧。
52
+ 下限按「一档控件高减掉轨道上下的衬距与描边」算,折了行每一行仍是这个高度,
53
+ 不写的话多行会被 align-content 均分成一叠扁条 */
35
54
  [data-scope='segmented'][data-part='root'][data-orientation='horizontal'] [data-scope='segmented'][data-part='item'] {
36
55
  block-size: auto;
56
+ min-block-size: calc(
57
+ var(--xh-segmented-h, var(--xh-_segmented-h)) - 2 * var(--xh-segmented-track-padding, var(--xh-space-0_5)) - 2 *
58
+ var(--xh-stroke-thin)
59
+ );
37
60
  }
38
61
 
39
62
  [data-scope='segmented'][data-part='root'][data-orientation='vertical'] {
40
63
  flex-direction: column;
64
+ flex-wrap: nowrap;
41
65
  }
42
66
 
43
67
  /* 撑满行宽:各段等分剩余空间,长短不一的文字也排得齐 */
@@ -66,7 +90,6 @@
66
90
 
67
91
  [data-scope='segmented'][data-part='root'][data-disabled] {
68
92
  background: var(--xh-segmented-bg-disabled, var(--xh-bg-muted));
69
- cursor: not-allowed;
70
93
  }
71
94
 
72
95
  /* 整组禁用时指示器落回轨道平面(不再浮起),但底色一点不兑淡:
@@ -79,10 +102,15 @@
79
102
  /* —— 语气 —— */
80
103
  /* 选择器带 [data-tone] 限定:不限定的话,放在语气容器里的分段控件会跟着改色 */
81
104
  [data-scope='segmented'][data-part='root'][data-tone] {
82
- --xh-_segmented-indicator-bg: var(--xh-_tone, var(--xh-bg-surface));
105
+ --xh-_segmented-indicator-bg: var(--xh-_tone, var(--xh-bg-surface-raised));
83
106
  --xh-_segmented-fg-selected: var(--xh-_tone-on, var(--xh-fg-default));
84
107
  }
85
108
 
109
+ /* 语气档的滑块是实心语气面,描边与底同色:raised 面必带描边,这里的描边只是把边位补齐,不另画一圈 */
110
+ [data-scope='segmented'][data-part='root'][data-tone] [data-scope='segmented'][data-part='indicator'] {
111
+ border-color: var(--xh-segmented-indicator-border, var(--xh-_tone, var(--xh-border-default)));
112
+ }
113
+
86
114
  /* —— 尺寸 —— */
87
115
  /* 缺省的 md 档写在上面的基础规则里 */
88
116
  [data-scope='segmented'][data-part='root'][data-size='sm'] {
@@ -121,10 +149,10 @@
121
149
  white-space: nowrap;
122
150
  cursor: pointer;
123
151
  user-select: none;
152
+ /* 段是轨道里铺开的一段(§9.2 Segmented item 归行级),按下只换面不缩放:transition 里没有 scale */
124
153
  transition:
125
154
  color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
126
- background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
127
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
155
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
128
156
  }
129
157
 
130
158
  /* 选中态:单选是 role=radio + aria-checked,样式一律读 data-state,不读 ARIA。
@@ -133,21 +161,31 @@
133
161
  color: var(--xh-segmented-item-fg-checked, var(--xh-_segmented-fg-selected));
134
162
  }
135
163
 
164
+ /* 指示器在场时选中段自己透空,环紧挨着的是压在它底下、与它同一块矩形的指示器实心底;
165
+ 环色与那块底同族就看不出来,改取选中段自己的前景色——那一支本来就配着这块底定的。
166
+ 指示器是可选部件,作者没渲染它时选中段直接坐在轨道底上,那一档的环仍取默认那一支 */
167
+ [data-scope='segmented'][data-part='root']:has([data-scope='segmented'][data-part='indicator']:not([hidden]))
168
+ [data-scope='segmented'][data-part='item'][data-state='checked']:focus-visible {
169
+ --xh-_ring-color: currentColor;
170
+ }
171
+
136
172
  /* 悬停只提亮未选中的那几段:选中段的底下压着指示器,再变色就成了两套强调。
137
- 底色用中性的悬停档——它是「指哪一段」的轻反馈,不表达选中 */
173
+ 底色用中性的悬停档——它是「指哪一段」的轻反馈,不表达选中;段坐在淡底轨道里,悬停取 200(§7.2) */
138
174
  [data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-state='checked']):hover {
139
175
  background-color: var(--xh-segmented-item-bg-hover, var(--xh-bg-subtle-hover));
140
176
  color: var(--xh-segmented-item-fg-hover, var(--xh-fg-default));
141
177
  }
142
178
 
143
- /* 按下去要有回应:整段轻微下压,松手即弹回。选中段也压——按在已选段上同样是一次点击。
144
- 只读段不压:它本来就不接受改值,压下去等于骗人 */
145
- [data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-readonly]):active {
146
- scale: var(--xh-segmented-item-press-scale, var(--xh-motion-scale-press));
179
+ /* 按下去要有回应:未选中段换到按下面(淡底承载 300),几何不动;只读段不压。
180
+ 选中段不叠按下面:它压着的白色滑块本身就是选中身份(§7.3 有滑块开关无叠加态) */
181
+ [data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-readonly]):not([data-state='checked']):is(:active, [data-pressed]) {
182
+ background-color: var(--xh-segmented-item-bg-pressed, var(--xh-bg-subtle-active));
183
+ transition-duration: var(--xh-motion-duration-press);
184
+ transition-timing-function: var(--xh-motion-ease-press);
147
185
  }
148
186
 
149
187
  /* 只读:值改不动,但对比度不降,光标也不摆出"禁止"的样子 */
150
- [data-scope='segmented'][data-part='item'][data-readonly] {
188
+ [data-scope='segmented'][data-part='item'][data-readonly]:not([data-disabled]) {
151
189
  cursor: default;
152
190
  }
153
191
 
@@ -156,7 +194,6 @@
156
194
  用了 fg-disabled 就不再叠 opacity:半透明会把底下的指示器透出来 */
157
195
  [data-scope='segmented'][data-part='item'][data-disabled] {
158
196
  color: var(--xh-fg-disabled);
159
- cursor: not-allowed;
160
197
  }
161
198
 
162
199
  /* 禁用且选中的那一段不换文字色:它压着的是指示器的实心底,换成 fg-disabled 后
@@ -166,12 +203,6 @@
166
203
  color: var(--xh-segmented-item-fg-checked-disabled, var(--xh-_segmented-fg-selected));
167
204
  }
168
205
 
169
- /* 焦点环往内收一格:段贴着轨道内缘,往外画会被 root 的描边切掉一半 */
170
- [data-scope='segmented'][data-part='item']:focus-visible {
171
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
172
- outline-offset: calc(-1 * var(--xh-ring-offset));
173
- }
174
-
175
206
  [data-scope='segmented'][data-part='item-text'] {
176
207
  color: inherit;
177
208
  user-select: none;
@@ -191,18 +222,23 @@
191
222
  inset-block-start: var(--xh-_segmented-indicator-y);
192
223
  inline-size: var(--xh-_segmented-indicator-w);
193
224
  block-size: var(--xh-_segmented-indicator-h);
225
+ /* 白色抬起面三件(§7.3 有滑块开关):surface-raised 底 + border-default 描边 + raised 影,描边必须在,影只是加成。
226
+ 尺寸由连接层按段的盒量出,描边吃进盒里(border-box),滑块与段仍是同一块矩形 */
227
+ border: var(--xh-stroke-thin) solid var(--xh-segmented-indicator-border, var(--xh-border-default));
194
228
  border-radius: var(--xh-segmented-indicator-radius, var(--xh-shape-inset));
195
229
  background: var(--xh-segmented-indicator-bg, var(--xh-_segmented-indicator-bg));
196
230
  box-shadow: var(--xh-segmented-indicator-shadow, var(--xh-elevation-raised));
197
231
  /* 段压在它上面,点击一律交给段;作者把它写在段之后时也不至于吞掉点击 */
198
232
  pointer-events: none;
199
- /* 用标准曲线而不是进场那条:滑块是被推过去的,起步就该有速度,
200
- 纯减速曲线看着像自己飘过去。四个几何量同时走,段宽不等时才不会先变形再挪位 */
233
+ /* 用连续档而不是进场那条:滑块是被推过去的,起步就该有速度,
234
+ 纯减速曲线看着像自己飘过去。四个几何量同时走,段宽不等时才不会先变形再挪位。
235
+ 投影单列一项:整组禁用时滑块落回轨道平面,那层投影跟着收 */
201
236
  transition:
202
- inset-inline-start var(--xh-motion-duration-enter) var(--xh-ease-standard),
203
- inset-block-start var(--xh-motion-duration-enter) var(--xh-ease-standard),
204
- inline-size var(--xh-motion-duration-enter) var(--xh-ease-standard),
205
- block-size var(--xh-motion-duration-enter) var(--xh-ease-standard);
237
+ inset-inline-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
238
+ inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
239
+ inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
240
+ block-size var(--xh-motion-duration-enter) var(--xh-motion-ease-continuous),
241
+ box-shadow var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
206
242
  }
207
243
 
208
244
  /* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
@@ -212,4 +248,33 @@
212
248
  [data-scope='segmented'][data-part='indicator'][hidden] {
213
249
  display: none;
214
250
  }
251
+
252
+ @media print {
253
+ /* 打印默认丢背景色:滑块那块底与它的落影都不画,「当前选的是哪一段」在纸上没了。
254
+ 选中段改画一圈实边、字加粗,两条都不吃底色 */
255
+ [data-scope='segmented'][data-part='item'][data-state='checked'] {
256
+ border: var(--xh-stroke-thin) solid currentColor;
257
+ font-weight: var(--xh-font-weight-bold);
258
+ }
259
+ }
260
+
261
+ @media (forced-colors: active) {
262
+ /* 按下:常态靠底色深一档表出,这一档里底色被统一换成 Canvas;按住那一下用系统高亮反色画回来 */
263
+ [data-scope='segmented'][data-part='item']:not([data-disabled]):not([data-readonly]):not([data-state='checked']):is(:active, [data-pressed]) {
264
+ background-color: Highlight;
265
+ color: HighlightText;
266
+ }
267
+ }
268
+
269
+ @media (pointer: coarse) {
270
+ /* 手指的落点比一段高:命中区由伪元素向块轴两侧外扩,段的盒与轨道内的分格一点不动。
271
+ 只扩块轴——段与段在行内轴上首尾相接,往两侧扩会与相邻段的命中区叠上。
272
+ 取 8px 是按最矮的 sm 档算的(28 + 8 × 2 = 44),md 与 lg 档更宽裕 */
273
+ [data-scope='segmented'][data-part='item']::before {
274
+ content: '';
275
+ position: absolute;
276
+ inset-block: -8px;
277
+ inset-inline: 0;
278
+ }
279
+ }
215
280
  }