@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/form.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
+ /* 定义 form 样式。 */
7
+
8
+ /* Form 独立皮肤同时传递引入提交 / 重置钮的动作控件配方;full bundle 递归去重。 */
9
+ @import '../family/action-control.css';
10
+
1
11
  @layer xihan.components {
2
12
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
13
  [data-scope='form'] {
@@ -12,16 +22,20 @@
12
22
  margin: 0;
13
23
  }
14
24
 
25
+ /* 网格:字段排进等宽列,各列下限写 0,一段长文本不会把自己那列撑宽。
26
+ 列数由 data-columns 逐档给,换档只改 --xh-_form-cols 这一个槽 */
27
+ [data-scope='form'][data-part='root'][data-layout='grid'] {
28
+ display: grid;
29
+ grid-template-columns: repeat(var(--xh-_form-cols), minmax(0, 1fr));
30
+
31
+ --xh-_form-cols: 1;
32
+ }
33
+
15
34
  /* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
16
35
  [data-scope='form'][data-part='root'][hidden] {
17
36
  display: none;
18
37
  }
19
38
 
20
- /* 标签左置:标签列宽的缺省档在这儿,labelWidth 会以行内样式盖过它 */
21
- [data-scope='form'][data-part='root'][data-layout='horizontal'] {
22
- --xh-form-label-w: 30%;
23
- }
24
-
25
39
  /* 横排一行流:字段并肩排,放不下自动折行 */
26
40
  [data-scope='form'][data-part='root'][data-layout='inline'] {
27
41
  flex-flow: row wrap;
@@ -29,6 +43,96 @@
29
43
  column-gap: var(--xh-form-inline-gap, var(--xh-space-4));
30
44
  }
31
45
 
46
+ /* 一列是网格档的缺省,这里从两列起逐档写 */
47
+ [data-scope='form'][data-part='root'][data-columns='2'] {
48
+ --xh-_form-cols: 2;
49
+ }
50
+
51
+ [data-scope='form'][data-part='root'][data-columns='3'] {
52
+ --xh-_form-cols: 3;
53
+ }
54
+
55
+ [data-scope='form'][data-part='root'][data-columns='4'] {
56
+ --xh-_form-cols: 4;
57
+ }
58
+
59
+ /* 逐档列数:移动优先,先按 data-columns 排定,视口每宽到一档就换成那一档的列数,
60
+ 没写的档沿用比它窄的那一档。四档自窄到宽依次写,只用 min-width:媒体查询不改选择器权重,
61
+ 宽视口上同时命中好几档时由源码序决定谁生效。
62
+ 宽度写字面量:自定义属性在 @media 条件里不参与求值。
63
+ 每档都从一列写起:base 分多列、某一档收回一列同样是合法的一档 */
64
+ @media (min-width: 640px) {
65
+ [data-scope='form'][data-part='root'][data-columns-sm='1'] {
66
+ --xh-_form-cols: 1;
67
+ }
68
+
69
+ [data-scope='form'][data-part='root'][data-columns-sm='2'] {
70
+ --xh-_form-cols: 2;
71
+ }
72
+
73
+ [data-scope='form'][data-part='root'][data-columns-sm='3'] {
74
+ --xh-_form-cols: 3;
75
+ }
76
+
77
+ [data-scope='form'][data-part='root'][data-columns-sm='4'] {
78
+ --xh-_form-cols: 4;
79
+ }
80
+ }
81
+
82
+ @media (min-width: 768px) {
83
+ [data-scope='form'][data-part='root'][data-columns-md='1'] {
84
+ --xh-_form-cols: 1;
85
+ }
86
+
87
+ [data-scope='form'][data-part='root'][data-columns-md='2'] {
88
+ --xh-_form-cols: 2;
89
+ }
90
+
91
+ [data-scope='form'][data-part='root'][data-columns-md='3'] {
92
+ --xh-_form-cols: 3;
93
+ }
94
+
95
+ [data-scope='form'][data-part='root'][data-columns-md='4'] {
96
+ --xh-_form-cols: 4;
97
+ }
98
+ }
99
+
100
+ @media (min-width: 1024px) {
101
+ [data-scope='form'][data-part='root'][data-columns-lg='1'] {
102
+ --xh-_form-cols: 1;
103
+ }
104
+
105
+ [data-scope='form'][data-part='root'][data-columns-lg='2'] {
106
+ --xh-_form-cols: 2;
107
+ }
108
+
109
+ [data-scope='form'][data-part='root'][data-columns-lg='3'] {
110
+ --xh-_form-cols: 3;
111
+ }
112
+
113
+ [data-scope='form'][data-part='root'][data-columns-lg='4'] {
114
+ --xh-_form-cols: 4;
115
+ }
116
+ }
117
+
118
+ @media (min-width: 1280px) {
119
+ [data-scope='form'][data-part='root'][data-columns-xl='1'] {
120
+ --xh-_form-cols: 1;
121
+ }
122
+
123
+ [data-scope='form'][data-part='root'][data-columns-xl='2'] {
124
+ --xh-_form-cols: 2;
125
+ }
126
+
127
+ [data-scope='form'][data-part='root'][data-columns-xl='3'] {
128
+ --xh-_form-cols: 3;
129
+ }
130
+
131
+ [data-scope='form'][data-part='root'][data-columns-xl='4'] {
132
+ --xh-_form-cols: 4;
133
+ }
134
+ }
135
+
32
136
  /* 字段容器只管排版与状态标记:标题、控件、描述、错误文案都是里面那个 Field 的活儿 */
33
137
  [data-scope='form'][data-part='field-group'] {
34
138
  display: flex;
@@ -40,6 +144,29 @@
40
144
  display: none;
41
145
  }
42
146
 
147
+ /* 网格排布下这一格占多宽,不写就占一列 */
148
+ [data-scope='form'][data-part='root'][data-layout='grid'] [data-scope='form'][data-part='field-group'] {
149
+ grid-column: var(--xh-_form-span, auto);
150
+ }
151
+
152
+ /* 占一列是上面的缺省,这里从跨两列起逐档写 */
153
+ [data-scope='form'][data-part='field-group'][data-span='2'] {
154
+ --xh-_form-span: auto / span 2;
155
+ }
156
+
157
+ [data-scope='form'][data-part='field-group'][data-span='3'] {
158
+ --xh-_form-span: auto / span 3;
159
+ }
160
+
161
+ [data-scope='form'][data-part='field-group'][data-span='4'] {
162
+ --xh-_form-span: auto / span 4;
163
+ }
164
+
165
+ /* 占满整行:从第一条列线排到最后一条,列数换档时不必跟着改跨度 */
166
+ [data-scope='form'][data-part='field-group'][data-span='full'] {
167
+ --xh-_form-span: 1 / -1;
168
+ }
169
+
43
170
  /* 出错的字段在起始缘竖一条色带:读屏之外还得有一眼看得见的定位标记。
44
171
  用逻辑属性,RTL 下自动换到右侧 */
45
172
  [data-scope='form'][data-part='field-group'][data-invalid] {
@@ -47,13 +174,6 @@
47
174
  border-inline-start: var(--xh-stroke-thick) solid var(--xh-form-field-invalid-border, var(--xh-border-invalid));
48
175
  }
49
176
 
50
- /* 容器带着 tabindex=-1:控件全禁用时焦点会落在它自己身上,
51
- 那一刻必须画环,否则键盘用户看不出自己被送到了哪儿 */
52
- [data-scope='form'][data-part='field-group']:focus-visible {
53
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
54
- outline-offset: var(--xh-ring-offset);
55
- }
56
-
57
177
  /* 提交失败后的错误汇总。role=alert 常挂,靠 hidden 显隐 */
58
178
  [data-scope='form'][data-part='error-summary'] {
59
179
  display: flex;
@@ -67,7 +187,8 @@
67
187
  color: var(--xh-form-summary-fg, var(--xh-fg-danger));
68
188
  font-size: var(--xh-form-summary-font-size, var(--xh-text-body-size));
69
189
  line-height: var(--xh-leading-normal);
70
- box-shadow: var(--xh-form-summary-shadow, var(--xh-elevation-raised));
190
+ /* 静态反馈面:边界由描边承担,不带落影(§8 solid 无影) */
191
+ box-shadow: var(--xh-form-summary-shadow, none);
71
192
  }
72
193
 
73
194
  /* 漏了这条,摘要一旦出现过就再也撤不下去(上面那条 display 盖掉了 UA 的 [hidden] 规则) */
@@ -83,17 +204,24 @@
83
204
  /* 从收起翻成显出的那一下给一小段入场:读屏靠 role=alert 播报,
84
205
  视觉这边也得有个"它是刚冒出来的"的交代,否则像一直杵在那儿 */
85
206
  [data-scope='form'][data-part='error-summary'][data-state='invalid'] {
86
- animation: xh-form-summary-enter var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
207
+ animation: xh-form-summary-enter var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
87
208
  }
88
209
 
89
- /* 摘要里的每一条是一个真链接,指向对应字段容器 */
210
+ /* 摘要里的每一条是一个真链接,指向对应字段容器。铺满一行的集合行(§9.2):悬停 / 按下只换面不缩放,
211
+ 底面坐在摘要的 surface 白底上,走白底承载阶梯 100 → 200;换面走按压时间线,释放回 release 档 */
90
212
  [data-scope='form'][data-part='error-summary-item'] {
91
213
  display: block;
214
+ padding-inline: var(--xh-form-summary-item-px, var(--xh-space-1));
215
+ border-radius: var(--xh-form-summary-item-radius, var(--xh-shape-control));
216
+ background: var(--xh-form-summary-item-bg, transparent);
92
217
  color: inherit;
93
218
  font-size: var(--xh-form-summary-item-font-size, var(--xh-text-secondary-size));
94
219
  text-decoration: underline;
95
- text-underline-offset: 2px;
220
+ text-underline-offset: var(--xh-form-summary-item-underline-offset, var(--xh-space-0_5));
96
221
  cursor: pointer;
222
+ transition:
223
+ background-color var(--xh-motion-duration-release) var(--xh-motion-ease-release),
224
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
97
225
  }
98
226
 
99
227
  /* 没有对应错误的条目由连接层给 hidden;上面那条 display 已把 UA 规则盖掉 */
@@ -101,87 +229,136 @@
101
229
  display: none;
102
230
  }
103
231
 
104
- [data-scope='form'][data-part='error-summary-item']:hover {
105
- color: var(--xh-form-summary-item-fg-hover, var(--xh-fg-danger-hover));
232
+ /* 摘要显出时条目逐条入场,越靠后起步越晚。
233
+ backwards 让还没轮到的条目停在首帧,不是先显出再重播 */
234
+ [data-scope='form'][data-part='error-summary'][data-state='invalid'] [data-part='error-summary-item'] {
235
+ animation: xh-form-summary-enter var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong) backwards;
106
236
  }
107
237
 
108
- [data-scope='form'][data-part='error-summary-item']:focus-visible {
109
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
110
- outline-offset: var(--xh-ring-offset);
238
+ /* 排序按"前面有几条露面的"数,不按 nth-child:作者一次把所有字段的条目都写上,
239
+ 没出错的那些带着 hidden 留在 DOM 里,按位置数会把空号也算进去。
240
+ 每多一节 ~ 就多要求前面多一条露面的条目,链越长的规则排得越后、赢过短链 */
241
+ [data-scope='form'][data-part='error-summary'][data-state='invalid']
242
+ [data-part='error-summary-item']:not([hidden])
243
+ ~ [data-part='error-summary-item']:not([hidden]) {
244
+ animation-delay: var(--xh-motion-stagger-step);
111
245
  }
112
246
 
113
- /* 两颗按钮共用一份底子:它们是同一种东西,只是干的活不同,
114
- 分开写迟早会改了一颗忘了另一颗 */
115
- [data-scope='form'][data-part='submit-trigger'],
116
- [data-scope='form'][data-part='reset-trigger'] {
117
- display: inline-flex;
118
- flex: none;
119
- align-items: center;
120
- justify-content: center;
121
- block-size: var(--xh-form-trigger-h, var(--xh-control-h-md));
122
- padding-block: 0;
123
- padding-inline: var(--xh-form-trigger-px, var(--xh-control-px-md));
124
- border: var(--xh-stroke-thin) solid var(--xh-form-trigger-border, var(--xh-border-control));
125
- border-radius: var(--xh-form-trigger-radius, var(--xh-shape-control));
126
- background: var(--xh-form-trigger-bg, var(--xh-bg-subtle));
127
- color: var(--xh-form-trigger-fg, var(--xh-fg-default));
128
- /* 表单控件不继承页面字体,只给字号会让按钮用 UA 默认字族,与周围文本对不上 */
129
- font-family: inherit;
130
- font-size: var(--xh-form-trigger-font-size, var(--xh-text-body-size));
131
- line-height: var(--xh-leading-none);
132
- white-space: nowrap;
133
- cursor: pointer;
134
- user-select: none;
135
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
247
+ [data-scope='form'][data-part='error-summary'][data-state='invalid']
248
+ [data-part='error-summary-item']:not([hidden])
249
+ ~ [data-part='error-summary-item']:not([hidden])
250
+ ~ [data-part='error-summary-item']:not([hidden]) {
251
+ animation-delay: calc(var(--xh-motion-stagger-step) * 2);
136
252
  }
137
253
 
138
- [data-scope='form'][data-part='submit-trigger'][hidden],
139
- [data-scope='form'][data-part='reset-trigger'][hidden] {
140
- display: none;
254
+ [data-scope='form'][data-part='error-summary'][data-state='invalid']
255
+ [data-part='error-summary-item']:not([hidden])
256
+ ~ [data-part='error-summary-item']:not([hidden])
257
+ ~ [data-part='error-summary-item']:not([hidden])
258
+ ~ [data-part='error-summary-item']:not([hidden]) {
259
+ animation-delay: calc(var(--xh-motion-stagger-step) * 3);
141
260
  }
142
261
 
143
- [data-scope='form'][data-part='submit-trigger']:hover:not(:disabled),
144
- [data-scope='form'][data-part='reset-trigger']:hover:not(:disabled) {
145
- border-color: var(--xh-form-trigger-border-hover, var(--xh-border-control-hover));
146
- background: var(--xh-form-trigger-bg-hover, var(--xh-bg-subtle-hover));
262
+ [data-scope='form'][data-part='error-summary'][data-state='invalid']
263
+ [data-part='error-summary-item']:not([hidden])
264
+ ~ [data-part='error-summary-item']:not([hidden])
265
+ ~ [data-part='error-summary-item']:not([hidden])
266
+ ~ [data-part='error-summary-item']:not([hidden])
267
+ ~ [data-part='error-summary-item']:not([hidden]) {
268
+ animation-delay: calc(var(--xh-motion-stagger-step) * 4);
147
269
  }
148
270
 
149
- [data-scope='form'][data-part='submit-trigger']:active:not(:disabled),
150
- [data-scope='form'][data-part='reset-trigger']:active:not(:disabled) {
151
- background: var(--xh-form-trigger-bg-active, var(--xh-bg-subtle-active));
271
+ /* 第 6 条起共用同一档延迟:这条要求前面有五条露面的,第七条往后同样命中,
272
+ 错误多时整批的等待时间不再随条数增长 */
273
+ [data-scope='form'][data-part='error-summary'][data-state='invalid']
274
+ [data-part='error-summary-item']:not([hidden])
275
+ ~ [data-part='error-summary-item']:not([hidden])
276
+ ~ [data-part='error-summary-item']:not([hidden])
277
+ ~ [data-part='error-summary-item']:not([hidden])
278
+ ~ [data-part='error-summary-item']:not([hidden])
279
+ ~ [data-part='error-summary-item']:not([hidden]) {
280
+ animation-delay: calc(var(--xh-motion-stagger-step) * 5);
152
281
  }
153
282
 
154
- [data-scope='form'][data-part='submit-trigger']:focus-visible,
155
- [data-scope='form'][data-part='reset-trigger']:focus-visible {
156
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
157
- outline-offset: var(--xh-ring-offset);
283
+ [data-scope='form'][data-part='error-summary-item']:hover {
284
+ background: var(--xh-form-summary-item-bg-hover, var(--xh-bg-subtle));
285
+ color: var(--xh-form-summary-item-fg-hover, var(--xh-fg-danger-hover));
158
286
  }
159
287
 
160
- /* 单体控件用 :disabled(集合条目才用 [data-disabled]):
161
- 整表禁用时提交键置灰,只读时重置键也一并落到这条上 */
162
- [data-scope='form'][data-part='submit-trigger']:disabled,
163
- [data-scope='form'][data-part='reset-trigger']:disabled {
164
- border-color: var(--xh-form-trigger-border-disabled, var(--xh-border-subtle));
165
- background: var(--xh-form-trigger-bg-disabled, var(--xh-bg-muted));
166
- color: var(--xh-fg-disabled);
167
- cursor: not-allowed;
288
+ /* 指针 :active 与 Headless 投影的 data-pressed(Space / Enter 与触屏按住)看见同一副按压面 */
289
+ [data-scope='form'][data-part='error-summary-item']:is(:active, [data-pressed]) {
290
+ background: var(--xh-form-summary-item-bg-pressed, var(--xh-bg-subtle-hover));
291
+ color: var(--xh-form-summary-item-fg-hover, var(--xh-fg-danger-hover));
292
+ transition-duration: var(--xh-motion-duration-press);
293
+ transition-timing-function: var(--xh-motion-ease-press);
168
294
  }
169
295
 
170
- /* 提交是这一组里的主操作,给它一层实心底色区分开 */
171
- [data-scope='form'][data-part='submit-trigger']:not(:disabled) {
172
- border-color: var(--xh-form-submit-border, var(--xh-form-submit-bg, var(--xh-bg-brand)));
173
- background: var(--xh-form-submit-bg, var(--xh-bg-brand));
174
- color: var(--xh-form-submit-fg, var(--xh-fg-on-brand));
296
+ /* 高对比档里底色被系统换掉,按下那一档用系统高亮反色画回 */
297
+ @media (forced-colors: active) {
298
+ [data-scope='form'][data-part='error-summary-item']:is(:active, [data-pressed]) {
299
+ background: Highlight;
300
+ color: HighlightText;
301
+ }
175
302
  }
176
303
 
177
- [data-scope='form'][data-part='submit-trigger']:hover:not(:disabled) {
178
- border-color: var(--xh-form-submit-border-hover, var(--xh-form-submit-bg-hover, var(--xh-bg-brand-hover)));
179
- background: var(--xh-form-submit-bg-hover, var(--xh-bg-brand-hover));
304
+ /* 两颗按钮是离散动作控件:盒几何、悬停 / 按下与 0.97 按压、焦点环、禁用面全由 Action Control 的 text 档给,
305
+ 组件只映射既有使用者槽。提交走 solid 档:表单提交是这一组里的主要动作,与 Button 缺省同为品牌实心;
306
+ 重置走 outline 档:非 Button 的触发器缺省中性描边(§7.2.2)。两颗共用的几何与字号写在一起 */
307
+ [data-scope='form'][data-part='submit-trigger'],
308
+ [data-scope='form'][data-part='reset-trigger'] {
309
+ --xh-action-visual-size: var(--xh-form-trigger-h, var(--xh-_action-profile-visual-size));
310
+ --xh-action-padding-inline: var(--xh-form-trigger-px, var(--xh-_action-profile-padding-inline));
311
+ --xh-action-radius: var(--xh-form-trigger-radius, var(--xh-shape-control));
312
+ --xh-action-font-size: var(--xh-form-trigger-font-size, var(--xh-text-body-size));
313
+
314
+ /* 按钮不参与弹性伸缩 */
315
+ flex: none;
316
+ }
317
+
318
+ /* 家族那条 display 会把 UA 的 [hidden]{display:none} 盖掉 */
319
+ [data-scope='form'][data-part='submit-trigger'][hidden],
320
+ [data-scope='form'][data-part='reset-trigger'][hidden] {
321
+ display: none;
322
+ }
323
+
324
+ /* 重置钮:中性描边,底 / 边 / 字与禁用面映到 outline 档的桥接槽(透明底 → 100 → 200) */
325
+ [data-scope='form'][data-part='reset-trigger'] {
326
+ --xh-action-bg-rest: var(--xh-form-trigger-bg, var(--xh-_action-variant-bg-rest));
327
+ --xh-action-bg-hover: var(--xh-form-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
328
+ --xh-action-bg-pressed: var(--xh-form-trigger-bg-active, var(--xh-_action-variant-bg-pressed));
329
+ --xh-action-bg-disabled: var(--xh-form-trigger-bg-disabled, var(--xh-_action-variant-bg-disabled));
330
+ --xh-action-fg-rest: var(--xh-form-trigger-fg, var(--xh-_action-variant-fg-rest));
331
+ --xh-action-fg-hover: var(--xh-form-trigger-fg, var(--xh-_action-variant-fg-hover));
332
+ --xh-action-fg-pressed: var(--xh-form-trigger-fg, var(--xh-_action-variant-fg-pressed));
333
+ --xh-action-border-rest: var(--xh-form-trigger-border, var(--xh-_action-variant-border-rest));
334
+ --xh-action-border-hover: var(--xh-form-trigger-border-hover, var(--xh-_action-variant-border-hover));
335
+ --xh-action-border-disabled: var(--xh-form-trigger-border-disabled, var(--xh-_action-variant-border-disabled));
336
+ --xh-action-highlight-rest: transparent;
337
+ --xh-action-shadow-rest: none;
338
+ --xh-action-shadow-hover: none;
339
+ --xh-action-shadow-pressed: none;
180
340
  }
181
341
 
182
- [data-scope='form'][data-part='submit-trigger']:active:not(:disabled) {
183
- border-color: var(--xh-form-submit-border-active, var(--xh-form-submit-bg-active, var(--xh-bg-brand-active)));
184
- background: var(--xh-form-submit-bg-active, var(--xh-bg-brand-active));
342
+ /* 提交钮:品牌实心,顶边一条极浅的内高光把这块面衬出厚度(三态同一支,禁用面由家族收掉)。
343
+ 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
344
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的 */
345
+ [data-scope='form'][data-part='submit-trigger'] {
346
+ --xh-action-bg-rest: var(--xh-form-submit-bg, var(--xh-_action-variant-bg-rest));
347
+ --xh-action-bg-hover: var(--xh-form-submit-bg-hover, var(--xh-_action-variant-bg-hover));
348
+ --xh-action-bg-pressed: var(--xh-form-submit-bg-active, var(--xh-_action-variant-bg-pressed));
349
+ --xh-action-bg-disabled: var(--xh-form-trigger-bg-disabled, var(--xh-_action-variant-bg-disabled));
350
+ --xh-action-fg-rest: var(--xh-form-submit-fg, var(--xh-_action-variant-fg-rest));
351
+ --xh-action-fg-hover: var(--xh-form-submit-fg, var(--xh-_action-variant-fg-hover));
352
+ --xh-action-fg-pressed: var(--xh-form-submit-fg, var(--xh-_action-variant-fg-pressed));
353
+ --xh-action-border-rest: var(--xh-form-submit-border, var(--xh-_action-variant-border-rest));
354
+ --xh-action-border-hover: var(--xh-form-submit-border-hover, var(--xh-_action-variant-border-hover));
355
+ --xh-action-border-pressed: var(--xh-form-submit-border-active, var(--xh-_action-variant-border-pressed));
356
+ --xh-action-border-disabled: var(--xh-form-trigger-border-disabled, var(--xh-_action-variant-border-disabled));
357
+ --xh-action-highlight-rest: transparent;
358
+ --xh-action-shadow-rest: var(--xh-form-submit-shadow, var(--xh-_highlight-brand));
359
+ --xh-action-shadow-hover: var(--xh-form-submit-shadow, var(--xh-_highlight-brand));
360
+ --xh-action-shadow-pressed: var(--xh-form-submit-shadow, var(--xh-_highlight-brand));
361
+ --xh-action-ring-color-focus-visible: currentColor;
185
362
  }
186
363
  }
187
364
 
@@ -1,4 +1,21 @@
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
+ /* 定义 gradient text 样式。 */
7
+
1
8
  @layer xihan.components {
9
+ /* 轴边界只路由简单前景值,渐变本身仍在组件根用本地 direction/from/to 计算。
10
+ 这样内层 default/more 能双向重置,也不会把未解析的组件变量冻结在祖先上。 */
11
+ :where(:root, [data-contrast='default']) {
12
+ --xh-_gradient-text-fg: transparent;
13
+ }
14
+
15
+ :where([data-contrast='more']) {
16
+ --xh-_gradient-text-fg: var(--xh-fg-default);
17
+ }
18
+
2
19
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
20
  [data-scope='gradient-text'] {
4
21
  --xh-gradient-text-skin: 1;
@@ -10,24 +27,23 @@
10
27
  [data-scope='gradient-text'][data-part='root'] {
11
28
  /* 走向由 data-direction 换掉这一个槽,背景那条声明只写一遍 */
12
29
  --xh-_gradient-text-dir: to right;
30
+ /* 两端颜色各收一个私有槽:语气档换的是这两支,使用者槽仍排在它们前面 */
31
+ --xh-_gradient-text-from: var(--xh-gradient-brand-from);
32
+ --xh-_gradient-text-to: var(--xh-gradient-brand-to);
13
33
 
14
34
  background-image: linear-gradient(
15
35
  var(--xh-_gradient-text-dir),
16
- var(--xh-gradient-text-from, var(--xh-color-brand-500)),
17
- var(--xh-gradient-text-to, var(--xh-color-brand-700))
36
+ var(--xh-gradient-text-from, var(--xh-_gradient-text-from)),
37
+ var(--xh-gradient-text-to, var(--xh-_gradient-text-to))
18
38
  );
19
39
  -webkit-background-clip: text;
20
40
  background-clip: text;
21
- color: transparent;
22
- -webkit-text-fill-color: transparent;
41
+ color: var(--xh-_gradient-text-fg);
42
+ -webkit-text-fill-color: currentColor;
23
43
  }
24
44
 
25
45
  /* —— 走向 —— */
26
46
  /* 逐档换算成 CSS 的 to <边或角>,四条边加四个角 */
27
- [data-scope='gradient-text'][data-part='root'][data-direction='to-right'] {
28
- --xh-_gradient-text-dir: to right;
29
- }
30
-
31
47
  [data-scope='gradient-text'][data-part='root'][data-direction='to-left'] {
32
48
  --xh-_gradient-text-dir: to left;
33
49
  }
@@ -56,8 +72,16 @@
56
72
  --xh-_gradient-text-dir: to top left;
57
73
  }
58
74
 
59
- /* 强制色模式下系统会禁掉背景图,留着透明前景整段字就彻底看不见了,这里把填充色还回去 */
60
- @media (forced-colors: active) {
75
+ /* —— 语气 —— */
76
+ /* 两端取该族主色与它压深一档的取值,深浅两态自动跟随。
77
+ 排在使用者槽之后:作者写了 from / to,六族语气一并让位 */
78
+ [data-scope='gradient-text'][data-part='root'][data-tone] {
79
+ --xh-_gradient-text-from: var(--xh-_tone);
80
+ --xh-_gradient-text-to: var(--xh-_tone-active);
81
+ }
82
+
83
+ /* 无 JS 时的系统高对比、强制色与打印统一退回单色;显式局部轴由上面的最近作用域标记负责。 */
84
+ @media (prefers-contrast: more), (forced-colors: active), print {
61
85
  [data-scope='gradient-text'][data-part='root'] {
62
86
  background-image: none;
63
87
  color: inherit;