@xihan-ui/styles 2.1.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 (152) hide show
  1. package/CHANGELOG.md +1227 -0
  2. package/README.md +6 -1
  3. package/component-tokens.d.ts +505 -96
  4. package/components.tokens.json +34636 -25846
  5. package/css/accordion.css +34 -8
  6. package/css/alert.css +59 -1
  7. package/css/anchor.css +46 -8
  8. package/css/approval.css +116 -76
  9. package/css/avatar-group.css +1 -1
  10. package/css/avatar.css +13 -5
  11. package/css/back-top.css +61 -42
  12. package/css/badge.css +62 -12
  13. package/css/bar-code.css +1 -1
  14. package/css/breadcrumb.css +62 -3
  15. package/css/button-group.css +4 -4
  16. package/css/button.css +67 -19
  17. package/css/calendar-picker.css +19 -0
  18. package/css/calendar-range-picker.css +39 -2
  19. package/css/card.css +115 -1
  20. package/css/carousel.css +148 -43
  21. package/css/cartesian-chart.css +830 -0
  22. package/css/cascader.css +181 -65
  23. package/css/checkbox-group.css +59 -89
  24. package/css/checkbox.css +16 -49
  25. package/css/citation.css +470 -0
  26. package/css/clipboard.css +20 -63
  27. package/css/code-view.css +101 -6
  28. package/css/collapsible.css +34 -8
  29. package/css/color-field.css +18 -0
  30. package/css/color-picker.css +55 -58
  31. package/css/color-slider.css +22 -15
  32. package/css/color-swatch-picker.css +3 -1
  33. package/css/combobox.css +80 -33
  34. package/css/command.css +45 -43
  35. package/css/context-menu.css +39 -22
  36. package/css/date-field.css +23 -0
  37. package/css/date-picker.css +57 -22
  38. package/css/date-range-picker.css +301 -12
  39. package/css/description.css +17 -1
  40. package/css/descriptions.css +42 -0
  41. package/css/dialog.css +94 -36
  42. package/css/diff-view.css +97 -12
  43. package/css/download-trigger.css +44 -78
  44. package/css/drawer.css +160 -119
  45. package/css/editable.css +19 -0
  46. package/css/empty-state.css +7 -6
  47. package/css/field-array.css +36 -0
  48. package/css/field.css +16 -18
  49. package/css/file-upload.css +125 -135
  50. package/css/flex.css +324 -8
  51. package/css/float-button.css +165 -38
  52. package/css/floating-panel.css +53 -19
  53. package/css/form.css +23 -17
  54. package/css/funnel-chart.css +106 -0
  55. package/css/graph-chart.css +205 -0
  56. package/css/grid-list.css +235 -0
  57. package/css/grid.css +252 -1
  58. package/css/heatmap.css +119 -36
  59. package/css/hierarchy-chart.css +298 -0
  60. package/css/hover-card.css +31 -14
  61. package/css/icon.css +100 -0
  62. package/css/image-cropper.css +33 -7
  63. package/css/image-viewer.css +167 -22
  64. package/css/image.css +23 -4
  65. package/css/input-group.css +11 -13
  66. package/css/json-viewer.css +50 -2
  67. package/css/layout.css +68 -18
  68. package/css/liquid.css +106 -0
  69. package/css/list.css +1 -1
  70. package/css/listbox.css +46 -6
  71. package/css/loading-bar.css +27 -13
  72. package/css/log.css +129 -33
  73. package/css/markdown-stream.css +1 -1
  74. package/css/marquee.css +163 -7
  75. package/css/matrix-code.css +1 -1
  76. package/css/mention.css +35 -19
  77. package/css/menu.css +35 -21
  78. package/css/menubar.css +36 -20
  79. package/css/message-feed.css +172 -51
  80. package/css/navigation-menu.css +172 -11
  81. package/css/notification.css +429 -108
  82. package/css/number-field.css +22 -0
  83. package/css/page-header.css +3 -1
  84. package/css/pagination.css +126 -24
  85. package/css/password-input.css +40 -8
  86. package/css/pie-chart.css +247 -0
  87. package/css/popconfirm.css +44 -50
  88. package/css/popover.css +50 -14
  89. package/css/progress.css +308 -10
  90. package/css/prompt-input.css +36 -0
  91. package/css/question-flow.css +97 -57
  92. package/css/radar-chart.css +233 -0
  93. package/css/radio-group.css +363 -5
  94. package/css/rating.css +21 -23
  95. package/css/reasoning.css +61 -54
  96. package/css/resizable.css +6 -1
  97. package/css/sankey-chart.css +174 -0
  98. package/css/scroll-area.css +32 -0
  99. package/css/scrollbar.css +1 -1
  100. package/css/select.css +74 -55
  101. package/css/side-nav.css +173 -24
  102. package/css/signature-pad.css +16 -1
  103. package/css/skeleton.css +13 -14
  104. package/css/slider.css +35 -13
  105. package/css/sortable.css +37 -7
  106. package/css/sparkline.css +164 -0
  107. package/css/spinner.css +50 -22
  108. package/css/splitter.css +7 -1
  109. package/css/statistic.css +10 -0
  110. package/css/steps.css +248 -29
  111. package/css/switch.css +23 -48
  112. package/css/table.css +158 -118
  113. package/css/tabs.css +231 -19
  114. package/css/tag-group.css +27 -3
  115. package/css/tag.css +53 -12
  116. package/css/tags-input.css +40 -3
  117. package/css/text-field.css +19 -0
  118. package/css/time-field.css +20 -1
  119. package/css/time-picker.css +44 -15
  120. package/css/time-range-picker.css +45 -16
  121. package/css/timeline.css +1 -1
  122. package/css/toggle-group.css +4 -4
  123. package/css/toggle.css +4 -3
  124. package/css/tool-call.css +59 -51
  125. package/css/toolbar.css +101 -3
  126. package/css/tooltip.css +15 -2
  127. package/css/tour.css +42 -12
  128. package/css/transfer.css +98 -75
  129. package/css/tree-select.css +232 -53
  130. package/css/tree.css +201 -55
  131. package/css/truncate.css +55 -12
  132. package/css/typography.css +93 -0
  133. package/css/virtualizer.css +56 -0
  134. package/css/watermark.css +23 -0
  135. package/family/action-control.css +14 -5
  136. package/family/chart.css +480 -0
  137. package/family/check-mark.css +94 -0
  138. package/family/choice-card.css +97 -0
  139. package/family/collection-item.css +9 -15
  140. package/family/field-chrome.css +1 -12
  141. package/family/loading-ring.css +95 -0
  142. package/family/material.css +72 -0
  143. package/family/menu-choice.css +56 -0
  144. package/family/motion.css +207 -10
  145. package/family/tag-list.css +59 -0
  146. package/index.css +22997 -13678
  147. package/index.unlayered.css +12928 -3605
  148. package/package.json +20 -8
  149. package/css/gradient-text.css +0 -91
  150. package/css/icon-wrapper.css +0 -81
  151. package/css/segmented.css +0 -280
  152. package/css/toast.css +0 -499
@@ -0,0 +1,94 @@
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
+ * 勾选格里的勾与半选杠:Checkbox、CheckboxGroup、Transfer、Table、QuestionFlow 多选共用一份标记语言。
8
+ *
9
+ * 连接层在画标记的节点上投影两位:data-xh-check-mark 是标记的状态(checked / indeterminate / unchecked),
10
+ * data-xh-check-mark-profile 说标记画在哪——
11
+ * box:节点就是方框(或铺满方框的指示器),标记是它的 ::before;作者往节点里放了自己的图形时不画。
12
+ * row:节点是一整行,方框由皮肤画在它的 ::before 上,标记是 ::after,叠在方框正中;
13
+ * 皮肤写两支桥接槽:--xh-check-mark-box-size(方框边长)与 --xh-check-mark-fg(标记色)。
14
+ *
15
+ * 标记常驻,不按状态生成或撤掉:未勾时透明并略缩,勾上时淡入并回到原尺寸——淡变走 micro,
16
+ * 缩放走 nudge,减弱动效下缩放归一、只剩淡变。勾与半选杠叠成两层遮罩,按状态只换两层的尺寸;
17
+ * 离开勾选时尺寸的切换延后一个 micro,淡出途中标记保持原来的形状,半选淡出时不会闪出一枚勾。
18
+ *
19
+ * 尺寸读节点上的 --xh-icon-size(方框边长 × 0.75,由各皮肤按方框的尺改接);
20
+ * 选择器只让 [data-xh-check-mark] 计入特指度,状态与形态包在 :where() 里,皮肤按部件覆盖即可压过。
21
+ */
22
+ @layer xihan.components {
23
+ [data-xh-check-mark]:where([data-xh-check-mark-profile='box']):empty::before,
24
+ [data-xh-check-mark]:where([data-xh-check-mark-profile='row'])::after {
25
+ content: '';
26
+ display: inline-block;
27
+ flex: none;
28
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
29
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
30
+ vertical-align: var(--xh-glyph-baseline-shift);
31
+ background-color: var(--xh-check-mark-fg, currentColor);
32
+ opacity: 0;
33
+ scale: var(--xh-motion-scale-enter);
34
+ pointer-events: none;
35
+ -webkit-mask: var(--xh-glyph-mark-check) center / 100% 100% no-repeat, var(--xh-glyph-mark-minus) center / 0 0 no-repeat;
36
+ mask: var(--xh-glyph-mark-check) center / 100% 100% no-repeat, var(--xh-glyph-mark-minus) center / 0 0 no-repeat;
37
+ transition:
38
+ opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
39
+ scale var(--xh-motion-duration-nudge) var(--xh-motion-ease-enter-strong),
40
+ -webkit-mask-size 0s var(--xh-motion-duration-micro),
41
+ mask-size 0s var(--xh-motion-duration-micro);
42
+ }
43
+
44
+ /* 行里的方框是行首那颗 ::before:标记按「方框与标记的边长差之半」内推即落在方框正中,纵向靠
45
+ inset-block: 0 + margin-block: auto 居中。粗指针下 Action Control 在同一个 ::after 上铺的热区
46
+ (起点 50%、44px 下限、-50% 平移)在这里逐项钉回,标记不被拖走、也不被撑大 */
47
+ [data-xh-check-mark]:where([data-xh-check-mark-profile='row'])::after {
48
+ position: absolute;
49
+ inset-block: 0;
50
+ inset-inline-start: 0;
51
+ min-inline-size: 0;
52
+ min-block-size: 0;
53
+ margin-block: auto;
54
+ margin-inline-start: calc(
55
+ (var(--xh-check-mark-box-size, var(--xh-control-indicator-size)) - var(--xh-icon-size, var(--xh-glyph-size-text))) / 2
56
+ );
57
+ translate: none;
58
+ }
59
+
60
+ [data-xh-check-mark]:where([data-xh-check-mark='checked'], [data-xh-check-mark='indeterminate']):where([data-xh-check-mark-profile='box']):empty::before,
61
+ [data-xh-check-mark]:where([data-xh-check-mark='checked'], [data-xh-check-mark='indeterminate']):where([data-xh-check-mark-profile='row'])::after {
62
+ opacity: 1;
63
+ scale: 1;
64
+ transition-delay: 0s;
65
+ }
66
+
67
+ /* 半选:aria-checked=mixed 在视觉上也得与全选分得开,横杠与勾同走字形令牌 */
68
+ [data-xh-check-mark]:where([data-xh-check-mark='indeterminate']):where([data-xh-check-mark-profile='box']):empty::before,
69
+ [data-xh-check-mark]:where([data-xh-check-mark='indeterminate']):where([data-xh-check-mark-profile='row'])::after {
70
+ -webkit-mask-size: 0 0, 100% 100%;
71
+ mask-size: 0 0, 100% 100%;
72
+ }
73
+
74
+ /* 强制色:遮罩保留字形轮廓,标记退出强制换色、直接写系统前景(不能取 currentColor:退出强制换色的伪元素
75
+ 读到的是被系统换掉之前的作者色);禁用取置灰前景。
76
+ 节点自己就是一颗动作控件的方框(Table 的勾选把手):悬停与按下时家族把方框涂成 Highlight,标记跟着换 HighlightText。
77
+ 方框另有实心面的(CheckboxGroup、Transfer 的勾选盒,行档的方框)在这一档里是 Canvas,整行悬停不换面,不在此列 */
78
+ @media (forced-colors: active) {
79
+ [data-xh-check-mark]:where([data-xh-check-mark-profile='box']):empty::before,
80
+ [data-xh-check-mark]:where([data-xh-check-mark-profile='row'])::after {
81
+ forced-color-adjust: none;
82
+ background-color: CanvasText;
83
+ }
84
+
85
+ [data-xh-check-mark][data-xh-action-control]:where([data-xh-check-mark-profile='box']):where(:not([data-disabled]):not([data-loading])):is(:hover, :active, [data-pressed]):empty::before {
86
+ background-color: HighlightText;
87
+ }
88
+
89
+ [data-xh-check-mark]:where([data-disabled]):where([data-xh-check-mark-profile='box']):empty::before,
90
+ [data-xh-check-mark]:where([data-disabled]):where([data-xh-check-mark-profile='row'])::after {
91
+ background-color: GrayText;
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,97 @@
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
+ * 选择卡片家族配方:RadioGroup 与 CheckboxGroup 的 card 档条目共用一副卡面——一张可点的描边卡,
8
+ * 行首照旧是圆圈 / 方框,文案与说明排在它右侧,整张卡是命中区。
9
+ *
10
+ * 连接层在 card 档条目上投影 data-xh-choice-card,并把 Action Control 的形态换成 outline(row 档照旧:
11
+ * 宽度由容器给、高度随内容、按下只换面不缩放)。配方只管卡面:
12
+ * 形状取 surface(8px),内衬 space-3 / space-4;
13
+ * 未选中是描边卡:透明底 + --xh-border-control,白底承载阶梯 100 → 200,不随语气染色;
14
+ * 选中是「页内持久集合的选中」那一种标记:卡面换品牌淡底 12 → 悬停 20 → 按压 28、前景 fg-on-brand-subtle,
15
+ * 写了 data-tone 时换成语气淡底;描边不换,行首的圆点 / 勾照常表达选中;
16
+ * 只读不给悬停与按下面,选中面照常;禁用走家族禁用面,选中又禁用时底色掺一半中性面,选中信息不丢。
17
+ *
18
+ * 选择器带上 [data-scope][data-part]:皮肤里条目的基础规则写的是 (0,2,0),配方排在皮肤之前,
19
+ * 同权重时皮肤赢;卡面要压过列表档的那几条(边归零、内衬归零、圆角取 control)。
20
+ */
21
+ @layer xihan.components {
22
+ [data-scope][data-part][data-xh-choice-card] {
23
+ --xh-action-radius: var(--xh-shape-surface);
24
+ --xh-action-padding-inline: var(--xh-space-4);
25
+ --xh-action-padding-block: var(--xh-space-3);
26
+ --xh-action-bg-rest: transparent;
27
+ --xh-action-bg-hover: var(--xh-bg-subtle);
28
+ --xh-action-bg-pressed: var(--xh-bg-subtle-hover);
29
+ --xh-action-bg-focus-visible: transparent;
30
+ --xh-action-bg-disabled: var(--xh-bg-subtle);
31
+ --xh-action-border-rest: var(--xh-border-control);
32
+ --xh-action-border-hover: var(--xh-border-control-hover);
33
+ --xh-action-border-pressed: var(--xh-border-control-hover);
34
+ --xh-action-border-focus-visible: var(--xh-border-control);
35
+ --xh-action-border-disabled: var(--xh-border-default);
36
+
37
+ /* 行首标记一列、文案一列;说明落在文案下方同一列(皮肤给说明写 grid-column: 2) */
38
+ display: grid;
39
+ grid-template-columns: auto minmax(0, 1fr);
40
+ align-items: center;
41
+ row-gap: var(--xh-space-1);
42
+ border-width: var(--xh-stroke-thin);
43
+ line-height: var(--xh-leading-normal);
44
+ }
45
+
46
+ [data-scope][data-part][data-xh-choice-card][data-state='checked'] {
47
+ --xh-action-bg-rest: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
48
+ --xh-action-bg-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-brand-subtle-hover));
49
+ --xh-action-bg-pressed: var(--xh-_tone-subtle-active, var(--xh-bg-brand-subtle-active));
50
+ --xh-action-bg-focus-visible: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
51
+ /* 掺的是淡底的不透明档:墨色淡底半透明,掺进去整块面会跟着变半透明 */
52
+ --xh-action-bg-disabled: color-mix(in oklab, var(--xh-_tone-subtle, var(--xh-bg-brand-subtle)) 50%, var(--xh-bg-subtle-opaque));
53
+ --xh-action-fg-rest: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
54
+ --xh-action-fg-hover: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
55
+ --xh-action-fg-pressed: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
56
+ --xh-action-fg-focus-visible: var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle));
57
+ }
58
+
59
+ /* 只读改不动:悬停与按下都停在静息面上(选中卡仍是淡底),收回可点的手型 */
60
+ [data-scope][data-part][data-xh-choice-card][data-readonly]:not([data-disabled]) {
61
+ --xh-action-bg-hover: transparent;
62
+ --xh-action-bg-pressed: transparent;
63
+ --xh-action-border-hover: var(--xh-border-control);
64
+ --xh-action-border-pressed: var(--xh-border-control);
65
+ --xh-action-cursor-rest: default;
66
+ --xh-action-cursor-hover: default;
67
+ --xh-action-cursor-pressed: default;
68
+ --xh-action-cursor-focus-visible: default;
69
+ }
70
+
71
+ [data-scope][data-part][data-xh-choice-card][data-readonly][data-state='checked']:not([data-disabled]) {
72
+ --xh-action-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
73
+ --xh-action-bg-pressed: var(--xh-_tone-subtle, var(--xh-bg-brand-subtle));
74
+ }
75
+
76
+ /* 卡面本身已够大:粗指针下不再把命中区外扩到 44px 高,外扩会压进相邻的卡 */
77
+ @media (pointer: coarse) {
78
+ [data-scope][data-part][data-xh-choice-card]::after {
79
+ min-block-size: 0;
80
+ }
81
+ }
82
+
83
+ /* 强制色:底色一律换成 Canvas,选中卡的淡底看不见了,描边换系统高亮色表出选中 */
84
+ @media (forced-colors: active) {
85
+ [data-scope][data-part][data-xh-choice-card][data-state='checked'] {
86
+ border-color: Highlight;
87
+ }
88
+ }
89
+
90
+ /* 打印丢底色:选中卡的淡底落不到纸上,描边加粗一档表出选中 */
91
+ @media print {
92
+ [data-scope][data-part][data-xh-choice-card][data-state='checked'] {
93
+ border-width: var(--xh-stroke-thick);
94
+ border-color: currentColor;
95
+ }
96
+ }
97
+ }
@@ -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'] {
@@ -116,10 +118,12 @@
116
118
  grid-column: suffix;
117
119
  }
118
120
 
121
+ /* 对号常驻在 indicator 列、未选中时透明:按选中态淡变,不按 visibility 瞬切 */
119
122
  [data-xh-collection-slot='indicator'] {
120
123
  grid-column: indicator;
121
124
  color: var(--xh-_collection-indicator-fg);
122
- visibility: hidden;
125
+ opacity: 0;
126
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
123
127
  }
124
128
 
125
129
  [data-xh-collection-slot='shortcut'],
@@ -455,7 +459,7 @@
455
459
  }
456
460
 
457
461
  [data-xh-collection-item]:is([aria-selected='true'], [data-state='checked']) [data-xh-collection-slot='indicator'] {
458
- visibility: visible;
462
+ opacity: 1;
459
463
  }
460
464
 
461
465
  [data-xh-collection-item][data-state='checked'] {
@@ -508,16 +512,6 @@
508
512
  display: none;
509
513
  }
510
514
 
511
- :where([data-motion='reduce']) [data-xh-collection-item] {
512
- transition: none;
513
- }
514
-
515
- @media (prefers-reduced-motion: reduce) {
516
- [data-xh-collection-item] {
517
- transition: none;
518
- }
519
- }
520
-
521
515
  @media (forced-colors: active) {
522
516
  [data-xh-collection-item] {
523
517
  --xh-_collection-bg: Canvas;
@@ -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
+ }