@xihan-ui/styles 1.0.0-alpha.2 → 1.0.0-alpha.3

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 (118) hide show
  1. package/CHANGELOG.md +447 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +56 -5
  4. package/css/alert.css +30 -5
  5. package/css/anchor.css +7 -7
  6. package/css/avatar-group.css +3 -3
  7. package/css/avatar.css +3 -3
  8. package/css/back-top.css +16 -1
  9. package/css/badge.css +16 -2
  10. package/css/breadcrumb.css +24 -4
  11. package/css/button-group.css +14 -13
  12. package/css/button.css +42 -11
  13. package/css/calendar.css +119 -2
  14. package/css/card.css +5 -5
  15. package/css/carousel.css +36 -5
  16. package/css/cascader.css +183 -102
  17. package/css/checkbox-group.css +41 -19
  18. package/css/checkbox.css +54 -8
  19. package/css/clipboard.css +2 -1
  20. package/css/code-block.css +12 -7
  21. package/css/collapsible.css +42 -2
  22. package/css/color-picker.css +111 -45
  23. package/css/combobox.css +114 -53
  24. package/css/composer.css +5 -3
  25. package/css/context-menu.css +97 -69
  26. package/css/date-field.css +91 -14
  27. package/css/date-picker.css +276 -65
  28. package/css/descriptions.css +2 -2
  29. package/css/dialog.css +40 -13
  30. package/css/download-trigger.css +76 -0
  31. package/css/drawer.css +45 -14
  32. package/css/dynamic-input.css +68 -17
  33. package/css/editable.css +12 -10
  34. package/css/ellipsis.css +1 -1
  35. package/css/empty-state.css +7 -7
  36. package/css/field.css +9 -6
  37. package/css/fieldset.css +69 -0
  38. package/css/file-upload.css +45 -7
  39. package/css/float-button.css +16 -1
  40. package/css/floating-panel.css +310 -0
  41. package/css/form.css +4 -4
  42. package/css/heatmap.css +410 -0
  43. package/css/highlight.css +1 -1
  44. package/css/hotkeys.css +90 -0
  45. package/css/hover-card.css +40 -45
  46. package/css/image-cropper.css +231 -0
  47. package/css/image-viewer.css +137 -12
  48. package/css/image.css +2 -2
  49. package/css/infinite-scroll.css +1 -1
  50. package/css/json-viewer.css +241 -0
  51. package/css/layout.css +6 -10
  52. package/css/list.css +8 -8
  53. package/css/listbox.css +20 -4
  54. package/css/loading-bar.css +7 -1
  55. package/css/log.css +1 -1
  56. package/css/marquee.css +9 -0
  57. package/css/masonry.css +63 -0
  58. package/css/mention.css +87 -33
  59. package/css/menu.css +113 -47
  60. package/css/menubar.css +146 -60
  61. package/css/navigation-menu.css +54 -29
  62. package/css/number-animation.css +3 -3
  63. package/css/number-field.css +173 -16
  64. package/css/overlay-arrow.css +51 -0
  65. package/css/page-header.css +5 -5
  66. package/css/pagination.css +13 -13
  67. package/css/password-input.css +356 -0
  68. package/css/pin-input.css +13 -10
  69. package/css/popconfirm.css +46 -10
  70. package/css/popover.css +70 -45
  71. package/css/popselect.css +183 -53
  72. package/css/progress.css +47 -7
  73. package/css/qr-code.css +1 -1
  74. package/css/radio-group.css +14 -8
  75. package/css/rating.css +2 -2
  76. package/css/reset.css +17 -0
  77. package/css/result.css +6 -6
  78. package/css/scroll-area.css +61 -89
  79. package/css/scrollbar.css +167 -0
  80. package/css/segmented.css +215 -0
  81. package/css/select.css +274 -125
  82. package/css/separator.css +2 -2
  83. package/css/side-nav.css +111 -19
  84. package/css/signature-pad.css +144 -0
  85. package/css/skeleton.css +7 -1
  86. package/css/slider.css +10 -10
  87. package/css/space.css +117 -0
  88. package/css/spinner.css +22 -10
  89. package/css/statistic.css +9 -9
  90. package/css/steps.css +25 -8
  91. package/css/switch.css +48 -6
  92. package/css/table.css +131 -37
  93. package/css/tabs.css +4 -4
  94. package/css/tag.css +177 -0
  95. package/css/tags-input.css +78 -40
  96. package/css/text-field.css +149 -36
  97. package/css/thread.css +1 -1
  98. package/css/time-field.css +97 -16
  99. package/css/time-picker.css +259 -69
  100. package/css/timeline.css +10 -10
  101. package/css/timer.css +119 -0
  102. package/css/toast.css +34 -10
  103. package/css/toaster.css +1 -1
  104. package/css/toggle.css +6 -6
  105. package/css/tone.css +10 -5
  106. package/css/toolbar.css +1 -1
  107. package/css/tooltip.css +36 -33
  108. package/css/tour.css +103 -58
  109. package/css/transfer.css +68 -17
  110. package/css/tree-select.css +185 -84
  111. package/css/tree.css +85 -1
  112. package/css/typography.css +4 -4
  113. package/css/undefined.css +11 -1
  114. package/css/virtualizer.css +3 -1
  115. package/css/watermark.css +1 -2
  116. package/index.css +17 -0
  117. package/index.unlayered.css +8659 -2799
  118. package/package.json +19 -3
package/css/alert.css CHANGED
@@ -5,6 +5,9 @@
5
5
  }
6
6
 
7
7
  [data-scope='alert'][data-part='root'] {
8
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
9
+ --xh-icon-size: var(--xh-alert-icon-size, var(--xh-glyph-size-text));
10
+
8
11
  /* 强调色随语气走,底色/描边/图标色都由它推导出来,换语气不必逐条属性各写一遍。
9
12
  没写 data-tone 时 --xh-_tone 没被声明,退回原来的 info 蓝 */
10
13
  --xh-_alert-accent: var(--xh-_tone-soft, var(--xh-color-info-500));
@@ -24,7 +27,7 @@
24
27
  border-radius: var(--xh-alert-radius, var(--xh-shape-surface));
25
28
  background: var(--xh-alert-bg, var(--xh-_alert-tint));
26
29
  color: var(--xh-alert-fg, var(--xh-fg-default));
27
- font-size: var(--xh-alert-font-size, var(--xh-font-size-md));
30
+ font-size: var(--xh-alert-font-size, var(--xh-text-body-size));
28
31
  line-height: var(--xh-alert-leading, var(--xh-leading-normal));
29
32
  }
30
33
 
@@ -40,7 +43,7 @@
40
43
  justify-content: center;
41
44
  flex: none;
42
45
  /* 与首行文字对齐:图标框高取一行正文的行高 */
43
- block-size: calc(var(--xh-font-size-md) * var(--xh-leading-normal));
46
+ block-size: calc(var(--xh-text-body-size) * var(--xh-leading-normal));
44
47
  inline-size: var(--xh-alert-icon-size, var(--xh-control-indicator-size));
45
48
  color: var(--xh-alert-icon-fg, var(--xh-_alert-accent));
46
49
  }
@@ -56,7 +59,7 @@
56
59
  [data-scope='alert'][data-part='title'] {
57
60
  flex: 1 1 auto;
58
61
  color: var(--xh-alert-title-fg, var(--xh-fg-default));
59
- font-size: var(--xh-alert-title-font-size, var(--xh-font-size-md));
62
+ font-size: var(--xh-alert-title-font-size, var(--xh-text-label-size));
60
63
  font-weight: var(--xh-alert-title-font-weight, var(--xh-font-weight-semibold));
61
64
  line-height: var(--xh-alert-title-leading, var(--xh-leading-tight));
62
65
  }
@@ -64,7 +67,7 @@
64
67
  [data-scope='alert'][data-part='description'] {
65
68
  flex: 1 1 100%;
66
69
  color: var(--xh-alert-description-fg, var(--xh-fg-muted));
67
- font-size: var(--xh-alert-description-font-size, var(--xh-font-size-sm));
70
+ font-size: var(--xh-alert-description-font-size, var(--xh-text-secondary-size));
68
71
  }
69
72
 
70
73
  /* 没写标题时说明自己占满这一行,否则它会挤在标题旁边 */
@@ -89,6 +92,10 @@
89
92
  font: inherit;
90
93
  line-height: var(--xh-leading-none);
91
94
  cursor: pointer;
95
+ transition:
96
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
97
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
98
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
92
99
  }
93
100
 
94
101
  /* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半 */
@@ -96,11 +103,17 @@
96
103
  display: none;
97
104
  }
98
105
 
106
+ /* 悬停与按下的底色跟着语气走:提示本体已是该语气的淡底,叉的底色在同一色系里再深两档 */
99
107
  [data-scope='alert'][data-part='close-trigger']:hover:not(:disabled) {
100
- background: color-mix(in oklab, var(--xh-_alert-accent) 16%, transparent);
108
+ background: var(--xh-alert-close-bg-hover, var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover)));
101
109
  color: var(--xh-alert-close-fg-hover, var(--xh-fg-default));
102
110
  }
103
111
 
112
+ [data-scope='alert'][data-part='close-trigger']:active {
113
+ background: var(--xh-alert-close-bg-active, var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active)));
114
+ scale: var(--xh-motion-scale-press);
115
+ }
116
+
104
117
  [data-scope='alert'][data-part='close-trigger']:disabled {
105
118
  color: var(--xh-fg-disabled);
106
119
  cursor: not-allowed;
@@ -110,4 +123,16 @@
110
123
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
111
124
  outline-offset: var(--xh-ring-offset);
112
125
  }
126
+
127
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
128
+ [data-scope='alert'][data-part='close-trigger']:empty::before {
129
+ content: '';
130
+ display: inline-block;
131
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
132
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
133
+ vertical-align: var(--xh-glyph-baseline-shift);
134
+ background-color: currentColor;
135
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
136
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
137
+ }
113
138
  }
package/css/anchor.css CHANGED
@@ -9,7 +9,7 @@
9
9
  [data-scope='anchor'][data-part='root'] {
10
10
  /* 尺寸档只换这两个私有槽,链接从 root 继承它们,换档不必给每个部件各写一条选择器 */
11
11
  --xh-_anchor-font-size: var(--xh-text-label-size);
12
- --xh-_anchor-link-px: var(--xh-space-3);
12
+ --xh-_anchor-link-px: var(--xh-control-px-md);
13
13
  /* 当前那一节的指示条与文字随语气走。没写 data-tone 时这两个槽都没被声明,退回原来的品牌色。
14
14
  指示条是装饰性的色条,取柔和档;文字要压在普通背景上读,取语气的文字档。
15
15
  聚焦环不在其列,它恒是 --xh-ring-focus */
@@ -22,14 +22,14 @@
22
22
  }
23
23
 
24
24
  /* —— 尺寸 —— */
25
- /* 缺省档写在上面的基础规则里;链接的内边距走控件内边距那把尺,缺省的 --xh-space-3 即它的中档 */
25
+ /* 缺省档写在上面的基础规则里;链接的内边距三档都走控件内边距那把尺 */
26
26
  [data-scope='anchor'][data-part='root'][data-size='sm'] {
27
- --xh-_anchor-font-size: var(--xh-font-size-sm);
27
+ --xh-_anchor-font-size: var(--xh-control-font-sm);
28
28
  --xh-_anchor-link-px: var(--xh-control-px-sm);
29
29
  }
30
30
 
31
31
  [data-scope='anchor'][data-part='root'][data-size='lg'] {
32
- --xh-_anchor-font-size: var(--xh-font-size-lg);
32
+ --xh-_anchor-font-size: var(--xh-control-font-lg);
33
33
  --xh-_anchor-link-px: var(--xh-control-px-lg);
34
34
  }
35
35
 
@@ -76,7 +76,7 @@
76
76
  display: inline-flex;
77
77
  align-items: center;
78
78
  /* 一节的标题可能很长,压不住会把整列撑开 */
79
- max-inline-size: var(--xh-anchor-link-max-w, 14rem);
79
+ max-inline-size: var(--xh-anchor-link-max-w, var(--xh-nav-link-max-w));
80
80
  padding-block: var(--xh-anchor-link-py, var(--xh-space-1));
81
81
  padding-inline: var(--xh-anchor-link-px, var(--xh-_anchor-link-px));
82
82
  border-radius: var(--xh-anchor-link-radius, var(--xh-shape-control));
@@ -103,7 +103,7 @@
103
103
 
104
104
  /* 当前那一节:颜色与字重都跟着变,不只靠指示条——
105
105
  指示条是可选部件,作者不渲染它时"当前在哪"仍然要看得出来 */
106
- [data-scope='anchor'][data-part='link'][data-active] {
106
+ [data-scope='anchor'][data-part='link'][data-current] {
107
107
  color: var(--xh-anchor-link-fg-active, var(--xh-_anchor-accent-text));
108
108
  font-weight: var(--xh-anchor-link-font-weight-active, var(--xh-font-weight-medium));
109
109
  }
@@ -117,7 +117,7 @@
117
117
  margin: 0;
118
118
  inset-inline-start: calc(var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick)) * -1);
119
119
  inline-size: var(--xh-anchor-indicator-thickness, var(--xh-stroke-thick));
120
- border-radius: var(--xh-anchor-indicator-radius, var(--xh-radius-full));
120
+ border-radius: var(--xh-anchor-indicator-radius, var(--xh-shape-pill));
121
121
  background: var(--xh-anchor-indicator-color, var(--xh-_anchor-accent));
122
122
  transition:
123
123
  inset-block-start var(--xh-motion-duration-enter) var(--xh-motion-ease-enter),
@@ -9,7 +9,7 @@
9
9
  [data-scope='avatar-group'][data-part='root'] {
10
10
  /* 私有槽位:整组共用的直径、字号与叠放量,换档只改这三个 */
11
11
  --xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-md));
12
- --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-sm));
12
+ --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-text-secondary-size));
13
13
  --xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-2_5));
14
14
 
15
15
  /* 流给组内每一枚 */
@@ -31,13 +31,13 @@
31
31
  字号与叠放量跟着直径一起缩放,小头像里回退字放得下、大头像里压住的那段也按比例长 */
32
32
  [data-scope='avatar-group'][data-part='root'][data-size='sm'] {
33
33
  --xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-sm));
34
- --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-xs));
34
+ --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-control-caption-sm));
35
35
  --xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-2));
36
36
  }
37
37
 
38
38
  [data-scope='avatar-group'][data-part='root'][data-size='lg'] {
39
39
  --xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-lg));
40
- --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-font-size-md));
40
+ --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-control-caption-lg));
41
41
  --xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-3));
42
42
  }
43
43
 
package/css/avatar.css CHANGED
@@ -16,7 +16,7 @@
16
16
  border-radius: var(--xh-avatar-radius, var(--xh-shape-pill));
17
17
  background: var(--xh-avatar-bg, var(--xh-bg-subtle));
18
18
  color: var(--xh-avatar-fg, var(--xh-fg-muted));
19
- font-size: var(--xh-avatar-font-size, var(--xh-font-size-sm));
19
+ font-size: var(--xh-avatar-font-size, var(--xh-text-secondary-size));
20
20
  font-weight: var(--xh-avatar-font-weight, var(--xh-font-weight-medium));
21
21
  line-height: var(--xh-leading-none);
22
22
  user-select: none;
@@ -27,13 +27,13 @@
27
27
  [data-scope='avatar'][data-part='root'][data-size='sm'] {
28
28
  inline-size: var(--xh-control-h-sm);
29
29
  block-size: var(--xh-control-h-sm);
30
- font-size: var(--xh-font-size-xs);
30
+ font-size: var(--xh-control-caption-sm);
31
31
  }
32
32
 
33
33
  [data-scope='avatar'][data-part='root'][data-size='lg'] {
34
34
  inline-size: var(--xh-control-h-lg);
35
35
  block-size: var(--xh-control-h-lg);
36
- font-size: var(--xh-font-size-md);
36
+ font-size: var(--xh-control-caption-lg);
37
37
  }
38
38
 
39
39
  /* 不声明 display,加载完成前的 hidden 直接交给浏览器的 [hidden] 规则收起 */
package/css/back-top.css CHANGED
@@ -7,6 +7,9 @@
7
7
  /* 定位壳:钉在视口的尾下角,用逻辑属性,RTL 下自动换到另一侧。
8
8
  不声明 display —— 收起态由连接层写 hidden,UA 的 [hidden]{display:none} 得压得住 */
9
9
  [data-scope='back-top'][data-part='root'] {
10
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
11
+ --xh-icon-size: var(--xh-back-top-icon-size, var(--xh-glyph-size-text));
12
+
10
13
  /* 尺寸档只换这一个私有槽,按钮从壳继承,换档不必给每个部件各写一条选择器 */
11
14
  --xh-_back-top-size: var(--xh-control-h-md);
12
15
 
@@ -39,7 +42,7 @@
39
42
  background: var(--xh-back-top-bg, var(--xh-bg-surface-raised));
40
43
  color: var(--xh-back-top-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
41
44
  /* 浮在内容之上,靠投影与页面拉开层次 */
42
- box-shadow: var(--xh-elevation-2);
45
+ box-shadow: var(--xh-back-top-shadow, var(--xh-elevation-sheet));
43
46
  cursor: pointer;
44
47
  transition:
45
48
  background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
@@ -63,4 +66,16 @@
63
66
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
64
67
  outline-offset: var(--xh-ring-offset);
65
68
  }
69
+
70
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
71
+ [data-scope='back-top'][data-part='trigger']:empty::before {
72
+ content: '';
73
+ display: inline-block;
74
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
75
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
76
+ vertical-align: var(--xh-glyph-baseline-shift);
77
+ background-color: currentColor;
78
+ -webkit-mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
79
+ mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
80
+ }
66
81
  }
package/css/badge.css CHANGED
@@ -14,12 +14,26 @@
14
14
  border-radius: var(--xh-shape-pill);
15
15
  background: var(--xh-badge-bg, var(--xh-bg-subtle));
16
16
  color: var(--xh-badge-fg, var(--xh-fg-default));
17
- font-size: var(--xh-badge-font-size, var(--xh-font-size-xs));
17
+ font-size: var(--xh-badge-font-size, var(--xh-text-caption-size));
18
18
  font-weight: var(--xh-badge-font-weight, var(--xh-font-weight-medium));
19
19
  line-height: var(--xh-leading-none);
20
20
  white-space: nowrap;
21
21
  }
22
22
 
23
+ /* 声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
24
+ 计数为 0 且没开 showZero 时连接层会发 hidden */
25
+ [data-scope='badge'][data-part='root'][hidden] {
26
+ display: none;
27
+ }
28
+
29
+ /* 圆点形态:只表示「有」,不表示「有几个」——收掉内边距与文字盒 */
30
+ [data-scope='badge'][data-part='root'][data-dot] {
31
+ inline-size: var(--xh-badge-dot-size, var(--xh-space-2));
32
+ block-size: var(--xh-badge-dot-size, var(--xh-space-2));
33
+ padding: 0;
34
+ font-size: 0;
35
+ }
36
+
23
37
  /* —— 变体 —— */
24
38
  /* 形态只决定颜色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的品牌/中性配色 */
25
39
  [data-scope='badge'][data-part='root'][data-variant='solid'] {
@@ -50,6 +64,6 @@
50
64
  gap: var(--xh-space-1_5);
51
65
  padding-inline: var(--xh-space-3);
52
66
  padding-block: var(--xh-space-1);
53
- font-size: var(--xh-font-size-sm);
67
+ font-size: var(--xh-text-secondary-size);
54
68
  }
55
69
  }
@@ -7,6 +7,9 @@
7
7
  /* 根节点是 nav 地标,不参与排版:整条路径的行为全在 list 上,
8
8
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
9
9
  [data-scope='breadcrumb'][data-part='root'] {
10
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
11
+ --xh-icon-size: var(--xh-breadcrumb-icon-size, var(--xh-glyph-size-text));
12
+
10
13
  /* 尺寸档只换这两个私有槽,列表与链接都从 root 继承它们,换档不必给每个部件各写一条选择器 */
11
14
  --xh-_breadcrumb-font-size: var(--xh-text-label-size);
12
15
  --xh-_breadcrumb-gap: var(--xh-space-2);
@@ -23,12 +26,12 @@
23
26
  /* 缺省档写在上面的基础规则里。间距量的是路径里文字与分隔符之间的距离,
24
27
  不在控件间距那把尺上(那把尺的大档与中档同值),三档一律取空间尺 */
25
28
  [data-scope='breadcrumb'][data-part='root'][data-size='sm'] {
26
- --xh-_breadcrumb-font-size: var(--xh-font-size-sm);
29
+ --xh-_breadcrumb-font-size: var(--xh-control-font-sm);
27
30
  --xh-_breadcrumb-gap: var(--xh-space-1_5);
28
31
  }
29
32
 
30
33
  [data-scope='breadcrumb'][data-part='root'][data-size='lg'] {
31
- --xh-_breadcrumb-font-size: var(--xh-font-size-lg);
34
+ --xh-_breadcrumb-font-size: var(--xh-control-font-lg);
32
35
  --xh-_breadcrumb-gap: var(--xh-space-3);
33
36
  }
34
37
 
@@ -66,7 +69,7 @@
66
69
  align-items: center;
67
70
  gap: var(--xh-breadcrumb-link-gap, var(--xh-space-1));
68
71
  /* 一层的名字可能很长(文档标题、订单号),压不住会把整条路径撑开 */
69
- max-inline-size: var(--xh-breadcrumb-link-max-w, 12rem);
72
+ max-inline-size: var(--xh-breadcrumb-link-max-w, var(--xh-nav-link-max-w));
70
73
  padding-inline: var(--xh-breadcrumb-link-px, var(--xh-space-1));
71
74
  border-radius: var(--xh-breadcrumb-link-radius, var(--xh-shape-control));
72
75
  color: inherit;
@@ -122,11 +125,28 @@
122
125
 
123
126
  /* 分隔符常常是个图标:给一个跟着字号走的方框,斜杠与图标混用时基线才不跳 */
124
127
  [data-scope='breadcrumb'][data-part='separator'] {
125
- inline-size: var(--xh-breadcrumb-separator-size, 1em);
128
+ inline-size: var(--xh-breadcrumb-separator-size, var(--xh-glyph-size-text));
126
129
  }
127
130
 
128
131
  [data-scope='breadcrumb'][data-part='ellipsis'] {
129
132
  inline-size: var(--xh-breadcrumb-ellipsis-size, var(--xh-space-5));
130
133
  cursor: default;
131
134
  }
135
+
136
+ /* 没写内容就由皮肤画兜底字形(向前的尖角);作者写了斜杠或自己的图形,这条即不命中 */
137
+ [data-scope='breadcrumb'][data-part='separator']:empty::before {
138
+ content: '';
139
+ display: inline-block;
140
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
141
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
142
+ vertical-align: var(--xh-glyph-baseline-shift);
143
+ background-color: currentColor;
144
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
145
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
146
+ }
147
+
148
+ /* 从右往左排版时「向前」在左边 */
149
+ [dir='rtl'] [data-scope='breadcrumb'][data-part='separator']:empty::before {
150
+ rotate: 180deg;
151
+ }
132
152
  }
@@ -30,26 +30,27 @@
30
30
 
31
31
  /* —— 尺寸 —— */
32
32
  /* 高度、内边距、间距、字号在容器上写一次,沿继承流给组内每一段。
33
- 三档都写出来:自定义属性会一路继承,组里再套一组时内层不写就会沿用外层的档 */
33
+ 三档都写出来:自定义属性会一路继承,组里再套一组时内层不写就会沿用外层的档。
34
+ 写私有槽而非 --xh-button-*:后者是使用者的入口,组内某一枚自己写了档位时要压得住容器 */
34
35
  [data-scope='button-group'][data-part='root'][data-size='sm'] {
35
- --xh-button-h: var(--xh-control-h-sm);
36
- --xh-button-px: var(--xh-control-px-sm);
37
- --xh-button-gap: var(--xh-control-gap-sm);
38
- --xh-button-font-size: var(--xh-font-size-sm);
36
+ --xh-_button-group-h: var(--xh-control-h-sm);
37
+ --xh-_button-group-px: var(--xh-control-px-sm);
38
+ --xh-_button-group-gap: var(--xh-control-gap-sm);
39
+ --xh-_button-group-font-size: var(--xh-control-font-sm);
39
40
  }
40
41
 
41
42
  [data-scope='button-group'][data-part='root'][data-size='md'] {
42
- --xh-button-h: var(--xh-control-h-md);
43
- --xh-button-px: var(--xh-control-px-md);
44
- --xh-button-gap: var(--xh-control-gap-md);
45
- --xh-button-font-size: var(--xh-font-size-md);
43
+ --xh-_button-group-h: var(--xh-control-h-md);
44
+ --xh-_button-group-px: var(--xh-control-px-md);
45
+ --xh-_button-group-gap: var(--xh-control-gap-md);
46
+ --xh-_button-group-font-size: var(--xh-control-font-md);
46
47
  }
47
48
 
48
49
  [data-scope='button-group'][data-part='root'][data-size='lg'] {
49
- --xh-button-h: var(--xh-control-h-lg);
50
- --xh-button-px: var(--xh-control-px-lg);
51
- --xh-button-gap: var(--xh-control-gap-lg);
52
- --xh-button-font-size: var(--xh-font-size-lg);
50
+ --xh-_button-group-h: var(--xh-control-h-lg);
51
+ --xh-_button-group-px: var(--xh-control-px-lg);
52
+ --xh-_button-group-gap: var(--xh-control-gap-lg);
53
+ --xh-_button-group-font-size: var(--xh-control-font-lg);
53
54
  }
54
55
 
55
56
  /* —— 形态 —— */
package/css/button.css CHANGED
@@ -21,17 +21,21 @@
21
21
  --xh-_bg-active: var(--xh-button-bg-active, var(--xh-bg-subtle-active));
22
22
  --xh-_fg: var(--xh-button-fg, var(--xh-fg-default));
23
23
 
24
+ /* 作者塞进来的图标跟着按钮的尺寸档走:xh-icon 的直径读的就是这个继承槽,
25
+ 它自己显式写了 size 时特异性更高,仍以作者写的为准 */
26
+ --xh-icon-size: var(--xh-button-icon-size, var(--xh-glyph-size-md));
27
+
24
28
  display: inline-flex;
25
29
  align-items: center;
26
30
  justify-content: center;
27
- gap: var(--xh-button-gap, var(--xh-control-gap-md));
28
- block-size: var(--xh-button-h, var(--xh-control-h-md));
29
- padding-inline: var(--xh-button-px, var(--xh-control-px-md));
31
+ gap: var(--xh-button-gap, var(--xh-_button-group-gap, var(--xh-control-gap-md)));
32
+ block-size: var(--xh-button-h, var(--xh-_button-group-h, var(--xh-control-h-md)));
33
+ padding-inline: var(--xh-button-px, var(--xh-_button-group-px, var(--xh-control-px-md)));
30
34
  border: var(--xh-stroke-thin) solid transparent;
31
35
  border-radius: var(--xh-button-radius, var(--xh-shape-control));
32
36
  background: var(--xh-_bg);
33
37
  color: var(--xh-_fg);
34
- font-size: var(--xh-button-font-size, var(--xh-text-label-size));
38
+ font-size: var(--xh-button-font-size, var(--xh-_button-group-font-size, var(--xh-text-label-size)));
35
39
  font-weight: var(--xh-button-font-weight, var(--xh-text-label-weight));
36
40
  line-height: var(--xh-leading-none);
37
41
  white-space: nowrap;
@@ -95,19 +99,46 @@
95
99
 
96
100
  /* —— 尺寸 —— */
97
101
  [data-scope='button'][data-part='root'][data-size='sm'] {
98
- block-size: var(--xh-control-h-sm);
99
- padding-inline: var(--xh-control-px-sm);
100
- font-size: var(--xh-font-size-sm);
102
+ --xh-icon-size: var(--xh-button-icon-size, var(--xh-glyph-size-sm));
103
+
104
+ block-size: var(--xh-button-h, var(--xh-control-h-sm));
105
+ padding-inline: var(--xh-button-px, var(--xh-control-px-sm));
106
+ font-size: var(--xh-button-font-size, var(--xh-control-font-sm));
101
107
  }
102
108
 
103
109
  [data-scope='button'][data-part='root'][data-size='lg'] {
104
- block-size: var(--xh-control-h-lg);
105
- padding-inline: var(--xh-control-px-lg);
106
- font-size: var(--xh-font-size-lg);
110
+ --xh-icon-size: var(--xh-button-icon-size, var(--xh-glyph-size-lg));
111
+
112
+ block-size: var(--xh-button-h, var(--xh-control-h-lg));
113
+ padding-inline: var(--xh-button-px, var(--xh-control-px-lg));
114
+ font-size: var(--xh-button-font-size, var(--xh-control-font-lg));
115
+ }
116
+
117
+ /* 只有图标:左右内距清零,宽度靠比例跟住当前档的高度——换尺寸档时仍是正方形,
118
+ 不必把档位抄进行内样式。写在尺寸档之后,压得住三档各自的 padding-inline */
119
+ [data-scope='button'][data-part='root'][data-icon-only] {
120
+ padding-inline: 0;
121
+ aspect-ratio: 1;
122
+ }
123
+
124
+ [data-scope='button'][data-part='root'][data-full-width] {
125
+ inline-size: 100%;
107
126
  }
108
127
 
109
128
  [data-scope='button'][data-part='indicator'] {
110
129
  display: inline-flex;
111
- animation: xh-spin 0.6s linear infinite;
130
+ animation: xh-spin var(--xh-button-spin-duration, var(--xh-spin-duration)) linear infinite;
131
+ }
132
+
133
+ /* 减少动效:指示器停转,"还在忙"由按钮自身的挂起样式与指示器图标继续表达。
134
+ 两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
135
+ @media (prefers-reduced-motion: reduce) {
136
+ [data-scope='button'][data-part='indicator'] {
137
+ animation: none;
138
+ }
139
+ }
140
+
141
+ :where([data-motion='reduce']) [data-scope='button'][data-part='indicator'] {
142
+ animation: none;
112
143
  }
113
144
  }
package/css/calendar.css CHANGED
@@ -5,6 +5,9 @@
5
5
  }
6
6
 
7
7
  [data-scope='calendar'][data-part='root'] {
8
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
9
+ --xh-icon-size: var(--xh-calendar-icon-size, var(--xh-glyph-size-text));
10
+
8
11
  display: flex;
9
12
  flex-direction: column;
10
13
  gap: var(--xh-calendar-gap, var(--xh-space-3));
@@ -37,7 +40,49 @@
37
40
  user-select: none;
38
41
  }
39
42
 
43
+ /* 标题里的年与月:点它们逐级钻上去(年 → 十年格、月 → 月格)。
44
+ 长得像标题而不像按钮——它本来就是标题,只是可点 */
45
+ [data-scope='calendar'][data-part='heading-year-trigger']:not([hidden]),
46
+ [data-scope='calendar'][data-part='heading-month-trigger']:not([hidden]) {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ padding-inline: var(--xh-calendar-heading-trigger-px, var(--xh-space-1));
50
+ border: var(--xh-stroke-thin) solid transparent;
51
+ border-radius: var(--xh-calendar-heading-trigger-radius, var(--xh-shape-control));
52
+ background: transparent;
53
+ color: var(--xh-calendar-heading-fg, var(--xh-fg-default));
54
+ font-size: var(--xh-calendar-heading-font-size, var(--xh-text-label-size));
55
+ font-weight: var(--xh-calendar-heading-font-weight, var(--xh-font-weight-semibold));
56
+ line-height: var(--xh-leading-none);
57
+ cursor: pointer;
58
+ transition: color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
59
+ }
60
+
61
+ [data-scope='calendar'][data-part='heading-year-trigger'][hidden],
62
+ [data-scope='calendar'][data-part='heading-month-trigger'][hidden] {
63
+ display: none;
64
+ }
65
+
66
+ [data-scope='calendar'][data-part='heading-year-trigger']:hover:not(:disabled),
67
+ [data-scope='calendar'][data-part='heading-month-trigger']:hover:not(:disabled) {
68
+ color: var(--xh-calendar-heading-trigger-fg-hover, var(--xh-fg-brand));
69
+ }
70
+
71
+ /* 到顶那一层(年视图的年那一截)只作标题显示:不再是可点的东西,光标也别装成能点 */
72
+ [data-scope='calendar'][data-part='heading-year-trigger']:disabled,
73
+ [data-scope='calendar'][data-part='heading-month-trigger']:disabled {
74
+ cursor: default;
75
+ }
76
+
77
+ [data-scope='calendar'][data-part='heading-year-trigger']:focus-visible,
78
+ [data-scope='calendar'][data-part='heading-month-trigger']:focus-visible {
79
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
80
+ outline-offset: var(--xh-ring-offset);
81
+ }
82
+
83
+ [data-scope='calendar'][data-part='prev-year-trigger'],
40
84
  [data-scope='calendar'][data-part='prev-trigger'],
85
+ [data-scope='calendar'][data-part='next-year-trigger'],
41
86
  [data-scope='calendar'][data-part='next-trigger'] {
42
87
  display: inline-flex;
43
88
  flex: none;
@@ -53,25 +98,33 @@
53
98
  transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
54
99
  }
55
100
 
101
+ [data-scope='calendar'][data-part='prev-year-trigger'],
56
102
  [data-scope='calendar'][data-part='prev-trigger'][hidden],
103
+ [data-scope='calendar'][data-part='next-year-trigger'],
57
104
  [data-scope='calendar'][data-part='next-trigger'][hidden] {
58
105
  display: none;
59
106
  }
60
107
 
108
+ [data-scope='calendar'][data-part='prev-year-trigger'],
61
109
  [data-scope='calendar'][data-part='prev-trigger']:hover:not(:disabled),
110
+ [data-scope='calendar'][data-part='next-year-trigger'],
62
111
  [data-scope='calendar'][data-part='next-trigger']:hover:not(:disabled) {
63
112
  background: var(--xh-calendar-nav-bg-hover, var(--xh-bg-subtle-hover));
64
113
  color: var(--xh-fg-default);
65
114
  }
66
115
 
67
116
  /* 翻月是单体控件,禁用走原生 :disabled(连接层输出的正是原生 disabled) */
117
+ [data-scope='calendar'][data-part='prev-year-trigger'],
68
118
  [data-scope='calendar'][data-part='prev-trigger']:disabled,
119
+ [data-scope='calendar'][data-part='next-year-trigger'],
69
120
  [data-scope='calendar'][data-part='next-trigger']:disabled {
70
121
  color: var(--xh-fg-disabled);
71
122
  cursor: not-allowed;
72
123
  }
73
124
 
125
+ [data-scope='calendar'][data-part='prev-year-trigger'],
74
126
  [data-scope='calendar'][data-part='prev-trigger']:focus-visible,
127
+ [data-scope='calendar'][data-part='next-year-trigger'],
75
128
  [data-scope='calendar'][data-part='next-trigger']:focus-visible {
76
129
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
77
130
  outline-offset: var(--xh-ring-offset);
@@ -83,6 +136,27 @@
83
136
  gap: var(--xh-calendar-grid-gap, var(--xh-space-1));
84
137
  }
85
138
 
139
+ /* 粗粒度视图:格子直接铺进网格,不再有周行那一层。
140
+ 月 3 列 × 4 行、季度 4 列一行、年 3 列——与常见日期控件同一套排布 */
141
+ [data-scope='calendar'][data-part='grid'][data-view='month'],
142
+ [data-scope='calendar'][data-part='grid'][data-view='year'] {
143
+ display: grid;
144
+ grid-template-columns: repeat(3, minmax(0, 1fr));
145
+ gap: var(--xh-calendar-period-gap, var(--xh-space-1));
146
+ }
147
+
148
+ [data-scope='calendar'][data-part='grid'][data-view='quarter'] {
149
+ display: grid;
150
+ grid-template-columns: repeat(4, minmax(0, 1fr));
151
+ gap: var(--xh-calendar-period-gap, var(--xh-space-1));
152
+ }
153
+
154
+ /* 粗粒度的格子比日子宽,文字居中、留出上下气口 */
155
+ [data-scope='calendar'][data-part='grid']:is([data-view='month'], [data-view='quarter'], [data-view='year']) [data-part='cell-trigger'] {
156
+ padding-block: var(--xh-calendar-period-py, var(--xh-space-2));
157
+ inline-size: 100%;
158
+ }
159
+
86
160
  [data-scope='calendar'][data-part='grid'][hidden] {
87
161
  display: none;
88
162
  }
@@ -110,6 +184,26 @@
110
184
  grid-template-columns: repeat(7, minmax(0, 1fr));
111
185
  }
112
186
 
187
+ /* 摆了周序号格的行多让出行首一列。写 :not([hidden]) 而不是靠顺序压过下面那条兜底——
188
+ 同特指度的规则谁在后面谁赢,收起态会被这条 display 掀开 */
189
+ [data-scope='calendar'][data-part='week-row']:not([hidden]):has(> [data-part='week-number']) {
190
+ display: grid;
191
+ grid-template-columns: var(--xh-calendar-week-number-w, 2.25rem) repeat(7, minmax(0, 1fr));
192
+ }
193
+
194
+ /* 周序号只是行的标号:比日子小一号、颜色压下去,不跟着选中态走 */
195
+ [data-scope='calendar'][data-part='week-number'] {
196
+ display: grid;
197
+ place-items: center;
198
+ color: var(--xh-calendar-week-number-fg, var(--xh-fg-subtle));
199
+ font-size: var(--xh-calendar-week-number-font-size, var(--xh-text-caption-size));
200
+ font-variant-numeric: tabular-nums;
201
+ user-select: none;
202
+ }
203
+
204
+ [data-scope='calendar'][data-part='week-number'][hidden] {
205
+ display: none;
206
+ }
113
207
  [data-scope='calendar'][data-part='week-row'][hidden] {
114
208
  display: none;
115
209
  }
@@ -120,7 +214,7 @@
120
214
  justify-content: center;
121
215
  block-size: var(--xh-calendar-week-day-h, var(--xh-control-h-sm));
122
216
  color: var(--xh-calendar-week-day-fg, var(--xh-fg-subtle));
123
- font-size: var(--xh-calendar-week-day-font-size, var(--xh-font-size-xs));
217
+ font-size: var(--xh-calendar-week-day-font-size, var(--xh-text-caption-size));
124
218
  font-weight: var(--xh-calendar-week-day-font-weight, var(--xh-font-weight-medium));
125
219
  line-height: var(--xh-leading-none);
126
220
  user-select: none;
@@ -136,7 +230,7 @@
136
230
  display: flex;
137
231
  align-items: center;
138
232
  justify-content: center;
139
- padding: var(--xh-calendar-cell-gap, 2px);
233
+ padding: var(--xh-calendar-cell-gap, var(--xh-space-0_5));
140
234
  }
141
235
 
142
236
  [data-scope='calendar'][data-part='cell'][hidden] {
@@ -221,4 +315,27 @@
221
315
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
222
316
  outline-offset: calc(-1 * var(--xh-ring-width));
223
317
  }
318
+
319
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
320
+ [data-scope='calendar'][data-part='prev-trigger']:empty::before {
321
+ content: '';
322
+ display: inline-block;
323
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
324
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
325
+ vertical-align: var(--xh-glyph-baseline-shift);
326
+ background-color: currentColor;
327
+ -webkit-mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
328
+ mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
329
+ }
330
+
331
+ [data-scope='calendar'][data-part='next-trigger']:empty::before {
332
+ content: '';
333
+ display: inline-block;
334
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
335
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
336
+ vertical-align: var(--xh-glyph-baseline-shift);
337
+ background-color: currentColor;
338
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
339
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
340
+ }
224
341
  }