@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,12 @@
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
+ /* 定义 toggle group 样式。 */
7
+
8
+ @import '../family/action-control.css';
9
+
1
10
  @layer xihan.components {
2
11
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
12
  [data-scope='toggle-group'] {
@@ -16,11 +25,120 @@
16
25
  --xh-_toggle-group-px: var(--xh-control-px-md);
17
26
  --xh-_toggle-group-gap: var(--xh-control-gap-md);
18
27
  --xh-_toggle-group-font-size: var(--xh-control-font-md);
28
+ --xh-_group-separator-size: calc(var(--xh-_toggle-group-h) / 2);
29
+
30
+ /* 形态的落点:没写 data-variant 时这十支保持缺省档的取值,段的规则读的是
31
+ 「使用者令牌 → 这十支 → 语义令牌」三级,使用者令牌永远排在形态之前。
32
+ 未选中那五支管段的壳,选中那五支管当前值那一段。
33
+ 缺省档(subtle)的段坐在自己的淡底面上,悬停 200 → 按下 300(§7.2 淡底承载);
34
+ 选中段是无滑块开关(§7.3):品牌淡底 + 淡底前景,悬停 20% → 按下 28% */
35
+ --xh-_toggle-group-item-bg: var(--xh-bg-subtle);
36
+ --xh-_toggle-group-item-bg-hover: var(--xh-bg-subtle-hover);
37
+ --xh-_toggle-group-item-bg-active: var(--xh-bg-subtle-active);
38
+ --xh-_toggle-group-item-fg: var(--xh-fg-default);
39
+ --xh-_toggle-group-item-border: transparent;
40
+ --xh-_toggle-group-item-bg-on: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
41
+ --xh-_toggle-group-item-bg-on-hover: var(
42
+ --xh-_tone-subtle-hover,
43
+ var(--xh-bg-brand-subtle-hover)
44
+ );
45
+ --xh-_toggle-group-item-bg-on-active: var(
46
+ --xh-_tone-subtle-active,
47
+ var(--xh-bg-brand-subtle-active)
48
+ );
49
+ --xh-_toggle-group-item-fg-on: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
50
+ --xh-_toggle-group-item-border-on: transparent;
51
+ --xh-_toggle-group-item-highlight-on: none;
19
52
 
53
+ /* 连续分段不能换行;窄容器由作者改为竖排或全宽布局。 */
20
54
  display: inline-flex;
55
+ flex-wrap: nowrap;
21
56
  align-items: stretch;
22
57
  }
23
58
 
59
+ /* —— 形态 ——
60
+ 四档与 toggle 一处对一处:未选中那些段长什么样在这里定,选中那一段用哪一档底也在这里定,
61
+ 切换仍由 data-state='on' 那一条统一完成。
62
+ 缺省档(没写 data-variant)使用中性浅底,选中段使用品牌淡底 */
63
+ [data-scope='toggle-group'][data-part='root'][data-variant='solid'] {
64
+ --xh-_toggle-group-item-bg: transparent;
65
+ --xh-_toggle-group-item-border: transparent;
66
+ --xh-_toggle-group-item-bg-on: var(--xh-_tone, var(--xh-bg-brand));
67
+ --xh-_toggle-group-item-bg-on-hover: var(--xh-_tone-hover, var(--xh-bg-brand-hover));
68
+ --xh-_toggle-group-item-bg-on-active: var(--xh-_tone-active, var(--xh-bg-brand-active));
69
+ --xh-_toggle-group-item-fg-on: var(--xh-_tone-on, var(--xh-fg-on-brand));
70
+ --xh-_toggle-group-item-border-on: var(--xh-_tone, var(--xh-bg-brand));
71
+ --xh-_toggle-group-item-highlight-on: var(--xh-_highlight-tone);
72
+ }
73
+
74
+ [data-scope='toggle-group'][data-part='root'][data-variant='solid']:is(
75
+ :not([data-tone]),
76
+ [data-tone='brand']
77
+ ) {
78
+ --xh-_toggle-group-item-bg-on: var(--xh-action-brand-solid);
79
+ --xh-_toggle-group-item-bg-on-hover: var(--xh-action-brand-solid-hover);
80
+ --xh-_toggle-group-item-bg-on-active: var(--xh-action-brand-solid-active);
81
+ --xh-_toggle-group-item-fg-on: var(--xh-action-on-brand-solid);
82
+ --xh-_toggle-group-item-border-on: var(--xh-action-brand-solid);
83
+ }
84
+
85
+ [data-scope='toggle-group'][data-part='root'][data-variant='subtle'] {
86
+ --xh-_toggle-group-item-bg: var(--xh-bg-subtle);
87
+ --xh-_toggle-group-item-bg-hover: var(--xh-bg-subtle-hover);
88
+ --xh-_toggle-group-item-bg-active: var(--xh-bg-subtle-active);
89
+ --xh-_toggle-group-item-fg: var(--xh-fg-default);
90
+ --xh-_toggle-group-item-border: transparent;
91
+ --xh-_toggle-group-item-bg-on: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
92
+ --xh-_toggle-group-item-bg-on-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-brand-subtle-hover));
93
+ --xh-_toggle-group-item-bg-on-active: var(--xh-_tone-subtle-active, var(--xh-bg-brand-subtle-active));
94
+ --xh-_toggle-group-item-fg-on: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
95
+ --xh-_toggle-group-item-border-on: transparent;
96
+ --xh-_toggle-group-item-highlight-on: none;
97
+ }
98
+
99
+ /* outline 与 ghost 的段坐在画布上:悬停 100 → 按下 200(§7.2 白底承载) */
100
+ [data-scope='toggle-group'][data-part='root'][data-variant='outline'] {
101
+ --xh-_toggle-group-item-bg: transparent;
102
+ --xh-_toggle-group-item-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle));
103
+ --xh-_toggle-group-item-bg-active: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
104
+ --xh-_toggle-group-item-fg: var(--xh-_tone-fg, var(--xh-fg-default));
105
+ --xh-_toggle-group-item-border: transparent;
106
+ --xh-_toggle-group-item-bg-on: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
107
+ --xh-_toggle-group-item-bg-on-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-brand-subtle-hover));
108
+ --xh-_toggle-group-item-bg-on-active: var(--xh-_tone-subtle-active, var(--xh-bg-brand-subtle-active));
109
+ --xh-_toggle-group-item-fg-on: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
110
+ --xh-_toggle-group-item-border-on: transparent;
111
+ --xh-_toggle-group-item-highlight-on: none;
112
+
113
+ position: relative;
114
+ border-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
115
+ }
116
+
117
+ [data-scope='toggle-group'][data-part='root'][data-variant='outline']::after {
118
+ content: '';
119
+ position: absolute;
120
+ z-index: 2;
121
+ inset: 0;
122
+ border: var(--xh-stroke-thin) solid
123
+ var(--xh-toggle-group-outline-color, var(--xh-_tone-border-control, var(--xh-border-control)));
124
+ border-radius: inherit;
125
+ pointer-events: none;
126
+ }
127
+
128
+ [data-scope='toggle-group'][data-part='root'][data-variant='ghost'] {
129
+ --xh-_toggle-group-item-bg: transparent;
130
+ --xh-_toggle-group-item-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle));
131
+ --xh-_toggle-group-item-bg-active: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
132
+ --xh-_toggle-group-item-fg: var(--xh-_tone-fg, var(--xh-fg-default));
133
+ --xh-_toggle-group-item-border: transparent;
134
+ --xh-_toggle-group-item-bg-on: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
135
+ --xh-_toggle-group-item-bg-on-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-brand-subtle-hover));
136
+ --xh-_toggle-group-item-bg-on-active: var(--xh-_tone-subtle-active, var(--xh-bg-brand-subtle-active));
137
+ --xh-_toggle-group-item-fg-on: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
138
+ --xh-_toggle-group-item-border-on: transparent;
139
+ --xh-_toggle-group-item-highlight-on: none;
140
+ }
141
+
24
142
  /* —— 尺寸 —— */
25
143
  /* 缺省档写在上面的基础规则里 */
26
144
  [data-scope='toggle-group'][data-part='root'][data-size='sm'] {
@@ -43,6 +161,7 @@
43
161
 
44
162
  [data-scope='toggle-group'][data-part='root'][data-orientation='vertical'] {
45
163
  flex-direction: column;
164
+ flex-wrap: nowrap;
46
165
  }
47
166
 
48
167
  /* root 会短暂拿到 tabindex=0,但它的 onFocus 立刻把焦点转投给条目,
@@ -51,44 +170,49 @@
51
170
  outline: none;
52
171
  }
53
172
 
54
- [data-scope='toggle-group'][data-part='root'][data-disabled] {
55
- cursor: not-allowed;
56
- }
57
-
173
+ /* 段是 Action Control 的 text 档定尺按钮:盒型、三档几何、悬停 / 按下 / 焦点 / 禁用面与过渡都由家族给,
174
+ 这里只把使用者槽映射到桥接槽(-gap / -h / -px / -bg / -bg-hover / -bg-active / -fg / -border / -bg-disabled /
175
+ -fg-disabled / -border-disabled / -font-size 使用者槽保留为第一参数,缺省落到 root 上按形态赋值的十支私有槽)。
176
+ 状态规则只改写桥接槽,底色 / 描边 / 前景三者永远同步换,不会出现选中了底色却没跟上描边 */
58
177
  [data-scope='toggle-group'][data-part='item'] {
59
- /* 私有槽位:组件令牌 → 语义令牌两级回退。状态规则只改写槽位,
60
- 底色/描边/前景三者永远同步换,不会出现选中了底色却没跟上描边 */
61
- --xh-_bg: var(--xh-toggle-group-item-bg, var(--xh-bg-canvas));
62
- --xh-_bg-hover: var(--xh-toggle-group-item-bg-hover, var(--xh-bg-subtle-hover));
63
- --xh-_bg-active: var(--xh-toggle-group-item-bg-active, var(--xh-bg-subtle-active));
64
- --xh-_fg: var(--xh-toggle-group-item-fg, var(--xh-fg-default));
65
- --xh-_border: var(--xh-toggle-group-item-border, var(--xh-border-control));
178
+ --xh-action-gap: var(--xh-toggle-group-item-gap, var(--xh-_toggle-group-gap));
179
+ --xh-action-visual-size: var(--xh-toggle-group-item-h, var(--xh-_toggle-group-h));
180
+ --xh-action-padding-inline: var(--xh-toggle-group-item-px, var(--xh-_toggle-group-px));
181
+ --xh-action-font-size: var(--xh-toggle-group-item-font-size, var(--xh-_toggle-group-font-size));
182
+ /* 中间段一律直角,圆角只由首末两端补回来 */
183
+ --xh-action-radius: 0;
184
+ --xh-action-bg-rest: var(--xh-toggle-group-item-bg, var(--xh-_toggle-group-item-bg));
185
+ --xh-action-bg-hover: var(--xh-toggle-group-item-bg-hover, var(--xh-_toggle-group-item-bg-hover));
186
+ --xh-action-bg-pressed: var(--xh-toggle-group-item-bg-active, var(--xh-_toggle-group-item-bg-active));
187
+ --xh-action-bg-focus-visible: var(--xh-toggle-group-item-bg, var(--xh-_toggle-group-item-bg));
188
+ --xh-action-bg-disabled: var(--xh-toggle-group-item-bg-disabled, var(--xh-bg-muted));
189
+ --xh-action-fg-rest: var(--xh-toggle-group-item-fg, var(--xh-_toggle-group-item-fg));
190
+ --xh-action-fg-hover: var(--xh-toggle-group-item-fg, var(--xh-_toggle-group-item-fg));
191
+ --xh-action-fg-pressed: var(--xh-toggle-group-item-fg, var(--xh-_toggle-group-item-fg));
192
+ --xh-action-fg-focus-visible: var(--xh-toggle-group-item-fg, var(--xh-_toggle-group-item-fg));
193
+ --xh-action-fg-disabled: var(--xh-toggle-group-item-fg-disabled, var(--xh-fg-disabled));
194
+ --xh-action-border-rest: var(--xh-toggle-group-item-border, var(--xh-_toggle-group-item-border));
195
+ --xh-action-border-hover: var(--xh-toggle-group-item-border, var(--xh-_toggle-group-item-border));
196
+ --xh-action-border-pressed: var(--xh-toggle-group-item-border, var(--xh-_toggle-group-item-border));
197
+ --xh-action-border-focus-visible: var(--xh-toggle-group-item-border, var(--xh-_toggle-group-item-border));
198
+ --xh-action-border-disabled: var(--xh-toggle-group-item-border-disabled, var(--xh-border-subtle));
199
+ --xh-action-highlight-rest: transparent;
200
+ --xh-action-highlight-hover: transparent;
201
+ --xh-action-highlight-pressed: transparent;
202
+ --xh-action-highlight-focus-visible: transparent;
203
+ --xh-action-highlight-disabled: transparent;
204
+ --xh-action-shadow-rest: none;
205
+ --xh-action-shadow-hover: none;
206
+ --xh-action-shadow-pressed: none;
207
+ --xh-action-shadow-focus-visible: none;
208
+ --xh-action-shadow-disabled: none;
209
+ /* 共边相接的分段按下只换面不缩放:相邻两段靠负外边距压成一条边,缩放任一段都会把接缝拉开 */
210
+ --xh-action-scale-pressed: none;
66
211
 
67
212
  /* 相邻两段靠负外边距压掉一条重边,谁的描边浮在上面必须能指定,
68
213
  因此条目必须是定位元素——静态元素的 z-index 不生效 */
69
- position: relative;
70
214
  z-index: 0;
71
- display: inline-flex;
72
- align-items: center;
73
- justify-content: center;
74
- gap: var(--xh-toggle-group-item-gap, var(--xh-_toggle-group-gap));
75
- block-size: var(--xh-toggle-group-item-h, var(--xh-_toggle-group-h));
76
- padding-inline: var(--xh-toggle-group-item-px, var(--xh-_toggle-group-px));
77
- border: var(--xh-stroke-thin) solid var(--xh-_border);
78
- /* 中间段一律直角,圆角只由首末两端补回来 */
79
- border-radius: 0;
80
- background: var(--xh-_bg);
81
- color: var(--xh-_fg);
82
- font-size: var(--xh-toggle-group-item-font-size, var(--xh-_toggle-group-font-size));
83
215
  font-weight: var(--xh-toggle-group-item-font-weight, var(--xh-text-label-weight));
84
- line-height: var(--xh-leading-none);
85
- white-space: nowrap;
86
- cursor: pointer;
87
- user-select: none;
88
- transition:
89
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
90
- border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
91
- color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
92
216
  }
93
217
 
94
218
  /* 共边:后一段往回挪一个描边宽度,两条相邻的边重合成一条。
@@ -106,80 +230,173 @@
106
230
  }
107
231
 
108
232
  /* 两端圆角用逻辑角属性写,rtl 与竖排都跟着换边,不必另写一套。
109
- 只认 root 的直接子节点:条目之间插了别的节点时宁可退化成直角,也不要圆错位置 */
233
+ 只认 root 的直接子节点:条目之间插了别的节点时宁可退化成直角,也不要圆错位置。
234
+ 角画在条目上,槽名也带 item 段,与同文件其余条目槽同段 */
110
235
  [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal']
111
236
  > [data-scope='toggle-group'][data-part='item']:first-child {
112
- border-start-start-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
113
- border-end-start-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
237
+ border-start-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
238
+ border-end-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
114
239
  }
115
240
 
116
241
  [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal']
117
242
  > [data-scope='toggle-group'][data-part='item']:last-child {
118
- border-start-end-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
119
- border-end-end-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
243
+ border-start-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
244
+ border-end-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
120
245
  }
121
246
 
122
247
  [data-scope='toggle-group'][data-part='root'][data-orientation='vertical']
123
248
  > [data-scope='toggle-group'][data-part='item']:first-child {
124
- border-start-start-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
125
- border-start-end-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
249
+ border-start-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
250
+ border-start-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
126
251
  }
127
252
 
128
253
  [data-scope='toggle-group'][data-part='root'][data-orientation='vertical']
129
254
  > [data-scope='toggle-group'][data-part='item']:last-child {
130
- border-end-start-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
131
- border-end-end-radius: var(--xh-toggle-group-radius, var(--xh-shape-control));
132
- }
133
-
134
- [data-scope='toggle-group'][data-part='item']:not([data-disabled]):hover {
135
- background: var(--xh-_bg-hover);
136
- }
137
-
138
- [data-scope='toggle-group'][data-part='item']:not([data-disabled]):active {
139
- background: var(--xh-_bg-active);
255
+ border-end-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
256
+ border-end-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
140
257
  }
141
258
 
142
259
  /* 选中态:单选是 role=radio + aria-checked,多选是原生按钮 + aria-pressed,
143
- 两套 ARIA 各出一半,样式一条都对不上——只有 data-state 是两种模式共同的出口 */
260
+ 两套 ARIA 各出一半,样式一条都对不上——只有 data-state 是两种模式共同的出口。
261
+ 无滑块开关(§7.3):品牌淡底 + 淡底前景,悬停 20% → 按下 28%,三态都经桥接槽交给家族画;
262
+ 用哪族颜色由 data-tone 决定:语气槽沿继承流下来,root 自己写了 tone 算、
263
+ 整组落在语气容器里也算;没有语气就退回品牌配色,与不接语气时逐值相同。
264
+ 使用者令牌排在语气之前:写了组件槽就以它为准。
265
+ 只有 solid 形态提供内高光(一条 inset 描边式 box-shadow),其余形态在根变量中关闭 */
144
266
  [data-scope='toggle-group'][data-part='item'][data-state='on'] {
145
- --xh-_bg: var(--xh-toggle-group-item-bg-on, var(--xh-bg-brand));
146
- --xh-_bg-hover: var(--xh-toggle-group-item-bg-on-hover, var(--xh-bg-brand-hover));
147
- --xh-_bg-active: var(--xh-toggle-group-item-bg-on-active, var(--xh-bg-brand-active));
148
- --xh-_fg: var(--xh-toggle-group-item-fg-on, var(--xh-fg-on-brand));
149
- --xh-_border: var(--xh-toggle-group-item-border-on, var(--xh-bg-brand));
267
+ --xh-action-bg-rest: var(--xh-toggle-group-item-bg-on, var(--xh-_toggle-group-item-bg-on));
268
+ --xh-action-bg-hover: var(--xh-toggle-group-item-bg-on-hover, var(--xh-_toggle-group-item-bg-on-hover));
269
+ --xh-action-bg-pressed: var(--xh-toggle-group-item-bg-on-active, var(--xh-_toggle-group-item-bg-on-active));
270
+ --xh-action-bg-focus-visible: var(--xh-toggle-group-item-bg-on, var(--xh-_toggle-group-item-bg-on));
271
+ --xh-action-bg-disabled: var(
272
+ --xh-toggle-group-item-bg-on-disabled,
273
+ color-mix(in oklab, var(--xh-_toggle-group-item-bg-on) 50%, var(--xh-bg-muted))
274
+ );
275
+ --xh-action-fg-rest: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
276
+ --xh-action-fg-hover: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
277
+ --xh-action-fg-pressed: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
278
+ --xh-action-fg-focus-visible: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
279
+ --xh-action-fg-disabled: var(--xh-toggle-group-item-fg-on-disabled, var(--xh-_toggle-group-item-fg-on));
280
+ --xh-action-border-rest: var(--xh-toggle-group-item-border-on, var(--xh-_toggle-group-item-border-on));
281
+ --xh-action-border-hover: var(--xh-toggle-group-item-border-on, var(--xh-_toggle-group-item-border-on));
282
+ --xh-action-border-pressed: var(--xh-toggle-group-item-border-on, var(--xh-_toggle-group-item-border-on));
283
+ --xh-action-border-focus-visible: var(--xh-toggle-group-item-border-on, var(--xh-_toggle-group-item-border-on));
284
+ --xh-action-border-disabled: var(--xh-toggle-group-item-border-on-disabled, var(--xh-_toggle-group-item-border-on));
285
+ --xh-action-shadow-rest: var(--xh-toggle-group-item-shadow, var(--xh-_toggle-group-item-highlight-on));
286
+ --xh-action-shadow-hover: var(--xh-toggle-group-item-shadow, var(--xh-_toggle-group-item-highlight-on));
287
+ --xh-action-shadow-pressed: var(--xh-toggle-group-item-shadow, var(--xh-_toggle-group-item-highlight-on));
288
+ --xh-action-shadow-focus-visible: var(--xh-toggle-group-item-shadow, var(--xh-_toggle-group-item-highlight-on));
150
289
 
151
290
  /* 抬一层,让 brand 描边压住邻居的灰边。共边处两条边重合在同一像素上,
152
291
  不抬层就由文档序决定谁在上,选中段的左右两侧会一边有色一边灰 */
153
292
  z-index: 1;
154
293
  }
155
294
 
156
- /* 集合条目一律 aria-disabled 而非原生 disabled(禁用项仍要能当方向键的起点),
157
- 所以这里读 data-disabled,写 :disabled 永远不命中。
158
- 另外禁用不能用 opacity 变淡:半透明会把压在下面那条边透出来,共边处当场变成两条线 */
159
- [data-scope='toggle-group'][data-part='item'][data-disabled] {
160
- --xh-_bg: var(--xh-toggle-group-item-bg-disabled, var(--xh-bg-muted));
161
- --xh-_fg: var(--xh-toggle-group-item-fg-disabled, var(--xh-fg-disabled));
162
- --xh-_border: var(--xh-toggle-group-item-border-disabled, var(--xh-border-subtle));
163
-
164
- cursor: not-allowed;
295
+ /* solid 档的选中面是实心语气底,默认环压上去不足 3:1:环色改取配对前景色,经家族的焦点环桥接槽灌入 */
296
+ [data-scope='toggle-group'][data-part='root'][data-variant='solid']
297
+ [data-scope='toggle-group'][data-part='item'][data-state='on'] {
298
+ --xh-action-ring-color-focus-visible: currentColor;
165
299
  }
166
300
 
167
- /* 禁用且选中:底色不能一路退回 muted,那样"这一段是当前值"的信息就整个没了。
168
- 掺一半 muted brand,既看得出选中,也看得出改不动 */
169
- [data-scope='toggle-group'][data-part='item'][data-disabled][data-state='on'] {
170
- --xh-_bg: var(
171
- --xh-toggle-group-item-bg-on-disabled,
172
- color-mix(in oklab, var(--xh-bg-brand) 50%, var(--xh-bg-muted))
173
- );
174
- --xh-_fg: var(--xh-toggle-group-item-fg-on-disabled, var(--xh-fg-on-brand));
175
- --xh-_border: var(--xh-toggle-group-item-border-on-disabled, var(--xh-bg-brand));
176
- }
301
+ /* 集合条目一律 aria-disabled 而非原生 disabled(禁用项仍要能当方向键的起点),禁用面由家族按 data-disabled 给:
302
+ / / 边读上面映射的 -disabled 三支,不用 opacity 变淡(半透明会把压在下面那条边透出来,共边处当场变成两条线);
303
+ 禁用且选中的段底色掺一半 muted 进 brand(映射在选中态那条里),既看得出选中,也看得出改不动;
304
+ 改不动的段收掉内高光:底已经掺了灰,再留一条亮线只剩噪点(家族的 -shadow-disabled 缺省 none) */
177
305
 
178
306
  /* 焦点环要浮在共边之上:outline 画在元素外侧,不抬层就会被后一段的底色与描边盖掉一半 */
179
307
  [data-scope='toggle-group'][data-part='item']:focus-visible {
180
308
  z-index: 2;
181
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
182
- outline-offset: var(--xh-ring-offset);
309
+ }
310
+
311
+ /* —— 撑满行宽 —— */
312
+ /* 整组占满可用宽度,每段等分剩余空间。inline-flex 改成 flex:行内盒撑不满一行 */
313
+ [data-scope='toggle-group'][data-part='root'][data-full-width] {
314
+ display: flex;
315
+ inline-size: 100%;
316
+ }
317
+
318
+ [data-scope='toggle-group'][data-part='root'][data-full-width]
319
+ > [data-scope='toggle-group'][data-part='item'] {
320
+ flex: 1;
321
+ }
322
+
323
+ /* —— 段间的线 —— */
324
+ /* 装饰性的一条线,读屏不念。段本来靠共边连成一体,插了它就是把一排开关分成几组。
325
+ 朝向是这条线自己的(横排里是竖线),与 root 的排布相反 */
326
+ [data-scope='toggle-group'][data-part='root'] > [data-xh-toggle-group-separator] {
327
+ flex: none;
328
+ align-self: center;
329
+ z-index: 2;
330
+ border-radius: var(--xh-toggle-group-separator-radius, var(--xh-shape-pill));
331
+ background: var(--xh-toggle-group-separator-color, var(--xh-fg-default));
332
+ opacity: var(--xh-toggle-group-separator-opacity, var(--xh-control-separator-opacity));
333
+ pointer-events: none;
334
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
335
+ }
336
+
337
+ [data-scope='toggle-group'][data-part='root'] > [data-xh-toggle-group-separator][data-orientation='vertical'] {
338
+ inline-size: var(--xh-toggle-group-separator-thickness, var(--xh-stroke-thin));
339
+ block-size: var(
340
+ --xh-toggle-group-separator-size,
341
+ var(--xh-_group-separator-size)
342
+ );
343
+ margin-inline-start: calc(-1 * var(--xh-toggle-group-separator-thickness, var(--xh-stroke-thin)));
344
+ }
345
+
346
+ [data-scope='toggle-group'][data-part='root'] > [data-xh-toggle-group-separator][data-orientation='horizontal'] {
347
+ block-size: var(--xh-toggle-group-separator-thickness, var(--xh-stroke-thin));
348
+ inline-size: var(
349
+ --xh-toggle-group-separator-size,
350
+ var(--xh-_group-separator-size)
351
+ );
352
+ margin-block-start: calc(-1 * var(--xh-toggle-group-separator-thickness, var(--xh-stroke-thin)));
353
+ }
354
+
355
+ /* 段都按不动了,段间那条线跟着退到弱边一档 */
356
+ [data-scope='toggle-group'][data-part='root'] > [data-xh-toggle-group-separator][data-disabled] {
357
+ background: var(--xh-toggle-group-separator-color-disabled, var(--xh-border-subtle));
358
+ opacity: var(--xh-toggle-group-separator-opacity-disabled, var(--xh-control-separator-disabled-opacity));
359
+ }
360
+
361
+ /* 插了分隔线之后首末两段不再是 root 的首末子节点,圆角改按元素类型认:
362
+ 条目是原生 button,分隔线不是。没有分隔线时这两条与上面按子节点认的那几条同值 */
363
+ [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal']
364
+ > [data-scope='toggle-group'][data-part='item']:first-of-type {
365
+ border-start-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
366
+ border-end-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
367
+ }
368
+
369
+ [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal']
370
+ > [data-scope='toggle-group'][data-part='item']:last-of-type {
371
+ border-start-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
372
+ border-end-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
373
+ }
374
+
375
+ [data-scope='toggle-group'][data-part='root'][data-orientation='vertical']
376
+ > [data-scope='toggle-group'][data-part='item']:first-of-type {
377
+ border-start-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
378
+ border-start-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
379
+ }
380
+
381
+ [data-scope='toggle-group'][data-part='root'][data-orientation='vertical']
382
+ > [data-scope='toggle-group'][data-part='item']:last-of-type {
383
+ border-end-start-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
384
+ border-end-end-radius: var(--xh-toggle-group-item-radius, var(--xh-shape-control));
385
+ }
386
+
387
+ /* 连接层把它写成 type=hidden,UA 自己就不渲染;这里的视觉隐藏是给元素升级前那一瞬兜底
388
+ (作者手写的是一个普通 input,升级完成前它是可见的文本框)。
389
+ 刻意不写 display:写了反而会盖掉 UA 对 type=hidden 的收起,把它显出来 */
390
+ [data-scope='toggle-group'][data-part='hidden-input'] {
391
+ position: absolute;
392
+ inline-size: 1px;
393
+ block-size: 1px;
394
+ padding: 0;
395
+ margin: -1px;
396
+ border: 0;
397
+ overflow: hidden;
398
+ clip-path: inset(50%);
399
+ white-space: nowrap;
183
400
  }
184
401
 
185
402
  /* 给了 display 的角色节点必须补这条:display 声明会盖掉 UA 的 [hidden]{display:none},
@@ -188,4 +405,20 @@
188
405
  [data-scope='toggle-group'][data-part='item'][hidden] {
189
406
  display: none;
190
407
  }
408
+
409
+ /* 手指落点由家族给:text 档的 ::after 只在块轴外扩到 44px、行内轴按段的盒不动——
410
+ 条目在行内轴上靠负外边距共边相接,往两侧扩会与相邻条目的命中区叠上 */
411
+
412
+ @media (forced-colors: active) {
413
+ /* 段间那条线画的是一块纯底色,这一档里底色被统一换成 Canvas,线整条消失,
414
+ 几组开关就连成了一长串。换成前景色画回来 */
415
+ [data-scope='toggle-group'][data-part='root'] > [data-xh-toggle-group-separator] {
416
+ background: CanvasText;
417
+ }
418
+
419
+ [data-scope='toggle-group'][data-part='root'][data-variant='outline']::after {
420
+ border-color: ButtonText;
421
+ }
422
+
423
+ }
191
424
  }