@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
+ /* TagsInput 独立皮肤同时传递引入字段视觉盒与字段内动作;full bundle 递归去重。 */
7
+ @import '../family/field-chrome.css';
8
+ @import '../family/action-control.css';
9
+
1
10
  @layer xihan.components {
2
11
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
12
  [data-scope='tags-input'] {
@@ -5,32 +14,36 @@
5
14
  }
6
15
 
7
16
  /* root 只负责纵向堆叠:标题一行、控件一行。可见的那个"框"长在 control 上,
8
- 因为标签、输入框、清空按钮都在它里面,边框必须把三者一起圈住 */
17
+ 因为标签、输入框、清空按钮都在它里面,边框必须把三者一起圈住。
18
+ 组件层只把既有公开槽映射到家族合同;形态三档由家族按 control 上的 data-variant 生成,皮肤不再声明 */
9
19
  [data-scope='tags-input'][data-part='root'] {
10
20
  /* 作者塞进来的图标跟着控件的尺寸档走;它自己写了 size 时仍以作者的为准 */
11
21
  --xh-icon-size: var(--xh-tags-input-icon-size, var(--xh-glyph-size-md));
12
22
 
13
- /* 尺寸档只换这六个私有槽,标题、框、输入框与标签都从 root 继承它们,
14
- 换档不必给每个部件各写一条选择器 */
23
+ /* 尺寸档只换这九个私有槽,标题、框、输入框与就地编辑框都从 root 继承它们,
24
+ 换档不必给每个部件各写一条选择器。标签本身是 tag,档位由 data-size 传下去,不走这些槽;
25
+ 就地编辑框的四个槽照 tag 那一档的行框、内衬与字号写,换进换出时与标签一样高 */
15
26
  --xh-_tags-input-control-h: var(--xh-control-h-md);
16
27
  --xh-_tags-input-control-px: var(--xh-control-px-md);
17
28
  --xh-_tags-input-control-gap: var(--xh-control-gap-md);
18
29
  --xh-_tags-input-input-font-size: var(--xh-control-font-md);
19
30
  --xh-_tags-input-item-font-size: var(--xh-control-caption-md);
20
- --xh-_tags-input-label-font-size: var(--xh-control-font-md);
21
- /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
22
- --xh-_tags-input-control-bg: var(--xh-bg-canvas);
23
- --xh-_tags-input-control-border: var(--xh-border-control);
24
- --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
25
- /* 聚焦环与标签块的强调色随语气走。没写 data-tone --xh-_tone 没被声明,退回原来的取值 */
26
- --xh-_tags-input-ring: var(--xh-ring-focus);
27
- --xh-_tags-input-accent: var(--xh-_tone, var(--xh-bg-brand));
28
- --xh-_tags-input-accent-fg: var(--xh-_tone-on, var(--xh-fg-on-brand));
31
+ --xh-_tags-input-item-py: var(--xh-space-1);
32
+ --xh-_tags-input-item-px: var(--xh-space-2);
33
+ --xh-_tags-input-item-line-h: var(--xh-control-indicator-md);
34
+ /* 光标走到的那颗标签是「当前项」,不是选中:淡底 + 淡底前景,随语气走。
35
+ 没写 data-tone --xh-_tone-* 没被声明,退回品牌淡底 */
36
+ --xh-_tags-input-accent: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
37
+ --xh-_tags-input-accent-fg: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
29
38
 
30
39
  display: inline-flex;
31
40
  flex-direction: column;
32
41
  gap: var(--xh-tags-input-gap, var(--xh-space-1));
33
- inline-size: 100%;
42
+ /* 不传尺寸时一律这么宽,宽度不随内容走;父容器给不出这么宽时整件跟着收,地板同步让步,不越出父容器。
43
+ 地板不高过缺省宽:使用者把缺省宽钉到底线以下时不必再放开底线 */
44
+ inline-size: var(--xh-tags-input-control-w, var(--xh-control-w));
45
+ min-inline-size: min(var(--xh-tags-input-control-w, var(--xh-control-w)), var(--xh-tags-input-control-min-w, var(--xh-control-min-w)), 100%);
46
+ max-inline-size: 100%;
34
47
  }
35
48
 
36
49
  /* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
@@ -38,29 +51,6 @@
38
51
  display: none;
39
52
  }
40
53
 
41
- /* —— 形态 —— */
42
- /* 形态只决定颜色怎么用;用哪族颜色由 data-tone 决定。
43
- 不做 solid:实心填充盖住了"这里能打字"这件事,输入框用不上它 */
44
- [data-scope='tags-input'][data-part='root'][data-variant='outline'] {
45
- --xh-_tags-input-control-bg: var(--xh-bg-canvas);
46
- --xh-_tags-input-control-border: var(--xh-border-control);
47
- --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
48
- }
49
-
50
- /* 填充式:底色圈出可输入的范围,描边让位给底色 */
51
- [data-scope='tags-input'][data-part='root'][data-variant='subtle'] {
52
- --xh-_tags-input-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
53
- --xh-_tags-input-control-border: transparent;
54
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
55
- }
56
-
57
- /* 无边框、透明底:静息时框完全隐入背景,可见反馈全靠悬停描边与聚焦环 */
58
- [data-scope='tags-input'][data-part='root'][data-variant='ghost'] {
59
- --xh-_tags-input-control-bg: transparent;
60
- --xh-_tags-input-control-border: transparent;
61
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
62
- }
63
-
64
54
  /* —— 尺寸 —— */
65
55
  [data-scope='tags-input'][data-part='root'][data-size='sm'] {
66
56
  --xh-icon-size: var(--xh-tags-input-icon-size, var(--xh-glyph-size-sm));
@@ -69,7 +59,8 @@
69
59
  --xh-_tags-input-control-gap: var(--xh-control-gap-sm);
70
60
  --xh-_tags-input-input-font-size: var(--xh-control-font-sm);
71
61
  --xh-_tags-input-item-font-size: var(--xh-control-caption-sm);
72
- --xh-_tags-input-label-font-size: var(--xh-control-font-sm);
62
+ --xh-_tags-input-item-py: var(--xh-space-0_5);
63
+ --xh-_tags-input-item-px: var(--xh-space-1_5);
73
64
  }
74
65
 
75
66
  [data-scope='tags-input'][data-part='root'][data-size='lg'] {
@@ -79,305 +70,183 @@
79
70
  --xh-_tags-input-control-gap: var(--xh-control-gap-lg);
80
71
  --xh-_tags-input-input-font-size: var(--xh-control-font-lg);
81
72
  --xh-_tags-input-item-font-size: var(--xh-control-caption-lg);
82
- --xh-_tags-input-label-font-size: var(--xh-control-font-lg);
73
+ --xh-_tags-input-item-px: var(--xh-space-3);
74
+ --xh-_tags-input-item-line-h: var(--xh-control-indicator-lg);
83
75
  }
84
76
 
85
77
  [data-scope='tags-input'][data-part='label'] {
86
78
  color: var(--xh-tags-input-label-fg, var(--xh-fg-default));
87
- font-size: var(--xh-tags-input-label-font-size, var(--xh-_tags-input-label-font-size));
79
+ font-size: var(--xh-tags-input-label-font-size, var(--xh-text-label-size));
88
80
  font-weight: var(--xh-tags-input-label-font-weight, var(--xh-text-label-weight));
89
- line-height: var(--xh-leading-none);
90
81
  }
91
82
 
92
83
  [data-scope='tags-input'][data-part='label'][data-disabled] {
93
84
  color: var(--xh-tags-input-label-fg-disabled, var(--xh-fg-subtle));
94
85
  }
95
86
 
96
- /* 标签换行排,输入框跟在最后一个标签后面。最小高度对齐单行输入框,
97
- 只有一个标签时看起来仍是一个普通输入框,而不是塌成一条缝 */
87
+ /* 标签换行排,输入框跟在最后一个标签后面:描边、底色、圆角、聚焦环、五态与悬停由 Field Chrome
88
+ 家族画在 control 上,可换行、自动高、半档纵向内衬与「只有一个标签时仍像普通输入框」的最小高
89
+ 由家族按 multi-tag 布局给。组件只映射既有公开槽;只读时盒上不是文本光标 */
98
90
  [data-scope='tags-input'][data-part='control'] {
99
- display: flex;
100
- flex-wrap: wrap;
101
- align-items: center;
102
- gap: var(--xh-tags-input-control-gap, var(--xh-_tags-input-control-gap));
103
- min-inline-size: var(--xh-tags-input-control-min-w, var(--xh-control-min-w));
104
- min-block-size: var(--xh-tags-input-control-h, var(--xh-_tags-input-control-h));
105
- /* 纵向只留半档:标签行加上下内距要装进控件档的高度里 */
106
- padding-block: var(--xh-tags-input-control-py, var(--xh-space-0_5));
107
- padding-inline: var(--xh-tags-input-control-px, var(--xh-_tags-input-control-px));
108
- border: var(--xh-stroke-thin) solid var(--xh-tags-input-control-border, var(--xh-_tags-input-control-border));
109
- border-radius: var(--xh-tags-input-control-radius, var(--xh-shape-control));
110
- background: var(--xh-tags-input-control-bg, var(--xh-_tags-input-control-bg));
111
- color: var(--xh-tags-input-control-fg, var(--xh-fg-default));
112
- cursor: text;
113
- transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
91
+ --xh-field-control-height: var(--xh-tags-input-control-h, var(--xh-_tags-input-control-h));
92
+ --xh-field-control-padding-inline: var(--xh-tags-input-control-px, var(--xh-_tags-input-control-px));
93
+ --xh-field-control-gap: var(--xh-tags-input-control-gap, var(--xh-_tags-input-control-gap));
94
+ --xh-field-control-min-inline-size: var(--xh-tags-input-control-min-w, var(--xh-control-min-w));
95
+ --xh-field-control-radius: var(--xh-tags-input-control-radius, var(--xh-shape-control));
96
+ --xh-field-bg-rest: var(--xh-tags-input-control-bg, var(--xh-_field-variant-bg-rest));
97
+ --xh-field-bg-hover: var(--xh-tags-input-control-bg-hover, var(--xh-_field-variant-bg-hover));
98
+ --xh-field-bg-read-only: var(--xh-tags-input-control-bg-readonly, var(--xh-_field-variant-bg-read-only));
99
+ --xh-field-bg-disabled: var(--xh-tags-input-control-bg-disabled, var(--xh-_field-variant-bg-disabled));
100
+ --xh-field-fg-rest: var(--xh-tags-input-control-fg, var(--xh-fg-default));
101
+ --xh-field-border-rest: var(--xh-tags-input-control-border, var(--xh-_field-variant-border-rest));
102
+ --xh-field-border-hover: var(--xh-tags-input-control-border-hover, var(--xh-_field-variant-border-hover));
103
+ --xh-field-border-focus: var(--xh-tags-input-control-border-focus, var(--xh-_field-variant-border-focus));
104
+ --xh-field-border-invalid: var(--xh-tags-input-control-border-invalid, var(--xh-_field-variant-border-invalid));
105
+ --xh-field-ring-focus: var(--xh-ring-focus);
106
+ --xh-field-ring-invalid: var(--xh-ring-invalid);
107
+ --xh-field-shadow-rest: var(--xh-tags-input-control-shadow, none);
108
+ --xh-field-cursor-read-only: default;
109
+ /* 家族 chrome 会重写 --xh-icon-size,使用者图标槽必须经桥接槽下发才能在盒内生效 */
110
+ --xh-field-glyph-size: var(--xh-tags-input-icon-size, var(--xh-_field-size-glyph-size));
111
+
112
+ /* 标签一多就换行,行数没有尽头:框到这个高度就不再长,剩下的标签在框内滚出来。
113
+ 上限取滚动面最小的那一档,与页面上其它滚动面用同一把尺 */
114
+ max-block-size: var(--xh-tags-input-control-max-h, var(--xh-viewport-h-sm));
115
+ overflow-y: auto;
114
116
  }
115
117
 
116
118
  [data-scope='tags-input'][data-part='control'][hidden] {
117
119
  display: none;
118
120
  }
119
121
 
120
- /* hover 只在中性态换描边:invalid at-max 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
121
- [data-scope='tags-input'][data-part='control']:hover:not([data-disabled], [data-invalid], [data-at-max]) {
122
- border-color: var(--xh-tags-input-control-border-hover, var(--xh-_tags-input-control-border-hover));
123
- }
124
-
125
- /* 焦点环画在这个框上:用户眼里"被聚焦的控件"就是整个框,
126
- 而真正持有焦点的是里面的 input(它自己那圈环因此让位,见下) */
127
- [data-scope='tags-input'][data-part='control']:focus-within:not([data-disabled]) {
128
- border-color: var(--xh-tags-input-control-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
129
- outline: var(--xh-ring-width) solid var(--xh-_tags-input-ring);
130
- outline-offset: var(--xh-ring-offset);
131
- }
132
-
133
- /* 顶到上限:再加进不去,边框先给个提示。放在 invalid 之前,
134
- 两者同时成立时按源序让 invalid 赢——真出错比"装满了"要紧 */
135
- [data-scope='tags-input'][data-part='control'][data-at-max] {
122
+ /* 顶到上限是 TagsInput 独有状态:再加进不去,边框先给个提示;invalid 同时出现时由 Field Chrome
123
+ 错误态优先——真出错比"装满了"要紧 */
124
+ [data-scope='tags-input'][data-part='control'][data-at-max]:not([data-invalid]) {
136
125
  border-color: var(--xh-tags-input-control-border-at-max, var(--xh-border-at-limit));
137
126
  }
138
127
 
139
- [data-scope='tags-input'][data-part='control'][data-invalid] {
140
- border-color: var(--xh-tags-input-control-border-invalid, var(--xh-border-invalid));
141
-
142
- /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
143
- --xh-_tags-input-ring: var(--xh-ring-invalid);
144
- }
145
-
146
- /* 只读仍可聚焦、可复制,所以不置灰,只把底色压下去表示"改不动" */
147
- [data-scope='tags-input'][data-part='control'][data-readonly] {
148
- background: var(--xh-tags-input-control-bg-readonly, var(--xh-bg-subtle));
149
- cursor: default;
150
- }
151
-
152
- /* control 是容器不是原生控件,禁用只能靠 data-disabled 表达,写 :disabled 永远不命中 */
153
- [data-scope='tags-input'][data-part='control'][data-disabled] {
154
- background: var(--xh-tags-input-control-bg-disabled, var(--xh-bg-subtle));
155
- color: var(--xh-fg-disabled);
156
- cursor: not-allowed;
157
- }
158
-
159
- /* 输入框贴着标签排,自己不画边框与底色——那两样归 control。
160
- min-inline-size 保证标签占满一行后它还能换到下一行继续输入,而不是被挤成零宽 */
128
+ /* 输入框贴着标签排:无边框无底无圆角无落影由家族重置,那两样归 control
129
+ min-inline-size 保证标签占满一行后它还能换到下一行继续输入,而不是被挤成零宽;
130
+ 占位与自动填充的颜色经桥接槽下发 */
161
131
  [data-scope='tags-input'][data-part='input'] {
162
- flex: 1 1 var(--xh-tags-input-input-basis, 6rem);
132
+ --xh-field-input-fg: var(--xh-tags-input-input-fg, var(--xh-fg-default));
133
+ --xh-field-input-font-size: var(--xh-tags-input-input-font-size, var(--xh-_tags-input-input-font-size));
134
+ --xh-field-placeholder-fg: var(--xh-tags-input-placeholder-fg, var(--xh-fg-subtle));
135
+ --xh-field-autofill-bg: var(--xh-tags-input-input-autofill-bg, var(--xh-bg-canvas));
136
+ --xh-field-autofill-fg: var(--xh-tags-input-input-autofill-fg, var(--xh-fg-default));
137
+
138
+ /* 撑满剩余宽度由家族的 flex: 1 1 auto 给,这里只换起算宽 */
139
+ flex-basis: var(--xh-tags-input-input-basis, 6rem);
163
140
  min-inline-size: var(--xh-tags-input-input-min-w, 4rem);
164
- padding: 0;
165
- border: 0;
166
- background: transparent;
167
- color: inherit;
168
- /* 表单控件不继承页面字体,只给字号会让输入框用 UA 默认字族,与周围文本对不上 */
169
- font-family: inherit;
170
- font-size: var(--xh-tags-input-input-font-size, var(--xh-_tags-input-input-font-size));
171
141
  /* 行盒收到标签那一行的高度以内,输入框不去顶高整个框 */
142
+ block-size: auto;
172
143
  line-height: var(--xh-leading-tight);
173
144
  }
174
145
 
175
- [data-scope='tags-input'][data-part='input']::placeholder {
176
- color: var(--xh-tags-input-placeholder-fg, var(--xh-fg-subtle));
177
- }
178
-
179
- /* 焦点环由 control 统一画(见上):这里再画一圈会在框里套框,两条环互相压着 */
180
- [data-scope='tags-input'][data-part='input']:focus-visible {
181
- outline: none;
182
- }
183
-
184
- /* input 是单体表单控件,禁用走原生 disabled */
185
- [data-scope='tags-input'][data-part='input']:disabled {
186
- color: var(--xh-fg-disabled);
187
- cursor: not-allowed;
188
- }
189
-
190
- /* 一个标签一颗胶囊。inline-size 交给内容决定,长标签由 item-text 截断 */
146
+ /* 一个标签一个条目。条目只是壳:可见的胶囊是里面 tag 的 root(就地编辑时换成 item-input),
147
+ 样子全归 tag.css,这里只管它在行里怎么占位——不缩、不超过一行;
148
+ 长标签由壳的上限压住,截断落在 tag 自己的 label 上 */
191
149
  [data-scope='tags-input'][data-part='item'] {
192
150
  display: inline-flex;
193
151
  flex: none;
194
152
  align-items: center;
195
153
  max-inline-size: 100%;
196
- border-radius: var(--xh-tags-input-item-radius, var(--xh-shape-pill));
197
- background: var(--xh-tags-input-item-bg, var(--xh-bg-subtle));
198
- color: var(--xh-tags-input-item-fg, var(--xh-fg-default));
199
- font-size: var(--xh-tags-input-item-font-size, var(--xh-_tags-input-item-font-size));
200
- line-height: var(--xh-leading-none);
201
- transition:
202
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
203
- color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
204
154
  }
205
155
 
206
156
  [data-scope='tags-input'][data-part='item'][hidden] {
207
157
  display: none;
208
158
  }
209
159
 
210
- /* 光标走到这颗标签上(退格第一下、方向键):整颗反白,与"删掉它"这件事对得上。
211
- 禁用态下不给高亮:那时候本来就走不进标签 */
212
- [data-scope='tags-input'][data-part='item'][data-highlighted]:not([data-disabled]) {
213
- background: var(--xh-tags-input-item-bg-highlight, var(--xh-_tags-input-accent));
214
- color: var(--xh-tags-input-item-fg-highlight, var(--xh-_tags-input-accent-fg));
215
- }
216
-
217
- /* 标签不是原生控件,禁用同样只能靠 data-disabled */
218
- [data-scope='tags-input'][data-part='item'][data-disabled] {
219
- color: var(--xh-fg-disabled);
220
- cursor: not-allowed;
221
- }
222
-
223
- /* 就地编辑时整颗胶囊让位给编辑框:底色撤掉,免得输入框外面套一圈灰底 */
224
- [data-scope='tags-input'][data-part='item'][data-editing] {
225
- background: transparent;
226
- }
227
-
228
- [data-scope='tags-input'][data-part='item-preview'] {
229
- display: inline-flex;
230
- align-items: center;
231
- gap: var(--xh-tags-input-item-gap, var(--xh-space-1));
232
- max-inline-size: 100%;
233
- padding-block: var(--xh-tags-input-item-py, var(--xh-space-0_5));
234
- padding-inline: var(--xh-tags-input-item-px, var(--xh-space-2));
160
+ /* 双击标签是进就地编辑,不是选字:选区一闪再换成编辑框,看起来像点错了 */
161
+ [data-scope='tags-input'][data-part='item'] > [data-scope='tag'][data-part='root'] {
235
162
  user-select: none;
236
163
  }
237
164
 
238
- /* 就地编辑时连接层给的是 hidden 属性;上面那条 display 会把 UA 规则盖掉,
239
- 少了这条预览会和编辑框叠在一起 */
240
- [data-scope='tags-input'][data-part='item-preview'][hidden] {
241
- display: none;
242
- }
243
-
244
- /* 长标签截断而不是把整行撑开:胶囊挤爆一行会把输入框顶到看不见的地方 */
245
- [data-scope='tags-input'][data-part='item-text'] {
246
- overflow: hidden;
247
- white-space: nowrap;
248
- text-overflow: ellipsis;
249
- }
250
-
251
- /* 删除按钮画成胶囊里的小圆钮,与文字同一行,尺寸取控件指示件档(随密度收) */
252
- [data-scope='tags-input'][data-part='item-delete-trigger'] {
253
- display: inline-flex;
254
- flex: none;
255
- align-items: center;
256
- justify-content: center;
257
- inline-size: var(--xh-tags-input-delete-size, var(--xh-control-indicator-size));
258
- block-size: var(--xh-tags-input-delete-size, var(--xh-control-indicator-size));
259
- padding: 0;
260
- border: 0;
261
- border-radius: var(--xh-tags-input-delete-radius, var(--xh-shape-inset));
262
- background: var(--xh-tags-input-delete-bg, transparent);
263
- color: var(--xh-tags-input-delete-fg, var(--xh-fg-muted));
264
- font-family: inherit;
265
- font-size: var(--xh-tags-input-delete-font-size, var(--xh-text-caption-size));
266
- line-height: var(--xh-leading-none);
267
- cursor: pointer;
268
- transition:
269
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
270
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
271
- }
272
-
273
- [data-scope='tags-input'][data-part='item-delete-trigger'][hidden] {
274
- display: none;
275
- }
276
-
277
- /* 整颗标签反白时按钮跟着改色,否则灰字压在品牌底色上会看不清 */
278
- [data-scope='tags-input'][data-part='item-delete-trigger'][data-highlighted]:not(:disabled) {
279
- color: var(--xh-tags-input-delete-fg-highlight, var(--xh-_tags-input-accent-fg));
280
- }
281
-
282
- [data-scope='tags-input'][data-part='item-delete-trigger']:hover:not(:disabled) {
283
- background: var(--xh-tags-input-delete-bg-hover, var(--xh-bg-subtle-hover));
284
- color: var(--xh-tags-input-delete-fg-hover, var(--xh-fg-default));
285
- }
286
-
287
- [data-scope='tags-input'][data-part='item-delete-trigger']:active:not(:disabled) {
288
- background: var(--xh-tags-input-delete-bg-active, var(--xh-bg-subtle-active));
289
- scale: var(--xh-motion-scale-press);
290
- }
291
-
292
- /* 按钮不占 Tab 位(tabindex=-1),正常操作走不到这里;
293
- 留着焦点环是给程序化聚焦兜底——删完把焦点交回输入框之前,它确实短暂持有过焦点 */
294
- [data-scope='tags-input'][data-part='item-delete-trigger']:focus-visible {
295
- outline: var(--xh-ring-width) solid var(--xh-_tags-input-ring);
296
- /* 比默认档窄一道:它长在胶囊里,按默认偏移画会压到相邻胶囊 */
297
- outline-offset: var(--xh-stroke-thin);
165
+ /* 光标走到这颗标签上(退格第一下、方向键):整颗换成「当前项」的淡底,与"删掉它"这件事对得上。
166
+ 反白画在 tag 的 root 上,描边一并收成透明——描边档的标签反白后不留一圈异色边;
167
+ 禁用态下不给高亮:那时候本来就走不进标签 */
168
+ [data-scope='tags-input'][data-part='item'][data-highlighted]:not([data-disabled]) > [data-scope='tag'][data-part='root'] {
169
+ border-color: transparent;
170
+ background: var(--xh-tags-input-item-bg-highlight, var(--xh-_tags-input-accent));
171
+ color: var(--xh-tags-input-item-fg-highlight, var(--xh-_tags-input-accent-fg));
298
172
  }
299
173
 
300
- /* 按钮是单体控件,禁用走原生 disabled */
301
- [data-scope='tags-input'][data-part='item-delete-trigger']:disabled {
302
- background: transparent;
303
- color: var(--xh-fg-disabled);
304
- cursor: not-allowed;
174
+ /* 反白的面是语气淡底,环压上去与面同族看不出来;叉自己的面是透空的,环取它的字色——
175
+ 上面那条反白规则已经把它换成配对的那支色 */
176
+ [data-scope='tags-input'][data-part='item'][data-highlighted]:not([data-disabled]) > [data-scope='tag'][data-part='root']
177
+ [data-scope='tag'][data-part='close-trigger']:focus-visible {
178
+ --xh-_ring-color: currentColor;
305
179
  }
306
180
 
307
181
  /* 就地编辑框:尺寸对齐胶囊,看起来像是在原地把标签改了,而不是另开一个框。
182
+ 阶梯照 tag 的档走:行框取指示符档,竖向内衬、横向内衬与字号随档从 root 的私有槽取。
308
183
  不声明 display —— 收起态靠 UA 的 [hidden]{display:none} 就够,
309
184
  自己加一条 display 反而要再补一条 [hidden] 规则去抵消它 */
310
185
  [data-scope='tags-input'][data-part='item-input'] {
186
+ /* 宽随正在改的那几个字走,不取原生 input 按 20 个字符算出来的宽:字段缺省宽只有 16rem,
187
+ 一个 20 字符宽的编辑框会把后面的输入框挤到下一行,进编辑态时框就长高了 */
188
+ field-sizing: content;
189
+ inline-size: auto;
190
+ min-inline-size: 3ch;
311
191
  max-inline-size: 100%;
312
- padding-block: var(--xh-tags-input-item-py, var(--xh-space-0_5));
313
- padding-inline: var(--xh-tags-input-item-px, var(--xh-space-2));
192
+ padding-block: var(--xh-tags-input-item-py, var(--xh-_tags-input-item-py));
193
+ padding-inline: var(--xh-tags-input-item-px, var(--xh-_tags-input-item-px));
314
194
  border: var(--xh-stroke-thin) solid var(--xh-tags-input-item-input-border, var(--xh-border-control));
315
- border-radius: var(--xh-tags-input-item-radius, var(--xh-shape-pill));
195
+ border-radius: var(--xh-tags-input-item-radius, var(--xh-shape-control));
316
196
  background: var(--xh-tags-input-item-input-bg, var(--xh-bg-canvas));
317
197
  color: var(--xh-tags-input-item-input-fg, var(--xh-fg-default));
318
198
  font-family: inherit;
319
199
  font-size: var(--xh-tags-input-item-font-size, var(--xh-_tags-input-item-font-size));
320
- line-height: var(--xh-leading-none);
200
+ /* 行框不低于胶囊里那一行的高,编辑框与它换掉的标签一样高,换进换出时行不跳 */
201
+ line-height: max(calc(var(--xh-leading-none) * 1em), var(--xh-_tags-input-item-line-h));
321
202
  }
322
203
 
323
204
  /* 它是真正持有焦点的那个节点,环画在自己身上;
324
205
  外层 control 的 :focus-within 环同时亮着也合理——焦点确实在框内 */
325
206
  [data-scope='tags-input'][data-part='item-input']:focus-visible {
326
- outline: var(--xh-ring-width) solid var(--xh-_tags-input-ring);
327
- /* 比默认档窄一道:它长在胶囊里,按默认偏移画会压到相邻胶囊 */
328
- outline-offset: var(--xh-stroke-thin);
207
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
208
+ outline-offset: var(--xh-ring-offset);
209
+ }
210
+
211
+ /* 校验失败时环也跟着变红:与外框上家族画的那圈同色,两圈相邻不至于一红一蓝 */
212
+ [data-scope='tags-input'][data-part='control'][data-invalid] [data-scope='tags-input'][data-part='item-input']:focus-visible {
213
+ outline-color: var(--xh-ring-invalid);
329
214
  }
330
215
 
331
216
  [data-scope='tags-input'][data-part='item-input']:disabled {
332
217
  color: var(--xh-fg-disabled);
333
- cursor: not-allowed;
334
218
  }
335
219
 
336
- /* 清空按钮贴在框的末端,与输入框同一行,尺寸取控件动作钮档(随密度收) */
220
+ /* 清空按钮贴在框的末端,与输入框同一行:正方视觉盒、inset 圆角、悬停 100 / 按下 200 与 0.97 按压、
221
+ 粗指针热区与 :focus-visible 关环全由 Action Control 的 field-inset ghost 档给,组件只映射既有覆盖槽。
222
+ 没值可清时连接层给 hidden 收起 */
337
223
  [data-scope='tags-input'][data-part='clear-trigger'] {
338
- display: inline-flex;
339
- flex: none;
340
- align-items: center;
341
- justify-content: center;
342
- inline-size: var(--xh-tags-input-action-size, var(--xh-control-action-size));
343
- block-size: var(--xh-tags-input-action-size, var(--xh-control-action-size));
344
- padding: 0;
345
- border: 0;
346
- border-radius: var(--xh-tags-input-action-radius, var(--xh-shape-control));
347
- background: var(--xh-tags-input-action-bg, transparent);
348
- color: var(--xh-tags-input-action-fg, var(--xh-fg-muted));
349
- font-family: inherit;
350
- font-size: var(--xh-tags-input-action-font-size, var(--xh-text-secondary-size));
351
- line-height: var(--xh-leading-none);
352
- cursor: pointer;
353
- transition:
354
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
355
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
356
- }
357
-
358
- /* 没值可清时连接层只打 hidden;上面那条 display 会盖掉 UA 规则,少了这条按钮就一直杵着 */
224
+ --xh-action-visual-size: var(--xh-tags-input-action-size, var(--xh-_action-profile-visual-size));
225
+ --xh-action-min-inline-size: var(--xh-tags-input-action-size, var(--xh-_action-profile-visual-size));
226
+ --xh-action-radius: var(--xh-tags-input-action-radius, var(--xh-shape-inset));
227
+ /* 底色阶梯由 ghost 档给(透明 → 100 → 200),使用者槽只作覆盖入口 */
228
+ --xh-action-bg-rest: var(--xh-tags-input-action-bg, var(--xh-_action-variant-bg-rest));
229
+ --xh-action-bg-hover: var(--xh-tags-input-action-bg-hover, var(--xh-_action-variant-bg-hover));
230
+ --xh-action-bg-pressed: var(--xh-tags-input-action-bg-active, var(--xh-_action-variant-bg-pressed));
231
+ --xh-action-fg-rest: var(--xh-tags-input-action-fg, var(--xh-fg-muted));
232
+ --xh-action-fg-hover: var(--xh-tags-input-action-fg-hover, var(--xh-fg-default));
233
+ --xh-action-border-rest: transparent;
234
+ --xh-action-highlight-rest: transparent;
235
+ --xh-action-shadow-rest: none;
236
+ --xh-action-shadow-hover: none;
237
+ --xh-action-shadow-pressed: none;
238
+ --xh-action-font-size: var(--xh-tags-input-action-font-size, var(--xh-text-secondary-size));
239
+ /* 配方尚未把 profile 字形档灌进 --xh-icon-size,钮内字形先按 field-inset 档逐钮取值 */
240
+ --xh-icon-size: var(--xh-_action-profile-glyph-size);
241
+
242
+ border-width: 0;
243
+ }
244
+
245
+ /* 没值可清时连接层只打 hidden;家族那条 display 会盖掉 UA 规则,少了这条按钮就一直杵着 */
359
246
  [data-scope='tags-input'][data-part='clear-trigger'][hidden] {
360
247
  display: none;
361
248
  }
362
249
 
363
- [data-scope='tags-input'][data-part='clear-trigger']:hover {
364
- background: var(--xh-tags-input-action-bg-hover, var(--xh-bg-subtle-hover));
365
- color: var(--xh-tags-input-action-fg-hover, var(--xh-fg-default));
366
- }
367
-
368
- [data-scope='tags-input'][data-part='clear-trigger']:active {
369
- background: var(--xh-tags-input-action-bg-active, var(--xh-bg-subtle-active));
370
- scale: var(--xh-motion-scale-press);
371
- }
372
-
373
- /* 按钮不占 Tab 位(tabindex=-1),正常操作走不到这里;
374
- 留着焦点环是给程序化聚焦兜底——清完把焦点交回输入框之前,它确实短暂持有过焦点 */
375
- [data-scope='tags-input'][data-part='clear-trigger']:focus-visible {
376
- outline: var(--xh-ring-width) solid var(--xh-_tags-input-ring);
377
- /* 比默认档窄一道:它长在框的末端,按默认偏移画会压到相邻胶囊 */
378
- outline-offset: var(--xh-stroke-thin);
379
- }
380
-
381
250
  /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
382
251
  [data-scope='tags-input'][data-part='clear-trigger']:empty::before {
383
252
  content: '';
@@ -390,14 +259,27 @@
390
259
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
391
260
  }
392
261
 
393
- [data-scope='tags-input'][data-part='item-delete-trigger']:empty::before {
394
- content: '';
395
- display: inline-block;
396
- inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
397
- block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
398
- vertical-align: var(--xh-glyph-baseline-shift);
399
- background-color: currentColor;
400
- -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
401
- mask: var(--xh-glyph-mark-close) center / contain no-repeat;
262
+ /* 计数:排在控件行下面靠尾端的一行小字,与标题分列 root 的两端 */
263
+ [data-scope='tags-input'][data-part='count'] {
264
+ align-self: flex-end;
265
+ color: var(--xh-tags-input-count-fg, var(--xh-fg-muted));
266
+ font-size: var(--xh-tags-input-count-font-size, var(--xh-_tags-input-item-font-size));
267
+ font-variant-numeric: tabular-nums;
268
+ line-height: var(--xh-leading-normal);
269
+ }
270
+
271
+ /* 没开 showCount 时连接层给的是 hidden 属性;上面那条 align-self 不影响显隐,
272
+ 但作者层给这个 part 声明任何一条 display 都会盖掉 UA 规则,这条把它还回去 */
273
+ [data-scope='tags-input'][data-part='count'][hidden] {
274
+ display: none;
275
+ }
276
+
277
+ /* 顶到上限:数字先于框被看见,与越界那一档同族颜色 */
278
+ [data-scope='tags-input'][data-part='count'][data-at-max] {
279
+ color: var(--xh-tags-input-count-fg-at-max, var(--xh-fg-warning));
280
+ }
281
+
282
+ [data-scope='tags-input'][data-part='count'][data-disabled] {
283
+ color: var(--xh-tags-input-count-fg-disabled, var(--xh-fg-disabled));
402
284
  }
403
285
  }