@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,18 @@
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
+ /* TimePicker 独立皮肤同时传递引入字段视觉盒、字段内动作与浮层集合行;full bundle 递归去重。 */
7
+ @import '../family/field-chrome.css';
8
+ @import '../family/action-control.css';
9
+ @import '../family/collection-item.css';
10
+
11
+ @import './scrollbar.css';
12
+
13
+ /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立。 */
14
+ @import '../family/motion.css';
15
+
1
16
  @layer xihan.components {
2
17
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
18
  [data-scope='time-picker'] {
@@ -6,8 +21,14 @@
6
21
 
7
22
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
8
23
  [data-scope='time-picker'][data-part='positioner'] {
24
+ /* 每个浮层独立声明方向,避免嵌套浮层继承祖先的进场位移。 */
25
+ --xh-_overlay-enter-up: 0;
26
+ --xh-_overlay-enter-down: 0;
27
+ --xh-_overlay-enter-left: 0;
28
+ --xh-_overlay-enter-right: 0;
29
+
9
30
  position: fixed;
10
- z-index: var(--xh-time-picker-layer, var(--xh-layer-popover));
31
+ z-index: var(--xh-time-picker-layer, var(--xh-_layer, var(--xh-layer-popover)));
11
32
  /* 空壳不吃指针,交互只发生在 content 里 */
12
33
  pointer-events: none;
13
34
  }
@@ -17,28 +38,37 @@
17
38
  visibility: hidden;
18
39
  }
19
40
 
41
+ /* 短位移沿实际落位的物理方向,不随书写方向翻转。 */
42
+ [data-scope='time-picker'][data-part='positioner'][data-placement^='top'] {
43
+ --xh-_overlay-enter-down: 1;
44
+ }
45
+
46
+ [data-scope='time-picker'][data-part='positioner'][data-placement^='bottom'] {
47
+ --xh-_overlay-enter-up: 1;
48
+ }
49
+
50
+ [data-scope='time-picker'][data-part='positioner'][data-placement^='left'] {
51
+ --xh-_overlay-enter-right: 1;
52
+ }
53
+
54
+ [data-scope='time-picker'][data-part='positioner'][data-placement^='right'] {
55
+ --xh-_overlay-enter-left: 1;
56
+ }
57
+
20
58
  /* 私有槽同时声明在根与 positioner 上:浮层被搬到 portal 落点,不是根的后代,继承不过去 */
21
59
  [data-scope='time-picker']:is([data-part='root'], [data-part='positioner']) {
22
60
  /* 尺寸档只换这几个私有槽,标题、输入行与浮层里的格子都从这两处继承它们,
23
- 换档不必给每个部件各写一条选择器 */
61
+ 换档不必给每个部件各写一条选择器;形态三档由家族按 control 上的 data-variant 生成,皮肤不再声明 */
24
62
  --xh-_time-picker-control-h: var(--xh-control-h-md);
25
63
  --xh-_time-picker-control-px: var(--xh-control-px-md);
26
64
  --xh-_time-picker-gap: var(--xh-control-gap-md);
27
65
  --xh-_time-picker-font-size: var(--xh-control-font-md);
28
- --xh-_time-picker-label-font-size: var(--xh-control-font-md);
29
- --xh-_time-picker-item-px: var(--xh-control-px-md);
30
66
 
31
- /* 形态档只换这三个私有槽:底色与两档描边 */
32
- --xh-_time-picker-control-bg: var(--xh-bg-canvas);
33
- --xh-_time-picker-control-border: var(--xh-border-control);
34
- --xh-_time-picker-control-border-hover: var(--xh-border-control-hover);
35
-
36
- /* 聚焦环、段位反白与列里的选中随语气走。没写 data-tone 时这几个 --xh-_tone* 没被声明,
37
- 退回原来的焦点色与品牌色 */
38
- --xh-_time-picker-ring: var(--xh-ring-focus);
39
- --xh-_time-picker-accent: var(--xh-_tone, var(--xh-bg-brand));
40
- --xh-_time-picker-accent-hover: var(--xh-_tone-hover, var(--xh-bg-brand-hover));
41
- --xh-_time-picker-accent-fg: var(--xh-_tone-on, var(--xh-fg-on-brand));
67
+ /* 段位强调随语气走:当前段是「当前项」,淡底 + 淡底前景;对号使用普通表面上的前景色。
68
+ 没写 data-tone 时这几个 --xh-_tone* 没被声明,退回品牌色 */
69
+ --xh-_time-picker-segment-bg: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
70
+ --xh-_time-picker-segment-fg: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
71
+ --xh-_time-picker-check-fg: var(--xh-_tone, var(--xh-fg-brand));
42
72
  }
43
73
 
44
74
  /* 与文本框、时间输入同一套堆叠:标签一行、控件一行 */
@@ -49,6 +79,12 @@
49
79
  display: inline-flex;
50
80
  flex-direction: column;
51
81
  gap: var(--xh-time-picker-gap, var(--xh-space-1));
82
+
83
+ /* 不传尺寸时一律这么宽,宽度不随内容走;父容器给不出这么宽时整件跟着收,地板同步让步,不越出父容器。
84
+ 地板不高过缺省宽:使用者把缺省宽钉到底线以下时不必再放开底线 */
85
+ inline-size: var(--xh-time-picker-control-w, var(--xh-control-w));
86
+ min-inline-size: min(var(--xh-time-picker-control-w, var(--xh-control-w)), var(--xh-time-picker-control-min-w, var(--xh-control-min-w)), 100%);
87
+ max-inline-size: 100%;
52
88
  }
53
89
 
54
90
  /* —— 尺寸 —— */
@@ -59,8 +95,6 @@
59
95
  --xh-_time-picker-control-px: var(--xh-control-px-sm);
60
96
  --xh-_time-picker-gap: var(--xh-control-gap-sm);
61
97
  --xh-_time-picker-font-size: var(--xh-control-font-sm);
62
- --xh-_time-picker-label-font-size: var(--xh-control-font-sm);
63
- --xh-_time-picker-item-px: var(--xh-control-px-sm);
64
98
  }
65
99
 
66
100
  [data-scope='time-picker']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
@@ -69,32 +103,6 @@
69
103
  --xh-_time-picker-control-px: var(--xh-control-px-lg);
70
104
  --xh-_time-picker-gap: var(--xh-control-gap-lg);
71
105
  --xh-_time-picker-font-size: var(--xh-control-font-lg);
72
- --xh-_time-picker-label-font-size: var(--xh-control-font-lg);
73
- --xh-_time-picker-item-px: var(--xh-control-px-lg);
74
- }
75
-
76
- /* —— 形态 —— */
77
- /* 输入类不做实心档:填满一个要往里打字的框,字与底就没法同时读。
78
- 形态只决定底与描边怎么画,用哪族颜色由 data-tone 决定 */
79
- [data-scope='time-picker']:is([data-part='root'], [data-part='positioner'])[data-variant='outline'] {
80
- --xh-_time-picker-control-bg: var(--xh-bg-canvas);
81
- --xh-_time-picker-control-border: var(--xh-border-control);
82
- --xh-_time-picker-control-border-hover: var(--xh-border-control-hover);
83
- }
84
-
85
- /* 填充式:底色顶替描边表达边界。描边只退成透明而不去掉,1px 的位置留着,
86
- 与 outline 档并排时基线对得上、聚焦画描边也不引起跳动 */
87
- [data-scope='time-picker']:is([data-part='root'], [data-part='positioner'])[data-variant='subtle'] {
88
- --xh-_time-picker-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
89
- --xh-_time-picker-control-border: transparent;
90
- --xh-_time-picker-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
91
- }
92
-
93
- /* 无框:底与常态描边透明,悬停与聚焦浮出描边 */
94
- [data-scope='time-picker']:is([data-part='root'], [data-part='positioner'])[data-variant='ghost'] {
95
- --xh-_time-picker-control-bg: transparent;
96
- --xh-_time-picker-control-border: transparent;
97
- --xh-_time-picker-control-border-hover: var(--xh-_tone-border, var(--xh-border-control-hover));
98
106
  }
99
107
 
100
108
  /* 声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
@@ -104,75 +112,54 @@
104
112
 
105
113
  [data-scope='time-picker'][data-part='label'] {
106
114
  color: var(--xh-time-picker-label-fg, var(--xh-fg-default));
107
- font-size: var(--xh-time-picker-label-font-size, var(--xh-_time-picker-label-font-size));
115
+ font-size: var(--xh-time-picker-label-font-size, var(--xh-text-label-size));
108
116
  font-weight: var(--xh-time-picker-label-font-weight, var(--xh-text-label-weight));
109
117
  line-height: var(--xh-leading-none);
110
118
  }
111
119
 
112
120
  [data-scope='time-picker'][data-part='label'][data-disabled] {
113
121
  color: var(--xh-time-picker-label-fg-disabled, var(--xh-fg-subtle));
114
- cursor: not-allowed;
115
122
  }
116
123
 
117
124
  /* 画成一个框的是 control:几段文字、展开按钮、清空按钮要看起来是一体的,
118
- 边框长在其中任何一个身上都会把另外几个割在框外 */
125
+ 边框长在其中任何一个身上都会把另外几个割在框外。描边、底色、圆角、聚焦环、五态与悬停由
126
+ Field Chrome 家族画在 control 上(焦点落在段或按钮上,家族 :focus-within 让整框亮起来);
127
+ 组件只映射既有公开槽(shadow 缺省 none:字段静息描边式、无影)。打开中不另画环,由浮层本身承担 */
119
128
  [data-scope='time-picker'][data-part='control'] {
120
- min-inline-size: var(--xh-time-picker-control-min-w, var(--xh-control-min-w));
121
- display: inline-flex;
122
- align-items: center;
123
- gap: var(--xh-time-picker-control-gap, var(--xh-_time-picker-gap));
124
- block-size: var(--xh-time-picker-control-h, var(--xh-_time-picker-control-h));
125
- padding-inline: var(--xh-time-picker-control-px, var(--xh-_time-picker-control-px));
126
- padding-block: 0;
127
- border: var(--xh-stroke-thin) solid var(--xh-time-picker-control-border, var(--xh-_time-picker-control-border));
128
- border-radius: var(--xh-time-picker-control-radius, var(--xh-shape-control));
129
- background: var(--xh-time-picker-control-bg, var(--xh-_time-picker-control-bg));
130
- color: var(--xh-time-picker-control-fg, var(--xh-fg-default));
129
+ --xh-field-control-height: var(--xh-time-picker-control-h, var(--xh-_time-picker-control-h));
130
+ --xh-field-control-padding-inline: var(--xh-time-picker-control-px, var(--xh-_time-picker-control-px));
131
+ --xh-field-control-gap: var(--xh-time-picker-control-gap, var(--xh-_time-picker-gap));
132
+ --xh-field-control-min-inline-size: var(--xh-time-picker-control-min-w, var(--xh-control-min-w));
133
+ --xh-field-control-radius: var(--xh-time-picker-control-radius, var(--xh-shape-control));
134
+ --xh-field-bg-rest: var(--xh-time-picker-control-bg, var(--xh-_field-variant-bg-rest));
135
+ --xh-field-bg-hover: var(--xh-time-picker-control-bg-hover, var(--xh-_field-variant-bg-hover));
136
+ --xh-field-bg-read-only: var(--xh-time-picker-control-bg-readonly, var(--xh-_field-variant-bg-read-only));
137
+ --xh-field-bg-disabled: var(--xh-time-picker-control-bg-disabled, var(--xh-_field-variant-bg-disabled));
138
+ --xh-field-fg-rest: var(--xh-time-picker-control-fg, var(--xh-fg-default));
139
+ --xh-field-border-rest: var(--xh-time-picker-control-border, var(--xh-_field-variant-border-rest));
140
+ --xh-field-border-hover: var(--xh-time-picker-control-border-hover, var(--xh-_field-variant-border-hover));
141
+ --xh-field-border-focus: var(--xh-time-picker-control-border-focus, var(--xh-_field-variant-border-focus));
142
+ --xh-field-border-invalid: var(--xh-time-picker-control-border-invalid, var(--xh-_field-variant-border-invalid));
143
+ --xh-field-ring-focus: var(--xh-ring-focus);
144
+ --xh-field-ring-invalid: var(--xh-ring-invalid);
145
+ --xh-field-shadow-rest: var(--xh-time-picker-control-shadow, none);
146
+ /* 段位靠键盘编辑,盒上不是文本光标 */
147
+ --xh-field-cursor-rest: default;
148
+ /* 家族 chrome 会重写 --xh-icon-size,使用者图标槽必须经桥接槽下发才能在盒内生效 */
149
+ --xh-field-glyph-size: var(--xh-time-picker-icon-size, var(--xh-_field-size-glyph-size));
150
+
131
151
  /* 表单控件不继承页面字体,只给字号会让它用 UA 默认字族,与周围文本对不上 */
132
152
  font-family: inherit;
133
153
  font-size: var(--xh-time-picker-font-size, var(--xh-_time-picker-font-size));
134
154
  /* 等宽数字:各位字宽不一时逐段填入会让整行左右跳 */
135
155
  font-variant-numeric: tabular-nums;
136
156
  line-height: var(--xh-leading-normal);
137
- transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
138
157
  }
139
158
 
140
159
  [data-scope='time-picker'][data-part='control'][hidden] {
141
160
  display: none;
142
161
  }
143
162
 
144
- /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
145
- [data-scope='time-picker'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
146
- border-color: var(--xh-time-picker-control-border-hover, var(--xh-_time-picker-control-border-hover));
147
- }
148
-
149
- /* 焦点真正落在段或按钮上,但整块看起来才是一个控件:内部有焦点时整框亮起来。
150
- control 自己不占 Tab 位,所以这里写的是 focus-within 而不是 focus-visible */
151
- [data-scope='time-picker'][data-part='control']:focus-within:not([data-disabled]) {
152
- border-color: var(--xh-time-picker-control-border-focus, var(--xh-_tone, var(--xh-border-control-focus)));
153
- outline: var(--xh-ring-width) solid var(--xh-_time-picker-ring);
154
- outline-offset: var(--xh-ring-offset);
155
- }
156
-
157
- [data-scope='time-picker'][data-part='control'][data-invalid] {
158
- border-color: var(--xh-time-picker-control-border-invalid, var(--xh-border-invalid));
159
-
160
- /* 校验失败时环也跟着变红:两圈等宽相邻却一红一蓝,读的人不知道哪个才是当前状态 */
161
- --xh-_time-picker-ring: var(--xh-ring-invalid);
162
- }
163
-
164
- /* 只读仍可聚焦、可换段,所以不置灰,只把底色压下去表示"改不动" */
165
- [data-scope='time-picker'][data-part='control'][data-readonly] {
166
- background: var(--xh-time-picker-control-bg-readonly, var(--xh-bg-subtle));
167
- }
168
-
169
- /* control 是个 div,没有 :disabled 可用;禁用态由连接层的 data-disabled 表达 */
170
- [data-scope='time-picker'][data-part='control'][data-disabled] {
171
- background: var(--xh-time-picker-control-bg-disabled, var(--xh-bg-subtle));
172
- color: var(--xh-fg-disabled);
173
- cursor: not-allowed;
174
- }
175
-
176
163
  /* 段位与作者写在段间的分隔符都在这一层里:它占满盒里剩下的宽度,
177
164
  尾部按钮因此靠在框内末端 */
178
165
  [data-scope='time-picker'][data-part='segment-group'] {
@@ -186,10 +173,14 @@
186
173
  display: none;
187
174
  }
188
175
 
176
+ [data-scope='time-picker'][data-part='segment-group'] > :not([data-scope]) {
177
+ color: var(--xh-time-picker-literal-fg, var(--xh-fg-subtle));
178
+ }
179
+
189
180
  /* 每一段是一小块可聚焦区,紧挨着排;间距长在段自己身上 */
190
- [data-scope='time-picker'][data-part='input'] {
181
+ [data-scope='time-picker'][data-part='segment'] {
191
182
  display: inline-block;
192
- padding-inline: var(--xh-time-picker-segment-px, var(--xh-space-1));
183
+ padding-inline: var(--xh-time-picker-segment-px, var(--xh-space-0_5));
193
184
  padding-block: 0;
194
185
  border-radius: var(--xh-time-picker-segment-radius, var(--xh-shape-inset));
195
186
  color: inherit;
@@ -204,103 +195,103 @@
204
195
 
205
196
  /* granularity / hourCycle 关掉的段由连接层打 hidden;上面那条 display 会把 UA 规则盖掉,
206
197
  少了这条,收起的段会一直杵在那儿 */
207
- [data-scope='time-picker'][data-part='input'][hidden] {
198
+ [data-scope='time-picker'][data-part='segment'][hidden] {
208
199
  display: none;
209
200
  }
210
201
 
211
202
  /* 还没填的段压成弱色:一行里哪几段是占位符,一眼要看得出来 */
212
- [data-scope='time-picker'][data-part='input'][data-placeholder] {
203
+ [data-scope='time-picker'][data-part='segment'][data-placeholder] {
213
204
  color: var(--xh-time-picker-placeholder-fg, var(--xh-fg-subtle));
214
205
  }
215
206
 
216
207
  /* 一行段长得差不多,光有边框亮起来看不出正在改哪一段:当前段必须自己有底色。
217
208
  data-focus 由机器给(它知道谁是当前段),:focus-visible 兜住机器状态还没回流的那一帧 */
218
- [data-scope='time-picker'][data-part='input'][data-focus]:not([data-disabled]),
219
- [data-scope='time-picker'][data-part='input']:focus-visible {
220
- background: var(--xh-time-picker-segment-bg-focus, var(--xh-_time-picker-accent));
221
- color: var(--xh-time-picker-segment-fg-focus, var(--xh-_time-picker-accent-fg));
209
+ [data-scope='time-picker'][data-part='segment'][data-focus]:not([data-disabled]),
210
+ [data-scope='time-picker'][data-part='segment']:focus-visible {
211
+ background: var(--xh-time-picker-segment-bg-focus, var(--xh-_time-picker-segment-bg));
212
+ color: var(--xh-time-picker-segment-fg-focus, var(--xh-_time-picker-segment-fg));
222
213
  outline: none;
223
214
  }
224
215
 
225
216
  /* 焦点态用了品牌底色之后,占位符那条弱色会被它盖住,这里明确让位给焦点态 */
226
- [data-scope='time-picker'][data-part='input'][data-focus][data-placeholder]:not([data-disabled]) {
227
- color: var(--xh-time-picker-segment-fg-focus, var(--xh-_time-picker-accent-fg));
217
+ [data-scope='time-picker'][data-part='segment'][data-focus][data-placeholder]:not([data-disabled]) {
218
+ color: var(--xh-time-picker-segment-fg-focus, var(--xh-_time-picker-segment-fg));
219
+ }
220
+
221
+ [data-scope='time-picker'][data-part='segment'][data-invalid] {
222
+ color: var(--xh-time-picker-segment-fg-invalid, var(--xh-fg-danger));
223
+ }
224
+
225
+ [data-scope='time-picker'][data-part='segment'][data-invalid]:is([data-focus], :focus-visible) {
226
+ background: var(
227
+ --xh-time-picker-segment-bg-invalid-focus,
228
+ var(--xh-bg-subtle)
229
+ );
230
+ color: var(--xh-time-picker-segment-fg-invalid-focus, var(--xh-fg-danger));
228
231
  }
229
232
 
230
- [data-scope='time-picker'][data-part='input']:hover:not([data-focus], [data-disabled]) {
231
- background: var(--xh-time-picker-segment-bg-hover, var(--xh-bg-subtle-hover));
233
+ [data-scope='time-picker'][data-part='segment']:hover:not([data-focus], [data-disabled]) {
234
+ background: var(--xh-time-picker-segment-bg-hover, var(--xh-bg-subtle));
232
235
  }
233
236
 
234
237
  /* 段是集合条目形态(role=spinbutton 的 span),禁用走 data-disabled 而不是 :disabled */
235
- [data-scope='time-picker'][data-part='input'][data-disabled] {
238
+ [data-scope='time-picker'][data-part='segment'][data-disabled] {
236
239
  color: var(--xh-fg-disabled);
237
- cursor: not-allowed;
238
240
  }
239
241
 
240
- /* 两个按钮同一副长相:贴在框内的小方钮,不占宽度也不撑高 control */
242
+ /* 两个按钮同一副长相:贴在框内末端的小方钮,不占宽度也不撑高 control。正方视觉盒、inset 圆角、
243
+ 悬停 100 / 按下 200 与 0.97 按压、粗指针热区、禁用面与 :focus-visible 关环(盒的 :focus-within
244
+ 已画了一圈)全由 Action Control 的 field-inset ghost 档给,组件只映射既有覆盖槽。
245
+ 打开中与悬停同档:展开钮不另上底,方向由浮层本身承担 */
241
246
  [data-scope='time-picker'][data-part='trigger'],
242
247
  [data-scope='time-picker'][data-part='clear-trigger'] {
243
- display: inline-flex;
244
- flex: none;
245
- align-items: center;
246
- justify-content: center;
247
- inline-size: var(--xh-time-picker-action-size, var(--xh-control-action-size));
248
- block-size: var(--xh-time-picker-action-size, var(--xh-control-action-size));
249
- padding: 0;
250
- border: 0;
251
- border-radius: var(--xh-time-picker-action-radius, var(--xh-shape-control));
252
- background: var(--xh-time-picker-action-bg, transparent);
253
- color: var(--xh-time-picker-action-fg, var(--xh-fg-muted));
254
- font-family: inherit;
255
- font-size: var(--xh-time-picker-action-font-size, var(--xh-text-secondary-size));
256
- line-height: var(--xh-leading-none);
257
- cursor: pointer;
258
- user-select: none;
259
- transition:
260
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
261
- scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
262
- }
263
-
264
-
248
+ --xh-action-visual-size: var(--xh-time-picker-action-size, var(--xh-_action-profile-visual-size));
249
+ --xh-action-min-inline-size: var(--xh-time-picker-action-size, var(--xh-_action-profile-visual-size));
250
+ --xh-action-radius: var(--xh-time-picker-action-radius, var(--xh-shape-inset));
251
+ /* 底色阶梯由 ghost 档给(透明 → 100 → 200),使用者槽只作覆盖入口 */
252
+ --xh-action-bg-rest: var(--xh-time-picker-action-bg, var(--xh-_action-variant-bg-rest));
253
+ --xh-action-bg-hover: var(--xh-time-picker-action-bg-hover, var(--xh-_action-variant-bg-hover));
254
+ --xh-action-bg-pressed: var(--xh-time-picker-action-bg-active, var(--xh-_action-variant-bg-pressed));
255
+ --xh-action-fg-rest: var(--xh-time-picker-action-fg, var(--xh-fg-muted));
256
+ --xh-action-fg-hover: var(--xh-time-picker-action-fg-hover, var(--xh-fg-default));
257
+ --xh-action-border-rest: transparent;
258
+ --xh-action-highlight-rest: transparent;
259
+ --xh-action-shadow-rest: none;
260
+ --xh-action-shadow-hover: none;
261
+ --xh-action-shadow-pressed: none;
262
+ --xh-action-font-size: var(--xh-time-picker-action-font-size, var(--xh-text-secondary-size));
263
+ /* 配方尚未把 profile 字形档灌进 --xh-icon-size,钮内字形先按 field-inset 档逐钮取值 */
264
+ --xh-icon-size: var(--xh-_action-profile-glyph-size);
265
+
266
+ border-width: 0;
267
+ }
268
+
269
+ /* 没值时连接层给的是 hidden 属性;家族那条 display 会把 UA 规则盖掉 */
265
270
  [data-scope='time-picker'][data-part='trigger'][hidden],
266
271
  [data-scope='time-picker'][data-part='clear-trigger'][hidden] {
267
272
  display: none;
268
273
  }
269
274
 
270
- [data-scope='time-picker'][data-part='trigger']:hover:not(:disabled),
271
- [data-scope='time-picker'][data-part='clear-trigger']:hover {
272
- background: var(--xh-time-picker-action-bg-hover, var(--xh-bg-subtle-hover));
273
- color: var(--xh-time-picker-action-fg-hover, var(--xh-fg-default));
274
- }
275
-
276
- [data-scope='time-picker'][data-part='trigger']:active:not(:disabled) {
277
- background: var(--xh-time-picker-action-bg-active, var(--xh-bg-subtle-active));
278
- }
279
-
280
- /* 清空钮按下时换底并微缩,给指针一个按到了的反馈 */
281
- [data-scope='time-picker'][data-part='clear-trigger']:active {
282
- background: var(--xh-time-picker-action-bg-active, var(--xh-bg-subtle-active));
283
- scale: var(--xh-motion-scale-press);
275
+ /* 打开中与悬停同档:展开钮的静息底换到悬停那一支中性面,不用品牌色、不另画环;方向由浮层本身承担 */
276
+ [data-scope='time-picker'][data-part='trigger'][data-state='open'] {
277
+ --xh-action-bg-rest: var(--xh-time-picker-action-bg-hover, var(--xh-_action-variant-bg-hover));
278
+ --xh-action-fg-rest: var(--xh-time-picker-action-fg-hover, var(--xh-fg-default));
284
279
  }
285
280
 
286
- /* 清空按钮退出了 Tab 序列,这条是给程序化聚焦兜底;
287
- 展开钮是常规 Tab 停靠点,它落焦时环由盒的 :focus-within 画,这里不再套一圈 */
288
- [data-scope='time-picker'][data-part='clear-trigger']:focus-visible {
289
- outline: var(--xh-ring-width) solid var(--xh-_time-picker-ring);
290
- outline-offset: var(--xh-ring-offset);
291
- }
292
-
293
- /* 下拉钮是单体控件,禁用走原生 :disabled(列里的格一律 data-disabled);
294
- 清空钮没值即收起,不做灰态 */
295
- [data-scope='time-picker'][data-part='trigger']:disabled {
296
- background: var(--xh-time-picker-action-bg, transparent);
297
- color: var(--xh-fg-disabled);
298
- cursor: not-allowed;
281
+ /* 有值时清空钮顶上来,展开钮让位:两颗并排堆着用户分不清点哪个 */
282
+ [data-scope='time-picker'][data-part='control']:has(
283
+ > [data-scope='time-picker'][data-part='clear-trigger']:not([hidden])
284
+ )
285
+ > [data-scope='time-picker'][data-part='trigger'] {
286
+ display: none;
299
287
  }
300
288
 
301
289
  /* 几列并排:整体高度由列自己撑,滚动发生在列里而不是整个面板上——
302
- 整面板滚会让时列与分列一起走,挑分的时候时就看不见了 */
290
+ 整面板滚会让时列与分列一起走,挑分的时候时就看不见了。
291
+ 含多列的锚定面板走 floating 材质:实体底 + --xh-border-default 描边 + --xh-elevation-floating 落影,
292
+ 不透景、不画顶光 */
303
293
  [data-scope='time-picker'][data-part='content'] {
294
+ position: relative;
304
295
  display: flex;
305
296
  align-items: stretch;
306
297
  padding-block: var(--xh-time-picker-content-py, var(--xh-space-1));
@@ -308,12 +299,14 @@
308
299
  /* 列自己定高,面板整体不该再长过页内滚动面那一档 */
309
300
  max-block-size: var(--xh-time-picker-content-max-h, var(--xh-viewport-h-lg));
310
301
  border: var(--xh-stroke-thin) solid var(--xh-time-picker-content-border, var(--xh-border-default));
311
- border-radius: var(--xh-time-picker-content-radius, var(--xh-shape-surface));
302
+ border-radius: var(--xh-time-picker-content-radius, var(--xh-shape-overlay));
312
303
  background: var(--xh-time-picker-content-bg, var(--xh-bg-surface));
313
304
  color: var(--xh-time-picker-content-fg, var(--xh-fg-default));
314
305
  font-variant-numeric: tabular-nums;
315
306
  box-shadow: var(--xh-time-picker-content-shadow, var(--xh-elevation-floating));
316
307
  pointer-events: auto;
308
+ /* 快捷选项列与各时间列的条子贴在各自的盒子上、挂在这一层里(它已是定位盒):轨道不画底 */
309
+ --xh-scrollbar-track-bg: transparent;
317
310
  }
318
311
 
319
312
  /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 dialog 一致:
@@ -328,68 +321,112 @@
328
321
  }
329
322
 
330
323
  [data-scope='time-picker'][data-part='content'][data-state='open'] {
331
- animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
324
+ /* 只在展开态挂着:随状态属性一起消失,不长期占着合成层 */
325
+ will-change: opacity, translate;
326
+ animation: xh-overlay-slide-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
332
327
  }
333
328
 
334
329
  /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
335
330
  免得动画结束到真收起之间闪一下原样 */
336
331
  [data-scope='time-picker'][data-part='content'][data-state='closed'] {
337
- animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
332
+ animation: xh-overlay-slide-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
338
333
  }
339
334
 
340
335
  /* 快捷选项也是一列,与时分秒那几列并排,排在行内起始一侧 */
341
- [data-scope='time-picker'][data-part='presets'] {
336
+ [data-scope='time-picker'][data-part='preset-group'] {
342
337
  display: flex;
343
338
  flex: none;
344
339
  flex-direction: column;
345
- gap: var(--xh-time-picker-presets-gap, var(--xh-list-option-gap));
346
- max-block-size: var(--xh-time-picker-presets-h, var(--xh-viewport-h-sm));
347
- padding-inline: var(--xh-time-picker-presets-px, var(--xh-space-1));
340
+ gap: var(--xh-time-picker-preset-group-gap, var(--xh-list-option-gap));
341
+ max-block-size: var(--xh-time-picker-preset-group-h, var(--xh-viewport-h-sm));
342
+ padding-inline: var(--xh-time-picker-preset-group-px, var(--xh-space-1));
348
343
  overflow-y: auto;
349
- border-inline-end: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-border-subtle));
350
- scrollbar-width: thin;
344
+ /* 浮层滚动面:滚到头不把页面一起带走 */
345
+ overscroll-behavior: contain;
346
+ border-inline-end: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-material-frosted-separator));
351
347
  }
352
348
 
353
- [data-scope='time-picker'][data-part='presets'][hidden] {
349
+ [data-scope='time-picker'][data-part='preset-group'][hidden] {
354
350
  display: none;
355
351
  }
356
352
 
353
+ /* 快捷选项:悬停 / 高亮 100、按下 200、禁用面由 Collection Item 家族按 overlay 语境给(选中 = 透明底 +
354
+ 行尾对号,正文保持 rest 色与常规字重)。选项没有正文部件,匿名文本进不了家族网格的 text 列,
355
+ 行保持块级排版,末端为对号预留固定轨 */
357
356
  [data-scope='time-picker'][data-part='preset'] {
358
- padding-block: var(--xh-time-picker-preset-py, var(--xh-space-1));
359
- padding-inline: var(--xh-time-picker-preset-px, var(--xh-space-3));
360
- border-radius: var(--xh-time-picker-preset-radius, var(--xh-shape-control));
361
- font-size: var(--xh-text-secondary-size);
362
- line-height: var(--xh-leading-normal);
357
+ --xh-collection-block-padding: var(--xh-time-picker-preset-py, var(--xh-space-1));
358
+ --xh-collection-inline-padding: var(--xh-time-picker-preset-px, var(--xh-space-3));
359
+ --xh-collection-font-size: var(--xh-text-secondary-size);
360
+ --xh-collection-radius: var(--xh-time-picker-preset-radius, var(--xh-shape-control));
361
+ /* 面板是实体面(floating),正文取页面前景 */
362
+ --xh-collection-fg-rest: var(--xh-time-picker-preset-fg, var(--xh-fg-default));
363
+ --xh-collection-fg-hover: var(--xh-time-picker-preset-fg, var(--xh-fg-default));
364
+ --xh-collection-fg-keyboard-highlight: var(--xh-time-picker-preset-fg, var(--xh-fg-default));
365
+ --xh-collection-fg-pressed: var(--xh-time-picker-preset-fg, var(--xh-fg-default));
366
+ --xh-collection-fg-selected: var(--xh-time-picker-preset-fg-checked, var(--xh-time-picker-preset-fg, var(--xh-fg-default)));
367
+ --xh-collection-fg-selected-highlight: var(--xh-time-picker-preset-fg-checked, var(--xh-time-picker-preset-fg, var(--xh-fg-default)));
368
+ --xh-collection-fg-selected-hover: var(--xh-time-picker-preset-fg-checked, var(--xh-time-picker-preset-fg, var(--xh-fg-default)));
369
+ --xh-collection-fg-selected-pressed: var(--xh-time-picker-preset-fg-checked, var(--xh-time-picker-preset-fg, var(--xh-fg-default)));
370
+ --xh-collection-fg-disabled: var(--xh-time-picker-preset-fg-disabled, var(--xh-fg-disabled));
371
+ --xh-collection-bg-hover: var(--xh-time-picker-preset-bg-hover, var(--xh-bg-subtle));
372
+ --xh-collection-bg-keyboard-highlight: var(--xh-time-picker-preset-bg-hover, var(--xh-bg-subtle));
373
+ --xh-collection-bg-selected-highlight: var(--xh-time-picker-preset-bg-hover, var(--xh-bg-subtle));
374
+ --xh-collection-bg-selected-hover: var(--xh-time-picker-preset-bg-hover, var(--xh-bg-subtle));
375
+ --xh-collection-bg-pressed: var(--xh-time-picker-preset-bg-pressed, var(--xh-bg-subtle-hover));
376
+ --xh-collection-bg-selected-pressed: var(--xh-time-picker-preset-bg-pressed, var(--xh-bg-subtle-hover));
377
+ --xh-collection-outline-keyboard-highlight: transparent;
378
+ --xh-collection-outline-selected-highlight: transparent;
379
+
380
+ position: relative;
381
+ display: block;
382
+ flex: none;
383
+ /* 对号的末端轨始终留着,切换选中时文字与整列宽度都不移动。 */
384
+ padding-inline-end: calc(
385
+ var(--xh-time-picker-preset-px, var(--xh-space-3))
386
+ + var(--xh-time-picker-preset-check-size, var(--xh-glyph-size-sm))
387
+ + var(--xh-space-1)
388
+ );
363
389
  white-space: nowrap;
364
- cursor: pointer;
365
390
  user-select: none;
366
391
  }
367
392
 
368
- /* 悬停与键盘锚点共用中性轻档,命中那一条才走品牌底;禁用的不响应悬停 */
369
- [data-scope='time-picker'][data-part='preset']:hover:not([data-disabled]) {
370
- background: var(--xh-time-picker-preset-bg-hover, var(--xh-bg-subtle));
393
+ /* 键盘焦点出现时环才接回并立即到位,不压在背景过渡的中间帧上 */
394
+ [data-scope='time-picker'][data-part='preset']:focus-visible:not(:hover) {
395
+ --xh-collection-outline-keyboard-highlight: var(--xh-ring-focus);
396
+ --xh-collection-outline-selected-highlight: var(--xh-ring-focus);
397
+
398
+ transition: none;
371
399
  }
372
400
 
373
- [data-scope='time-picker'][data-part='preset']:focus-visible,
374
- [data-scope='time-picker'][data-part='presets']:focus-visible {
375
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
376
- outline-offset: calc(-1 * var(--xh-ring-width));
401
+ /* 对号是 preset 自身的正式选中出口:全部条目恒留末端轨,不依赖作者补节点。 */
402
+ [data-scope='time-picker'][data-part='preset']::after {
403
+ content: '';
404
+ position: absolute;
405
+ inset-block-start: 50%;
406
+ inset-inline-end: var(--xh-time-picker-preset-px, var(--xh-space-3));
407
+ inline-size: var(--xh-time-picker-preset-check-size, var(--xh-glyph-size-sm));
408
+ block-size: var(--xh-time-picker-preset-check-size, var(--xh-glyph-size-sm));
409
+ background-color: var(--xh-time-picker-preset-check-fg, var(--xh-_time-picker-check-fg));
410
+ opacity: 0;
411
+ translate: 0 -50%;
412
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
413
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
414
+ pointer-events: none;
415
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
377
416
  }
378
417
 
379
- /* 命中的那一条与选中的格子同一副实心底:同一份浮层里两种「选中」不该长成两个样 */
380
- [data-scope='time-picker'][data-part='preset'][data-state='checked'] {
381
- background: var(--xh-time-picker-preset-bg-checked, var(--xh-_time-picker-accent));
382
- color: var(--xh-time-picker-preset-fg-checked, var(--xh-_time-picker-accent-fg));
383
- font-weight: var(--xh-font-weight-medium);
418
+ /* 命中只显示对号;正文不反白、不增重,底色通道留给临时交互状态。 */
419
+ [data-scope='time-picker'][data-part='preset'][data-state='checked']::after {
420
+ opacity: 1;
384
421
  }
385
422
 
386
- [data-scope='time-picker'][data-part='preset'][data-state='checked']:hover:not([data-disabled]) {
387
- background: var(--xh-time-picker-preset-bg-checked-hover, var(--xh-_time-picker-accent-hover));
423
+ /* 上面给了 display,UA 的 [hidden]{display:none} 已被盖掉,这里补回来 */
424
+ [data-scope='time-picker'][data-part='preset'][hidden] {
425
+ display: none;
388
426
  }
389
427
 
390
- [data-scope='time-picker'][data-part='preset'][data-disabled] {
391
- color: var(--xh-time-picker-preset-fg-disabled, var(--xh-fg-disabled));
392
- cursor: not-allowed;
428
+ [data-scope='time-picker'][data-part='preset'][data-disabled]::after {
429
+ background-color: var(--xh-time-picker-preset-fg-disabled, var(--xh-fg-disabled));
393
430
  }
394
431
 
395
432
  /* 一列一个滚动区:列与列之间用细分隔线,视觉上"时 | 分 | 秒"三栏分明 */
@@ -397,14 +434,15 @@
397
434
  display: flex;
398
435
  flex: none;
399
436
  flex-direction: column;
400
- gap: var(--xh-time-picker-column-gap, var(--xh-list-option-gap));
401
- min-inline-size: var(--xh-time-picker-column-min-w, 3.5rem);
437
+ gap: var(--xh-time-picker-column-gap, 0);
438
+ min-inline-size: var(--xh-time-picker-column-min-w, var(--xh-overlay-column-min-w));
402
439
  /* 几列并排:定高而不是随内容收,否则时列与分列的可选值一多一少就错位 */
403
440
  block-size: var(--xh-time-picker-column-h, var(--xh-viewport-h-sm));
404
- padding-inline: var(--xh-time-picker-column-px, var(--xh-space-1));
441
+ padding-inline: var(--xh-time-picker-column-px, 0);
405
442
  overflow-y: auto;
443
+ /* 浮层滚动面:滚到头不把页面一起带走 */
444
+ overscroll-behavior: contain;
406
445
  /* 滚动容器在某些浏览器里会被自动塞进 Tab 序列,是否画环见下方按 tabindex 分档的两条 */
407
- scrollbar-width: thin;
408
446
  }
409
447
 
410
448
  /* granularity 关掉的列(精度不到秒时的秒列)由连接层打 hidden */
@@ -412,39 +450,76 @@
412
450
  display: none;
413
451
  }
414
452
 
415
- [data-scope='time-picker'][data-part='column'] + [data-scope='time-picker'][data-part='column'] {
416
- border-inline-start: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-border-subtle));
453
+ /* 每列后面紧跟着它自己的贴层条子节点,相邻选择器接不到下一列,按「前面有过列」取第二列起 */
454
+ [data-scope='time-picker'][data-part='column'] ~ [data-scope='time-picker'][data-part='column'] {
455
+ border-inline-start: var(--xh-stroke-thin) solid var(--xh-time-picker-column-divider, var(--xh-material-frosted-separator));
417
456
  }
418
457
 
419
458
  /* 焦点落在列上有两种情形:指针打开、这一段还空着、还没有任何格当锚点,或整列被界裁空。
420
459
  那一刻它认领着 Tab 位,环画在列内沿;有锚点时环长在格上,列不再画 */
421
460
  [data-scope='time-picker'][data-part='column'][tabindex='0']:focus-visible {
422
- outline: var(--xh-ring-width) solid var(--xh-_time-picker-ring);
423
- outline-offset: calc(-1 * var(--xh-ring-width));
461
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
462
+ outline-offset: var(--xh-ring-offset);
424
463
  }
425
464
 
426
465
  [data-scope='time-picker'][data-part='column']:not([tabindex='0']):focus-visible {
427
466
  outline: none;
428
467
  }
429
468
 
469
+ /* 时间格:悬停 / 高亮 100、按下 200 由 Collection Item 家族按 overlay 语境给,选中只留末端对号——
470
+ 浮层瞬态集合的选中不上品牌淡底、不加粗、不变字色。格里只有数字、没有正文部件,保持自己的
471
+ 居中排版与等宽标记轨,家族只给状态面。行的字色与字重按值选择族的同一套映射写(--xh-time-picker-item-fg
472
+ / -fg-selected / -font-weight-selected 使用者槽,缺省落家族配方的行字色 --xh-material-frosted-fg:
473
+ 它在各主题与 forced-colors 下都等于 --xh-fg-default,floating 面板上的面色仍由 content 自己给) */
430
474
  [data-scope='time-picker'][data-part='item'] {
475
+ --xh-_time-picker-item-rail: max(
476
+ var(--xh-time-picker-item-px, var(--xh-space-0_5)),
477
+ calc(var(--xh-time-picker-item-check-size, var(--xh-glyph-size-sm)) + var(--xh-space-0_5))
478
+ );
479
+ --xh-collection-block-padding: var(--xh-time-picker-item-py, 0);
480
+ /* 两侧留同宽轨:对号绝对落在末端,数字仍在整格的数学中心。 */
481
+ --xh-collection-inline-padding: var(--xh-_time-picker-item-rail);
482
+ --xh-collection-font-size: var(--xh-time-picker-item-font-size, var(--xh-_time-picker-font-size));
483
+ --xh-collection-radius: var(--xh-time-picker-item-radius, var(--xh-shape-control));
484
+ --xh-collection-fg-rest: var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg));
485
+ --xh-collection-fg-hover: var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg));
486
+ --xh-collection-fg-keyboard-highlight: var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg));
487
+ --xh-collection-fg-pressed: var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg));
488
+ --xh-collection-fg-selected: var(--xh-time-picker-item-fg-selected, var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg)));
489
+ --xh-collection-fg-selected-highlight: var(--xh-time-picker-item-fg-selected, var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg)));
490
+ --xh-collection-fg-selected-hover: var(--xh-time-picker-item-fg-selected, var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg)));
491
+ --xh-collection-fg-selected-pressed: var(--xh-time-picker-item-fg-selected, var(--xh-time-picker-item-fg, var(--xh-material-frosted-fg)));
492
+ --xh-collection-font-weight-selected: var(--xh-time-picker-item-font-weight-selected, var(--xh-font-weight-regular));
493
+ --xh-collection-font-weight-selected-highlight: var(--xh-time-picker-item-font-weight-selected, var(--xh-font-weight-regular));
494
+ --xh-collection-font-weight-selected-hover: var(--xh-time-picker-item-font-weight-selected, var(--xh-font-weight-regular));
495
+ --xh-collection-font-weight-selected-pressed: var(--xh-time-picker-item-font-weight-selected, var(--xh-font-weight-regular));
496
+ --xh-collection-bg-hover: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
497
+ --xh-collection-bg-keyboard-highlight: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
498
+ --xh-collection-bg-selected-highlight: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
499
+ --xh-collection-bg-selected-hover: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
500
+ --xh-collection-bg-pressed: var(--xh-time-picker-item-bg-pressed, var(--xh-bg-subtle-hover));
501
+ --xh-collection-bg-selected-pressed: var(--xh-time-picker-item-bg-pressed, var(--xh-bg-subtle-hover));
502
+ --xh-collection-outline-keyboard-highlight: transparent;
503
+ --xh-collection-outline-selected-highlight: transparent;
504
+
505
+ position: relative;
431
506
  display: flex;
432
507
  flex: none;
433
508
  align-items: center;
434
509
  justify-content: center;
435
- padding-block: var(--xh-time-picker-item-py, var(--xh-list-option-py-md));
436
- padding-inline: var(--xh-time-picker-item-px, var(--xh-_time-picker-item-px));
437
- border-radius: var(--xh-time-picker-item-radius, var(--xh-shape-control));
438
- color: var(--xh-time-picker-item-fg, var(--xh-fg-default));
439
- font-size: var(--xh-time-picker-item-font-size, var(--xh-_time-picker-font-size));
510
+ block-size: var(--xh-time-picker-item-h, var(--xh-overlay-column-item-h));
440
511
  /* 居中的单个数字格没有截断层,行高保持紧排,列内多露几格 */
441
512
  line-height: var(--xh-leading-none);
442
513
  white-space: nowrap;
443
- cursor: pointer;
444
514
  user-select: none;
445
- transition:
446
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
447
- color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
515
+ }
516
+
517
+ /* 键盘焦点出现时环才接回并立即到位,不压在背景过渡的中间帧上 */
518
+ [data-scope='time-picker'][data-part='item']:focus-visible:not(:hover) {
519
+ --xh-collection-outline-keyboard-highlight: var(--xh-ring-focus);
520
+ --xh-collection-outline-selected-highlight: var(--xh-ring-focus);
521
+
522
+ transition: none;
448
523
  }
449
524
 
450
525
  /* 作者自己藏掉某几格时要让位,有 display 就得补这条 */
@@ -452,36 +527,49 @@
452
527
  display: none;
453
528
  }
454
529
 
455
- /* 悬停与键盘锚点共用中性灰轻档;焦点所在与选中互相独立:可以停在一个没被选中的格上 */
456
- [data-scope='time-picker'][data-part='item'][data-highlighted]:not([data-disabled]),
457
- [data-scope='time-picker'][data-part='item']:hover:not([data-disabled]) {
458
- background: var(--xh-time-picker-item-bg-hover, var(--xh-bg-subtle));
530
+ [data-scope='time-picker'][data-part='item']::after {
531
+ content: '';
532
+ position: absolute;
533
+ inset-block-start: 50%;
534
+ inset-inline-end: var(--xh-space-0_5);
535
+ inline-size: var(--xh-time-picker-item-check-size, var(--xh-glyph-size-sm));
536
+ block-size: var(--xh-time-picker-item-check-size, var(--xh-glyph-size-sm));
537
+ background-color: var(--xh-time-picker-item-check-fg, var(--xh-_time-picker-check-fg));
538
+ opacity: 0;
539
+ translate: 0 -50%;
540
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
541
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
542
+ pointer-events: none;
543
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
459
544
  }
460
545
 
461
- [data-scope='time-picker'][data-part='item'][data-state='checked'] {
462
- background: var(--xh-time-picker-item-bg-checked, var(--xh-_time-picker-accent));
463
- color: var(--xh-time-picker-item-fg-checked, var(--xh-_time-picker-accent-fg));
464
- font-weight: var(--xh-time-picker-item-weight-checked, var(--xh-font-weight-medium));
546
+ /* 选中只画对号,正文与静止底保持普通态;悬停 / 高亮 / 按下面由家族给 */
547
+ [data-scope='time-picker'][data-part='item'][data-state='checked']::after {
548
+ opacity: 1;
465
549
  }
466
550
 
467
- /* 选中格上再落焦点或悬停时,底色留在品牌色一侧:上面那条中性轻档的选择器更具体,
468
- 不写这条就只有底色被换走、文字仍是品牌底上的反白色 */
469
- [data-scope='time-picker'][data-part='item'][data-state='checked'][data-highlighted]:not([data-disabled]),
470
- [data-scope='time-picker'][data-part='item'][data-state='checked']:hover:not([data-disabled]) {
471
- background: var(--xh-time-picker-item-bg-checked-hover, var(--xh-_time-picker-accent-hover));
551
+ /* 禁用走 aria-disabled 而非原生 disabled,家族按 aria-disabled 给禁用面;标记跟着降级 */
552
+ [data-scope='time-picker'][data-part='item'][data-disabled]::after {
553
+ background-color: var(--xh-fg-disabled);
472
554
  }
473
555
 
474
- [data-scope='time-picker'][data-part='item']:focus-visible {
475
- outline: var(--xh-ring-width) solid var(--xh-_time-picker-ring);
476
- /* 往内收:选项在滚动列里挨着排,环画在外沿会被列的溢出裁掉 */
477
- outline-offset: calc(-1 * var(--xh-ring-offset));
478
- }
556
+ @media (forced-colors: active) {
557
+ [data-scope='time-picker'][data-part='segment'][data-invalid]:is([data-focus], :focus-visible) {
558
+ outline: var(--xh-ring-width) solid Highlight;
559
+ outline-offset: var(--xh-ring-offset);
560
+ }
479
561
 
480
- /* 禁用走 aria-disabled 而非原生 disabled(原生 disabled 不派 click,禁用守卫就走不到),
481
- 所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
482
- [data-scope='time-picker'][data-part='item'][data-disabled] {
483
- color: var(--xh-fg-disabled);
484
- cursor: not-allowed;
562
+ /* mask 保留对号轮廓,系统色接管墨色;关闭自动调整避免伪元素底被系统抹成透明。 */
563
+ [data-scope='time-picker'][data-part='preset']::after,
564
+ [data-scope='time-picker'][data-part='item']::after {
565
+ background-color: CanvasText;
566
+ forced-color-adjust: none;
567
+ }
568
+
569
+ [data-scope='time-picker'][data-part='preset'][data-disabled]::after,
570
+ [data-scope='time-picker'][data-part='item'][data-disabled]::after {
571
+ background-color: GrayText;
572
+ }
485
573
  }
486
574
 
487
575
  /* 连接层把它写成 type=hidden,UA 自己就不渲染;这里的视觉隐藏是给元素升级前那一瞬兜底
@@ -519,34 +607,17 @@
519
607
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
520
608
  vertical-align: var(--xh-glyph-baseline-shift);
521
609
  background-color: currentColor;
522
- -webkit-mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
523
- mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
610
+ -webkit-mask: var(--xh-glyph-mark-clock) center / contain no-repeat;
611
+ mask: var(--xh-glyph-mark-clock) center / contain no-repeat;
524
612
  }
525
613
  }
526
614
 
527
615
  @layer xihan.motion {
528
- /* 浮层进场:淡入 + 轻微上浮,方向与它从输入行下方展开一致。
529
- 关键帧写在自己文件里并带组件前缀,不去动共享的 motion.css */
530
- @keyframes xh-pop-in {
531
- from {
532
- opacity: 0;
533
- scale: var(--xh-motion-scale-enter);
534
- }
535
-
536
- to {
537
- opacity: 1;
538
- scale: 1;
539
- }
540
- }
541
- @keyframes xh-pop-out {
542
- from {
543
- opacity: 1;
544
- scale: 1;
545
- }
546
-
547
- to {
548
- opacity: 0;
549
- scale: var(--xh-motion-scale-enter);
616
+ @media print {
617
+ /* 打印:定位层与遮罩是交互期才存在的东西,落到纸上只会盖住底下的正文。
618
+ 收起写在这份皮肤里而不是 reset:reset 层排在组件层之前,组件层里任何一条 display 都压得住它。 */
619
+ [data-scope='time-picker'][data-part='positioner'] {
620
+ display: none;
550
621
  }
551
622
  }
552
623
  }