@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,318 +1,150 @@
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
+ /* TextField 独立皮肤同时传递引入字段视觉盒与字段内动作;full bundle 递归去重。 */
7
+ @import '../family/field-chrome.css';
8
+ @import '../family/action-control.css';
9
+
1
10
  @layer xihan.components {
2
- /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
11
  [data-scope='text-field'] {
4
12
  --xh-text-field-skin: 1;
5
13
  }
6
14
 
7
- /* root 只负责纵向堆叠:标签一行、输入行一行。
8
- 输入框与清空按钮收进 control 部件即得一体式:视觉盒画在 control 上,框内两件都退成透明分段。
9
- 不写 control 时退回两件并排的观感(下方 input 与清空按钮的基础规则原样生效) */
15
+ /* 组件层只把既有公开槽映射到家族合同,并保留 label/count 等 TextField 专属结构;
16
+ 形态三档由家族按 control 上的 data-variant 生成,皮肤不再声明。 */
10
17
  [data-scope='text-field'][data-part='root'] {
11
- /* 作者塞进来的图标跟着控件的尺寸档走;它自己写了 size 时仍以作者的为准 */
12
- --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-md));
13
-
14
- /* 尺寸档只换这几个私有槽,标题、输入框与清空按钮都从 root 继承它们,
15
- 换档不必给每个部件各写一条选择器 */
16
18
  --xh-_text-field-h: var(--xh-control-h-md);
17
19
  --xh-_text-field-px: var(--xh-control-px-md);
18
20
  --xh-_text-field-gap: var(--xh-control-gap-md);
19
21
  --xh-_text-field-font-size: var(--xh-control-font-md);
20
- --xh-_text-field-label-font-size: var(--xh-control-font-md);
21
22
  --xh-_text-field-action-font-size: var(--xh-control-caption-md);
22
23
 
23
- /* 形态档只换这三个私有槽:底、常态描边、悬停描边 */
24
- --xh-_text-field-bg: var(--xh-bg-canvas);
25
- --xh-_text-field-border: var(--xh-border-control);
26
- --xh-_text-field-border-hover: var(--xh-border-control-hover);
27
-
28
- /* 语气只落在聚焦这一处:环与聚焦态描边。正文颜色不归它管。
29
- 没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色与常态描边 */
30
- --xh-_text-field-ring: var(--xh-ring-focus);
31
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control-focus)));
24
+ --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-md));
32
25
 
33
26
  display: inline-flex;
34
27
  flex-direction: column;
35
28
  gap: var(--xh-text-field-gap, var(--xh-space-1));
29
+ /* 不传尺寸时一律这么宽,宽度不随内容走;父容器给不出这么宽时整件跟着收,地板同步让步,不越出父容器。
30
+ 地板不高过缺省宽:使用者把缺省宽钉到底线以下时不必再放开底线 */
31
+ inline-size: var(--xh-text-field-control-w, var(--xh-control-w));
32
+ min-inline-size: min(var(--xh-text-field-control-w, var(--xh-control-w)), var(--xh-text-field-control-min-w, var(--xh-control-min-w)), 100%);
33
+ max-inline-size: 100%;
36
34
  }
37
35
 
38
- /* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
39
36
  [data-scope='text-field'][data-part='root'][hidden] {
40
37
  display: none;
41
38
  }
42
39
 
43
- /* —— 尺寸 —— */
44
- /* 缺省档写在上面的基础规则里 */
45
40
  [data-scope='text-field'][data-part='root'][data-size='sm'] {
46
- --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-sm));
47
41
  --xh-_text-field-h: var(--xh-control-h-sm);
48
42
  --xh-_text-field-px: var(--xh-control-px-sm);
49
43
  --xh-_text-field-gap: var(--xh-control-gap-sm);
50
44
  --xh-_text-field-font-size: var(--xh-control-font-sm);
51
- --xh-_text-field-label-font-size: var(--xh-control-font-sm);
52
45
  --xh-_text-field-action-font-size: var(--xh-control-caption-sm);
46
+ --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-sm));
53
47
  }
54
48
 
55
49
  [data-scope='text-field'][data-part='root'][data-size='lg'] {
56
- --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-lg));
57
50
  --xh-_text-field-h: var(--xh-control-h-lg);
58
51
  --xh-_text-field-px: var(--xh-control-px-lg);
59
52
  --xh-_text-field-gap: var(--xh-control-gap-lg);
60
53
  --xh-_text-field-font-size: var(--xh-control-font-lg);
61
- --xh-_text-field-label-font-size: var(--xh-control-font-lg);
62
54
  --xh-_text-field-action-font-size: var(--xh-control-caption-lg);
63
- }
64
-
65
- /* —— 形态 —— */
66
- /* 形态只决定底与描边怎么画;用哪族颜色由 data-tone 决定。
67
- 输入框没有实心档:填满一个要往里打字的框,字与底就没法同时读 */
68
- [data-scope='text-field'][data-part='root'][data-variant='outline'] {
69
- --xh-_text-field-bg: var(--xh-bg-canvas);
70
- --xh-_text-field-border: var(--xh-border-control);
71
- --xh-_text-field-border-hover: var(--xh-border-control-hover);
72
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control-focus)));
73
- }
74
-
75
- /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
76
- 与 outline 档并排时基线对得上、聚焦画描边也不引起跳动 */
77
- [data-scope='text-field'][data-part='root'][data-variant='subtle'] {
78
- --xh-_text-field-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
79
- --xh-_text-field-border: transparent;
80
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
81
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control-focus));
82
- }
83
-
84
- /* 无框:底与常态描边透明,悬停与聚焦浮出描边 */
85
- [data-scope='text-field'][data-part='root'][data-variant='ghost'] {
86
- --xh-_text-field-bg: transparent;
87
- --xh-_text-field-border: transparent;
88
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
89
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control-focus));
55
+ --xh-icon-size: var(--xh-text-field-icon-size, var(--xh-glyph-size-lg));
90
56
  }
91
57
 
92
58
  [data-scope='text-field'][data-part='label'] {
93
59
  color: var(--xh-text-field-label-fg, var(--xh-fg-default));
94
- font-size: var(--xh-text-field-label-font-size, var(--xh-_text-field-label-font-size));
60
+ font-size: var(--xh-text-field-label-font-size, var(--xh-text-label-size));
95
61
  font-weight: var(--xh-text-field-label-font-weight, var(--xh-text-label-weight));
96
- line-height: var(--xh-leading-none);
97
62
  }
98
63
 
99
64
  [data-scope='text-field'][data-part='label'][data-disabled] {
100
65
  color: var(--xh-text-field-label-fg-disabled, var(--xh-fg-subtle));
101
66
  }
102
67
 
103
- /* —— 一体式 control:输入框与清空按钮同框 —— */
104
- /* control 是唯一的视觉盒:描边、底色、圆角、聚焦环全画在它身上,框内两件都退成透明分段。
105
- :focus-within 而不是 :focus——持有焦点的是框里的输入框,被聚焦的"控件"在眼里是整个框 */
106
68
  [data-scope='text-field'][data-part='control'] {
107
- display: inline-flex;
108
- align-items: center;
109
- gap: var(--xh-text-field-control-gap, var(--xh-_text-field-gap));
110
- min-inline-size: var(--xh-text-field-control-min-w, var(--xh-control-min-w));
111
- block-size: var(--xh-text-field-control-h, var(--xh-_text-field-h));
112
- padding-inline: var(--xh-text-field-control-px, var(--xh-_text-field-px));
113
- border: var(--xh-stroke-thin) solid var(--xh-text-field-control-border, var(--xh-_text-field-border));
114
- border-radius: var(--xh-text-field-control-radius, var(--xh-shape-control));
115
- background: var(--xh-text-field-control-bg, var(--xh-_text-field-bg));
116
- color: var(--xh-text-field-control-fg, var(--xh-fg-default));
117
- transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
118
- }
119
-
120
- [data-scope='text-field'][data-part='control'][hidden] {
121
- display: none;
122
- }
123
-
124
- /* hover 只在中性态换描边:invalid at-limit 正拿边框颜色说事,
125
- hover 盖掉那条信息就没了 */
126
- [data-scope='text-field'][data-part='control']:hover:not([data-disabled], [data-invalid], [data-at-limit]) {
127
- border-color: var(--xh-text-field-control-border-hover, var(--xh-_text-field-border-hover));
128
- }
129
-
130
- [data-scope='text-field'][data-part='control']:focus-within:not([data-disabled]) {
131
- border-color: var(--xh-text-field-control-border-focus, var(--xh-_text-field-border-focus));
132
- outline: var(--xh-ring-width) solid var(--xh-_text-field-ring);
133
- outline-offset: var(--xh-ring-offset);
134
- }
135
-
136
- /* 顶到字数上限:再敲进不去,边框先给个提示。放在 invalid 之前,
137
- 两者同时成立时按源序让 invalid 赢 */
138
- [data-scope='text-field'][data-part='control'][data-at-limit] {
139
- border-color: var(--xh-text-field-control-border-at-limit, var(--xh-border-at-limit));
140
- }
141
-
142
- [data-scope='text-field'][data-part='control'][data-invalid] {
143
- border-color: var(--xh-text-field-control-border-invalid, var(--xh-border-invalid));
144
-
145
- /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
146
- --xh-_text-field-ring: var(--xh-ring-invalid);
147
- }
148
-
149
- /* 只读仍可聚焦、可复制,所以不置灰,只把底色压下去表示"改不动" */
150
- [data-scope='text-field'][data-part='control'][data-readonly] {
151
- background: var(--xh-text-field-control-bg-readonly, var(--xh-bg-subtle));
152
- }
153
-
154
- [data-scope='text-field'][data-part='control'][data-disabled] {
155
- background: var(--xh-text-field-control-bg-disabled, var(--xh-bg-subtle));
156
- color: var(--xh-fg-disabled);
157
- cursor: not-allowed;
158
- }
159
-
160
- /* 盒内 input:无边框无底无圆角,观感全归 control;行内内衬也归 control,
161
- 这里再留一份就是框内套了一圈空白。它占满剩余宽度,把清空按钮顶到最右 */
162
- [data-scope='text-field'][data-part='control'] [data-part='input'] {
163
- flex: 1 1 auto;
164
- min-inline-size: 0;
165
- block-size: 100%;
166
- padding-inline: 0;
167
- border: 0;
168
- border-radius: 0;
169
- background: transparent;
170
- }
171
-
172
- /* 盒内 input 不再自己画各态,全部交还 control。hover 这条带上与基础规则同样的
173
- :not 条件:基础 hover 的特异度里有它们,不带就打不过 */
174
- [data-scope='text-field'][data-part='control'] [data-part='input']:hover:not(:disabled, [data-invalid], [data-at-limit]) {
175
- border-color: transparent;
176
- }
177
-
178
- [data-scope='text-field'][data-part='control'] [data-part='input']:focus-visible {
179
- border-color: transparent;
180
- outline: none;
181
- }
182
-
183
- [data-scope='text-field'][data-part='control'] [data-part='input'][data-at-limit],
184
- [data-scope='text-field'][data-part='control'] [data-part='input'][data-invalid] {
185
- border-color: transparent;
186
- }
187
-
188
- [data-scope='text-field'][data-part='control'] [data-part='input']:disabled,
189
- [data-scope='text-field'][data-part='control'] [data-part='input'][readonly] {
190
- background: transparent;
191
- }
192
-
193
- /* 尾部动作钮不参与分宽,宽度由它自己的方钮尺寸决定 */
194
- [data-scope='text-field'][data-part='control'] [data-part='clear-trigger'] {
195
- flex: none;
69
+ --xh-field-control-height: var(--xh-text-field-control-h, var(--xh-_text-field-h));
70
+ --xh-field-control-padding-inline: var(--xh-text-field-control-px, var(--xh-_text-field-px));
71
+ --xh-field-control-gap: var(--xh-text-field-control-gap, var(--xh-_text-field-gap));
72
+ --xh-field-control-min-inline-size: var(--xh-text-field-control-min-w, var(--xh-control-min-w));
73
+ --xh-field-control-radius: var(--xh-text-field-control-radius, var(--xh-shape-control));
74
+ --xh-field-bg-rest: var(--xh-text-field-control-bg, var(--xh-_field-variant-bg-rest));
75
+ --xh-field-bg-hover: var(--xh-text-field-control-bg-hover, var(--xh-_field-variant-bg-hover));
76
+ --xh-field-bg-read-only: var(--xh-text-field-control-bg-readonly, var(--xh-_field-variant-bg-read-only));
77
+ --xh-field-bg-disabled: var(--xh-text-field-control-bg-disabled, var(--xh-_field-variant-bg-disabled));
78
+ --xh-field-fg-rest: var(--xh-text-field-control-fg, var(--xh-fg-default));
79
+ --xh-field-border-rest: var(--xh-text-field-control-border, var(--xh-_field-variant-border-rest));
80
+ --xh-field-border-hover: var(--xh-text-field-control-border-hover, var(--xh-_field-variant-border-hover));
81
+ --xh-field-border-focus: var(--xh-text-field-control-border-focus, var(--xh-_field-variant-border-focus));
82
+ --xh-field-border-invalid: var(--xh-text-field-control-border-invalid, var(--xh-_field-variant-border-invalid));
83
+ --xh-field-ring-focus: var(--xh-ring-focus);
84
+ --xh-field-ring-invalid: var(--xh-ring-invalid);
85
+ --xh-field-shadow-rest: var(--xh-text-field-control-shadow, none);
86
+ /* 家族 chrome 会重写 --xh-icon-size,使用者图标槽必须经桥接槽下发才能在盒内生效 */
87
+ --xh-field-glyph-size: var(--xh-text-field-icon-size, var(--xh-_field-size-glyph-size));
88
+ }
89
+
90
+ [data-scope='text-field'][data-part='prefix'],
91
+ [data-scope='text-field'][data-part='suffix'] {
92
+ --xh-field-affix-fg: var(--xh-text-field-affix-fg, var(--xh-fg-muted));
93
+ --xh-field-affix-fg-disabled: var(--xh-text-field-affix-fg-disabled, var(--xh-fg-disabled));
94
+ --xh-field-affix-font-size: var(--xh-text-field-affix-font-size, var(--xh-_text-field-font-size));
196
95
  }
197
96
 
198
97
  [data-scope='text-field'][data-part='input'] {
199
- min-inline-size: var(--xh-text-field-input-min-w, var(--xh-control-min-w));
200
- block-size: var(--xh-text-field-input-h, var(--xh-_text-field-h));
201
- padding-inline: var(--xh-text-field-input-px, var(--xh-_text-field-px));
202
- padding-block: 0;
203
- border: var(--xh-stroke-thin) solid var(--xh-text-field-input-border, var(--xh-_text-field-border));
204
- border-radius: var(--xh-text-field-input-radius, var(--xh-shape-control));
205
- background: var(--xh-text-field-input-bg, var(--xh-_text-field-bg));
206
- color: var(--xh-text-field-input-fg, var(--xh-fg-default));
207
- /* 表单控件不继承页面字体,只给字号会让输入框用 UA 默认字族,与周围文本对不上 */
208
- font-family: inherit;
209
- font-size: var(--xh-text-field-input-font-size, var(--xh-_text-field-font-size));
210
- line-height: var(--xh-leading-normal);
211
- transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
212
- }
213
-
214
- /* 多行宿主:定高换成行数撑高,纵向留出内边距;autoSize 接管高度后拉柄与滚动都收掉 */
215
- [data-scope='text-field'][data-part='input'][data-multiline] {
216
- block-size: auto;
217
- min-block-size: var(--xh-text-field-input-h, var(--xh-_text-field-h));
218
- padding-block: var(--xh-text-field-textarea-py, var(--xh-space-2));
219
- resize: vertical;
220
- }
221
-
222
- [data-scope='text-field'][data-part='input'][data-multiline][data-autosize] {
223
- overflow: hidden;
224
- resize: none;
225
- }
226
-
227
- [data-scope='text-field'][data-part='input']::placeholder {
228
- color: var(--xh-text-field-placeholder-fg, var(--xh-fg-subtle));
229
- }
230
-
231
- /* hover 只在中性态换描边:invalid 与 at-limit 正拿边框颜色说事,
232
- 被 hover 盖掉那条信息就没了 */
233
- [data-scope='text-field'][data-part='input']:hover:not(:disabled, [data-invalid], [data-at-limit]) {
234
- border-color: var(--xh-text-field-input-border-hover, var(--xh-_text-field-border-hover));
98
+ --xh-field-input-fg: var(--xh-text-field-input-fg, var(--xh-fg-default));
99
+ --xh-field-input-font-size: var(--xh-text-field-input-font-size, var(--xh-_text-field-font-size));
100
+ --xh-field-placeholder-fg: var(--xh-text-field-placeholder-fg, var(--xh-fg-subtle));
101
+ --xh-field-autofill-bg: var(--xh-text-field-input-autofill-bg, var(--xh-bg-canvas));
102
+ --xh-field-autofill-fg: var(--xh-text-field-input-autofill-fg, var(--xh-fg-default));
103
+ --xh-field-textarea-padding-block: var(--xh-text-field-textarea-py, var(--xh-space-2));
235
104
  }
236
105
 
237
- /* 聚焦态描边与环共用一族语气色。这条特异度低于上面的 hover、也低于下面的
238
- at-limit 与 invalid,三者仍按原来的次序赢过它 */
239
- [data-scope='text-field'][data-part='input']:focus-visible {
240
- border-color: var(--xh-text-field-input-border-focus, var(--xh-_text-field-border-focus));
241
- outline: var(--xh-ring-width) solid var(--xh-_text-field-ring);
242
- outline-offset: var(--xh-ring-offset);
243
- }
244
-
245
- /* 顶到字数上限:再敲进不去,边框先给个提示。放在 invalid 之前,
246
- 两者同时成立时按源序让 invalid 赢——真出错比"写满了"要紧 */
247
- [data-scope='text-field'][data-part='input'][data-at-limit] {
248
- border-color: var(--xh-text-field-input-border-at-limit, var(--xh-border-at-limit));
249
- }
250
-
251
- [data-scope='text-field'][data-part='input'][data-invalid] {
252
- border-color: var(--xh-text-field-input-border-invalid, var(--xh-border-invalid));
253
-
254
- /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
255
- --xh-_text-field-ring: var(--xh-ring-invalid);
106
+ [data-scope='text-field'][data-part='control'][hidden] {
107
+ display: none;
256
108
  }
257
109
 
258
- /* 只读仍可聚焦、可复制,所以不置灰,只把底色压下去表示"改不动" */
259
- [data-scope='text-field'][data-part='input'][readonly] {
260
- background: var(--xh-text-field-input-bg-readonly, var(--xh-bg-subtle));
110
+ /* autoSize 的量高值写在 textarea 上;外壳只负责滚动上限,不能复制量高算法。 */
111
+ [data-scope='text-field'][data-part='control']:has([data-xh-field-input][data-xh-field-auto-size]) {
112
+ max-block-size: var(--xh-text-field-control-max-h, var(--xh-viewport-h-sm));
113
+ overflow-y: auto;
261
114
  }
262
115
 
263
- /* input 是单体表单控件,禁用走原生 disabled */
264
- [data-scope='text-field'][data-part='input']:disabled {
265
- background: var(--xh-text-field-input-bg-disabled, var(--xh-bg-subtle));
266
- color: var(--xh-fg-disabled);
267
- cursor: not-allowed;
116
+ /* 字数上限是 TextField 独有状态;invalid 同时出现时由 Field Chrome 的错误态优先。 */
117
+ [data-scope='text-field'][data-part='control'][data-at-max]:not([data-invalid]) {
118
+ border-color: var(--xh-text-field-control-border-at-max, var(--xh-border-at-limit));
268
119
  }
269
120
 
270
- /* 清空按钮是 input 的兄弟节点而不是子节点,由作者与 input 排成一行;
271
- 它按行内动作钮的尺寸画,在作者那一行里居中即与框对齐 */
121
+ /* clear 的视觉、悬停/按压阶梯与粗指针热区来自 field-inset ghost 档,组件只映射既有覆盖槽。 */
272
122
  [data-scope='text-field'][data-part='clear-trigger'] {
273
- display: inline-flex;
274
- flex: none;
275
- align-items: center;
276
- justify-content: center;
277
- inline-size: var(--xh-text-field-action-size, var(--xh-control-action-size));
278
- block-size: var(--xh-text-field-action-size, var(--xh-control-action-size));
279
- padding: 0;
280
- border: 0;
281
- border-radius: var(--xh-text-field-action-radius, var(--xh-shape-control));
282
- background: var(--xh-text-field-action-bg, transparent);
283
- color: var(--xh-text-field-action-fg, var(--xh-fg-muted));
284
- font-family: inherit;
285
- font-size: var(--xh-text-field-action-font-size, var(--xh-_text-field-action-font-size));
286
- line-height: var(--xh-leading-none);
287
- cursor: pointer;
288
- user-select: none;
289
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter), scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
123
+ --xh-action-visual-size: var(--xh-text-field-action-size, var(--xh-_action-profile-visual-size));
124
+ --xh-action-min-inline-size: var(--xh-text-field-action-size, var(--xh-_action-profile-visual-size));
125
+ --xh-action-radius: var(--xh-text-field-action-radius, var(--xh-shape-inset));
126
+ /* 底色阶梯由 ghost 档给(透明 → 100 → 200),使用者槽只作覆盖入口 */
127
+ --xh-action-bg-rest: var(--xh-text-field-action-bg, var(--xh-_action-variant-bg-rest));
128
+ --xh-action-bg-hover: var(--xh-text-field-action-bg-hover, var(--xh-_action-variant-bg-hover));
129
+ --xh-action-bg-pressed: var(--xh-text-field-action-bg-active, var(--xh-_action-variant-bg-pressed));
130
+ --xh-action-fg-rest: var(--xh-text-field-action-fg, var(--xh-fg-muted));
131
+ --xh-action-fg-hover: var(--xh-text-field-action-fg-hover, var(--xh-fg-default));
132
+ --xh-action-border-rest: transparent;
133
+ --xh-action-highlight-rest: transparent;
134
+ --xh-action-shadow-rest: none;
135
+ --xh-action-shadow-hover: none;
136
+ --xh-action-shadow-pressed: none;
137
+ --xh-action-font-size: var(--xh-text-field-action-font-size, var(--xh-_text-field-action-font-size));
138
+ /* 配方尚未把 profile 字形档灌进 --xh-icon-size,钮内字形先按 field-inset 档逐钮取值 */
139
+ --xh-icon-size: var(--xh-_action-profile-glyph-size);
140
+
141
+ border-width: 0;
290
142
  }
291
143
 
292
- /* 没开 clearable 或清不了时连接层给的是 hidden 属性;上面那条 display 会把 UA 规则盖掉,
293
- 少了这条按钮就一直杵在那儿 */
294
144
  [data-scope='text-field'][data-part='clear-trigger'][hidden] {
295
145
  display: none;
296
146
  }
297
147
 
298
- [data-scope='text-field'][data-part='clear-trigger']:hover {
299
- background: var(--xh-text-field-action-bg-hover, var(--xh-bg-subtle-hover));
300
- color: var(--xh-text-field-action-fg-hover, var(--xh-fg-default));
301
- }
302
-
303
- [data-scope='text-field'][data-part='clear-trigger']:active {
304
- background: var(--xh-text-field-action-bg-active, var(--xh-bg-subtle-active));
305
- scale: var(--xh-motion-scale-press);
306
- }
307
-
308
- /* 按钮不占 Tab 位(tabindex=-1)也不抢焦点,正常操作走不到这里;
309
- 留着是给程序化聚焦兜底,落焦时得看得见 */
310
- [data-scope='text-field'][data-part='clear-trigger']:focus-visible {
311
- outline: var(--xh-ring-width) solid var(--xh-_text-field-ring);
312
- outline-offset: var(--xh-ring-offset);
313
- }
314
-
315
- /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
316
148
  [data-scope='text-field'][data-part='clear-trigger']:empty::before {
317
149
  content: '';
318
150
  display: inline-block;
@@ -323,4 +155,24 @@
323
155
  -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
324
156
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
325
157
  }
158
+
159
+ [data-scope='text-field'][data-part='count'] {
160
+ align-self: flex-end;
161
+ color: var(--xh-text-field-count-fg, var(--xh-fg-muted));
162
+ font-size: var(--xh-text-field-count-font-size, var(--xh-_text-field-action-font-size));
163
+ font-variant-numeric: tabular-nums;
164
+ line-height: var(--xh-leading-normal);
165
+ }
166
+
167
+ [data-scope='text-field'][data-part='count'][hidden] {
168
+ display: none;
169
+ }
170
+
171
+ [data-scope='text-field'][data-part='count'][data-at-max] {
172
+ color: var(--xh-text-field-count-fg-at-max, var(--xh-fg-warning));
173
+ }
174
+
175
+ [data-scope='text-field'][data-part='count'][data-disabled] {
176
+ color: var(--xh-text-field-count-fg-disabled, var(--xh-fg-disabled));
177
+ }
326
178
  }