@xihan-ui/styles 2.0.0 → 3.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 (156) hide show
  1. package/CHANGELOG.md +1328 -0
  2. package/README.md +6 -1
  3. package/component-tokens.d.ts +505 -111
  4. package/components.tokens.json +34750 -26291
  5. package/css/accordion.css +39 -13
  6. package/css/alert.css +61 -3
  7. package/css/anchor.css +49 -11
  8. package/css/approval.css +124 -84
  9. package/css/avatar-group.css +1 -1
  10. package/css/avatar.css +13 -5
  11. package/css/back-top.css +63 -44
  12. package/css/badge.css +63 -13
  13. package/css/bar-code.css +1 -1
  14. package/css/breadcrumb.css +63 -4
  15. package/css/button-group.css +5 -5
  16. package/css/button.css +69 -21
  17. package/css/calendar-picker.css +27 -8
  18. package/css/calendar-range-picker.css +48 -11
  19. package/css/card.css +116 -2
  20. package/css/carousel.css +153 -48
  21. package/css/cartesian-chart.css +830 -0
  22. package/css/cascader.css +184 -70
  23. package/css/checkbox-group.css +69 -99
  24. package/css/checkbox.css +21 -54
  25. package/css/citation.css +470 -0
  26. package/css/clipboard.css +23 -66
  27. package/css/code-view.css +103 -8
  28. package/css/collapsible.css +37 -11
  29. package/css/color-field.css +18 -0
  30. package/css/color-picker.css +57 -62
  31. package/css/color-slider.css +26 -19
  32. package/css/color-swatch-picker.css +8 -6
  33. package/css/combobox.css +82 -37
  34. package/css/command.css +48 -48
  35. package/css/context-menu.css +43 -28
  36. package/css/date-field.css +23 -0
  37. package/css/date-picker.css +57 -24
  38. package/css/date-range-picker.css +301 -14
  39. package/css/description.css +17 -1
  40. package/css/descriptions.css +43 -1
  41. package/css/dialog.css +99 -43
  42. package/css/diff-view.css +101 -16
  43. package/css/download-trigger.css +46 -80
  44. package/css/drawer.css +168 -133
  45. package/css/editable.css +19 -0
  46. package/css/empty-state.css +8 -7
  47. package/css/field-array.css +36 -0
  48. package/css/field.css +17 -19
  49. package/css/fieldset.css +1 -1
  50. package/css/file-upload.css +126 -136
  51. package/css/flex.css +324 -8
  52. package/css/float-button.css +168 -41
  53. package/css/floating-panel.css +59 -27
  54. package/css/form.css +26 -20
  55. package/css/funnel-chart.css +106 -0
  56. package/css/graph-chart.css +205 -0
  57. package/css/grid-list.css +235 -0
  58. package/css/grid.css +252 -1
  59. package/css/heatmap.css +119 -36
  60. package/css/hierarchy-chart.css +298 -0
  61. package/css/hover-card.css +33 -18
  62. package/css/icon.css +100 -0
  63. package/css/image-cropper.css +34 -8
  64. package/css/image-viewer.css +169 -26
  65. package/css/image.css +23 -4
  66. package/css/infinite-scroll.css +2 -2
  67. package/css/input-group.css +13 -15
  68. package/css/json-viewer.css +55 -7
  69. package/css/kbd.css +1 -1
  70. package/css/layout.css +71 -21
  71. package/css/liquid.css +106 -0
  72. package/css/list.css +2 -2
  73. package/css/listbox.css +72 -23
  74. package/css/loading-bar.css +27 -13
  75. package/css/log.css +131 -35
  76. package/css/markdown-stream.css +1 -1
  77. package/css/marquee.css +163 -7
  78. package/css/matrix-code.css +1 -1
  79. package/css/mention.css +35 -21
  80. package/css/menu.css +40 -28
  81. package/css/menubar.css +42 -28
  82. package/css/message-feed.css +174 -53
  83. package/css/navigation-menu.css +177 -18
  84. package/css/notification.css +431 -110
  85. package/css/number-field.css +22 -0
  86. package/css/page-header.css +4 -2
  87. package/css/pagination.css +129 -29
  88. package/css/password-input.css +40 -8
  89. package/css/pie-chart.css +247 -0
  90. package/css/popconfirm.css +50 -58
  91. package/css/popover.css +55 -21
  92. package/css/progress.css +308 -10
  93. package/css/prompt-input.css +37 -1
  94. package/css/question-flow.css +104 -64
  95. package/css/radar-chart.css +233 -0
  96. package/css/radio-group.css +372 -14
  97. package/css/rating.css +25 -27
  98. package/css/reasoning.css +62 -55
  99. package/css/reset.css +1 -1
  100. package/css/resizable.css +6 -1
  101. package/css/sankey-chart.css +174 -0
  102. package/css/scroll-area.css +32 -0
  103. package/css/scrollbar.css +1 -1
  104. package/css/select.css +76 -59
  105. package/css/side-nav.css +177 -30
  106. package/css/signature-pad.css +23 -8
  107. package/css/skeleton.css +13 -14
  108. package/css/slider.css +39 -17
  109. package/css/sortable.css +38 -8
  110. package/css/sparkline.css +164 -0
  111. package/css/spinner.css +50 -22
  112. package/css/splitter.css +8 -2
  113. package/css/statistic.css +10 -0
  114. package/css/steps.css +257 -38
  115. package/css/switch.css +30 -55
  116. package/css/table.css +168 -128
  117. package/css/tabs.css +243 -31
  118. package/css/tag-group.css +65 -37
  119. package/css/tag.css +55 -14
  120. package/css/tags-input.css +40 -3
  121. package/css/text-field.css +19 -0
  122. package/css/time-field.css +20 -1
  123. package/css/time-picker.css +44 -17
  124. package/css/time-range-picker.css +45 -18
  125. package/css/timeline.css +1 -1
  126. package/css/toggle-group.css +8 -8
  127. package/css/toggle.css +6 -5
  128. package/css/tool-call.css +64 -56
  129. package/css/toolbar.css +105 -7
  130. package/css/tooltip.css +18 -7
  131. package/css/tour.css +49 -21
  132. package/css/transfer.css +104 -81
  133. package/css/tree-select.css +235 -58
  134. package/css/tree.css +240 -147
  135. package/css/truncate.css +55 -12
  136. package/css/typography.css +93 -0
  137. package/css/virtualizer.css +57 -1
  138. package/css/watermark.css +23 -0
  139. package/family/action-control.css +14 -5
  140. package/family/chart.css +480 -0
  141. package/family/check-mark.css +94 -0
  142. package/family/choice-card.css +97 -0
  143. package/family/collection-item.css +70 -27
  144. package/family/field-chrome.css +1 -12
  145. package/family/loading-ring.css +95 -0
  146. package/family/material.css +72 -0
  147. package/family/menu-choice.css +56 -0
  148. package/family/motion.css +208 -11
  149. package/family/tag-list.css +59 -0
  150. package/index.css +23363 -14091
  151. package/index.unlayered.css +23198 -13922
  152. package/package.json +20 -8
  153. package/css/gradient-text.css +0 -91
  154. package/css/icon-wrapper.css +0 -81
  155. package/css/segmented.css +0 -280
  156. package/css/toast.css +0 -499
@@ -53,10 +53,12 @@
53
53
  描边在这里常驻 solid、静息透明,靠颜色表达键盘高亮。宿主页面常见的
54
54
  button:focus:not(:focus-visible) { outline: none } 复位(VitePress 等)是无层规则,压过本份;
55
55
  指针落焦时它把简写复位成 none,outline-color 同时落到 currentColor;焦点离开、规则失效的那一刻
56
- solid 立即回来,颜色若还在过渡就画成一圈实心边(上一条目闪边)。颜色即时切换后这条路径没有中间帧 */
56
+ solid 立即回来,颜色若还在过渡就画成一圈实心边(上一条目闪边)。颜色即时切换后这条路径没有中间帧。
57
+ 不透明度同一节奏:集合在后台刷新时保留上一帧、条目按 micro 淡下,数据到了再淡回 */
57
58
  transition:
58
- background-color var(--xh-motion-duration-release) var(--xh-motion-ease-release),
59
- color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
59
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
60
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
61
+ opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
60
62
  }
61
63
 
62
64
  [data-xh-collection-item][data-xh-collection-size='sm'] {
@@ -103,18 +105,25 @@
103
105
  font-size: var(--xh-collection-description-font-size, var(--xh-control-caption-md));
104
106
  }
105
107
 
108
+ /* 快捷键提示:与说明同档同色的次级文字,只是落位在行尾而不是第 2 行。
109
+ 不换行——它是一串按键记号,折行会被读成两个组合。跟着 description 那支前景走,因此也不跟语气。 */
106
110
  [data-xh-collection-slot='shortcut'] {
107
111
  grid-column: shortcut;
112
+ color: var(--xh-_collection-description-fg);
113
+ font-size: var(--xh-collection-shortcut-font-size, var(--xh-control-caption-md));
114
+ white-space: nowrap;
108
115
  }
109
116
 
110
117
  [data-xh-collection-slot='suffix'] {
111
118
  grid-column: suffix;
112
119
  }
113
120
 
121
+ /* 对号常驻在 indicator 列、未选中时透明:按选中态淡变,不按 visibility 瞬切 */
114
122
  [data-xh-collection-slot='indicator'] {
115
123
  grid-column: indicator;
116
124
  color: var(--xh-_collection-indicator-fg);
117
- visibility: hidden;
125
+ opacity: 0;
126
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
118
127
  }
119
128
 
120
129
  [data-xh-collection-slot='shortcut'],
@@ -124,20 +133,9 @@
124
133
  margin-inline-start: var(--xh-collection-gap, var(--xh-_collection-gap));
125
134
  }
126
135
 
127
- /* page 上下文:对号是前导标记(leading);当前项的起始侧指示条按配方开关(none),none 即只由行面与字色表达。 */
136
+ /* page 上下文:对号与 overlay 同在行尾的 indicator 列(trailing);当前项的起始侧指示条按配方开关(none),none 即只由行面与字色表达。 */
128
137
  [data-xh-collection-item][data-xh-collection-context='page'] {
129
138
  position: relative;
130
- grid-template-columns:
131
- [indicator] max-content
132
- [prefix] max-content
133
- [text] minmax(0, 1fr)
134
- [shortcut] max-content
135
- [suffix] max-content;
136
- }
137
-
138
- [data-xh-collection-item][data-xh-collection-context='page'] [data-xh-collection-slot='indicator'] {
139
- margin-inline-start: 0;
140
- margin-inline-end: var(--xh-collection-gap, var(--xh-_collection-gap));
141
139
  }
142
140
 
143
141
  [data-xh-collection-item][data-in-path] {
@@ -188,6 +186,31 @@
188
186
  transition-timing-function: var(--xh-motion-ease-press);
189
187
  }
190
188
 
189
+ /* 语气段:条目自身动作的性质,静息只换字、hover / 高亮 / 按下换语气淡底,节奏与中性行一致。
190
+ 必须排在上下文段之前:语气与 selected / current 同特指度,靠源序让选中与当前压过语气。 */
191
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]) {
192
+ --xh-_collection-bg: transparent;
193
+ --xh-_collection-fg: var(--xh-tone-fg);
194
+ }
195
+
196
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):hover {
197
+ --xh-_collection-bg: var(--xh-tone-subtle);
198
+ --xh-_collection-fg: var(--xh-tone-fg);
199
+ }
200
+
201
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):is(:focus-visible, [data-highlighted]) {
202
+ --xh-_collection-bg: var(--xh-tone-subtle);
203
+ --xh-_collection-fg: var(--xh-tone-fg);
204
+ }
205
+
206
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):is(:active, [data-pressed]) {
207
+ --xh-_collection-bg: var(--xh-tone-subtle-hover);
208
+ --xh-_collection-fg: var(--xh-tone-fg);
209
+
210
+ transition-duration: var(--xh-motion-duration-press);
211
+ transition-timing-function: var(--xh-motion-ease-press);
212
+ }
213
+
191
214
  [data-xh-collection-item][data-xh-collection-context='overlay']:is([aria-selected='true'], [data-selected]):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]) {
192
215
  --xh-_collection-bg: var(--xh-collection-bg-selected, transparent);
193
216
  --xh-_collection-fg: var(--xh-collection-fg-selected, var(--xh-material-frosted-fg));
@@ -436,7 +459,7 @@
436
459
  }
437
460
 
438
461
  [data-xh-collection-item]:is([aria-selected='true'], [data-state='checked']) [data-xh-collection-slot='indicator'] {
439
- visibility: visible;
462
+ opacity: 1;
440
463
  }
441
464
 
442
465
  [data-xh-collection-item][data-state='checked'] {
@@ -489,16 +512,6 @@
489
512
  display: none;
490
513
  }
491
514
 
492
- :where([data-motion='reduce']) [data-xh-collection-item] {
493
- transition: none;
494
- }
495
-
496
- @media (prefers-reduced-motion: reduce) {
497
- [data-xh-collection-item] {
498
- transition: none;
499
- }
500
- }
501
-
502
515
  @media (forced-colors: active) {
503
516
  [data-xh-collection-item] {
504
517
  --xh-_collection-bg: Canvas;
@@ -535,6 +548,36 @@
535
548
  --xh-_collection-indicator-fg: HighlightText;
536
549
  }
537
550
 
551
+ /* 语气在强制颜色下退出:逐态用系统色盖回家族缺省,只留图标与文案通道。
552
+ 语气段在媒体查询外的特指度比这里的基础态各高一级,必须逐条同形盖回,不能只写一条。 */
553
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]) {
554
+ --xh-_collection-bg: Canvas;
555
+ --xh-_collection-fg: CanvasText;
556
+ --xh-_collection-outline: transparent;
557
+ --xh-_collection-indicator-fg: ButtonText;
558
+ }
559
+
560
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):hover {
561
+ --xh-_collection-bg: Highlight;
562
+ --xh-_collection-fg: HighlightText;
563
+ --xh-_collection-outline: transparent;
564
+ --xh-_collection-indicator-fg: HighlightText;
565
+ }
566
+
567
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):is(:focus-visible, [data-highlighted]) {
568
+ --xh-_collection-bg: Canvas;
569
+ --xh-_collection-fg: CanvasText;
570
+ --xh-_collection-outline: Highlight;
571
+ --xh-_collection-indicator-fg: Highlight;
572
+ }
573
+
574
+ [data-xh-collection-item][data-tone]:not([data-xh-collection-context='nav']):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):is(:active, [data-pressed]) {
575
+ --xh-_collection-bg: Highlight;
576
+ --xh-_collection-fg: HighlightText;
577
+ --xh-_collection-outline: transparent;
578
+ --xh-_collection-indicator-fg: HighlightText;
579
+ }
580
+
538
581
  [data-xh-collection-item][data-xh-collection-context='overlay']:is([aria-selected='true'], [data-selected]):not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]) {
539
582
  --xh-_collection-bg: Canvas;
540
583
  --xh-_collection-fg: CanvasText;
@@ -38,8 +38,7 @@
38
38
  transition:
39
39
  background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
40
40
  border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
41
- box-shadow var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
42
- outline-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
41
+ box-shadow var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
43
42
  }
44
43
 
45
44
  [data-xh-field-chrome][data-variant='outline'] {
@@ -236,16 +235,6 @@
236
235
  -webkit-text-fill-color: var(--xh-field-autofill-fg, var(--xh-fg-default));
237
236
  }
238
237
 
239
- @media (prefers-reduced-motion: reduce) {
240
- [data-xh-field-chrome] {
241
- transition: none;
242
- }
243
- }
244
-
245
- :where([data-motion='reduce']) [data-xh-field-chrome] {
246
- transition: none;
247
- }
248
-
249
238
  @media (forced-colors: active) {
250
239
  [data-xh-field-chrome] {
251
240
  background-color: Canvas;
@@ -0,0 +1,95 @@
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
+ /*
7
+ * 加载环家族配方:「这里正在等」的那枚圆环,与 Spinner 环档同一副画法——一整圈轨道色,
8
+ * 只有起始边换成前景色,绕中心匀速转,转起来才看得出方向。
9
+ *
10
+ * 连接层在承载者上投影 data-xh-loading-ring,并用共享的 data-loading 说此刻在不在等。
11
+ * 环画在承载者的 ::before 上:伪元素有没有、多大、摆在哪由皮肤决定(皮肤写 content 与尺寸),
12
+ * 配方只负责把它画成环、随 data-loading 淡入淡出并转停。收起时环停在当前角度淡出,
13
+ * 与皮肤里接替它的那枚字形交叉淡变;不在等时不转。
14
+ *
15
+ * 轨道取 --xh-border-default、环粗取 --xh-stroke-thick;起始边颜色走私有槽 --xh-_loading-ring-fg,
16
+ * 皮肤按自己的语气与公开槽给,没给时取 currentColor。转一圈的时长走私有槽 --xh-_loading-ring-duration,
17
+ * 皮肤把自己的公开时长槽接进来,没给时取 --xh-motion-loop-spin。
18
+ *
19
+ * 进行中的动作钮投影 data-xh-loading-ring="overlay":环居中压在钮上、不占排布,钮宽不变,直径取钮的图标档。
20
+ * 进入在途要等一个 micro 才起淡,不到一个 micro 就结束的短请求什么都不闪;退出在途不等,按 micro 淡出。
21
+ * 钮里原有的内容由皮肤按同一段等待淡出留位,与环交叉。
22
+ *
23
+ * 转圈与淡变的关键帧与时长走 motion.css:引入本配方的皮肤同时 @import 它;家族文件之间不互相引入,
24
+ * 全量入口里每份家族只内联一次。
25
+ */
26
+ @layer xihan.components {
27
+ [data-xh-loading-ring]::before {
28
+ /* 环粗算进直径,换厚度不会把环撑大 */
29
+ box-sizing: border-box;
30
+ border: var(--xh-stroke-thick) solid var(--xh-border-default);
31
+ border-block-start-color: var(--xh-_loading-ring-fg, currentColor);
32
+ border-radius: var(--xh-shape-circle);
33
+ /* 承载者的这枚伪元素在别的状态下可能画着字形:环不带底、不带遮罩 */
34
+ background: none;
35
+ -webkit-mask: none;
36
+ mask: none;
37
+ opacity: 0;
38
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
39
+ /* 不在等时停在当前角度,淡出途中不先跳回零度 */
40
+ animation: xh-spin var(--xh-_loading-ring-duration, var(--xh-motion-loop-spin)) var(--xh-motion-ease-loop) infinite paused;
41
+ }
42
+
43
+ [data-xh-loading-ring][data-loading]::before {
44
+ opacity: 1;
45
+ animation-play-state: running;
46
+ }
47
+
48
+ /* 压在动作钮上的环:钮是定位盒(Action Control 给 position: relative),环在钮正中、不进排布 */
49
+ [data-xh-loading-ring='overlay']::before {
50
+ content: '';
51
+ position: absolute;
52
+ inset: 0;
53
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
54
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
55
+ margin: auto;
56
+ pointer-events: none;
57
+ }
58
+
59
+ /* 只在进入在途时等:退出那一刻撤掉这一档,淡出不延迟 */
60
+ [data-xh-loading-ring='overlay'][data-loading]::before {
61
+ transition-delay: var(--xh-motion-duration-micro);
62
+ }
63
+
64
+ /* 减弱动效与打印:环停下并整圈换成点线,静止的形状仍读得出「还没好」;淡入淡出照常。
65
+ 两组规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
66
+ @media (prefers-reduced-motion: reduce) {
67
+ [data-xh-loading-ring]::before {
68
+ border-style: dotted;
69
+ border-color: var(--xh-_loading-ring-fg, currentColor);
70
+ animation: none;
71
+ }
72
+ }
73
+
74
+ :where([data-motion='reduce']) [data-xh-loading-ring]::before {
75
+ border-style: dotted;
76
+ border-color: var(--xh-_loading-ring-fg, currentColor);
77
+ animation: none;
78
+ }
79
+
80
+ @media print {
81
+ [data-xh-loading-ring]::before {
82
+ border-style: dotted;
83
+ border-color: var(--xh-_loading-ring-fg, currentColor);
84
+ animation: none;
85
+ }
86
+ }
87
+
88
+ /* 强制色:轨道取系统文字色,起始边取高亮色,转向照样读得出 */
89
+ @media (forced-colors: active) {
90
+ [data-xh-loading-ring]::before {
91
+ border-color: CanvasText;
92
+ border-block-start-color: Highlight;
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,72 @@
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
+ /*
7
+ * 材质家族配方:frosted 面,以及它在 liquid 档的替身。
8
+ *
9
+ * 连接层在部件上投影 data-xh-material="frosted":锚定瞬态浮层的内容面(菜单、选择、气泡、浮动面板……)
10
+ * 与浮在内容之上的圆钮(回到顶部、浮动钮、轮播控制、回到底部)。配方在部件上声明一组私有槽
11
+ * --xh-_material-*,一种材质一套取值:底、交互阶梯(悬停 / 按下 / 键盘聚焦面)、前景、描边、投影、
12
+ * 背景滤镜与 1px 内侧顶光。
13
+ *
14
+ * 面 配方直接画描边、背景(1px 顶光叠在底色之上,随面本身不随内容滚动)、前景、投影与背景滤镜,
15
+ * 读桥接槽 --xh-frosted-*;皮肤只把使用者槽接进来:--xh-frosted-bg: var(使用者槽, var(--xh-_material-bg))
16
+ * 圆钮 面由 Action Control 家族画,皮肤把 --xh-action-* 桥接槽指向这组私有槽;配方只补背景滤镜
17
+ *
18
+ * data-material="liquid" 下,同时投影了 data-xh-liquid 的部件把这组私有槽换成液态面的取值(液态层
19
+ * liquid.css 在同一部件上声明 --xh-_liquid-*),皮肤不必为液态档再写一遍;可按的圆钮挂上按住形变。
20
+ * 减少透明、高对比、强制色与打印由材质令牌在令牌层降级,这里不另写。
21
+ */
22
+ @layer xihan.components {
23
+ [data-xh-material='frosted'] {
24
+ --xh-_material-bg: var(--xh-material-frosted-bg);
25
+ /* 圆钮的交互阶梯:磨砂面半透明,悬停 / 按下换成不透明的淡底一档、二档,不叠在透景上发灰 */
26
+ --xh-_material-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle-opaque));
27
+ --xh-_material-bg-pressed: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover-opaque));
28
+ --xh-_material-bg-focus: var(--xh-material-frosted-focus-surface);
29
+ --xh-_material-fg: var(--xh-material-frosted-fg);
30
+ --xh-_material-border: var(--xh-material-frosted-border);
31
+ --xh-_material-shadow: var(--xh-material-frosted-shadow);
32
+ --xh-_material-backdrop: var(--xh-material-frosted-backdrop);
33
+ --xh-_material-highlight: var(--xh-material-frosted-highlight);
34
+
35
+ -webkit-backdrop-filter: var(--xh-frosted-backdrop, var(--xh-_material-backdrop));
36
+ backdrop-filter: var(--xh-frosted-backdrop, var(--xh-_material-backdrop));
37
+ }
38
+
39
+ /* 面:四件套加 1px 顶光。顶光是背景的最上一层,只占内侧一像素、画在面本身上,滚动的内容面也钉在顶上;
40
+ 高对比与强制色下令牌把它归零,四边描边照常完整 */
41
+ [data-xh-material='frosted']:not([data-xh-action-control]) {
42
+ border: var(--xh-stroke-thin) solid var(--xh-frosted-border, var(--xh-_material-border));
43
+ background:
44
+ linear-gradient(
45
+ to bottom,
46
+ var(--xh-frosted-highlight, var(--xh-_material-highlight)) 0 var(--xh-stroke-thin),
47
+ transparent var(--xh-stroke-thin)
48
+ ),
49
+ var(--xh-frosted-bg, var(--xh-_material-bg));
50
+ color: var(--xh-frosted-fg, var(--xh-_material-fg));
51
+ box-shadow: var(--xh-frosted-shadow, var(--xh-_material-shadow));
52
+ }
53
+
54
+ /* liquid 档:浮在内容之上的导航层部件换成液态面。同一组私有槽换值,皮肤的桥接照旧;面内不加顶光,
55
+ 亮边已由液态层画在朝光源的一侧 */
56
+ :where([data-material='liquid']) [data-xh-material][data-xh-liquid] {
57
+ --xh-_material-bg: var(--xh-_liquid-bg);
58
+ --xh-_material-bg-hover: var(--xh-_liquid-bg-hover);
59
+ --xh-_material-bg-pressed: var(--xh-_liquid-bg-pressed);
60
+ --xh-_material-bg-focus: var(--xh-material-liquid-focus-surface);
61
+ --xh-_material-fg: var(--xh-material-liquid-fg);
62
+ --xh-_material-border: var(--xh-material-liquid-border);
63
+ --xh-_material-shadow: var(--xh-_liquid-shadow);
64
+ --xh-_material-backdrop: var(--xh-material-liquid-backdrop);
65
+ --xh-_material-highlight: transparent;
66
+ }
67
+
68
+ /* 按住液态圆钮时的黏滞形变由液态面逐帧写进来,松手弹回。只挂在可按的面上 */
69
+ :where([data-material='liquid']) [data-xh-action-control][data-xh-material][data-xh-liquid] {
70
+ transform: var(--xh-_liquid-deform);
71
+ }
72
+ }
@@ -0,0 +1,56 @@
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
+ /* Menu / ContextMenu / Menubar 的 checkbox 与 radio 共用标记语言。 */
7
+
8
+ @layer xihan.components {
9
+ [data-xh-menu-choice-indicator] {
10
+ visibility: hidden;
11
+ opacity: 0;
12
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
13
+ }
14
+
15
+ [data-xh-menu-choice-indicator][data-state='checked'] {
16
+ visibility: visible;
17
+ opacity: 1;
18
+ }
19
+
20
+ [data-xh-menu-choice-indicator='checkbox']:empty::before {
21
+ content: '';
22
+ display: inline-block;
23
+ inline-size: var(--xh-icon-size, var(--xh-control-indicator-size));
24
+ block-size: var(--xh-icon-size, var(--xh-control-indicator-size));
25
+ background-color: currentColor;
26
+ -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
27
+ mask: var(--xh-glyph-mark-check) center / contain no-repeat;
28
+ }
29
+
30
+ [data-xh-menu-choice-indicator='radio']:empty::before {
31
+ content: '';
32
+ display: inline-block;
33
+ inline-size: var(--xh-space-2);
34
+ block-size: var(--xh-space-2);
35
+ border-radius: var(--xh-shape-circle);
36
+ background-color: currentColor;
37
+ }
38
+
39
+ /* 强制色:勾与圆点都是伪元素上的一块底色,这一档里会被换成 Canvas 而消失;退出强制换色、直接写系统前景。
40
+ 标记坐在菜单条目里,按下与没被高亮时的悬停,家族把条目涂成 Highlight,标记跟着换 HighlightText;禁用取 GrayText */
41
+ @media (forced-colors: active) {
42
+ [data-xh-menu-choice-indicator]:empty::before {
43
+ forced-color-adjust: none;
44
+ background-color: CanvasText;
45
+ }
46
+
47
+ [data-xh-collection-item]:not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error]):is(:active, [data-pressed], :hover:not(:focus-visible, [data-highlighted]))
48
+ [data-xh-menu-choice-indicator]:empty::before {
49
+ background-color: HighlightText;
50
+ }
51
+
52
+ [data-xh-menu-choice-indicator][data-disabled]:empty::before {
53
+ background-color: GrayText;
54
+ }
55
+ }
56
+ }
package/family/motion.css CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /* 定义 motion 样式。 */
7
7
 
8
- /* 共享关键帧的唯一真源(规范 §9.4 / §9.5)。
8
+ /* 共享关键帧的唯一真源。
9
9
  *
10
10
  * 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
11
11
  * 动画会静默地整个不跑。所以引用这里任一名字的皮肤都 @import 本文件,单独引入那份皮肤时
@@ -13,17 +13,17 @@
13
13
  * @import 去重,同名同帧体即使重复插入也无副作用。
14
14
  *
15
15
  * 本文件只放跨皮肤共用的关键帧,皮肤内不得重定义这些名字(check-keyframe-refs 判红);
16
- * 组件专属关键帧仍住在各自皮肤。幅度只引 --xh-motion-distance-sm 与 --xh-motion-scale-enter /
17
- * -exit,减弱动效档由令牌层把它们归零。四个方向槽 --xh-_overlay-enter-* 由浮层皮肤按
18
- * placement 写在 positioner 上,四个都没写时位移退回 0。
16
+ * 组件专属关键帧仍住在各自皮肤。幅度只引 --xh-motion-distance-sm / -md 与 --xh-motion-scale-enter /
17
+ * -exit,整幅位移经私有槽取 --xh-motion-travel,减弱动效档由令牌层把它们归零。四个方向槽
18
+ * --xh-_overlay-enter-* 由浮层皮肤按 placement 写在 positioner 上,四个都没写时位移退回 0。
19
19
  */
20
20
  @layer xihan.motion {
21
21
  /* ── 锚定列表 / 菜单:沿落位方向短位移,不缩放文字与选中标记 ──
22
22
  Menu、Select、Combobox、Cascader、ContextMenu、Menubar、Mention、TreeSelect、
23
- Date / Time picker、Tooltip */
23
+ Date / Time picker、ColorPicker、Tooltip */
24
24
  @keyframes xh-overlay-slide-in {
25
25
  from {
26
- opacity: 0;
26
+ opacity: var(--xh-_enter-from-opacity, 0);
27
27
  translate:
28
28
  calc((var(--xh-_overlay-enter-right, 0) - var(--xh-_overlay-enter-left, 0)) * var(--xh-motion-distance-sm))
29
29
  calc((var(--xh-_overlay-enter-down, 0) - var(--xh-_overlay-enter-up, 0)) * var(--xh-motion-distance-sm));
@@ -54,7 +54,7 @@
54
54
  起点朝哪个方向退让由 placement 写进四个方向槽(那一侧写 1),四个都没写就退回原地缩放 */
55
55
  @keyframes xh-overlay-pop-in {
56
56
  from {
57
- opacity: 0;
57
+ opacity: var(--xh-_enter-from-opacity, 0);
58
58
  scale: var(--xh-motion-scale-enter);
59
59
  translate:
60
60
  calc((var(--xh-_overlay-enter-right, 0) - var(--xh-_overlay-enter-left, 0)) * var(--xh-motion-distance-sm))
@@ -82,10 +82,12 @@
82
82
  }
83
83
 
84
84
  /* ── 无锚定弹出:原地缩放淡入,没有方向 ──
85
- NavigationMenu、SideNav popout、FloatingPanel、FloatButton 列表、Pagination 弹层 */
85
+ NavigationMenu、SideNav popout、FloatingPanel、FloatButton 列表、Pagination 弹层;
86
+ 页内浮现的小件也取它:Approval、QuestionFlow 的结果标记,MessageFeed、Log 的回底钮;
87
+ 行内横排的胶囊集合(TagsInput、TagGroup、Select 标签行)加入一枚也取它:竖向上浮与来源方向不符,还会探出字段外壳 */
86
88
  @keyframes xh-pop-in {
87
89
  from {
88
- opacity: 0;
90
+ opacity: var(--xh-_enter-from-opacity, 0);
89
91
  scale: var(--xh-motion-scale-enter);
90
92
  }
91
93
 
@@ -100,7 +102,7 @@
100
102
  Cascader 列项的淡入 */
101
103
  @keyframes xh-fade-in {
102
104
  from {
103
- opacity: 0;
105
+ opacity: var(--xh-_enter-from-opacity, 0);
104
106
  }
105
107
 
106
108
  to {
@@ -121,7 +123,7 @@
121
123
  /* 页内内容的上浮进场:淡入叠一小段向上位移。Command 的分组、EmptyState、QuestionFlow */
122
124
  @keyframes xh-rise-in {
123
125
  from {
124
- opacity: 0;
126
+ opacity: var(--xh-_enter-from-opacity, 0);
125
127
  translate: 0 var(--xh-motion-distance-sm);
126
128
  }
127
129
 
@@ -163,4 +165,199 @@
163
165
  padding-block-end: 0;
164
166
  }
165
167
  }
168
+
169
+ /* ── 列表条目进场:淡入叠一段向上位移,比页内上浮大一档 ──
170
+ Approval、MessageFeed、QuestionFlow、ToolCall 的条目 */
171
+ @keyframes xh-item-in {
172
+ from {
173
+ opacity: var(--xh-_enter-from-opacity, 0);
174
+ translate: 0 var(--xh-motion-distance-md);
175
+ }
176
+
177
+ to {
178
+ opacity: 1;
179
+ translate: 0 0;
180
+ }
181
+ }
182
+
183
+ /* 自上而下的显现:新揭开的内容从上方落位。DiffView 展开的折叠块、Form 的错误汇总 */
184
+ @keyframes xh-drop-in {
185
+ from {
186
+ opacity: var(--xh-_enter-from-opacity, 0);
187
+ translate: 0 calc(-1 * var(--xh-motion-distance-sm));
188
+ }
189
+
190
+ to {
191
+ opacity: 1;
192
+ translate: 0 0;
193
+ }
194
+ }
195
+
196
+ /* ── 面板(sheet):模态与强反馈面,竖向一小段位移叠缩放 ──
197
+ 位移与缩放写独立属性,互不覆盖,手势期间写 translate 也不会把 scale 抹掉。Dialog、Notification */
198
+ @keyframes xh-sheet-in {
199
+ from {
200
+ opacity: var(--xh-_enter-from-opacity, 0);
201
+ translate: 0 var(--xh-motion-distance-md);
202
+ scale: var(--xh-motion-scale-enter);
203
+ }
204
+
205
+ to {
206
+ opacity: 1;
207
+ translate: 0 0;
208
+ scale: 1;
209
+ }
210
+ }
211
+
212
+ @keyframes xh-sheet-out {
213
+ from {
214
+ opacity: 1;
215
+ translate: 0 0;
216
+ scale: 1;
217
+ }
218
+
219
+ to {
220
+ opacity: 0;
221
+ translate: 0 var(--xh-motion-distance-md);
222
+ scale: var(--xh-motion-scale-exit);
223
+ }
224
+ }
225
+
226
+ /* ── 整幅滑入(slide):面板从所在边整条推入推出 ──
227
+ 方向由皮肤在元素上写进 --xh-_slide-from-x / --xh-_slide-from-y(取正负整幅位移令牌或 0),
228
+ 两个都没写时位移退回 0。整幅位移令牌在减弱动效下归零,进出场只剩时长。Drawer */
229
+ @keyframes xh-slide-in {
230
+ from {
231
+ translate: var(--xh-_slide-from-x, 0) var(--xh-_slide-from-y, 0);
232
+ }
233
+
234
+ to {
235
+ translate: 0 0;
236
+ }
237
+ }
238
+
239
+ @keyframes xh-slide-out {
240
+ from {
241
+ translate: 0 0;
242
+ }
243
+
244
+ to {
245
+ translate: var(--xh-_slide-from-x, 0) var(--xh-_slide-from-y, 0);
246
+ }
247
+ }
248
+
249
+ /* 整幅滑入配套的淡变:起止端取 --xh-motion-travel-opacity,缺省为 1 即不淡变,
250
+ 减弱动效下为 0,整幅位移归零后由它接住进出场。与 xh-slide-in / -out 并列播放,
251
+ 时长取淡变档(enter / exit),不随几何时长一起归零。Drawer */
252
+ @keyframes xh-slide-fade-in {
253
+ from {
254
+ opacity: var(--xh-_enter-from-opacity, var(--xh-motion-travel-opacity));
255
+ }
256
+
257
+ to {
258
+ opacity: 1;
259
+ }
260
+ }
261
+
262
+ @keyframes xh-slide-fade-out {
263
+ from {
264
+ opacity: 1;
265
+ }
266
+
267
+ to {
268
+ opacity: var(--xh-motion-travel-opacity);
269
+ }
270
+ }
271
+
272
+ /* ── 循环:匀速转圈与扫过的流光 ──
273
+ 时长取循环令牌,减弱动效下由各皮肤停掉并换成静态替代。
274
+ 转圈写独立的 rotate 属性,与元素自身的 transform 叠加而不互相覆盖。
275
+ 流光的亮带从右扫到左:消费方把渐变画成自身两倍宽(background-size: 200% 100%),
276
+ 只移动背景位置,不动布局也不动 transform。Reasoning、ToolCall 的在跑文字 */
277
+ @keyframes xh-spin {
278
+ to {
279
+ rotate: 1turn;
280
+ }
281
+ }
282
+
283
+ @keyframes xh-shimmer {
284
+ from {
285
+ background-position: 150% center;
286
+ }
287
+
288
+ to {
289
+ background-position: -50% center;
290
+ }
291
+ }
292
+
293
+ /* 呼吸:进行中、给不出进度、需要被察觉的状态点。明暗与缩放一起起伏,峰值落在 42%,
294
+ 周期 --xh-motion-loop-breathe、缓动 --xh-motion-ease-breathe。只动 opacity 与 scale。
295
+ 光环画在状态点的 ::after 上,同周期从点本身的大小外扩淡尽,只播 3 个周期,状态点本身持续到状态结束。
296
+ 减弱动效下两者都停,状态点停在满不透明度。Badge 的 pulse */
297
+ @keyframes xh-breathe {
298
+ 0%,
299
+ 100% {
300
+ opacity: 0.5;
301
+ scale: var(--xh-motion-scale-breathe);
302
+ }
303
+
304
+ 42% {
305
+ opacity: 1;
306
+ scale: 1;
307
+ }
308
+ }
309
+
310
+ @keyframes xh-breathe-halo {
311
+ from {
312
+ opacity: 0.32;
313
+ scale: 1;
314
+ }
315
+
316
+ 60%,
317
+ to {
318
+ opacity: 0;
319
+ scale: var(--xh-motion-scale-halo);
320
+ }
321
+ }
322
+
323
+ /* ── 交互光:一道光沿 1px 描边环扫过一次 ──
324
+ 光带画在三倍宽的背景里、居中,遮罩只留描边环;背景位置从 100% 走到 0%,光带从起始缘外扫到末缘外。
325
+ 只动背景位置,不动几何;只播一遍,不循环 */
326
+ @keyframes xh-glint {
327
+ from {
328
+ background-position: 100% 0;
329
+ }
330
+
331
+ to {
332
+ background-position: 0% 0;
333
+ }
334
+ }
335
+
336
+ /* ── 数值:倒计时条从占满一整条收到零 ──
337
+ 条子自己不改尺寸,靠裁切从行尾往行首收:只重绘、不重排。裁掉哪一侧随书写方向由
338
+ --xh-_countdown-cut-left / -right 给出,缺省按 LTR 收掉右侧;前端的圆角取
339
+ --xh-_countdown-radius。走一遍就到头,时长由连接层写进 Notification 的时长槽。 */
340
+ @keyframes xh-countdown {
341
+ from {
342
+ clip-path: inset(0 0 0 0 round var(--xh-_countdown-radius, 0));
343
+ }
344
+
345
+ to {
346
+ clip-path: inset(0 var(--xh-_countdown-cut-right, 100%) 0 var(--xh-_countdown-cut-left, 0) round var(--xh-_countdown-radius, 0));
347
+ }
348
+ }
349
+
350
+ /* ── 数据:新出现的折线从头描到尾 ──
351
+ 连接层给路径写 pathLength="1" 把长度归一,消费方把虚线设成一整段(stroke-dasharray: 1),
352
+ 虚线偏移从 1 走到 0。只动 stroke-dashoffset,不动几何。时长取 reveal、曲线取 continuous,
353
+ 与柱从基线长出同一档;减弱动效下时长降到 1ms,折线直接在场。CartesianChart */
354
+ @keyframes xh-draw {
355
+ from {
356
+ stroke-dashoffset: 1;
357
+ }
358
+
359
+ to {
360
+ stroke-dashoffset: 0;
361
+ }
362
+ }
166
363
  }