@xihan-ui/styles 1.0.0-alpha.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 (114) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +27 -0
  4. package/css/accordion.css +108 -0
  5. package/css/affix.css +27 -0
  6. package/css/alert.css +108 -0
  7. package/css/anchor.css +137 -0
  8. package/css/avatar-group.css +82 -0
  9. package/css/avatar.css +55 -0
  10. package/css/back-top.css +61 -0
  11. package/css/badge.css +50 -0
  12. package/css/breadcrumb.css +127 -0
  13. package/css/button-group.css +131 -0
  14. package/css/button.css +98 -0
  15. package/css/calendar.css +219 -0
  16. package/css/card.css +116 -0
  17. package/css/carousel.css +193 -0
  18. package/css/cascader.css +397 -0
  19. package/css/checkbox-group.css +185 -0
  20. package/css/checkbox.css +91 -0
  21. package/css/clipboard.css +133 -0
  22. package/css/code-block.css +81 -0
  23. package/css/collapsible.css +63 -0
  24. package/css/color-picker.css +424 -0
  25. package/css/combobox.css +433 -0
  26. package/css/composer.css +127 -0
  27. package/css/context-menu.css +263 -0
  28. package/css/countdown.css +21 -0
  29. package/css/date-field.css +200 -0
  30. package/css/date-picker.css +231 -0
  31. package/css/descriptions.css +200 -0
  32. package/css/dialog.css +127 -0
  33. package/css/drawer.css +372 -0
  34. package/css/dynamic-input.css +157 -0
  35. package/css/editable.css +249 -0
  36. package/css/ellipsis.css +41 -0
  37. package/css/empty-state.css +78 -0
  38. package/css/field.css +65 -0
  39. package/css/file-upload.css +298 -0
  40. package/css/flex.css +95 -0
  41. package/css/float-button.css +121 -0
  42. package/css/form.css +185 -0
  43. package/css/gradient-text.css +62 -0
  44. package/css/grid.css +428 -0
  45. package/css/highlight.css +21 -0
  46. package/css/hover-card.css +146 -0
  47. package/css/icon-wrapper.css +64 -0
  48. package/css/icon.css +54 -0
  49. package/css/image.css +45 -0
  50. package/css/infinite-scroll.css +22 -0
  51. package/css/layers.css +2 -0
  52. package/css/layout.css +169 -0
  53. package/css/list.css +117 -0
  54. package/css/listbox.css +174 -0
  55. package/css/loading-bar.css +66 -0
  56. package/css/log.css +66 -0
  57. package/css/marquee.css +182 -0
  58. package/css/mention.css +222 -0
  59. package/css/menu.css +144 -0
  60. package/css/menubar.css +271 -0
  61. package/css/motion.css +58 -0
  62. package/css/navigation-menu.css +270 -0
  63. package/css/number-animation.css +32 -0
  64. package/css/number-field.css +219 -0
  65. package/css/page-header.css +85 -0
  66. package/css/pagination.css +148 -0
  67. package/css/pin-input.css +157 -0
  68. package/css/popconfirm.css +150 -0
  69. package/css/popover.css +150 -0
  70. package/css/popselect.css +207 -0
  71. package/css/progress.css +37 -0
  72. package/css/qr-code.css +50 -0
  73. package/css/radio-group.css +101 -0
  74. package/css/rating.css +141 -0
  75. package/css/reset.css +22 -0
  76. package/css/result.css +104 -0
  77. package/css/scroll-area.css +176 -0
  78. package/css/select.css +264 -0
  79. package/css/separator.css +17 -0
  80. package/css/skeleton.css +78 -0
  81. package/css/slider.css +197 -0
  82. package/css/spinner.css +74 -0
  83. package/css/splitter.css +127 -0
  84. package/css/statistic.css +67 -0
  85. package/css/steps.css +252 -0
  86. package/css/switch.css +61 -0
  87. package/css/table.css +404 -0
  88. package/css/tabs.css +157 -0
  89. package/css/tags-input.css +360 -0
  90. package/css/text-field.css +195 -0
  91. package/css/thread.css +107 -0
  92. package/css/time-field.css +200 -0
  93. package/css/time-picker.css +347 -0
  94. package/css/time.css +20 -0
  95. package/css/timeline.css +284 -0
  96. package/css/toast.css +195 -0
  97. package/css/toaster.css +69 -0
  98. package/css/toggle-group.css +160 -0
  99. package/css/toggle.css +103 -0
  100. package/css/tone.css +85 -0
  101. package/css/toolbar.css +114 -0
  102. package/css/tooltip.css +109 -0
  103. package/css/tour.css +305 -0
  104. package/css/transfer.css +318 -0
  105. package/css/tree-select.css +441 -0
  106. package/css/tree.css +204 -0
  107. package/css/typography.css +151 -0
  108. package/css/undefined.css +38 -0
  109. package/css/virtualizer.css +104 -0
  110. package/css/visually-hidden.css +13 -0
  111. package/css/watermark.css +48 -0
  112. package/index.css +113 -0
  113. package/index.unlayered.css +16164 -0
  114. package/package.json +163 -0
@@ -0,0 +1,263 @@
1
+ @layer xihan.components {
2
+ /* 根只是把触发区与浮层圈在一起做作用域,不该在作者布局里多插一层盒子 */
3
+ [data-scope='context-menu'][data-part='root'] {
4
+ /* 尺寸档只换这四个私有槽,条目与分组标题都从 root 继承它们,
5
+ 换档不必给每个部件各写一条选择器。浮层在 positioner 里、也是 root 的后代,一并继承
6
+ (display:contents 不影响继承:自定义属性沿 DOM 树传) */
7
+ --xh-_context-menu-item-py: var(--xh-space-2);
8
+ --xh-_context-menu-item-px: var(--xh-control-px-sm);
9
+ --xh-_context-menu-item-gap: var(--xh-control-gap-md);
10
+ --xh-_context-menu-font-size: var(--xh-text-body-size);
11
+
12
+ /* 条目高亮底与标记位强调色随语气走。没写 data-tone 时这两个语气槽没被声明,各自退回原来的取值 */
13
+ --xh-_context-menu-item-highlight-bg: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
14
+ --xh-_context-menu-accent: var(--xh-_tone, var(--xh-fg-subtle));
15
+
16
+ display: contents;
17
+ }
18
+
19
+ [data-scope='context-menu'][data-part='root'][hidden] {
20
+ display: none;
21
+ }
22
+
23
+ /* —— 尺寸 —— */
24
+ /* 缺省档写在上面的基础规则里。条目内外边距缺省档本就不在 control-h/px 那把尺上
25
+ (高度由 padding 撑出来、行内内缩取的是 sm 档),故按 space 档上下各挪一级 */
26
+ [data-scope='context-menu'][data-part='root'][data-size='sm'] {
27
+ --xh-_context-menu-item-py: var(--xh-space-1);
28
+ --xh-_context-menu-item-px: var(--xh-space-1);
29
+ --xh-_context-menu-item-gap: var(--xh-control-gap-sm);
30
+ --xh-_context-menu-font-size: var(--xh-font-size-sm);
31
+ }
32
+
33
+ [data-scope='context-menu'][data-part='root'][data-size='lg'] {
34
+ --xh-_context-menu-item-py: var(--xh-space-3);
35
+ --xh-_context-menu-item-px: var(--xh-space-3);
36
+ --xh-_context-menu-item-gap: var(--xh-control-gap-lg);
37
+ --xh-_context-menu-font-size: var(--xh-font-size-lg);
38
+ }
39
+
40
+ /* 触发区是作者自己的一块内容,尺寸与排布归他;这里只管交互观感:
41
+ 长按会先选中区域内的文字,长按菜单弹出时手指底下是一片高亮,很难看 */
42
+ [data-scope='context-menu'][data-part='trigger'] {
43
+ user-select: none;
44
+ }
45
+
46
+ /* 触发区自带 Tab 位(Shift+F10 / 菜单键的落点),必须画得出焦点 */
47
+ [data-scope='context-menu'][data-part='trigger']:focus-visible {
48
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
49
+ outline-offset: var(--xh-ring-offset);
50
+ }
51
+
52
+ /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
53
+ [data-scope='context-menu'][data-part='positioner'] {
54
+ position: fixed;
55
+ z-index: var(--xh-layer-popover);
56
+ /* 空壳不吃指针,交互只发生在 content 上 */
57
+ pointer-events: none;
58
+ }
59
+
60
+ /* 锚点被滚出可视区:整个浮层随之收起 */
61
+ [data-scope='context-menu'][data-part='positioner'][data-hidden] {
62
+ visibility: hidden;
63
+ }
64
+
65
+ [data-scope='context-menu'][data-part='content'] {
66
+ display: flex;
67
+ flex-direction: column;
68
+ min-inline-size: var(--xh-context-menu-min-w, var(--xh-overlay-menu-min-w));
69
+ max-inline-size: var(--xh-context-menu-max-w, var(--xh-overlay-max-w));
70
+ padding-block: var(--xh-context-menu-py, var(--xh-space-1));
71
+ padding-inline: var(--xh-context-menu-px, var(--xh-space-1));
72
+ border: var(--xh-stroke-thin) solid var(--xh-context-menu-border, var(--xh-border-default));
73
+ border-radius: var(--xh-context-menu-radius, var(--xh-shape-surface));
74
+ background: var(--xh-context-menu-bg, var(--xh-bg-surface));
75
+ color: var(--xh-context-menu-fg, var(--xh-fg-default));
76
+ box-shadow: var(--xh-context-menu-shadow, var(--xh-elevation-2));
77
+ pointer-events: auto;
78
+ }
79
+
80
+ /* display 会盖掉 hidden 属性的 UA 规则,收起态显式让位 */
81
+ [data-scope='context-menu'][data-part='content'][hidden] {
82
+ display: none;
83
+ }
84
+
85
+ /* 容器只是焦点域兜底落点,落焦不画环:高亮永远长在条目上 */
86
+ [data-scope='context-menu'][data-part='content']:focus-visible {
87
+ outline: none;
88
+ }
89
+
90
+ /* 展开时轻微涨开:菜单是被光标"点出来"的,纯淡入显得它一直都在
91
+ (不设 transform-origin:那个属性没有逻辑关键字,写死方向会在 RTL 下反着涨) */
92
+ [data-scope='context-menu'][data-part='content'][data-state='open'] {
93
+ animation: xh-context-menu-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
94
+ }
95
+
96
+ /* 关掉动效的用户不该被涨开动画晃一下;这里只管本组件,公共那份不动 */
97
+ @media (prefers-reduced-motion: reduce) {
98
+ [data-scope='context-menu'][data-part='content'][data-state='open'] {
99
+ animation-duration: 0.01ms;
100
+ }
101
+ }
102
+
103
+ [data-scope='context-menu'][data-part='group'] {
104
+ display: flex;
105
+ flex-direction: column;
106
+ }
107
+
108
+ [data-scope='context-menu'][data-part='group'][hidden] {
109
+ display: none;
110
+ }
111
+
112
+ /* 分组标题不是条目、进不了导航,画成小号次要文字,
113
+ 内缩与条目对齐(同一个 padding-inline),标题与条目文字才在一条竖线上 */
114
+ [data-scope='context-menu'][data-part='group-label'] {
115
+ display: block;
116
+ padding-block: var(--xh-context-menu-group-label-py, var(--xh-space-1));
117
+ padding-inline: var(--xh-context-menu-group-label-px, var(--xh-_context-menu-item-px));
118
+ color: var(--xh-context-menu-group-label-fg, var(--xh-fg-subtle));
119
+ font-size: var(--xh-context-menu-group-label-font-size, var(--xh-font-size-xs));
120
+ font-weight: var(--xh-context-menu-group-label-font-weight, var(--xh-font-weight-medium));
121
+ line-height: var(--xh-leading-none);
122
+ user-select: none;
123
+ }
124
+
125
+ [data-scope='context-menu'][data-part='group-label'][hidden] {
126
+ display: none;
127
+ }
128
+
129
+ [data-scope='context-menu'][data-part='item'] {
130
+ display: flex;
131
+ align-items: center;
132
+ gap: var(--xh-context-menu-item-gap, var(--xh-_context-menu-item-gap));
133
+ padding-block: var(--xh-context-menu-item-py, var(--xh-_context-menu-item-py));
134
+ padding-inline: var(--xh-context-menu-item-px, var(--xh-_context-menu-item-px));
135
+ border-radius: var(--xh-context-menu-item-radius, var(--xh-shape-control));
136
+ color: var(--xh-context-menu-item-fg, var(--xh-fg-default));
137
+ font-size: var(--xh-context-menu-item-font-size, var(--xh-_context-menu-font-size));
138
+ line-height: var(--xh-leading-none);
139
+ white-space: nowrap;
140
+ cursor: pointer;
141
+ user-select: none;
142
+ }
143
+
144
+ /* 条目可以按需收起(按上下文过滤掉的命令),有 display 就得补这条 */
145
+ [data-scope='context-menu'][data-part='item'][hidden] {
146
+ display: none;
147
+ }
148
+
149
+ /* 键盘高亮与指针高亮共用一套底色:条目本身承载焦点,不另画描边。
150
+ data-highlighted 跟的是连接层记的焦点条目,与 :focus 说的是同一件事,
151
+ 子部件够不着那个伪类,只能读这个标记 */
152
+ [data-scope='context-menu'][data-part='item']:not([data-disabled]):is(:hover, :focus, [data-highlighted]) {
153
+ background: var(--xh-context-menu-item-bg-highlight, var(--xh-_context-menu-item-highlight-bg));
154
+ }
155
+
156
+ [data-scope='context-menu'][data-part='item']:focus {
157
+ outline: none;
158
+ }
159
+
160
+ /* 禁用走 aria-disabled 而非原生 disabled:条目仍要可聚焦(它还得当方向键的起点),
161
+ 所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
162
+ [data-scope='context-menu'][data-part='item'][data-disabled] {
163
+ color: var(--xh-fg-disabled);
164
+ cursor: not-allowed;
165
+ }
166
+
167
+ [data-scope='context-menu'][data-part='item-text'] {
168
+ flex: 1;
169
+ overflow: hidden;
170
+ white-space: nowrap;
171
+ text-overflow: ellipsis;
172
+ }
173
+
174
+ [data-scope='context-menu'][data-part='item-text'][hidden] {
175
+ display: none;
176
+ }
177
+
178
+ /* 标记位(勾选符号 / 图标 / 快捷键提示):定宽占位,切换内容不引起行宽抖动 */
179
+ [data-scope='context-menu'][data-part='item-indicator'] {
180
+ display: inline-flex;
181
+ flex: none;
182
+ align-items: center;
183
+ justify-content: center;
184
+ inline-size: var(--xh-context-menu-item-indicator-size, var(--xh-control-indicator-size));
185
+ color: var(--xh-context-menu-item-indicator-fg, var(--xh-_context-menu-accent));
186
+ }
187
+
188
+ [data-scope='context-menu'][data-part='item-indicator'][hidden] {
189
+ display: none;
190
+ }
191
+
192
+ [data-scope='context-menu'][data-part='item-indicator'][data-disabled] {
193
+ color: var(--xh-fg-disabled);
194
+ }
195
+
196
+ [data-scope='context-menu'][data-part='separator'] {
197
+ block-size: var(--xh-context-menu-separator-thickness, var(--xh-stroke-thin));
198
+ margin-block: var(--xh-context-menu-separator-my, var(--xh-space-1));
199
+ background: var(--xh-context-menu-separator-color, var(--xh-border-default));
200
+ }
201
+
202
+ [data-scope='context-menu'][data-part='separator'][hidden] {
203
+ display: none;
204
+ }
205
+
206
+ /* 箭头是旋转 45° 的方块,只保留朝向锚点那两条边的描边;
207
+ 引擎不产出箭头偏移,因此沿交叉轴固定居中 */
208
+ [data-scope='context-menu'][data-part='arrow'] {
209
+ position: absolute;
210
+ inline-size: var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size));
211
+ block-size: var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size));
212
+ background: var(--xh-context-menu-bg, var(--xh-bg-surface));
213
+ border: var(--xh-stroke-thin) solid var(--xh-context-menu-border, var(--xh-border-default));
214
+ rotate: 45deg;
215
+ }
216
+
217
+ [data-scope='context-menu'][data-part='arrow'][hidden] {
218
+ display: none;
219
+ }
220
+
221
+ [data-scope='context-menu'][data-part='arrow'][data-placement^='bottom'] {
222
+ inset-block-start: calc(var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / -2);
223
+ inset-inline-start: calc(50% - var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / 2);
224
+ border-block-end: 0;
225
+ border-inline-end: 0;
226
+ }
227
+
228
+ [data-scope='context-menu'][data-part='arrow'][data-placement^='top'] {
229
+ inset-block-end: calc(var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / -2);
230
+ inset-inline-start: calc(50% - var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / 2);
231
+ border-block-start: 0;
232
+ border-inline-start: 0;
233
+ }
234
+
235
+ [data-scope='context-menu'][data-part='arrow'][data-placement^='right'] {
236
+ inset-inline-start: calc(var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / -2);
237
+ inset-block-start: calc(50% - var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / 2);
238
+ border-block-start: 0;
239
+ border-inline-end: 0;
240
+ }
241
+
242
+ [data-scope='context-menu'][data-part='arrow'][data-placement^='left'] {
243
+ inset-inline-end: calc(var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / -2);
244
+ inset-block-start: calc(50% - var(--xh-context-menu-arrow-size, var(--xh-overlay-arrow-size)) / 2);
245
+ border-block-end: 0;
246
+ border-inline-start: 0;
247
+ }
248
+ }
249
+
250
+ @layer xihan.motion {
251
+ /* 自带前缀独占一个名字,不动公共的那份关键帧 */
252
+ @keyframes xh-context-menu-in {
253
+ from {
254
+ opacity: 0;
255
+ scale: 0.96;
256
+ }
257
+
258
+ to {
259
+ opacity: 1;
260
+ scale: 1;
261
+ }
262
+ }
263
+ }
@@ -0,0 +1,21 @@
1
+ @layer xihan.components {
2
+ [data-scope='countdown'][data-part='root'] {
3
+ display: inline-block;
4
+ color: var(--xh-countdown-fg, var(--xh-fg-default));
5
+ /* 不自带字号:倒计时多半嵌在一句话里或摆在别人的数值槽里,跟着上下文走 */
6
+ /* 等宽数字:逐位宽度一致,秒数换位时冒号不会左右挪动 */
7
+ font-variant-numeric: tabular-nums;
8
+ line-height: var(--xh-leading-tight);
9
+ }
10
+
11
+ /* 上面声明了 display,会盖掉 UA 的 [hidden] 规则,收起态要在这里接回来 */
12
+ [data-scope='countdown'][data-part='root'][hidden] {
13
+ display: none;
14
+ }
15
+
16
+ /* 到点之后这串 00:00:00 不再是活的信息,退一档;它与"暂停在 30 秒上"是两回事,
17
+ 后者仍然是要盯着看的数,所以退档只认 data-finished,不认 data-state */
18
+ [data-scope='countdown'][data-part='root'][data-finished] {
19
+ color: var(--xh-countdown-finished-fg, var(--xh-fg-muted));
20
+ }
21
+ }
@@ -0,0 +1,200 @@
1
+ @layer xihan.components {
2
+ /* 与文本框、数字框同一套堆叠:标签一行、分段框一行 */
3
+ [data-scope='date-field'][data-part='root'] {
4
+ /* 尺寸档只换这四个私有槽,标题与分段框都从 root 继承它们,换档不必给每个部件各写一条选择器 */
5
+ --xh-_date-field-control-h: var(--xh-control-h-md);
6
+ --xh-_date-field-control-px: var(--xh-control-px-md);
7
+ --xh-_date-field-font-size: var(--xh-text-body-size);
8
+ --xh-_date-field-label-font-size: var(--xh-text-label-size);
9
+ /* 形态档只换这三个私有槽:底色与两档描边 */
10
+ --xh-_date-field-control-bg: var(--xh-bg-canvas);
11
+ --xh-_date-field-control-border: var(--xh-border-default);
12
+ --xh-_date-field-control-border-hover: var(--xh-border-strong);
13
+ /* 聚焦环与段位反白随语气走。没写 data-tone 时这几个 --xh-_tone* 没被声明,退回原来的焦点色与品牌色 */
14
+ --xh-_date-field-ring: var(--xh-ring-focus);
15
+ --xh-_date-field-segment-bg: var(--xh-_tone, var(--xh-bg-brand));
16
+ --xh-_date-field-segment-fg: var(--xh-_tone-on, var(--xh-fg-on-brand));
17
+
18
+ display: inline-flex;
19
+ flex-direction: column;
20
+ gap: var(--xh-date-field-gap, var(--xh-space-1));
21
+ }
22
+
23
+ /* —— 尺寸 —— */
24
+ [data-scope='date-field'][data-part='root'][data-size='sm'] {
25
+ --xh-_date-field-control-h: var(--xh-control-h-sm);
26
+ --xh-_date-field-control-px: var(--xh-control-px-sm);
27
+ --xh-_date-field-font-size: var(--xh-font-size-sm);
28
+ --xh-_date-field-label-font-size: var(--xh-font-size-sm);
29
+ }
30
+
31
+ [data-scope='date-field'][data-part='root'][data-size='lg'] {
32
+ --xh-_date-field-control-h: var(--xh-control-h-lg);
33
+ --xh-_date-field-control-px: var(--xh-control-px-lg);
34
+ --xh-_date-field-font-size: var(--xh-font-size-lg);
35
+ --xh-_date-field-label-font-size: var(--xh-font-size-lg);
36
+ }
37
+
38
+ /* —— 形态 —— */
39
+ /* 描边式:与缺省等价,写出来是为了三档形态在皮肤里都看得见 */
40
+ [data-scope='date-field'][data-part='root'][data-variant='outline'] {
41
+ --xh-_date-field-control-bg: var(--xh-bg-canvas);
42
+ --xh-_date-field-control-border: var(--xh-border-default);
43
+ --xh-_date-field-control-border-hover: var(--xh-border-strong);
44
+ }
45
+
46
+ /* 填充式:底色顶替描边,悬停时才浮出一道淡边 */
47
+ [data-scope='date-field'][data-part='root'][data-variant='subtle'] {
48
+ --xh-_date-field-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
49
+ --xh-_date-field-control-border: transparent;
50
+ --xh-_date-field-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
51
+ }
52
+
53
+ /* 无框式:底与边都让开,可见反馈只剩聚焦那一档 */
54
+ [data-scope='date-field'][data-part='root'][data-variant='ghost'] {
55
+ --xh-_date-field-control-bg: transparent;
56
+ --xh-_date-field-control-border: transparent;
57
+ --xh-_date-field-control-border-hover: transparent;
58
+ }
59
+
60
+ /* 声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
61
+ [data-scope='date-field'][data-part='root'][hidden] {
62
+ display: none;
63
+ }
64
+
65
+ [data-scope='date-field'][data-part='label'] {
66
+ color: var(--xh-date-field-label-fg, var(--xh-fg-default));
67
+ font-size: var(--xh-date-field-label-font-size, var(--xh-_date-field-label-font-size));
68
+ font-weight: var(--xh-date-field-label-font-weight, var(--xh-text-label-weight));
69
+ line-height: var(--xh-leading-none);
70
+ /* 点标题会把焦点送进首段,指针得说明这件事 */
71
+ cursor: default;
72
+ }
73
+
74
+ [data-scope='date-field'][data-part='label'][hidden] {
75
+ display: none;
76
+ }
77
+
78
+ [data-scope='date-field'][data-part='label'][data-disabled] {
79
+ color: var(--xh-date-field-label-fg-disabled, var(--xh-fg-subtle));
80
+ cursor: not-allowed;
81
+ }
82
+
83
+ /* 分段框整体长得像一个输入框:边框与背景长在 control 上,各段只是里面的文字。
84
+ 段与段之间的分隔符('/'、'年')由作者自己写在段之间,不在角色表里 */
85
+ [data-scope='date-field'][data-part='control'] {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ block-size: var(--xh-date-field-control-h, var(--xh-_date-field-control-h));
89
+ padding-inline: var(--xh-date-field-control-px, var(--xh-_date-field-control-px));
90
+ padding-block: 0;
91
+ border: var(--xh-stroke-thin) solid var(--xh-date-field-control-border, var(--xh-_date-field-control-border));
92
+ border-radius: var(--xh-date-field-control-radius, var(--xh-shape-control));
93
+ background: var(--xh-date-field-control-bg, var(--xh-_date-field-control-bg));
94
+ color: var(--xh-date-field-control-fg, var(--xh-fg-default));
95
+ /* 表单控件不继承页面字体,只给字号会让分段框用 UA 默认字族 */
96
+ font-family: inherit;
97
+ font-size: var(--xh-date-field-font-size, var(--xh-_date-field-font-size));
98
+ line-height: var(--xh-leading-none);
99
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
100
+ }
101
+
102
+ [data-scope='date-field'][data-part='control'][hidden] {
103
+ display: none;
104
+ }
105
+
106
+ /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
107
+ [data-scope='date-field'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
108
+ border-color: var(--xh-date-field-control-border-hover, var(--xh-_date-field-control-border-hover));
109
+ }
110
+
111
+ /* 焦点落在某一段上,而边框长在 control 上:焦点环得由内向外借一层。
112
+ control 自己不占 Tab 位,:focus-within 是它唯一能感知组内焦点的方式 */
113
+ [data-scope='date-field'][data-part='control']:focus-within {
114
+ border-color: var(--xh-date-field-control-border-focus, var(--xh-_date-field-ring));
115
+ outline: var(--xh-ring-width) solid var(--xh-_date-field-ring);
116
+ outline-offset: var(--xh-ring-offset);
117
+ }
118
+
119
+ [data-scope='date-field'][data-part='control'][data-invalid] {
120
+ border-color: var(--xh-date-field-control-border-invalid, var(--xh-color-danger-500));
121
+ }
122
+
123
+ /* 只读仍可聚焦、可换段,不置灰,只把底色压下去表示"改不动" */
124
+ [data-scope='date-field'][data-part='control'][data-readonly] {
125
+ background: var(--xh-date-field-control-bg-readonly, var(--xh-bg-subtle));
126
+ }
127
+
128
+ /* 整组禁用:段位是 div 而非原生控件,禁用只表达得成 data-disabled */
129
+ [data-scope='date-field'][data-part='control'][data-disabled] {
130
+ background: var(--xh-date-field-control-bg-disabled, var(--xh-bg-subtle));
131
+ color: var(--xh-fg-disabled);
132
+ cursor: not-allowed;
133
+ }
134
+
135
+ /* 每一段是一块可聚焦的文字:宽度随内容走,两侧留一点让选中底色不贴着数字 */
136
+ [data-scope='date-field'][data-part='segment'] {
137
+ display: inline-block;
138
+ padding-inline: var(--xh-date-field-segment-px, var(--xh-space-1));
139
+ padding-block: var(--xh-date-field-segment-py, var(--xh-space-0));
140
+ border-radius: var(--xh-date-field-segment-radius, var(--xh-radius-sm));
141
+ color: inherit;
142
+ font: inherit;
143
+ /* 等宽数字:各位字宽不一时,上下键连按会让整行数字左右跳 */
144
+ font-variant-numeric: tabular-nums;
145
+ line-height: var(--xh-leading-none);
146
+ text-align: center;
147
+ /* 段位靠键盘编辑,不是文本:让它被选中只会在拖选时选出半截日期 */
148
+ user-select: none;
149
+ /* 触屏上连点两下不该被当成缩放手势 */
150
+ touch-action: manipulation;
151
+ }
152
+
153
+ /* granularity 用不上的段带 hidden 留在文档里(不卸载作者节点)。
154
+ 上面给了 display,UA 的 [hidden]{display:none} 已被盖掉,这里补回来 */
155
+ [data-scope='date-field'][data-part='segment'][hidden] {
156
+ display: none;
157
+ }
158
+
159
+ /* 未填的段用弱色显示占位串,和填好的数字拉开差别 */
160
+ [data-scope='date-field'][data-part='segment'][data-placeholder] {
161
+ color: var(--xh-date-field-placeholder-fg, var(--xh-fg-subtle));
162
+ }
163
+
164
+ /* 段位是集合里的条目,用 data-* 而不是 :disabled —— 它是 div,没有原生禁用态 */
165
+ [data-scope='date-field'][data-part='segment'][data-disabled] {
166
+ color: var(--xh-fg-disabled);
167
+ cursor: not-allowed;
168
+ }
169
+
170
+ /* 正在编辑的那一段要看得出来:整行数字长得一模一样,光标那道线这里根本没有。
171
+ data-focus 由机器给(它知道当前是哪一段),:focus-visible 兜住机器状态还没回流的那一帧。
172
+ 焦点环画在 control 上,段位这里只反白,两层各管各的不打架 */
173
+ [data-scope='date-field'][data-part='segment'][data-focus],
174
+ [data-scope='date-field'][data-part='segment']:focus-visible {
175
+ background: var(--xh-date-field-segment-bg-focus, var(--xh-_date-field-segment-bg));
176
+ color: var(--xh-date-field-segment-fg-focus, var(--xh-_date-field-segment-fg));
177
+ outline: none;
178
+ }
179
+
180
+ /* 反白之后占位串那条弱色规则会被盖掉,专门再压一遍才看得清 */
181
+ [data-scope='date-field'][data-part='segment'][data-focus][data-placeholder] {
182
+ color: var(--xh-date-field-segment-fg-focus, var(--xh-_date-field-segment-fg));
183
+ }
184
+
185
+ /* 连接层把它写成 type=hidden,UA 自己就不渲染;这里的视觉隐藏是给元素升级前那一瞬兜底
186
+ (作者手写的是一个普通 input,升级完成前它是可见的文本框)。
187
+ 刻意不写 display:写了反而会盖掉 UA 对 type=hidden 的收起,把它显出来 */
188
+ [data-scope='date-field'][data-part='hidden-input'] {
189
+ position: absolute;
190
+ inline-size: 1px;
191
+ block-size: 1px;
192
+ padding: 0;
193
+ margin: -1px;
194
+ border: 0;
195
+ overflow: hidden;
196
+ clip-path: inset(50%);
197
+ white-space: nowrap;
198
+ pointer-events: none;
199
+ }
200
+ }