@xihan-ui/styles 1.0.0-alpha.0 → 1.0.0-alpha.1

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 (58) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/css/back-top.css +2 -2
  3. package/css/button-group.css +1 -1
  4. package/css/button.css +1 -1
  5. package/css/calendar.css +1 -1
  6. package/css/carousel.css +2 -2
  7. package/css/cascader.css +199 -24
  8. package/css/checkbox-group.css +20 -20
  9. package/css/checkbox.css +1 -1
  10. package/css/clipboard.css +3 -3
  11. package/css/color-picker.css +21 -5
  12. package/css/combobox.css +23 -20
  13. package/css/composer.css +1 -1
  14. package/css/context-menu.css +56 -26
  15. package/css/date-field.css +5 -5
  16. package/css/date-picker.css +66 -2
  17. package/css/drawer.css +3 -3
  18. package/css/dynamic-input.css +2 -2
  19. package/css/editable.css +6 -6
  20. package/css/field.css +32 -1
  21. package/css/file-upload.css +3 -3
  22. package/css/float-button.css +2 -2
  23. package/css/form.css +17 -5
  24. package/css/hover-card.css +15 -11
  25. package/css/image-viewer.css +176 -0
  26. package/css/listbox.css +9 -6
  27. package/css/mention.css +14 -22
  28. package/css/menu.css +38 -23
  29. package/css/menubar.css +28 -17
  30. package/css/number-field.css +16 -16
  31. package/css/pin-input.css +6 -6
  32. package/css/popconfirm.css +23 -0
  33. package/css/popover.css +15 -11
  34. package/css/popselect.css +31 -16
  35. package/css/progress.css +68 -1
  36. package/css/radio-group.css +1 -1
  37. package/css/select.css +148 -17
  38. package/css/side-nav.css +163 -0
  39. package/css/slider.css +55 -0
  40. package/css/steps.css +2 -2
  41. package/css/switch.css +27 -0
  42. package/css/table.css +6 -6
  43. package/css/tags-input.css +7 -7
  44. package/css/text-field.css +23 -10
  45. package/css/thread.css +1 -1
  46. package/css/time-field.css +5 -5
  47. package/css/time-picker.css +36 -26
  48. package/css/toggle-group.css +1 -1
  49. package/css/toggle.css +1 -1
  50. package/css/tone.css +22 -0
  51. package/css/tooltip.css +20 -15
  52. package/css/tour.css +16 -12
  53. package/css/transfer.css +11 -9
  54. package/css/tree-select.css +26 -18
  55. package/css/tree.css +8 -5
  56. package/index.css +6 -2
  57. package/index.unlayered.css +1499 -413
  58. package/package.json +4 -2
@@ -0,0 +1,163 @@
1
+ @layer xihan.components {
2
+ [data-scope='side-nav'][data-part='root'] {
3
+ inline-size: var(--xh-side-nav-w, 240px);
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: var(--xh-side-nav-gap, var(--xh-space-1));
7
+ padding: var(--xh-side-nav-p, var(--xh-space-2));
8
+ color: var(--xh-side-nav-fg, var(--xh-fg-default));
9
+ }
10
+
11
+ /* 折叠成图标栏:整栏收窄,文字随行宽被裁掉 */
12
+ [data-scope='side-nav'][data-part='root'][data-collapsed] {
13
+ inline-size: var(--xh-side-nav-collapsed-w, 56px);
14
+ }
15
+
16
+ [data-scope='side-nav'][data-part='list'],
17
+ [data-scope='side-nav'][data-part='branch-content'] {
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--xh-side-nav-gap, var(--xh-space-1));
21
+ margin: 0;
22
+ padding: 0;
23
+ list-style: none;
24
+ }
25
+
26
+ /* 子层靠嵌套缩进,层级越深自然越靠里 */
27
+ [data-scope='side-nav'][data-part='branch-content'] {
28
+ padding-inline-start: var(--xh-side-nav-indent, var(--xh-space-4));
29
+ }
30
+
31
+ [data-scope='side-nav'][data-part='branch-content'][hidden] {
32
+ display: none;
33
+ }
34
+
35
+ [data-scope='side-nav'][data-part='group'] {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: var(--xh-side-nav-gap, var(--xh-space-1));
39
+ list-style: none;
40
+ }
41
+
42
+ [data-scope='side-nav'][data-part='group-label'] {
43
+ padding-block: var(--xh-space-1);
44
+ padding-inline: var(--xh-control-px-md);
45
+ font-size: var(--xh-font-size-xs);
46
+ color: var(--xh-fg-subtle);
47
+ user-select: none;
48
+ }
49
+
50
+ /* 折叠时分组标题没有落点,藏掉 */
51
+ [data-scope='side-nav'][data-part='group-label'][data-collapsed] {
52
+ display: none;
53
+ }
54
+
55
+ [data-scope='side-nav'][data-part='branch'] {
56
+ display: flex;
57
+ flex-direction: column;
58
+ gap: var(--xh-side-nav-gap, var(--xh-space-1));
59
+ list-style: none;
60
+ }
61
+
62
+ /* —— 行:分支按钮与链接同一副长相 —— */
63
+ [data-scope='side-nav'][data-part='branch-trigger'],
64
+ [data-scope='side-nav'][data-part='link'] {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: var(--xh-control-gap-md);
68
+ inline-size: 100%;
69
+ min-block-size: var(--xh-control-h-md);
70
+ padding-inline: var(--xh-control-px-md);
71
+ border: none;
72
+ border-radius: var(--xh-shape-control);
73
+ background: none;
74
+ color: inherit;
75
+ font-size: var(--xh-text-body-size);
76
+ text-align: start;
77
+ text-decoration: none;
78
+ cursor: pointer;
79
+ }
80
+
81
+ [data-scope='side-nav'][data-part='branch-trigger']:hover,
82
+ [data-scope='side-nav'][data-part='link']:hover {
83
+ background: var(--xh-bg-subtle-hover);
84
+ }
85
+
86
+ [data-scope='side-nav'][data-part='branch-trigger']:focus-visible,
87
+ [data-scope='side-nav'][data-part='link']:focus-visible {
88
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
89
+ outline-offset: var(--xh-ring-offset);
90
+ }
91
+
92
+ /* 选中的那条:品牌淡底 + 强调字 */
93
+ [data-scope='side-nav'][data-part='link'][data-selected] {
94
+ background: var(--xh-bg-brand-subtle);
95
+ color: var(--xh-fg-brand);
96
+ font-weight: var(--xh-font-weight-medium);
97
+ }
98
+
99
+ /* 选中项的祖先枝:只染字色,一路指到当前页 */
100
+ [data-scope='side-nav'][data-part='branch-trigger'][data-active] {
101
+ color: var(--xh-fg-brand);
102
+ }
103
+
104
+ [data-scope='side-nav'][data-part='branch-trigger'][data-disabled],
105
+ [data-scope='side-nav'][data-part='link'][data-disabled] {
106
+ color: var(--xh-fg-disabled);
107
+ cursor: not-allowed;
108
+ }
109
+
110
+ [data-scope='side-nav'][data-part='branch-text'],
111
+ [data-scope='side-nav'][data-part='link-text'] {
112
+ flex: 1;
113
+ min-inline-size: 0;
114
+ overflow: hidden;
115
+ text-overflow: ellipsis;
116
+ white-space: nowrap;
117
+ }
118
+
119
+ /* 折叠成图标栏:文字与展开指示整个藏掉、行内容居中,不裁半个字。
120
+ 弹出面板里的行不在此列——面板是正常宽度的浮层,文字照常显示 */
121
+ [data-scope='side-nav'][data-part='root'][data-collapsed] [data-part='branch-text']:not([data-popout] *),
122
+ [data-scope='side-nav'][data-part='root'][data-collapsed] [data-part='link-text']:not([data-popout] *),
123
+ [data-scope='side-nav'][data-part='root'][data-collapsed] [data-part='branch-indicator']:not([data-popout] *) {
124
+ display: none;
125
+ }
126
+
127
+ [data-scope='side-nav'][data-part='root'][data-collapsed] [data-part='branch-trigger']:not([data-popout] *),
128
+ [data-scope='side-nav'][data-part='root'][data-collapsed] [data-part='link']:not([data-popout] *) {
129
+ justify-content: center;
130
+ padding-inline: 0;
131
+ }
132
+
133
+ /* 折叠态的弹出面板:贴着触发按钮旁侧的浮层卡片,坐标由连接层写在行内样式上。
134
+ 面板自己不吃子层缩进(padding 整圈盖掉),面板内的嵌套子层照常缩进 */
135
+ [data-scope='side-nav'][data-part='branch-content'][data-popout] {
136
+ z-index: var(--xh-side-nav-popout-layer, var(--xh-layer-popover));
137
+ min-inline-size: var(--xh-side-nav-popout-min-w, var(--xh-overlay-menu-min-w));
138
+ max-inline-size: var(--xh-side-nav-popout-max-w, var(--xh-overlay-max-w));
139
+ padding: var(--xh-side-nav-popout-p, var(--xh-space-1));
140
+ border: var(--xh-stroke-thin) solid var(--xh-side-nav-popout-border, var(--xh-border-default));
141
+ border-radius: var(--xh-side-nav-popout-radius, var(--xh-shape-surface));
142
+ background: var(--xh-side-nav-popout-bg, var(--xh-bg-surface));
143
+ box-shadow: var(--xh-side-nav-popout-shadow, var(--xh-elevation-2));
144
+ pointer-events: auto;
145
+ }
146
+
147
+ [data-scope='side-nav'][data-part='branch-indicator'] {
148
+ margin-inline-start: auto;
149
+ display: inline-flex;
150
+ flex: none;
151
+ transition: rotate var(--xh-duration-fast) var(--xh-ease-standard);
152
+ }
153
+
154
+ [data-scope='side-nav'][data-part='branch-indicator'][data-state='open'] {
155
+ rotate: 90deg;
156
+ }
157
+
158
+ @media (prefers-reduced-motion: reduce) {
159
+ [data-scope='side-nav'][data-part='branch-indicator'] {
160
+ transition: none;
161
+ }
162
+ }
163
+ }
package/css/slider.css CHANGED
@@ -186,6 +186,61 @@
186
186
  --xh-_track-thickness: var(--xh-slider-track-thickness, var(--xh-space-2));
187
187
  }
188
188
 
189
+ /* —— 刻度:圆点钉在轨道上、文案排在轨道外侧,坐标由连接层按百分比内联给出 —— */
190
+ [data-scope='slider'][data-part='marks'] {
191
+ position: absolute;
192
+ inset: 0;
193
+ pointer-events: none;
194
+ }
195
+
196
+ [data-scope='slider'][data-part='mark'] {
197
+ position: absolute;
198
+ inset-block-start: 50%;
199
+ inline-size: var(--xh-slider-mark-size, var(--xh-space-1));
200
+ block-size: var(--xh-slider-mark-size, var(--xh-space-1));
201
+ border-radius: var(--xh-shape-pill);
202
+ background: var(--xh-slider-mark-bg, var(--xh-border-strong));
203
+ translate: -50% -50%;
204
+ }
205
+
206
+ /* 落进已选区间的刻度点跟 range 同色 */
207
+ [data-scope='slider'][data-part='mark'][data-active] {
208
+ background: var(--xh-slider-mark-bg-active, var(--xh-_tone, var(--xh-bg-brand)));
209
+ }
210
+
211
+ [data-scope='slider'][data-part='mark-label'] {
212
+ position: absolute;
213
+ inset-block-start: 100%;
214
+ margin-block-start: var(--xh-slider-mark-label-gap, var(--xh-space-1));
215
+ color: var(--xh-slider-mark-label-fg, var(--xh-fg-subtle));
216
+ font-size: var(--xh-slider-mark-label-font-size, var(--xh-font-size-xs));
217
+ line-height: var(--xh-leading-none);
218
+ white-space: nowrap;
219
+ translate: -50% 0;
220
+ cursor: pointer;
221
+ pointer-events: auto;
222
+ user-select: none;
223
+ }
224
+
225
+ [data-scope='slider'][data-part='mark-label'][data-active] {
226
+ color: var(--xh-slider-mark-label-fg-active, var(--xh-fg-default));
227
+ }
228
+
229
+ /* 竖直轨道:点与文案换轴,坐标由连接层写在 block 轴上 */
230
+ [data-scope='slider'][data-part='root'][data-orientation='vertical'] [data-part='mark'] {
231
+ inset-block-start: auto;
232
+ inset-inline-start: 50%;
233
+ translate: -50% 50%;
234
+ }
235
+
236
+ [data-scope='slider'][data-part='root'][data-orientation='vertical'] [data-part='mark-label'] {
237
+ inset-block-start: auto;
238
+ inset-inline-start: 100%;
239
+ margin-block-start: 0;
240
+ margin-inline-start: var(--xh-slider-mark-label-gap, var(--xh-space-1));
241
+ translate: 0 50%;
242
+ }
243
+
189
244
  /* display 会盖掉 UA 的 [hidden]{display:none},凡是被赋了 display 的角色节点都要显式让位 */
190
245
  [data-scope='slider'][data-part='root'][hidden],
191
246
  [data-scope='slider'][data-part='control'][hidden] {
package/css/steps.css CHANGED
@@ -176,8 +176,8 @@
176
176
  }
177
177
 
178
178
  [data-scope='steps'][data-part='item'][data-disabled] [data-scope='steps'][data-part='indicator'] {
179
- border-color: var(--xh-fg-disabled);
180
- color: var(--xh-fg-disabled);
179
+ border-color: var(--xh-steps-indicator-border-disabled, var(--xh-fg-disabled));
180
+ color: var(--xh-steps-indicator-fg-disabled, var(--xh-fg-disabled));
181
181
  }
182
182
 
183
183
  /* 标题与说明都在右列:不给 display,网格布局会替它们块级化,
package/css/switch.css CHANGED
@@ -58,4 +58,31 @@
58
58
  [data-scope='switch'][data-part='thumb'][data-state='checked'] {
59
59
  translate: var(--xh-_switch-thumb-size) 0;
60
60
  }
61
+
62
+ /* 转圈的关键帧定义在本文件里:引用别处文件的动画名时那份文件不一定在场,动画会静默不跑 */
63
+ @keyframes xh-switch-rotate {
64
+ to {
65
+ transform: rotate(1turn);
66
+ }
67
+ }
68
+
69
+ /* 提交中:指针挂起、滑块里转圈;不是禁用,焦点与对比度都保持 */
70
+ [data-scope='switch'][data-part='root'][data-loading] {
71
+ cursor: wait;
72
+ }
73
+
74
+ [data-scope='switch'][data-part='thumb'][data-loading] {
75
+ display: grid;
76
+ place-items: center;
77
+ }
78
+
79
+ [data-scope='switch'][data-part='thumb'][data-loading]::after {
80
+ content: '';
81
+ inline-size: 60%;
82
+ block-size: 60%;
83
+ border: var(--xh-stroke-thin) solid transparent;
84
+ border-block-start-color: var(--xh-switch-loading-fg, var(--xh-bg-brand));
85
+ border-radius: var(--xh-shape-pill);
86
+ animation: xh-switch-rotate var(--xh-switch-loading-duration, calc(var(--xh-duration-slow) * 2)) linear infinite;
87
+ }
61
88
  }
package/css/table.css CHANGED
@@ -135,10 +135,10 @@
135
135
  border-block-end: none;
136
136
  }
137
137
 
138
- /* 键盘高亮与指针高亮共用一套底色。data-highlighted 跟的是连接层记的焦点行,
138
+ /* 悬停与键盘锚点共用中性灰轻档。data-highlighted 跟的是连接层记的焦点行,
139
139
  与选中互相独立:可以停在一个没被选中的行上 */
140
140
  [data-scope='table'][data-part='body'] > [data-scope='table'][data-part='row']:not([data-disabled]):is(:hover, [data-highlighted]) {
141
- background: var(--xh-table-row-bg-highlight, var(--xh-bg-subtle-hover));
141
+ background: var(--xh-table-row-bg-hover, var(--xh-bg-subtle));
142
142
  }
143
143
 
144
144
  /* 选中比高亮更"实":它表达的是数据状态,翻页回来还在 */
@@ -223,14 +223,14 @@
223
223
  切换选中不引起行宽抖动 */
224
224
  [data-scope='table'][data-part='select-all-trigger'],
225
225
  [data-scope='table'][data-part='row-select-trigger'] {
226
- border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-strong));
226
+ border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-control));
227
227
  color: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
228
228
  visibility: visible;
229
229
  }
230
230
 
231
231
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='all'], [data-state='some']),
232
232
  [data-scope='table'][data-part='row-select-trigger'][data-selected] {
233
- border-color: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
233
+ border-color: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
234
234
  background: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
235
235
  }
236
236
 
@@ -379,7 +379,7 @@
379
379
  }
380
380
 
381
381
  /* 两个状态节点常挂,只在表体为空时才显形 */
382
- [data-scope='table'][data-part='empty-state'],
382
+ [data-scope='table'][data-part='empty'],
383
383
  [data-scope='table'][data-part='loading-state'] {
384
384
  display: flex;
385
385
  flex-direction: column;
@@ -393,7 +393,7 @@
393
393
  text-align: center;
394
394
  }
395
395
 
396
- [data-scope='table'][data-part='empty-state'][hidden],
396
+ [data-scope='table'][data-part='empty'][hidden],
397
397
  [data-scope='table'][data-part='loading-state'][hidden] {
398
398
  display: none;
399
399
  }
@@ -12,8 +12,8 @@
12
12
  --xh-_tags-input-label-font-size: var(--xh-text-label-size);
13
13
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
14
14
  --xh-_tags-input-control-bg: var(--xh-bg-canvas);
15
- --xh-_tags-input-control-border: var(--xh-border-default);
16
- --xh-_tags-input-control-border-hover: var(--xh-border-strong);
15
+ --xh-_tags-input-control-border: var(--xh-border-control);
16
+ --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
17
17
  /* 聚焦环与标签块的强调色随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的取值 */
18
18
  --xh-_tags-input-ring: var(--xh-ring-focus);
19
19
  --xh-_tags-input-accent: var(--xh-_tone, var(--xh-bg-brand));
@@ -35,22 +35,22 @@
35
35
  不做 solid:实心填充盖住了"这里能打字"这件事,输入框用不上它 */
36
36
  [data-scope='tags-input'][data-part='root'][data-variant='outline'] {
37
37
  --xh-_tags-input-control-bg: var(--xh-bg-canvas);
38
- --xh-_tags-input-control-border: var(--xh-border-default);
39
- --xh-_tags-input-control-border-hover: var(--xh-border-strong);
38
+ --xh-_tags-input-control-border: var(--xh-border-control);
39
+ --xh-_tags-input-control-border-hover: var(--xh-border-control-hover);
40
40
  }
41
41
 
42
42
  /* 填充式:底色圈出可输入的范围,描边让位给底色 */
43
43
  [data-scope='tags-input'][data-part='root'][data-variant='subtle'] {
44
44
  --xh-_tags-input-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
45
45
  --xh-_tags-input-control-border: transparent;
46
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
46
+ --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
47
47
  }
48
48
 
49
49
  /* 无边框、透明底:静息时框完全隐入背景,可见反馈全靠悬停描边与聚焦环 */
50
50
  [data-scope='tags-input'][data-part='root'][data-variant='ghost'] {
51
51
  --xh-_tags-input-control-bg: transparent;
52
52
  --xh-_tags-input-control-border: transparent;
53
- --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
53
+ --xh-_tags-input-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
54
54
  }
55
55
 
56
56
  /* —— 尺寸 —— */
@@ -290,7 +290,7 @@
290
290
  max-inline-size: 100%;
291
291
  padding-block: var(--xh-tags-input-item-py, var(--xh-space-1));
292
292
  padding-inline: var(--xh-tags-input-item-px, var(--xh-space-2));
293
- border: var(--xh-stroke-thin) solid var(--xh-tags-input-item-input-border, var(--xh-border-strong));
293
+ border: var(--xh-stroke-thin) solid var(--xh-tags-input-item-input-border, var(--xh-border-control));
294
294
  border-radius: var(--xh-tags-input-item-radius, var(--xh-shape-pill));
295
295
  background: var(--xh-tags-input-item-input-bg, var(--xh-bg-canvas));
296
296
  color: var(--xh-tags-input-item-input-fg, var(--xh-fg-default));
@@ -13,13 +13,13 @@
13
13
 
14
14
  /* 形态档只换这三个私有槽:底、常态描边、悬停描边 */
15
15
  --xh-_text-field-bg: var(--xh-bg-canvas);
16
- --xh-_text-field-border: var(--xh-border-default);
17
- --xh-_text-field-border-hover: var(--xh-border-strong);
16
+ --xh-_text-field-border: var(--xh-border-control);
17
+ --xh-_text-field-border-hover: var(--xh-border-control-hover);
18
18
 
19
19
  /* 语气只落在聚焦这一处:环与聚焦态描边。正文颜色不归它管。
20
20
  没写 data-tone 时 --xh-_tone 没被声明,退回原来的聚焦环色与常态描边 */
21
21
  --xh-_text-field-ring: var(--xh-ring-focus);
22
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-default)));
22
+ --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control)));
23
23
 
24
24
  display: inline-flex;
25
25
  flex-direction: column;
@@ -54,9 +54,9 @@
54
54
  输入框没有实心档:填满一个要往里打字的框,字与底就没法同时读 */
55
55
  [data-scope='text-field'][data-part='root'][data-variant='outline'] {
56
56
  --xh-_text-field-bg: var(--xh-bg-canvas);
57
- --xh-_text-field-border: var(--xh-border-default);
58
- --xh-_text-field-border-hover: var(--xh-border-strong);
59
- --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-default)));
57
+ --xh-_text-field-border: var(--xh-border-control);
58
+ --xh-_text-field-border-hover: var(--xh-border-control-hover);
59
+ --xh-_text-field-border-focus: var(--xh-text-field-input-border, var(--xh-_tone, var(--xh-border-control)));
60
60
  }
61
61
 
62
62
  /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
@@ -64,16 +64,16 @@
64
64
  [data-scope='text-field'][data-part='root'][data-variant='subtle'] {
65
65
  --xh-_text-field-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
66
66
  --xh-_text-field-border: transparent;
67
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-default));
68
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-default));
67
+ --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
68
+ --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control));
69
69
  }
70
70
 
71
71
  /* 无框:底与描边都透明,平时只看得见字,悬停与聚焦才浮出边界 */
72
72
  [data-scope='text-field'][data-part='root'][data-variant='ghost'] {
73
73
  --xh-_text-field-bg: transparent;
74
74
  --xh-_text-field-border: transparent;
75
- --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-default));
76
- --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-default));
75
+ --xh-_text-field-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
76
+ --xh-_text-field-border-focus: var(--xh-_tone, var(--xh-border-control));
77
77
  }
78
78
 
79
79
  [data-scope='text-field'][data-part='label'] {
@@ -102,6 +102,19 @@
102
102
  transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
103
103
  }
104
104
 
105
+ /* 多行宿主:定高换成行数撑高,纵向留出内边距;autoSize 接管高度后拉柄与滚动都收掉 */
106
+ [data-scope='text-field'][data-part='input'][data-multiline] {
107
+ block-size: auto;
108
+ min-block-size: var(--xh-text-field-input-h, var(--xh-_text-field-h));
109
+ padding-block: var(--xh-text-field-textarea-py, var(--xh-space-2));
110
+ resize: vertical;
111
+ }
112
+
113
+ [data-scope='text-field'][data-part='input'][data-multiline][data-autosize] {
114
+ overflow: hidden;
115
+ resize: none;
116
+ }
117
+
105
118
  [data-scope='text-field'][data-part='input']::placeholder {
106
119
  color: var(--xh-text-field-placeholder-fg, var(--xh-fg-subtle));
107
120
  }
package/css/thread.css CHANGED
@@ -57,7 +57,7 @@
57
57
  min-inline-size: var(--xh-thread-scroll-button-h, var(--xh-control-h-md));
58
58
  block-size: var(--xh-thread-scroll-button-h, var(--xh-control-h-md));
59
59
  padding-inline: var(--xh-thread-scroll-button-px, var(--xh-control-px-md));
60
- border: var(--xh-stroke-thin) solid var(--xh-thread-scroll-button-border, var(--xh-border-default));
60
+ border: var(--xh-stroke-thin) solid var(--xh-thread-scroll-button-border, var(--xh-border-control));
61
61
  border-radius: var(--xh-thread-scroll-button-radius, var(--xh-shape-pill));
62
62
  background: var(--xh-thread-scroll-button-bg, var(--xh-bg-surface));
63
63
  color: var(--xh-thread-scroll-button-fg, var(--xh-fg-default));
@@ -8,8 +8,8 @@
8
8
  --xh-_time-field-label-font-size: var(--xh-text-label-size);
9
9
  /* 形态档只换这三个私有槽:底色与两档描边 */
10
10
  --xh-_time-field-control-bg: var(--xh-bg-canvas);
11
- --xh-_time-field-control-border: var(--xh-border-default);
12
- --xh-_time-field-control-border-hover: var(--xh-border-strong);
11
+ --xh-_time-field-control-border: var(--xh-border-control);
12
+ --xh-_time-field-control-border-hover: var(--xh-border-control-hover);
13
13
  /* 聚焦描边与段位反白随语气走。没写 data-tone 时这几个 --xh-_tone* 没被声明,退回原来的焦点色与品牌色 */
14
14
  --xh-_time-field-ring: var(--xh-ring-focus);
15
15
  --xh-_time-field-segment-bg: var(--xh-_tone, var(--xh-bg-brand));
@@ -39,15 +39,15 @@
39
39
  /* 描边式:与缺省等价,写出来是为了三档形态在皮肤里都看得见 */
40
40
  [data-scope='time-field'][data-part='root'][data-variant='outline'] {
41
41
  --xh-_time-field-control-bg: var(--xh-bg-canvas);
42
- --xh-_time-field-control-border: var(--xh-border-default);
43
- --xh-_time-field-control-border-hover: var(--xh-border-strong);
42
+ --xh-_time-field-control-border: var(--xh-border-control);
43
+ --xh-_time-field-control-border-hover: var(--xh-border-control-hover);
44
44
  }
45
45
 
46
46
  /* 填充式:底色顶替描边,悬停时才浮出一道淡边 */
47
47
  [data-scope='time-field'][data-part='root'][data-variant='subtle'] {
48
48
  --xh-_time-field-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
49
49
  --xh-_time-field-control-border: transparent;
50
- --xh-_time-field-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
50
+ --xh-_time-field-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
51
51
  }
52
52
 
53
53
  /* 无框式:底与边都让开,可见反馈只剩聚焦那一档 */
@@ -35,7 +35,7 @@
35
35
  block-size: var(--xh-time-picker-control-h, var(--xh-control-h-md));
36
36
  padding-inline: var(--xh-time-picker-control-px, var(--xh-control-px-md));
37
37
  padding-block: 0;
38
- border: var(--xh-stroke-thin) solid var(--xh-time-picker-control-border, var(--xh-border-default));
38
+ border: var(--xh-stroke-thin) solid var(--xh-time-picker-control-border, var(--xh-border-control));
39
39
  border-radius: var(--xh-time-picker-control-radius, var(--xh-shape-control));
40
40
  background: var(--xh-time-picker-control-bg, var(--xh-bg-canvas));
41
41
  color: var(--xh-time-picker-control-fg, var(--xh-fg-default));
@@ -54,7 +54,7 @@
54
54
 
55
55
  /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
56
56
  [data-scope='time-picker'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
57
- border-color: var(--xh-time-picker-control-border-hover, var(--xh-border-strong));
57
+ border-color: var(--xh-time-picker-control-border-hover, var(--xh-border-control-hover));
58
58
  }
59
59
 
60
60
  /* 焦点真正落在段或按钮上,但整块看起来才是一个控件:内部有焦点时整框亮起来。
@@ -242,8 +242,7 @@
242
242
  max-block-size: var(--xh-time-picker-column-max-h, 12rem);
243
243
  padding-inline: var(--xh-time-picker-column-px, var(--xh-space-1));
244
244
  overflow-y: auto;
245
- /* 滚动容器在某些浏览器里会被自动塞进 Tab 序列,落焦时不画环——
246
- 焦点该落在格上,列只在整列被界卡空时才兜底占一个 Tab 位 */
245
+ /* 滚动容器在某些浏览器里会被自动塞进 Tab 序列,是否画环见下方按 tabindex 分档的两条 */
247
246
  scrollbar-width: thin;
248
247
  }
249
248
 
@@ -256,51 +255,62 @@
256
255
  border-inline-start: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-border-subtle));
257
256
  }
258
257
 
259
- [data-scope='time-picker'][data-part='column']:focus-visible {
258
+ /* 焦点落在列上有两种情形:指针打开、这一段还空着、还没有任何格当锚点,或整列被界裁空。
259
+ 那一刻它认领着 Tab 位,环画在列内沿;有锚点时环长在格上,列不再画 */
260
+ [data-scope='time-picker'][data-part='column'][tabindex='0']:focus-visible {
261
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
262
+ outline-offset: calc(-1 * var(--xh-ring-width));
263
+ }
264
+
265
+ [data-scope='time-picker'][data-part='column']:not([tabindex='0']):focus-visible {
260
266
  outline: none;
261
267
  }
262
268
 
263
- [data-scope='time-picker'][data-part='option'] {
269
+ [data-scope='time-picker'][data-part='item'] {
264
270
  display: flex;
265
271
  flex: none;
266
272
  align-items: center;
267
273
  justify-content: center;
268
- padding-block: var(--xh-time-picker-option-py, var(--xh-space-1));
269
- padding-inline: var(--xh-time-picker-option-px, var(--xh-space-2));
270
- border-radius: var(--xh-time-picker-option-radius, var(--xh-shape-control));
271
- color: var(--xh-time-picker-option-fg, var(--xh-fg-default));
272
- font-size: var(--xh-time-picker-option-font-size, var(--xh-text-body-size));
274
+ padding-block: var(--xh-time-picker-item-py, var(--xh-space-1_5));
275
+ padding-inline: var(--xh-time-picker-item-px, var(--xh-control-px-md));
276
+ border-radius: var(--xh-time-picker-item-radius, var(--xh-shape-control));
277
+ color: var(--xh-time-picker-item-fg, var(--xh-fg-default));
278
+ font-size: var(--xh-time-picker-item-font-size, var(--xh-text-body-size));
279
+ /* 居中的单个数字格没有截断层,行高保持紧排,列内多露几格 */
273
280
  line-height: var(--xh-leading-none);
274
281
  white-space: nowrap;
275
282
  cursor: pointer;
276
283
  user-select: none;
284
+ transition:
285
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
286
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
277
287
  }
278
288
 
279
289
  /* 作者自己藏掉某几格时要让位,有 display 就得补这条 */
280
- [data-scope='time-picker'][data-part='option'][hidden] {
290
+ [data-scope='time-picker'][data-part='item'][hidden] {
281
291
  display: none;
282
292
  }
283
293
 
284
- /* 焦点所在与选中互相独立:可以停在一个没被选中的格上 */
285
- [data-scope='time-picker'][data-part='option'][data-highlighted]:not([data-disabled]),
286
- [data-scope='time-picker'][data-part='option']:hover:not([data-disabled]) {
287
- background: var(--xh-time-picker-option-bg-highlight, var(--xh-bg-subtle-hover));
294
+ /* 悬停与键盘锚点共用中性灰轻档;焦点所在与选中互相独立:可以停在一个没被选中的格上 */
295
+ [data-scope='time-picker'][data-part='item'][data-highlighted]:not([data-disabled]),
296
+ [data-scope='time-picker'][data-part='item']:hover:not([data-disabled]) {
297
+ background: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
288
298
  }
289
299
 
290
- [data-scope='time-picker'][data-part='option'][data-state='checked'] {
291
- background: var(--xh-time-picker-option-bg-checked, var(--xh-bg-brand));
292
- color: var(--xh-time-picker-option-fg-checked, var(--xh-fg-on-brand));
293
- font-weight: var(--xh-time-picker-option-weight-checked, var(--xh-font-weight-medium));
300
+ [data-scope='time-picker'][data-part='item'][data-state='checked'] {
301
+ background: var(--xh-time-picker-item-bg-checked, var(--xh-bg-brand));
302
+ color: var(--xh-time-picker-item-fg-checked, var(--xh-fg-on-brand));
303
+ font-weight: var(--xh-time-picker-item-weight-checked, var(--xh-font-weight-medium));
294
304
  }
295
305
 
296
- /* 选中格上再落焦点或悬停时,底色留在品牌色一侧:上面那条中性高亮的选择器更具体,
306
+ /* 选中格上再落焦点或悬停时,底色留在品牌色一侧:上面那条中性轻档的选择器更具体,
297
307
  不写这条就只有底色被换走、文字仍是品牌底上的反白色 */
298
- [data-scope='time-picker'][data-part='option'][data-state='checked'][data-highlighted]:not([data-disabled]),
299
- [data-scope='time-picker'][data-part='option'][data-state='checked']:hover:not([data-disabled]) {
300
- background: var(--xh-time-picker-option-bg-checked-highlight, var(--xh-bg-brand-hover));
308
+ [data-scope='time-picker'][data-part='item'][data-state='checked'][data-highlighted]:not([data-disabled]),
309
+ [data-scope='time-picker'][data-part='item'][data-state='checked']:hover:not([data-disabled]) {
310
+ background: var(--xh-time-picker-item-bg-checked-hover, var(--xh-bg-brand-hover));
301
311
  }
302
312
 
303
- [data-scope='time-picker'][data-part='option']:focus-visible {
313
+ [data-scope='time-picker'][data-part='item']:focus-visible {
304
314
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
305
315
  /* 往内收:选项在滚动列里挨着排,环画在外沿会被列的溢出裁掉 */
306
316
  outline-offset: calc(-1 * var(--xh-ring-offset));
@@ -308,7 +318,7 @@
308
318
 
309
319
  /* 禁用走 aria-disabled 而非原生 disabled(原生 disabled 不派 click,禁用守卫就走不到),
310
320
  所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
311
- [data-scope='time-picker'][data-part='option'][data-disabled] {
321
+ [data-scope='time-picker'][data-part='item'][data-disabled] {
312
322
  color: var(--xh-fg-disabled);
313
323
  cursor: not-allowed;
314
324
  }
@@ -31,7 +31,7 @@
31
31
  --xh-_bg-hover: var(--xh-toggle-group-item-bg-hover, var(--xh-bg-subtle-hover));
32
32
  --xh-_bg-active: var(--xh-toggle-group-item-bg-active, var(--xh-bg-subtle-active));
33
33
  --xh-_fg: var(--xh-toggle-group-item-fg, var(--xh-fg-default));
34
- --xh-_border: var(--xh-toggle-group-item-border, var(--xh-border-default));
34
+ --xh-_border: var(--xh-toggle-group-item-border, var(--xh-border-control));
35
35
 
36
36
  /* 相邻两段靠负外边距压掉一条重边,谁的描边浮在上面必须能指定,
37
37
  因此条目必须是定位元素——静态元素的 z-index 不生效 */
package/css/toggle.css CHANGED
@@ -68,7 +68,7 @@
68
68
  --xh-_bg-pressed: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active));
69
69
  --xh-_fg-pressed: var(--xh-_tone-fg, var(--xh-fg-default));
70
70
 
71
- border-color: var(--xh-_tone-border, var(--xh-border-default));
71
+ border-color: var(--xh-_tone-border-control, var(--xh-border-control));
72
72
  }
73
73
 
74
74
  [data-scope='toggle'][data-part='root'][data-variant='ghost'] {
package/css/tone.css CHANGED
@@ -38,6 +38,9 @@
38
38
  --xh-_tone-subtle-hover: color-mix(in oklab, var(--xh-_tone) 20%, var(--xh-bg-surface));
39
39
  --xh-_tone-subtle-active: color-mix(in oklab, var(--xh-_tone) 28%, var(--xh-bg-surface));
40
40
  --xh-_tone-border: color-mix(in oklab, var(--xh-_tone) 40%, var(--xh-bg-surface));
41
+ /* 控件的可操作区边界要 3:1,兑了底色的 --xh-_tone-border 六族全在 1.44–2.18,够不着。
42
+ 这一支直接取主色本体;两族在各自的底上仍不够,在下面按主题单独兜 */
43
+ --xh-_tone-border-control: var(--xh-_tone);
41
44
  /* 在普通背景上表达该语气的文字色:往前景色兑,浅色态变深、深色态变浅 */
42
45
  --xh-_tone-fg: color-mix(in oklab, var(--xh-_tone) 72%, var(--xh-fg-default));
43
46
  }
@@ -82,4 +85,23 @@
82
85
  --xh-_tone-on: var(--xh-color-neutral-950);
83
86
  --xh-_tone-shift: var(--xh-color-neutral-0);
84
87
  }
88
+
89
+ /* 主色本体在各自的底上有两族够不到 3:1:黄在白底上只有 2.70,中性在深色底上只有 2.54。
90
+ 语气色是固定原语、不随主题翻,所以这两族只能按主题各兜一次。
91
+ 浅色是缺省态(不写 data-theme 也算浅色),深色靠属性选择器压过它 */
92
+ [data-tone='warning'] {
93
+ --xh-_tone-border-control: var(--xh-color-warning-700);
94
+ }
95
+
96
+ [data-theme='dark'] [data-tone='warning'] {
97
+ --xh-_tone-border-control: var(--xh-color-warning-600);
98
+ }
99
+
100
+ [data-tone='neutral'] {
101
+ --xh-_tone-border-control: var(--xh-color-neutral-600);
102
+ }
103
+
104
+ [data-theme='dark'] [data-tone='neutral'] {
105
+ --xh-_tone-border-control: var(--xh-color-neutral-550);
106
+ }
85
107
  }