@xihan-ui/styles 1.0.0-alpha.2 → 1.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 (122) hide show
  1. package/CHANGELOG.md +2177 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +80 -6
  4. package/css/alert.css +43 -14
  5. package/css/anchor.css +8 -8
  6. package/css/avatar-group.css +7 -3
  7. package/css/avatar.css +9 -3
  8. package/css/back-top.css +22 -1
  9. package/css/badge.css +104 -32
  10. package/css/breadcrumb.css +25 -5
  11. package/css/button-group.css +18 -13
  12. package/css/button.css +48 -11
  13. package/css/calendar.css +150 -7
  14. package/css/card.css +20 -11
  15. package/css/carousel.css +36 -5
  16. package/css/cascader.css +211 -124
  17. package/css/checkbox-group.css +72 -22
  18. package/css/checkbox.css +70 -13
  19. package/css/clipboard.css +2 -1
  20. package/css/code-block.css +12 -7
  21. package/css/collapsible.css +49 -3
  22. package/css/color-picker.css +132 -46
  23. package/css/combobox.css +132 -60
  24. package/css/composer.css +5 -3
  25. package/css/context-menu.css +113 -74
  26. package/css/date-field.css +93 -16
  27. package/css/date-picker.css +293 -72
  28. package/css/descriptions.css +11 -5
  29. package/css/dialog.css +47 -14
  30. package/css/download-trigger.css +76 -0
  31. package/css/drawer.css +57 -16
  32. package/css/dynamic-input.css +75 -17
  33. package/css/editable.css +12 -10
  34. package/css/ellipsis.css +7 -1
  35. package/css/empty-state.css +22 -12
  36. package/css/field.css +16 -6
  37. package/css/fieldset.css +69 -0
  38. package/css/file-upload.css +46 -8
  39. package/css/flex.css +13 -7
  40. package/css/float-button.css +23 -1
  41. package/css/floating-panel.css +316 -0
  42. package/css/form.css +4 -4
  43. package/css/grid.css +11 -5
  44. package/css/heatmap.css +411 -0
  45. package/css/highlight.css +2 -2
  46. package/css/hotkeys.css +90 -0
  47. package/css/hover-card.css +43 -45
  48. package/css/image-cropper.css +233 -0
  49. package/css/image-viewer.css +155 -17
  50. package/css/image.css +2 -2
  51. package/css/infinite-scroll.css +1 -1
  52. package/css/json-viewer.css +274 -0
  53. package/css/layout.css +19 -15
  54. package/css/list.css +22 -13
  55. package/css/listbox.css +24 -6
  56. package/css/loading-bar.css +12 -5
  57. package/css/log.css +7 -3
  58. package/css/marquee.css +9 -0
  59. package/css/masonry.css +63 -0
  60. package/css/mention.css +100 -36
  61. package/css/menu.css +127 -50
  62. package/css/menubar.css +155 -61
  63. package/css/navigation-menu.css +56 -31
  64. package/css/notification.css +377 -0
  65. package/css/number-animation.css +3 -3
  66. package/css/number-field.css +182 -19
  67. package/css/overlay-arrow.css +51 -0
  68. package/css/page-header.css +12 -5
  69. package/css/pagination.css +171 -14
  70. package/css/password-input.css +356 -0
  71. package/css/pin-input.css +15 -12
  72. package/css/popconfirm.css +55 -12
  73. package/css/popover.css +73 -45
  74. package/css/popselect.css +207 -57
  75. package/css/progress.css +54 -8
  76. package/css/qr-code.css +1 -1
  77. package/css/radio-group.css +27 -10
  78. package/css/rating.css +4 -4
  79. package/css/reset.css +17 -0
  80. package/css/result.css +21 -11
  81. package/css/scroll-area.css +61 -89
  82. package/css/scrollbar.css +170 -0
  83. package/css/segmented.css +215 -0
  84. package/css/select.css +298 -131
  85. package/css/separator.css +2 -2
  86. package/css/side-nav.css +127 -24
  87. package/css/signature-pad.css +144 -0
  88. package/css/skeleton.css +7 -1
  89. package/css/slider.css +14 -12
  90. package/css/space.css +117 -0
  91. package/css/spinner.css +22 -10
  92. package/css/statistic.css +9 -9
  93. package/css/steps.css +29 -12
  94. package/css/switch.css +57 -8
  95. package/css/table.css +146 -44
  96. package/css/tabs.css +13 -5
  97. package/css/tag.css +179 -0
  98. package/css/tags-input.css +80 -42
  99. package/css/text-field.css +151 -38
  100. package/css/thread.css +11 -3
  101. package/css/time-field.css +99 -18
  102. package/css/time-picker.css +261 -71
  103. package/css/timeline.css +15 -15
  104. package/css/timer.css +119 -0
  105. package/css/toast.css +129 -55
  106. package/css/toggle-group.css +30 -4
  107. package/css/toggle.css +12 -6
  108. package/css/tone.css +57 -22
  109. package/css/toolbar.css +1 -1
  110. package/css/tooltip.css +40 -31
  111. package/css/tour.css +112 -61
  112. package/css/transfer.css +98 -21
  113. package/css/tree-select.css +215 -89
  114. package/css/tree.css +131 -5
  115. package/css/typography.css +5 -5
  116. package/css/undefined.css +12 -1
  117. package/css/virtualizer.css +3 -1
  118. package/css/watermark.css +1 -2
  119. package/index.css +18 -1
  120. package/index.unlayered.css +10356 -3255
  121. package/package.json +20 -4
  122. package/css/toaster.css +0 -74
@@ -0,0 +1,356 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='password-input'] {
4
+ --xh-password-input-skin: 1;
5
+ }
6
+
7
+ /* root 只负责纵向堆叠:标签一行、输入行一行。
8
+ 输入框、切换钮与大写锁定提示收进 control 部件即得一体式:视觉盒画在 control 上,
9
+ 框内三件都退成透明分段,整枚控件从头到尾只有一道描边。
10
+ 不写 control 时退回三件并排的观感(下面 input 与按钮的基础规则原样生效) */
11
+ [data-scope='password-input'][data-part='root'] {
12
+ /* 作者塞进来的图标跟着控件的尺寸档走;它自己写了 size 时仍以作者的为准 */
13
+ --xh-icon-size: var(--xh-password-input-icon-size, var(--xh-glyph-size-md));
14
+
15
+ /* 尺寸档只换这几个私有槽,标题、输入框、切换钮与提示都从 root 继承它们,
16
+ 换档不必给每个部件各写一条选择器 */
17
+ --xh-_password-input-h: var(--xh-control-h-md);
18
+ --xh-_password-input-px: var(--xh-control-px-md);
19
+ --xh-_password-input-gap: var(--xh-control-gap-md);
20
+ --xh-_password-input-font-size: var(--xh-control-font-md);
21
+ --xh-_password-input-label-font-size: var(--xh-control-font-md);
22
+ /* 提示与切换钮里的字形都比正文小一档,三个尺寸档各自换过,不是一个恒等的中转 */
23
+ --xh-_password-input-hint-font-size: var(--xh-control-caption-md);
24
+ --xh-_password-input-trigger-font-size: var(--xh-control-caption-md);
25
+
26
+ /* 盒子的圆角 */
27
+ --xh-_password-input-radius: var(--xh-password-input-input-radius, var(--xh-shape-control));
28
+
29
+ /* 形态档只换这三个私有槽:底、常态描边、悬停描边 */
30
+ --xh-_password-input-bg: var(--xh-bg-canvas);
31
+ --xh-_password-input-border: var(--xh-border-control);
32
+ --xh-_password-input-border-hover: var(--xh-border-control-hover);
33
+
34
+ /* 聚焦这一处的两个取值。语气只改描边,环恒用 --xh-ring-focus:
35
+ 环要在各种底上都读得出来,跟着语气走会掉到 warning 那种够不着对比度的档上 */
36
+ --xh-_password-input-border-focus: var(--xh-border-control-focus);
37
+ --xh-_password-input-ring: var(--xh-ring-focus);
38
+
39
+ display: inline-flex;
40
+ flex-direction: column;
41
+ gap: var(--xh-password-input-gap, var(--xh-space-1));
42
+ }
43
+
44
+ /* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
45
+ [data-scope='password-input'][data-part='root'][hidden] {
46
+ display: none;
47
+ }
48
+
49
+ /* —— 尺寸 —— */
50
+ /* 缺省档写在上面的基础规则里 */
51
+ [data-scope='password-input'][data-part='root'][data-size='sm'] {
52
+ --xh-icon-size: var(--xh-password-input-icon-size, var(--xh-glyph-size-sm));
53
+ --xh-_password-input-h: var(--xh-control-h-sm);
54
+ --xh-_password-input-px: var(--xh-control-px-sm);
55
+ --xh-_password-input-gap: var(--xh-control-gap-sm);
56
+ --xh-_password-input-font-size: var(--xh-control-font-sm);
57
+ --xh-_password-input-label-font-size: var(--xh-control-font-sm);
58
+ --xh-_password-input-hint-font-size: var(--xh-control-caption-sm);
59
+ --xh-_password-input-trigger-font-size: var(--xh-control-caption-sm);
60
+ }
61
+
62
+ [data-scope='password-input'][data-part='root'][data-size='lg'] {
63
+ --xh-icon-size: var(--xh-password-input-icon-size, var(--xh-glyph-size-lg));
64
+ --xh-_password-input-h: var(--xh-control-h-lg);
65
+ --xh-_password-input-px: var(--xh-control-px-lg);
66
+ --xh-_password-input-gap: var(--xh-control-gap-lg);
67
+ --xh-_password-input-font-size: var(--xh-control-font-lg);
68
+ --xh-_password-input-label-font-size: var(--xh-control-font-lg);
69
+ --xh-_password-input-hint-font-size: var(--xh-control-caption-lg);
70
+ --xh-_password-input-trigger-font-size: var(--xh-control-caption-lg);
71
+ }
72
+
73
+ /* —— 形态 —— */
74
+ /* 形态只决定底与描边怎么画;用哪族颜色由 data-tone 决定。
75
+ 输入框没有实心档:填满一个要往里打字的框,字与底就没法同时读 */
76
+ [data-scope='password-input'][data-part='root'][data-variant='outline'] {
77
+ --xh-_password-input-bg: var(--xh-bg-canvas);
78
+ --xh-_password-input-border: var(--xh-border-control);
79
+ --xh-_password-input-border-hover: var(--xh-border-control-hover);
80
+ }
81
+
82
+ /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
83
+ 与 outline 档并排时基线对得上、聚焦画描边也不引起跳动 */
84
+ [data-scope='password-input'][data-part='root'][data-variant='subtle'] {
85
+ --xh-_password-input-bg: var(--xh-bg-subtle);
86
+ --xh-_password-input-border: transparent;
87
+ --xh-_password-input-border-hover: var(--xh-border-control-hover);
88
+ }
89
+
90
+ /* 无框:底与常态描边透明,悬停与聚焦浮出描边 */
91
+ [data-scope='password-input'][data-part='root'][data-variant='ghost'] {
92
+ --xh-_password-input-bg: transparent;
93
+ --xh-_password-input-border: transparent;
94
+ --xh-_password-input-border-hover: var(--xh-border-control-hover);
95
+ }
96
+
97
+ /* —— 语气 —— */
98
+ /* 必须带 [data-tone] 限定:语气槽是沿继承流下来的,不限定的话,
99
+ 放进带语气的容器(提示条、通知)里的密码框会跟着一起改色,作者根本没写过 tone */
100
+ [data-scope='password-input'][data-part='root'][data-tone] {
101
+ --xh-_password-input-border-focus: var(--xh-_tone);
102
+ }
103
+
104
+ [data-scope='password-input'][data-part='root'][data-variant='subtle'][data-tone] {
105
+ --xh-_password-input-bg: var(--xh-_tone-subtle);
106
+ --xh-_password-input-border-hover: var(--xh-_tone-border);
107
+ }
108
+
109
+ [data-scope='password-input'][data-part='root'][data-variant='ghost'][data-tone] {
110
+ --xh-_password-input-border-hover: var(--xh-_tone-border);
111
+ }
112
+
113
+ /* —— 标题 —— */
114
+ [data-scope='password-input'][data-part='label'] {
115
+ color: var(--xh-password-input-label-fg, var(--xh-fg-default));
116
+ font-size: var(--xh-password-input-label-font-size, var(--xh-_password-input-label-font-size));
117
+ font-weight: var(--xh-password-input-label-font-weight, var(--xh-text-label-weight));
118
+ line-height: var(--xh-leading-none);
119
+ }
120
+
121
+ [data-scope='password-input'][data-part='label'][data-disabled] {
122
+ color: var(--xh-password-input-label-fg-disabled, var(--xh-fg-subtle));
123
+ }
124
+
125
+ /* —— 一体式 control:输入框、切换钮与提示同框 —— */
126
+ /* control 是唯一的视觉盒:描边、底色、圆角、聚焦环全画在它身上。
127
+ :focus-within 而不是 :focus——盒里有两个 Tab 停靠点,输入框与切换钮各占一个 */
128
+ [data-scope='password-input'][data-part='control'] {
129
+ display: inline-flex;
130
+ min-inline-size: var(--xh-password-input-control-min-w, var(--xh-control-min-w));
131
+ /* 居中而不是拉伸:提示是一行文字,被拉满整框高度后字会贴着框顶 */
132
+ align-items: center;
133
+ gap: var(--xh-password-input-control-gap, var(--xh-_password-input-gap));
134
+ block-size: var(--xh-password-input-control-h, var(--xh-_password-input-h));
135
+ padding-inline: var(--xh-password-input-control-px, var(--xh-_password-input-px));
136
+ border: var(--xh-stroke-thin) solid var(--xh-password-input-control-border, var(--xh-_password-input-border));
137
+ border-radius: var(--xh-_password-input-radius);
138
+ background: var(--xh-password-input-control-bg, var(--xh-_password-input-bg));
139
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
140
+ }
141
+
142
+ [data-scope='password-input'][data-part='control'][hidden] {
143
+ display: none;
144
+ }
145
+
146
+ /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
147
+ [data-scope='password-input'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
148
+ border-color: var(--xh-password-input-control-border-hover, var(--xh-_password-input-border-hover));
149
+ }
150
+
151
+ [data-scope='password-input'][data-part='control']:focus-within:not([data-disabled]) {
152
+ border-color: var(--xh-password-input-control-border-focus, var(--xh-_password-input-border-focus));
153
+ outline: var(--xh-ring-width) solid var(--xh-_password-input-ring);
154
+ outline-offset: var(--xh-ring-offset);
155
+ }
156
+
157
+ [data-scope='password-input'][data-part='control'][data-invalid] {
158
+ border-color: var(--xh-password-input-control-border-invalid, var(--xh-border-invalid));
159
+
160
+ /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
161
+ --xh-_password-input-ring: var(--xh-ring-invalid);
162
+ }
163
+
164
+ /* 只读仍可聚焦、可复制,所以不置灰,只把底色压下去表示"改不动" */
165
+ [data-scope='password-input'][data-part='control'][data-readonly] {
166
+ background: var(--xh-password-input-control-bg-readonly, var(--xh-bg-subtle));
167
+ }
168
+
169
+ [data-scope='password-input'][data-part='control'][data-disabled] {
170
+ background: var(--xh-password-input-control-bg-disabled, var(--xh-bg-subtle));
171
+ color: var(--xh-fg-disabled);
172
+ cursor: not-allowed;
173
+ }
174
+
175
+ /* —— 输入框 —— */
176
+ /* 不写 control 时它自己就是那个框:描边、圆角、底都长在它身上 */
177
+ [data-scope='password-input'][data-part='input'] {
178
+ min-inline-size: var(--xh-password-input-input-min-w, var(--xh-control-min-w));
179
+ block-size: var(--xh-password-input-input-h, var(--xh-_password-input-h));
180
+ padding-inline: var(--xh-password-input-input-px, var(--xh-_password-input-px));
181
+ padding-block: 0;
182
+ border: var(--xh-stroke-thin) solid var(--xh-password-input-input-border, var(--xh-_password-input-border));
183
+ border-radius: var(--xh-_password-input-radius);
184
+ background: var(--xh-password-input-input-bg, var(--xh-_password-input-bg));
185
+ color: var(--xh-password-input-input-fg, var(--xh-fg-default));
186
+ /* 表单控件不继承页面字体,只给字号会让输入框用 UA 默认字族,与周围文本对不上 */
187
+ font-family: inherit;
188
+ font-size: var(--xh-password-input-input-font-size, var(--xh-_password-input-font-size));
189
+ line-height: var(--xh-leading-normal);
190
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
191
+ }
192
+
193
+ [data-scope='password-input'][data-part='input']::placeholder {
194
+ color: var(--xh-password-input-placeholder-fg, var(--xh-fg-subtle));
195
+ }
196
+
197
+ [data-scope='password-input'][data-part='input']:hover:not(:disabled, [data-invalid]) {
198
+ border-color: var(--xh-password-input-input-border-hover, var(--xh-_password-input-border-hover));
199
+ }
200
+
201
+ [data-scope='password-input'][data-part='input']:focus-visible {
202
+ border-color: var(--xh-password-input-input-border-focus, var(--xh-_password-input-border-focus));
203
+ outline: var(--xh-ring-width) solid var(--xh-_password-input-ring);
204
+ outline-offset: var(--xh-ring-offset);
205
+ }
206
+
207
+ [data-scope='password-input'][data-part='input'][data-invalid] {
208
+ border-color: var(--xh-password-input-input-border-invalid, var(--xh-border-invalid));
209
+
210
+ --xh-_password-input-ring: var(--xh-ring-invalid);
211
+ }
212
+
213
+ [data-scope='password-input'][data-part='input'][readonly] {
214
+ background: var(--xh-password-input-input-bg-readonly, var(--xh-bg-subtle));
215
+ }
216
+
217
+ /* input 是单体表单控件,禁用走原生 disabled */
218
+ [data-scope='password-input'][data-part='input']:disabled {
219
+ background: var(--xh-password-input-input-bg-disabled, var(--xh-bg-subtle));
220
+ color: var(--xh-fg-disabled);
221
+ cursor: not-allowed;
222
+ }
223
+
224
+ /* 盒内 input:无边框无底无圆角,观感全归 control;它自己不画聚焦环,
225
+ 盒子已经在 :focus-within 上画了一圈,再画一圈就成了两道 */
226
+ [data-scope='password-input'][data-part='control'] [data-part='input'] {
227
+ flex: 1 1 auto;
228
+ min-inline-size: 0;
229
+ block-size: 100%;
230
+ padding-inline: 0;
231
+ border: 0;
232
+ border-radius: 0;
233
+ background: transparent;
234
+ }
235
+
236
+ [data-scope='password-input'][data-part='control'] [data-part='input']:hover:not(:disabled, [data-invalid]) {
237
+ border-color: transparent;
238
+ }
239
+
240
+ [data-scope='password-input'][data-part='control'] [data-part='input']:focus-visible {
241
+ border-color: transparent;
242
+ outline: none;
243
+ }
244
+
245
+ [data-scope='password-input'][data-part='control'] [data-part='input'][data-invalid] {
246
+ border-color: transparent;
247
+ }
248
+
249
+ [data-scope='password-input'][data-part='control'] [data-part='input']:disabled,
250
+ [data-scope='password-input'][data-part='control'] [data-part='input'][readonly] {
251
+ background: transparent;
252
+ }
253
+
254
+ /* —— 明暗切换钮 —— */
255
+ /* 行内动作方钮,常态只剩符号:自带一块底色会把一个盒子读成两块拼起来的 */
256
+ [data-scope='password-input'][data-part='visibility-trigger'] {
257
+ display: inline-flex;
258
+ flex: none;
259
+ align-items: center;
260
+ justify-content: center;
261
+ inline-size: var(--xh-password-input-trigger-size, var(--xh-control-action-size));
262
+ block-size: var(--xh-password-input-trigger-size, var(--xh-control-action-size));
263
+ padding: 0;
264
+ border: 0;
265
+ border-radius: var(--xh-password-input-trigger-radius, var(--xh-shape-control));
266
+ background: var(--xh-password-input-trigger-bg, transparent);
267
+ color: var(--xh-password-input-trigger-fg, var(--xh-fg-muted));
268
+ font-family: inherit;
269
+ font-size: var(--xh-password-input-trigger-font-size, var(--xh-_password-input-trigger-font-size));
270
+ line-height: var(--xh-leading-none);
271
+ cursor: pointer;
272
+ user-select: none;
273
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
274
+
275
+ --xh-_password-input-mark: var(--xh-glyph-mark-eye);
276
+ }
277
+
278
+ [data-scope='password-input'][data-part='visibility-trigger'][hidden] {
279
+ display: none;
280
+ }
281
+
282
+ [data-scope='password-input'][data-part='visibility-trigger']:hover:not(:disabled) {
283
+ background: var(--xh-password-input-trigger-bg-hover, var(--xh-bg-subtle-hover));
284
+ color: var(--xh-password-input-trigger-fg-hover, var(--xh-fg-default));
285
+ }
286
+
287
+ [data-scope='password-input'][data-part='visibility-trigger']:active:not(:disabled) {
288
+ background: var(--xh-password-input-trigger-bg-active, var(--xh-bg-subtle-active));
289
+ }
290
+
291
+ /* 不写 control 时它自成一件,落焦要有自己的环 */
292
+ [data-scope='password-input'][data-part='visibility-trigger']:focus-visible {
293
+ outline: var(--xh-ring-width) solid var(--xh-_password-input-ring);
294
+ outline-offset: var(--xh-ring-offset);
295
+ }
296
+
297
+ /* 盒里有两个 Tab 停靠点,盒子在 :focus-within 上画的那一圈两者完全一样,
298
+ 分不出焦点在框里还是在钮上,所以钮上再画一圈自己的环。
299
+ 环往内收,压在按钮自己的方框里,不与盒子外面那一圈叠在一起。
300
+ 指示焦点只能用环不能用底色:可用的几档底色压在盒底上都到不了 3:1,
301
+ 换了色也等于没画 */
302
+ [data-scope='password-input'][data-part='control'] [data-part='visibility-trigger']:focus-visible {
303
+ outline: var(--xh-ring-width) solid var(--xh-_password-input-ring);
304
+ outline-offset: calc(-1 * var(--xh-ring-offset));
305
+ }
306
+
307
+ /* 明暗两态各一枚字形:换的是这个槽,兜底盒的量法只写一遍 */
308
+ [data-scope='password-input'][data-part='visibility-trigger'][data-state='visible'] {
309
+ --xh-_password-input-mark: var(--xh-glyph-mark-eye-off);
310
+ }
311
+
312
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这条即不命中 */
313
+ [data-scope='password-input'][data-part='visibility-trigger']:empty::before {
314
+ content: '';
315
+ display: inline-block;
316
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
317
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
318
+ vertical-align: var(--xh-glyph-baseline-shift);
319
+ background-color: currentColor;
320
+ -webkit-mask: var(--xh-_password-input-mark) center / contain no-repeat;
321
+ mask: var(--xh-_password-input-mark) center / contain no-repeat;
322
+ }
323
+
324
+ [data-scope='password-input'][data-part='visibility-trigger']:disabled {
325
+ background: var(--xh-password-input-trigger-bg, transparent);
326
+ color: var(--xh-fg-disabled);
327
+ cursor: not-allowed;
328
+ }
329
+
330
+ /* —— 大写锁定提示 —— */
331
+ /* 贴在切换钮之前的一小块提示,字号比正文小一档,颜色取次级前景:
332
+ 它是提示不是报错,抢不过框里正在输入的内容 */
333
+ [data-scope='password-input'][data-part='caps-lock-indicator'] {
334
+ display: inline-flex;
335
+ flex: none;
336
+ align-items: center;
337
+ gap: var(--xh-password-input-hint-gap, var(--xh-space-1));
338
+ padding-inline: var(--xh-password-input-hint-px, var(--xh-space-1));
339
+ color: var(--xh-password-input-hint-fg, var(--xh-fg-muted));
340
+ font-size: var(--xh-password-input-hint-font-size, var(--xh-_password-input-hint-font-size));
341
+ line-height: var(--xh-leading-none);
342
+ }
343
+
344
+ /* 作者自己给这个节点写 hidden 时照样收起;上面那条 display 会把 UA 规则盖掉,
345
+ 少了这条它就一直杵在那儿 */
346
+ [data-scope='password-input'][data-part='caps-lock-indicator'][hidden] {
347
+ display: none;
348
+ }
349
+
350
+ /* 没开大写锁定时只把这块收成零宽,不用 display / visibility 撤掉它:
351
+ 播报区一旦从渲染树里消失就不再是活区域,重新出现时读屏当作插入了个新节点,多数不念。
352
+ 此时区内文字是空串,留着的只有一个不占位的空盒 */
353
+ [data-scope='password-input'][data-part='caps-lock-indicator'][data-state='hidden'] {
354
+ padding-inline: 0;
355
+ }
356
+ }
package/css/pin-input.css CHANGED
@@ -7,10 +7,10 @@
7
7
  /* 与文本框、数字框同一套堆叠:标签一行、格子一行 */
8
8
  [data-scope='pin-input'][data-part='root'] {
9
9
  /* 尺寸档只换这四个私有槽,标题与格子都从 root 继承它们,换档不必给每个部件各写一条选择器 */
10
- --xh-_pin-input-box-size: var(--xh-control-h-lg);
11
- --xh-_pin-input-box-gap: var(--xh-space-2);
12
- --xh-_pin-input-box-font-size: var(--xh-font-size-xl);
13
- --xh-_pin-input-label-font-size: var(--xh-text-label-size);
10
+ --xh-_pin-input-box-size: var(--xh-control-box-md);
11
+ --xh-_pin-input-box-gap: var(--xh-control-gap-md);
12
+ --xh-_pin-input-box-font-size: var(--xh-text-heading-3-size);
13
+ --xh-_pin-input-label-font-size: var(--xh-control-font-md);
14
14
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
15
15
  --xh-_pin-input-box-bg: var(--xh-bg-canvas);
16
16
  --xh-_pin-input-box-border: var(--xh-border-control);
@@ -54,18 +54,18 @@
54
54
 
55
55
  /* —— 尺寸 —— */
56
56
  [data-scope='pin-input'][data-part='root'][data-size='sm'] {
57
- --xh-_pin-input-box-size: var(--xh-control-h-md);
57
+ --xh-_pin-input-box-size: var(--xh-control-box-sm);
58
58
  --xh-_pin-input-box-gap: var(--xh-control-gap-sm);
59
- --xh-_pin-input-box-font-size: var(--xh-font-size-lg);
60
- --xh-_pin-input-label-font-size: var(--xh-font-size-sm);
59
+ --xh-_pin-input-box-font-size: var(--xh-control-font-lg);
60
+ --xh-_pin-input-label-font-size: var(--xh-control-font-sm);
61
61
  }
62
62
 
63
63
  /* 格子是正方形,缺省档已经占到控件高度表的顶档,lg 档由顶档加一格间距合成,不另立数值 */
64
64
  [data-scope='pin-input'][data-part='root'][data-size='lg'] {
65
- --xh-_pin-input-box-size: calc(var(--xh-control-h-lg) + var(--xh-space-2));
65
+ --xh-_pin-input-box-size: var(--xh-control-box-lg);
66
66
  --xh-_pin-input-box-gap: var(--xh-control-gap-lg);
67
- --xh-_pin-input-box-font-size: var(--xh-font-size-2xl);
68
- --xh-_pin-input-label-font-size: var(--xh-font-size-lg);
67
+ --xh-_pin-input-box-font-size: var(--xh-text-heading-2-size);
68
+ --xh-_pin-input-label-font-size: var(--xh-control-font-lg);
69
69
  }
70
70
 
71
71
  [data-scope='pin-input'][data-part='label'] {
@@ -121,13 +121,16 @@
121
121
  :focus-visible 兜住机器状态还没回流的那一帧,两条同时写不冲突 */
122
122
  [data-scope='pin-input'][data-part='input'][data-focus],
123
123
  [data-scope='pin-input'][data-part='input']:focus-visible {
124
- border-color: var(--xh-pin-input-box-border-focus, var(--xh-_pin-input-ring));
124
+ border-color: var(--xh-pin-input-box-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
125
125
  outline: var(--xh-ring-width) solid var(--xh-_pin-input-ring);
126
126
  outline-offset: var(--xh-ring-offset);
127
127
  }
128
128
 
129
129
  [data-scope='pin-input'][data-part='input'][data-invalid] {
130
- border-color: var(--xh-pin-input-box-border-invalid, var(--xh-color-danger-500));
130
+ border-color: var(--xh-pin-input-box-border-invalid, var(--xh-border-invalid));
131
+
132
+ /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
133
+ --xh-_pin-input-ring: var(--xh-ring-invalid);
131
134
  }
132
135
 
133
136
  /* 每格都是原生 disabled 的单体控件(禁用的格子不该能聚焦),所以用 :disabled */
@@ -10,13 +10,26 @@
10
10
  @layer xihan.motion {
11
11
  /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
12
12
  动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
13
- @keyframes xh-fade-in {
13
+ @keyframes xh-pop-in {
14
14
  from {
15
15
  opacity: 0;
16
+ scale: var(--xh-motion-scale-enter);
16
17
  }
17
18
 
18
19
  to {
19
20
  opacity: 1;
21
+ scale: 1;
22
+ }
23
+ }
24
+ @keyframes xh-pop-out {
25
+ from {
26
+ opacity: 1;
27
+ scale: 1;
28
+ }
29
+
30
+ to {
31
+ opacity: 0;
32
+ scale: var(--xh-motion-scale-enter);
20
33
  }
21
34
  }
22
35
  }
@@ -35,7 +48,7 @@
35
48
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
36
49
  [data-scope='popconfirm'][data-part='positioner'] {
37
50
  position: fixed;
38
- z-index: var(--xh-layer-popover);
51
+ z-index: var(--xh-popconfirm-layer, var(--xh-layer-popover));
39
52
  /* 空壳不吃指针,交互只发生在 content 上 */
40
53
  pointer-events: none;
41
54
  }
@@ -65,7 +78,7 @@
65
78
  border-radius: var(--xh-popconfirm-radius, var(--xh-shape-surface));
66
79
  background: var(--xh-popconfirm-bg, var(--xh-bg-surface));
67
80
  color: var(--xh-popconfirm-fg, var(--xh-fg-default));
68
- box-shadow: var(--xh-popconfirm-shadow, var(--xh-elevation-2));
81
+ box-shadow: var(--xh-popconfirm-shadow, var(--xh-elevation-floating));
69
82
  pointer-events: auto;
70
83
  }
71
84
 
@@ -73,17 +86,24 @@
73
86
  grid-column: 1 / -1;
74
87
  }
75
88
 
76
- /* display 会盖掉 hidden 属性的 UA 规则,收起态显式让位 */
77
- [data-scope='popconfirm'][data-part='content'][hidden] {
78
- display: none;
79
- }
89
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 dialog 一致:
90
+ 收起态连接层会给 contenthidden,而上面那条 display 正是要盖掉 UA 的
91
+ [hidden]{display:none}——退场动画得先能播。presence 读的是 content 的 animationName,
92
+ 真正的收起由宿主在退场结束后落成内联 display:none(Vue 那边直接不渲染)。
93
+ 其余声明了 display 的角色节点仍补 [hidden],那几处没有退场动画。 */
80
94
 
81
95
  [data-scope='popconfirm'][data-part='content']:focus-visible {
82
96
  outline: none;
83
97
  }
84
98
 
85
99
  [data-scope='popconfirm'][data-part='content'][data-state='open'] {
86
- animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
100
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
101
+ }
102
+
103
+ /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
104
+ 免得动画结束到真收起之间闪一下原样 */
105
+ [data-scope='popconfirm'][data-part='content'][data-state='closed'] {
106
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
87
107
  }
88
108
 
89
109
  /* —— 尺寸 —— */
@@ -121,10 +141,10 @@
121
141
  align-items: center;
122
142
  justify-content: center;
123
143
  block-size: var(--xh-control-h-sm);
124
- padding-inline: var(--xh-control-px-sm);
144
+ padding-inline: var(--xh-popconfirm-cancel-trigger-px, var(--xh-control-px-sm));
125
145
  border: var(--xh-stroke-thin) solid transparent;
126
- border-radius: var(--xh-shape-control);
127
- font-size: var(--xh-font-size-sm);
146
+ border-radius: var(--xh-popconfirm-action-radius, var(--xh-shape-control));
147
+ font-size: var(--xh-text-secondary-size);
128
148
  font-weight: var(--xh-text-label-weight);
129
149
  line-height: var(--xh-leading-none);
130
150
  white-space: nowrap;
@@ -161,7 +181,7 @@
161
181
  border: var(--xh-stroke-thin) solid transparent;
162
182
  border-block-start-color: currentcolor;
163
183
  border-radius: var(--xh-shape-pill);
164
- animation: xh-popconfirm-rotate var(--xh-popconfirm-loading-duration, calc(var(--xh-duration-slow) * 2)) linear infinite;
184
+ animation: xh-popconfirm-rotate var(--xh-popconfirm-loading-duration, var(--xh-spin-duration)) linear infinite;
165
185
  }
166
186
 
167
187
  [data-scope='popconfirm'][data-part='confirm-trigger']:hover {
@@ -191,4 +211,27 @@
191
211
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
192
212
  outline-offset: var(--xh-ring-offset);
193
213
  }
214
+
215
+ /* 减少动效:圆环停下并整圈换成虚线,静止的形状仍然读得出"还没好"。
216
+ 两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
217
+ @media (prefers-reduced-motion: reduce) {
218
+ [data-scope='popconfirm'][data-part='confirm-trigger'][data-loading]::before {
219
+ border-style: dotted;
220
+ border-color: currentColor;
221
+ animation: none;
222
+ }
223
+ }
224
+
225
+ :where([data-motion='reduce']) [data-scope='popconfirm'][data-part='confirm-trigger'][data-loading]::before {
226
+ border-style: dotted;
227
+ border-color: currentColor;
228
+ animation: none;
229
+ }
230
+
231
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
232
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
233
+ [data-scope='popconfirm'][data-part='root'][hidden],
234
+ [data-scope='popconfirm'][data-part='cancel-trigger'][hidden] {
235
+ display: none;
236
+ }
194
237
  }