@xihan-ui/styles 1.0.0-alpha.1 → 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 (129) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +1 -1
  3. package/css/accordion.css +61 -5
  4. package/css/affix.css +5 -0
  5. package/css/alert.css +35 -5
  6. package/css/anchor.css +12 -7
  7. package/css/avatar-group.css +8 -3
  8. package/css/avatar.css +8 -3
  9. package/css/back-top.css +21 -1
  10. package/css/badge.css +21 -2
  11. package/css/breadcrumb.css +29 -4
  12. package/css/button-group.css +19 -13
  13. package/css/button.css +57 -11
  14. package/css/calendar.css +124 -2
  15. package/css/card.css +10 -5
  16. package/css/carousel.css +41 -5
  17. package/css/cascader.css +188 -102
  18. package/css/checkbox-group.css +46 -19
  19. package/css/checkbox.css +59 -8
  20. package/css/clipboard.css +7 -1
  21. package/css/code-block.css +17 -7
  22. package/css/collapsible.css +47 -2
  23. package/css/color-picker.css +117 -46
  24. package/css/combobox.css +132 -52
  25. package/css/composer.css +10 -3
  26. package/css/context-menu.css +101 -75
  27. package/css/countdown.css +5 -0
  28. package/css/date-field.css +96 -14
  29. package/css/date-picker.css +281 -65
  30. package/css/descriptions.css +7 -2
  31. package/css/dialog.css +109 -22
  32. package/css/download-trigger.css +76 -0
  33. package/css/drawer.css +75 -23
  34. package/css/dynamic-input.css +73 -17
  35. package/css/editable.css +17 -10
  36. package/css/ellipsis.css +6 -1
  37. package/css/empty-state.css +12 -7
  38. package/css/field.css +14 -6
  39. package/css/fieldset.css +69 -0
  40. package/css/file-upload.css +50 -7
  41. package/css/flex.css +5 -0
  42. package/css/float-button.css +21 -1
  43. package/css/floating-panel.css +310 -0
  44. package/css/form.css +10 -5
  45. package/css/gradient-text.css +5 -0
  46. package/css/grid.css +5 -0
  47. package/css/heatmap.css +410 -0
  48. package/css/highlight.css +6 -1
  49. package/css/hotkeys.css +90 -0
  50. package/css/hover-card.css +58 -50
  51. package/css/icon-wrapper.css +5 -0
  52. package/css/icon.css +5 -0
  53. package/css/image-cropper.css +231 -0
  54. package/css/image-viewer.css +167 -22
  55. package/css/image.css +7 -2
  56. package/css/infinite-scroll.css +6 -1
  57. package/css/json-viewer.css +241 -0
  58. package/css/layout.css +11 -10
  59. package/css/list.css +13 -8
  60. package/css/listbox.css +25 -4
  61. package/css/loading-bar.css +12 -1
  62. package/css/log.css +6 -1
  63. package/css/marquee.css +14 -0
  64. package/css/masonry.css +63 -0
  65. package/css/mention.css +105 -32
  66. package/css/menu.css +131 -46
  67. package/css/menubar.css +150 -66
  68. package/css/navigation-menu.css +59 -29
  69. package/css/number-animation.css +8 -3
  70. package/css/number-field.css +178 -16
  71. package/css/overlay-arrow.css +51 -0
  72. package/css/page-header.css +10 -5
  73. package/css/pagination.css +18 -13
  74. package/css/password-input.css +356 -0
  75. package/css/pin-input.css +18 -10
  76. package/css/popconfirm.css +73 -16
  77. package/css/popover.css +88 -44
  78. package/css/popselect.css +201 -52
  79. package/css/progress.css +52 -7
  80. package/css/qr-code.css +6 -1
  81. package/css/radio-group.css +19 -8
  82. package/css/rating.css +7 -2
  83. package/css/reset.css +17 -0
  84. package/css/result.css +11 -6
  85. package/css/scroll-area.css +65 -94
  86. package/css/scrollbar.css +167 -0
  87. package/css/segmented.css +215 -0
  88. package/css/select.css +292 -124
  89. package/css/separator.css +7 -2
  90. package/css/side-nav.css +116 -19
  91. package/css/signature-pad.css +144 -0
  92. package/css/skeleton.css +12 -1
  93. package/css/slider.css +15 -10
  94. package/css/space.css +117 -0
  95. package/css/spinner.css +31 -11
  96. package/css/splitter.css +5 -0
  97. package/css/statistic.css +14 -9
  98. package/css/steps.css +30 -8
  99. package/css/switch.css +62 -13
  100. package/css/table.css +136 -37
  101. package/css/tabs.css +9 -4
  102. package/css/tag.css +177 -0
  103. package/css/tags-input.css +83 -40
  104. package/css/text-field.css +154 -36
  105. package/css/thread.css +6 -1
  106. package/css/time-field.css +102 -16
  107. package/css/time-picker.css +264 -69
  108. package/css/time.css +5 -0
  109. package/css/timeline.css +15 -10
  110. package/css/timer.css +119 -0
  111. package/css/toast.css +46 -21
  112. package/css/toaster.css +6 -1
  113. package/css/toggle-group.css +5 -0
  114. package/css/toggle.css +11 -6
  115. package/css/tone.css +10 -5
  116. package/css/toolbar.css +6 -1
  117. package/css/tooltip.css +54 -38
  118. package/css/tour.css +128 -63
  119. package/css/transfer.css +73 -17
  120. package/css/tree-select.css +203 -83
  121. package/css/tree.css +90 -1
  122. package/css/typography.css +9 -4
  123. package/css/undefined.css +11 -1
  124. package/css/virtualizer.css +8 -1
  125. package/css/watermark.css +6 -2
  126. package/index.css +17 -1
  127. package/index.unlayered.css +9394 -2883
  128. package/package.json +19 -4
  129. package/css/motion.css +0 -58
package/css/dialog.css CHANGED
@@ -1,8 +1,67 @@
1
+ @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-fade-in {
5
+ from {
6
+ opacity: 0;
7
+ }
8
+
9
+ to {
10
+ opacity: 1;
11
+ }
12
+ }
13
+
14
+ @keyframes xh-fade-out {
15
+ from {
16
+ opacity: 1;
17
+ }
18
+
19
+ to {
20
+ opacity: 0;
21
+ }
22
+ }
23
+
24
+ /* 幅度走令牌,减弱动效时由令牌层归零;位移与缩放用独立属性而非 transform 简写,
25
+ 两者互不覆盖,手势期间写 translate 也不会把 scale 抹掉 */
26
+ @keyframes xh-dialog-in {
27
+ from {
28
+ opacity: 0;
29
+ translate: 0 var(--xh-motion-distance-md);
30
+ scale: var(--xh-motion-scale-enter);
31
+ }
32
+
33
+ to {
34
+ opacity: 1;
35
+ translate: 0 0;
36
+ scale: 1;
37
+ }
38
+ }
39
+
40
+ @keyframes xh-dialog-out {
41
+ from {
42
+ opacity: 1;
43
+ translate: 0 0;
44
+ scale: 1;
45
+ }
46
+
47
+ to {
48
+ opacity: 0;
49
+ translate: 0 var(--xh-motion-distance-md);
50
+ scale: var(--xh-motion-scale-enter);
51
+ }
52
+ }
53
+ }
54
+
1
55
  @layer xihan.components {
56
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
57
+ [data-scope='dialog'] {
58
+ --xh-dialog-skin: 1;
59
+ }
60
+
2
61
  [data-scope='dialog'][data-part='backdrop'] {
3
62
  position: fixed;
4
63
  inset: 0;
5
- z-index: var(--xh-layer-modal);
64
+ z-index: var(--xh-dialog-backdrop-layer, var(--xh-layer-modal));
6
65
  background: var(--xh-dialog-backdrop-bg, var(--xh-bg-overlay));
7
66
  }
8
67
 
@@ -10,14 +69,15 @@
10
69
  animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
11
70
  }
12
71
 
72
+ /* 退场补 forwards:动画播完到宿主真正卸载之间还有一帧,不定住终态遮罩会闪回全黑 */
13
73
  [data-scope='dialog'][data-part='backdrop'][data-state='closed'] {
14
- animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
74
+ animation: xh-fade-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
15
75
  }
16
76
 
17
77
  [data-scope='dialog'][data-part='positioner'] {
18
78
  position: fixed;
19
79
  inset: 0;
20
- z-index: var(--xh-layer-modal);
80
+ z-index: var(--xh-dialog-layer, var(--xh-layer-modal));
21
81
  display: flex;
22
82
  align-items: center;
23
83
  justify-content: center;
@@ -29,10 +89,13 @@
29
89
  }
30
90
 
31
91
  [data-scope='dialog'][data-part='content'] {
92
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
93
+ --xh-icon-size: var(--xh-dialog-icon-size, var(--xh-glyph-size-text));
94
+
32
95
  /* 尺寸档只换这一个私有槽。它声明在 content 而不是别处:dialog 的解剖里没有 root,
33
96
  positioner 又不是必需部件,content 才是这层浮层恒在的最外层,且它会被 portal 到 body,
34
97
  选择器只认得它自己身上那一份 data-size。 */
35
- --xh-_dialog-max-w: 32rem;
98
+ --xh-_dialog-max-w: var(--xh-overlay-sheet-w-md);
36
99
 
37
100
  position: relative;
38
101
  inline-size: 100%;
@@ -40,43 +103,43 @@
40
103
  display: flex;
41
104
  flex-direction: column;
42
105
  gap: var(--xh-dialog-gap, var(--xh-stack-gap-md));
43
- padding-block: var(--xh-dialog-py, var(--xh-section-py));
44
- padding-inline: var(--xh-dialog-px, var(--xh-control-px-lg));
106
+ padding-block: var(--xh-dialog-py, var(--xh-surface-py-md));
107
+ padding-inline: var(--xh-dialog-px, var(--xh-surface-px-md));
45
108
  border-radius: var(--xh-dialog-radius, var(--xh-shape-surface));
46
109
  background: var(--xh-dialog-bg, var(--xh-bg-surface));
47
110
  color: var(--xh-dialog-fg, var(--xh-fg-default));
48
- box-shadow: var(--xh-dialog-shadow, var(--xh-elevation-3));
111
+ box-shadow: var(--xh-dialog-shadow, var(--xh-elevation-sheet));
49
112
  }
50
113
 
51
- /* 收起态:connect 会给 content 打 hidden,但上面那条 display 会盖掉 UA 的
52
- [hidden]{display:none}。meta 里 positioner 并非必需部件,按最小合规结构
53
- (只有 trigger + content)写时,没有这一条收起的对话框就一直摊在页面上。 */
54
- [data-scope='dialog'][data-part='content'][hidden] {
55
- display: none;
56
- }
114
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 drawer 一致:
115
+ 收起态连接层会给 content 打 hidden,而上面那条 display: flex 正是要盖掉 UA 的
116
+ [hidden]{display:none}——退场动画得先能播。presence 读的是 content 的 animationName,
117
+ 读到才申领租约、等 animationend 才卸载;一旦 display: none,元素不生成盒子、
118
+ 动画根本不启动,探测器直接放弃租约,退场动画一帧都播不出来。
119
+ 真正的收起由适配器兜住:Vue 卸载整棵,WC 写内联 style.display。
120
+ 其余声明了 display 的角色节点仍补 [hidden],那几处没有退场动画。 */
57
121
 
58
122
  /* —— 尺寸 —— */
59
123
  /* 只有最大宽度分档;中间档不写规则,缺省即中档。
60
124
  宽度上限之外的一切(内边距、字号、圆角)都不随档位动:弹层的语气归里面的内容表达。 */
61
125
  [data-scope='dialog'][data-part='content'][data-size='sm'] {
62
- --xh-_dialog-max-w: 24rem;
126
+ --xh-_dialog-max-w: var(--xh-overlay-sheet-w-sm);
63
127
  }
64
128
 
65
129
  [data-scope='dialog'][data-part='content'][data-size='lg'] {
66
- --xh-_dialog-max-w: 48rem;
130
+ --xh-_dialog-max-w: var(--xh-overlay-sheet-w-lg);
67
131
  }
68
132
 
69
133
  [data-scope='dialog'][data-part='content']:focus-visible {
70
134
  outline: none;
71
135
  }
72
136
 
73
- /* 入场用 @starting-style 只驱动动画名切换;退场由 presence 保留 DOM 后播放 */
74
137
  [data-scope='dialog'][data-part='content'][data-state='open'] {
75
138
  animation: xh-dialog-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
76
139
  }
77
140
 
78
141
  [data-scope='dialog'][data-part='content'][data-state='closed'] {
79
- animation: xh-dialog-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit);
142
+ animation: xh-dialog-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
80
143
  }
81
144
 
82
145
  [data-scope='dialog'][data-part='title'] {
@@ -96,7 +159,7 @@
96
159
  否则长标题会直接钻到按钮底下。只在真有关闭按钮时让位。 */
97
160
  [data-scope='dialog'][data-part='content']:has([data-scope='dialog'][data-part='close-trigger'])
98
161
  [data-scope='dialog'][data-part='title'] {
99
- padding-inline-end: calc(var(--xh-control-h-sm) + var(--xh-space-3));
162
+ padding-inline-end: calc(var(--xh-dialog-close-size, var(--xh-control-h-sm)) + var(--xh-space-3));
100
163
  }
101
164
 
102
165
  [data-scope='dialog'][data-part='close-trigger'] {
@@ -106,22 +169,46 @@
106
169
  display: inline-flex;
107
170
  align-items: center;
108
171
  justify-content: center;
109
- block-size: var(--xh-control-h-sm);
110
- inline-size: var(--xh-control-h-sm);
172
+ block-size: var(--xh-dialog-close-size, var(--xh-control-h-sm));
173
+ inline-size: var(--xh-dialog-close-size, var(--xh-control-h-sm));
111
174
  border: 0;
112
- border-radius: var(--xh-shape-control);
175
+ border-radius: var(--xh-dialog-close-radius, var(--xh-shape-control));
113
176
  background: transparent;
114
177
  color: var(--xh-fg-muted);
115
178
  cursor: pointer;
179
+ transition:
180
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
181
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
182
+ }
183
+
184
+ [data-scope='dialog'][data-part='close-trigger'][hidden] {
185
+ display: none;
116
186
  }
117
187
 
118
188
  [data-scope='dialog'][data-part='close-trigger']:hover {
119
- background: var(--xh-bg-subtle);
189
+ background: var(--xh-dialog-close-bg-hover, var(--xh-bg-subtle-hover));
120
190
  color: var(--xh-fg-default);
121
191
  }
122
192
 
193
+ [data-scope='dialog'][data-part='close-trigger']:active {
194
+ background: var(--xh-dialog-close-bg-active, var(--xh-bg-subtle-active));
195
+ scale: var(--xh-motion-scale-press);
196
+ }
197
+
123
198
  [data-scope='dialog'][data-part='close-trigger']:focus-visible {
124
199
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
125
200
  outline-offset: var(--xh-ring-offset);
126
201
  }
202
+
203
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
204
+ [data-scope='dialog'][data-part='close-trigger']:empty::before {
205
+ content: '';
206
+ display: inline-block;
207
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
208
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
209
+ vertical-align: var(--xh-glyph-baseline-shift);
210
+ background-color: currentColor;
211
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
212
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
213
+ }
127
214
  }
@@ -0,0 +1,76 @@
1
+ @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='download-trigger'] {
4
+ --xh-download-trigger-skin: 1;
5
+ }
6
+
7
+ /*
8
+ * 触发器就是这一个原生按钮,两个适配器都由组件自己渲染它,
9
+ * 所以外观得由设计系统给出一份完整的中性按钮:底色、描边、高度、字号都上令牌,
10
+ * 要换成品牌样式的作者改 --xh-download-trigger-* 这一族槽位,或直接写自己的类名。
11
+ */
12
+ [data-scope='download-trigger'][data-part='root'] {
13
+ display: inline-flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ gap: var(--xh-download-trigger-gap, var(--xh-control-gap-md));
17
+ block-size: var(--xh-download-trigger-h, var(--xh-control-h-md));
18
+ padding-inline: var(--xh-download-trigger-px, var(--xh-control-px-md));
19
+ padding-block: 0;
20
+ border: var(--xh-stroke-thin) solid var(--xh-download-trigger-border, var(--xh-border-control));
21
+ border-radius: var(--xh-download-trigger-radius, var(--xh-shape-control));
22
+ background: var(--xh-download-trigger-bg, var(--xh-bg-canvas));
23
+ color: var(--xh-download-trigger-fg, var(--xh-fg-default));
24
+ /* 表单控件不继承页面字体,只给字号会让按钮用 UA 默认字族 */
25
+ font-family: inherit;
26
+ font-size: var(--xh-download-trigger-font-size, var(--xh-text-label-size));
27
+ font-weight: var(--xh-download-trigger-font-weight, var(--xh-text-label-weight));
28
+ line-height: var(--xh-leading-none);
29
+ white-space: nowrap;
30
+ cursor: pointer;
31
+ /* 导出键常被连点,触屏上默认会当成双击缩放 */
32
+ user-select: none;
33
+ touch-action: manipulation;
34
+ transition:
35
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
36
+ border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
37
+ }
38
+
39
+ /* 上面声明了 display,会盖掉 UA 的 [hidden] 规则,收起态要在这里接回来 */
40
+ [data-scope='download-trigger'][data-part='root'][hidden] {
41
+ display: none;
42
+ }
43
+
44
+ [data-scope='download-trigger'][data-part='root']:hover {
45
+ border-color: var(--xh-download-trigger-border-hover, var(--xh-border-control-hover));
46
+ background: var(--xh-download-trigger-bg-hover, var(--xh-bg-subtle-hover));
47
+ }
48
+
49
+ [data-scope='download-trigger'][data-part='root']:active {
50
+ background: var(--xh-download-trigger-bg-active, var(--xh-bg-subtle-active));
51
+ }
52
+
53
+ [data-scope='download-trigger'][data-part='root']:focus-visible {
54
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
55
+ outline-offset: var(--xh-ring-offset);
56
+ }
57
+
58
+ /* 取数在途:按钮留在原地不动,只换指针形状——位置一变,正要再点的人就点空了 */
59
+ [data-scope='download-trigger'][data-part='root'][data-state='preparing'] {
60
+ cursor: progress;
61
+ }
62
+
63
+ /*
64
+ * 单体原生控件的禁用走 :disabled。前景与底色一起换,禁用前后两侧都由令牌管着;
65
+ * 用了 fg-disabled 就不再叠 opacity——两样一起用会压到读不出来。
66
+ * 这条排在悬停与按下之后,特异度相同、后写的赢。
67
+ * 描边仍按可操作区那一档:这是一颗独立按钮,四周没有别的结构标出它的位置,
68
+ * 描边一压下去整颗按钮在页面上就没影了。
69
+ */
70
+ [data-scope='download-trigger'][data-part='root']:disabled {
71
+ border-color: var(--xh-download-trigger-border-disabled, var(--xh-border-control));
72
+ background: var(--xh-download-trigger-bg-disabled, var(--xh-bg-muted));
73
+ color: var(--xh-fg-disabled);
74
+ cursor: not-allowed;
75
+ }
76
+ }
package/css/drawer.css CHANGED
@@ -1,4 +1,26 @@
1
1
  @layer xihan.motion {
2
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
3
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
4
+ @keyframes xh-fade-in {
5
+ from {
6
+ opacity: 0;
7
+ }
8
+
9
+ to {
10
+ opacity: 1;
11
+ }
12
+ }
13
+
14
+ @keyframes xh-fade-out {
15
+ from {
16
+ opacity: 1;
17
+ }
18
+
19
+ to {
20
+ opacity: 0;
21
+ }
22
+ }
23
+
2
24
  /* 四条边各一对滑入/滑出。位移量用 translate 的百分比,参照的是面板自己的边框盒,
3
25
  所以不管 --xh-drawer-size 被改成多少,"正好推到视口外"这件事都成立。
4
26
 
@@ -85,18 +107,20 @@
85
107
  translate: 0 var(--xh-_drawer-shift-block, 100%);
86
108
  }
87
109
  }
88
-
89
- @media (prefers-reduced-motion: reduce) {
90
- [data-scope='drawer'][data-part] {
91
- animation-duration: 0.01ms !important;
92
- }
93
- }
94
110
  }
95
111
 
96
112
  @layer xihan.components {
113
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
114
+ [data-scope='drawer'] {
115
+ --xh-drawer-skin: 1;
116
+ }
117
+
97
118
  /* root 留在页面原地,只是 data-side / data-state 的落点,不该凭空多出一层盒子把
98
119
  trigger 从作者的 flex / grid 行里挤出去,故 display: contents。 */
99
120
  [data-scope='drawer'][data-part='root'] {
121
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
122
+ --xh-icon-size: var(--xh-drawer-icon-size, var(--xh-glyph-size-text));
123
+
100
124
  display: contents;
101
125
  }
102
126
 
@@ -156,10 +180,18 @@
156
180
  [data-scope='drawer'][data-part='backdrop'] {
157
181
  position: fixed;
158
182
  inset: 0;
159
- z-index: var(--xh-layer-drawer);
183
+ z-index: var(--xh-drawer-backdrop-layer, var(--xh-layer-drawer));
160
184
  background: var(--xh-drawer-backdrop-bg, var(--xh-bg-overlay));
161
185
  }
162
186
 
187
+ /* 挂在局部容器里:遮罩与定位层从视口坐标换成容器坐标,只罩住那个容器。
188
+ 作者要给那个容器加 position(relative 之类),否则 absolute 会往上找到别的定位祖先——
189
+ 这一条写进了示例与 props 说明 */
190
+ [data-scope='drawer'][data-part='backdrop'][data-contained],
191
+ [data-scope='drawer'][data-part='positioner'][data-contained] {
192
+ position: absolute;
193
+ }
194
+
163
195
  [data-scope='drawer'][data-part='backdrop'][data-state='open'] {
164
196
  animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
165
197
  }
@@ -175,7 +207,7 @@
175
207
  [data-scope='drawer'][data-part='positioner'] {
176
208
  position: fixed;
177
209
  inset: 0;
178
- z-index: var(--xh-layer-drawer);
210
+ z-index: var(--xh-drawer-layer, var(--xh-layer-drawer));
179
211
  pointer-events: none;
180
212
  }
181
213
 
@@ -191,18 +223,18 @@
191
223
  /* 尺寸档只换这一个私有槽:左右放置时它是面板宽度、上下放置时是面板高度,
192
224
  两种取法都在下面「四条边」那两条规则里。声明在 content 而不是 root:
193
225
  content 会被 portal 到 body,root 上的槽位继承不过来(data-side 也是同一个道理) */
194
- --xh-_drawer-size: 20rem;
226
+ --xh-_drawer-size: var(--xh-overlay-drawer-w-md);
195
227
 
196
228
  position: fixed;
197
- z-index: var(--xh-layer-drawer);
229
+ z-index: var(--xh-drawer-layer, var(--xh-layer-drawer));
198
230
  display: flex;
199
231
  flex-direction: column;
200
232
  gap: var(--xh-drawer-gap, var(--xh-stack-gap-md));
201
- padding-block: var(--xh-drawer-py, var(--xh-section-py));
202
- padding-inline: var(--xh-drawer-px, var(--xh-control-px-lg));
233
+ padding-block: var(--xh-drawer-py, var(--xh-surface-py-md));
234
+ padding-inline: var(--xh-drawer-px, var(--xh-surface-px-md));
203
235
  background: var(--xh-drawer-bg, var(--xh-bg-surface));
204
236
  color: var(--xh-drawer-fg, var(--xh-fg-default));
205
- box-shadow: var(--xh-drawer-shadow, var(--xh-elevation-3));
237
+ box-shadow: var(--xh-drawer-shadow, var(--xh-elevation-sheet));
206
238
  overflow: auto;
207
239
  /* 尺寸是照视口那条边算出来的,padding 再往外顶就会把面板挤出屏幕、
208
240
  逼出一条横向滚动条。reset 层已有同款兜底,这里显式写一遍表明尺寸算法依赖它 */
@@ -218,9 +250,9 @@
218
250
  /* 这里刻意没有 [data-part='content'][hidden] { display: none },与 dialog 一致。
219
251
  收起态连接层会给 content 打 hidden,而上面这条 display: flex 正是要盖掉
220
252
  UA 的 [hidden]{display:none}——退场动画得先能播:
221
- Vue 侧 presence 读的是 content 的 animationName,读到就申领租约、等 animationend
222
- 才卸载;一旦 display: none,动画根本不会启动,animationend 永不到达,
223
- 租约挂死,面板就永久留在 DOM 里(每开合一次多一份)。
253
+ presence 读的是 content 的 animationName,读到就申领租约、等 animationend 才卸载;
254
+ 一旦 display: none,元素不生成盒子、动画根本不启动,退场探测器会直接放弃申领
255
+ (否则就要等一个永不到来的 animationend),面板不播动画就地卸载。
224
256
  真正的收起两个适配器各自兜住了:Vue 卸载整棵,WC 写内联 style.display。
225
257
  其余声明了 display 的角色节点仍补了 [hidden],那几处没有退场动画,作者手写 hidden 要生效。 */
226
258
 
@@ -233,11 +265,11 @@
233
265
  /* 只有面板厚度分档;中间档不写规则,缺省即中档。
234
266
  data-size 与 data-side 一样同时打在 root 与 content 上,这里只认 content 自己那一份。 */
235
267
  [data-scope='drawer'][data-part='content'][data-size='sm'] {
236
- --xh-_drawer-size: 16rem;
268
+ --xh-_drawer-size: var(--xh-overlay-drawer-w-sm);
237
269
  }
238
270
 
239
271
  [data-scope='drawer'][data-part='content'][data-size='lg'] {
240
- --xh-_drawer-size: 28rem;
272
+ --xh-_drawer-size: var(--xh-overlay-drawer-w-lg);
241
273
  }
242
274
 
243
275
  /* —— 四条边 ——
@@ -337,7 +369,7 @@
337
369
  否则长标题会直接钻到按钮底下。只在真有关闭按钮时让位。 */
338
370
  [data-scope='drawer'][data-part='content']:has([data-scope='drawer'][data-part='close-trigger'])
339
371
  [data-scope='drawer'][data-part='title'] {
340
- padding-inline-end: calc(var(--xh-control-h-sm) + var(--xh-space-3));
372
+ padding-inline-end: calc(var(--xh-drawer-close-size, var(--xh-control-h-sm)) + var(--xh-space-3));
341
373
  }
342
374
 
343
375
  [data-scope='drawer'][data-part='close-trigger'] {
@@ -347,13 +379,16 @@
347
379
  display: inline-flex;
348
380
  align-items: center;
349
381
  justify-content: center;
350
- block-size: var(--xh-control-h-sm);
351
- inline-size: var(--xh-control-h-sm);
382
+ block-size: var(--xh-drawer-close-size, var(--xh-control-h-sm));
383
+ inline-size: var(--xh-drawer-close-size, var(--xh-control-h-sm));
352
384
  border: 0;
353
- border-radius: var(--xh-shape-control);
385
+ border-radius: var(--xh-drawer-close-radius, var(--xh-shape-control));
354
386
  background: transparent;
355
387
  color: var(--xh-fg-muted);
356
388
  cursor: pointer;
389
+ transition:
390
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
391
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
357
392
  }
358
393
 
359
394
  [data-scope='drawer'][data-part='close-trigger'][hidden] {
@@ -361,12 +396,29 @@
361
396
  }
362
397
 
363
398
  [data-scope='drawer'][data-part='close-trigger']:hover {
364
- background: var(--xh-bg-subtle);
399
+ background: var(--xh-drawer-close-bg-hover, var(--xh-bg-subtle-hover));
365
400
  color: var(--xh-fg-default);
366
401
  }
367
402
 
403
+ [data-scope='drawer'][data-part='close-trigger']:active {
404
+ background: var(--xh-drawer-close-bg-active, var(--xh-bg-subtle-active));
405
+ scale: var(--xh-motion-scale-press);
406
+ }
407
+
368
408
  [data-scope='drawer'][data-part='close-trigger']:focus-visible {
369
409
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
370
410
  outline-offset: var(--xh-ring-offset);
371
411
  }
412
+
413
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
414
+ [data-scope='drawer'][data-part='close-trigger']:empty::before {
415
+ content: '';
416
+ display: inline-block;
417
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
418
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
419
+ vertical-align: var(--xh-glyph-baseline-shift);
420
+ background-color: currentColor;
421
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
422
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
423
+ }
372
424
  }
@@ -1,6 +1,14 @@
1
1
  @layer xihan.components {
2
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3
+ [data-scope='dynamic-input'] {
4
+ --xh-dynamic-input-skin: 1;
5
+ }
6
+
2
7
  /* 一行一条,纵向堆叠;新增把手跟在最后一行下面 */
3
8
  [data-scope='dynamic-input'][data-part='root'] {
9
+ /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
10
+ --xh-icon-size: var(--xh-dynamic-input-icon-size, var(--xh-glyph-size-text));
11
+
4
12
  display: flex;
5
13
  flex-direction: column;
6
14
  gap: var(--xh-dynamic-input-gap, var(--xh-space-2));
@@ -42,55 +50,69 @@
42
50
  }
43
51
 
44
52
  /* —— 行内三个把手 —— */
45
- [data-scope='dynamic-input'][data-part='remove-trigger'],
53
+ [data-scope='dynamic-input'][data-part='item-delete-trigger'],
46
54
  [data-scope='dynamic-input'][data-part='move-up-trigger'],
47
55
  [data-scope='dynamic-input'][data-part='move-down-trigger'] {
48
56
  display: inline-flex;
49
57
  flex: none;
50
58
  align-items: center;
51
59
  justify-content: center;
52
- inline-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
53
- block-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
54
60
  padding: 0;
55
61
  border: 0;
56
- border-radius: var(--xh-dynamic-input-trigger-radius, var(--xh-shape-control));
57
62
  background: var(--xh-dynamic-input-trigger-bg, transparent);
58
63
  color: var(--xh-dynamic-input-trigger-fg, var(--xh-fg-muted));
59
64
  font-family: inherit;
60
- font-size: var(--xh-dynamic-input-trigger-font-size, var(--xh-font-size-sm));
65
+ font-size: var(--xh-dynamic-input-trigger-font-size, var(--xh-text-secondary-size));
61
66
  line-height: var(--xh-leading-none);
62
67
  cursor: pointer;
63
- transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
68
+ transition:
69
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
70
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
71
+ }
72
+
73
+ /* 行级删除把手:命中区取行内动作按钮尺寸,圆角取控件圆角 */
74
+ [data-scope='dynamic-input'][data-part='item-delete-trigger'] {
75
+ inline-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
76
+ block-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
77
+ border-radius: var(--xh-dynamic-input-trigger-radius, var(--xh-shape-control));
78
+ }
79
+
80
+ [data-scope='dynamic-input'][data-part='move-up-trigger'],
81
+ [data-scope='dynamic-input'][data-part='move-down-trigger'] {
82
+ inline-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
83
+ block-size: var(--xh-dynamic-input-trigger-size, var(--xh-control-action-size));
84
+ border-radius: var(--xh-dynamic-input-trigger-radius, var(--xh-shape-control));
64
85
  }
65
86
 
66
87
  /* 不换序时连接层给换序把手写 hidden;上面那条 display 会把 UA 的 [hidden]{display:none}
67
88
  盖掉,少了这条把手还留在原地。删除把手同样声明了 display,作者自己收起它时要的是同一条 */
68
- [data-scope='dynamic-input'][data-part='remove-trigger'][hidden],
89
+ [data-scope='dynamic-input'][data-part='item-delete-trigger'][hidden],
69
90
  [data-scope='dynamic-input'][data-part='move-up-trigger'][hidden],
70
91
  [data-scope='dynamic-input'][data-part='move-down-trigger'][hidden] {
71
92
  display: none;
72
93
  }
73
94
 
74
95
  /* 按不动的把手不给悬停与按下反馈:它仍然可聚焦、可点,反馈会让人以为点得动 */
75
- [data-scope='dynamic-input'][data-part='remove-trigger']:hover:not([aria-disabled='true']),
96
+ [data-scope='dynamic-input'][data-part='item-delete-trigger']:hover:not([aria-disabled='true']),
76
97
  [data-scope='dynamic-input'][data-part='move-up-trigger']:hover:not([aria-disabled='true']),
77
98
  [data-scope='dynamic-input'][data-part='move-down-trigger']:hover:not([aria-disabled='true']) {
78
99
  background: var(--xh-dynamic-input-trigger-bg-hover, var(--xh-bg-subtle-hover));
79
100
  color: var(--xh-dynamic-input-trigger-fg-hover, var(--xh-fg-default));
80
101
  }
81
102
 
82
- [data-scope='dynamic-input'][data-part='remove-trigger']:active:not([aria-disabled='true']),
83
- [data-scope='dynamic-input'][data-part='move-up-trigger']:active:not([aria-disabled='true']),
84
- [data-scope='dynamic-input'][data-part='move-down-trigger']:active:not([aria-disabled='true']) {
103
+ [data-scope='dynamic-input'][data-part='item-delete-trigger']:not([aria-disabled='true']):active,
104
+ [data-scope='dynamic-input'][data-part='move-up-trigger']:not([aria-disabled='true']):active,
105
+ [data-scope='dynamic-input'][data-part='move-down-trigger']:not([aria-disabled='true']):active {
85
106
  background: var(--xh-dynamic-input-trigger-bg-active, var(--xh-bg-subtle-active));
107
+ scale: var(--xh-motion-scale-press);
86
108
  }
87
109
 
88
110
  /* 删除把手悬停转危险色:它是这一行里唯一不可撤销的动作 */
89
- [data-scope='dynamic-input'][data-part='remove-trigger']:hover:not([aria-disabled='true']) {
90
- color: var(--xh-dynamic-input-remove-fg-hover, var(--xh-fg-danger-hover));
111
+ [data-scope='dynamic-input'][data-part='item-delete-trigger']:hover:not([aria-disabled='true']) {
112
+ color: var(--xh-dynamic-input-item-delete-fg-hover, var(--xh-fg-danger-hover));
91
113
  }
92
114
 
93
- [data-scope='dynamic-input'][data-part='remove-trigger']:focus-visible,
115
+ [data-scope='dynamic-input'][data-part='item-delete-trigger']:focus-visible,
94
116
  [data-scope='dynamic-input'][data-part='move-up-trigger']:focus-visible,
95
117
  [data-scope='dynamic-input'][data-part='move-down-trigger']:focus-visible {
96
118
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
@@ -99,7 +121,7 @@
99
121
 
100
122
  /* 到上下限、或整份禁用时用 aria-disabled 表达(原生 disabled 不派 click,禁用守卫走不到),
101
123
  所以样式也得认这个属性,写 :disabled 永远不命中 */
102
- [data-scope='dynamic-input'][data-part='remove-trigger'][aria-disabled='true'],
124
+ [data-scope='dynamic-input'][data-part='item-delete-trigger'][aria-disabled='true'],
103
125
  [data-scope='dynamic-input'][data-part='move-up-trigger'][aria-disabled='true'],
104
126
  [data-scope='dynamic-input'][data-part='move-down-trigger'][aria-disabled='true'] {
105
127
  background: transparent;
@@ -139,7 +161,7 @@
139
161
  background: var(--xh-dynamic-input-add-bg-hover, var(--xh-bg-subtle-hover));
140
162
  }
141
163
 
142
- [data-scope='dynamic-input'][data-part='add-trigger']:active:not([aria-disabled='true']) {
164
+ [data-scope='dynamic-input'][data-part='add-trigger']:not([aria-disabled='true']):active {
143
165
  background: var(--xh-dynamic-input-add-bg-active, var(--xh-bg-subtle-active));
144
166
  }
145
167
 
@@ -149,9 +171,43 @@
149
171
  }
150
172
 
151
173
  [data-scope='dynamic-input'][data-part='add-trigger'][aria-disabled='true'] {
152
- border-color: var(--xh-border-subtle);
174
+ border-color: var(--xh-dynamic-input-add-border-disabled, var(--xh-border-subtle));
153
175
  background: transparent;
154
176
  color: var(--xh-fg-disabled);
155
177
  cursor: not-allowed;
156
178
  }
179
+
180
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
181
+ [data-scope='dynamic-input'][data-part='move-up-trigger']:empty::before {
182
+ content: '';
183
+ display: inline-block;
184
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
185
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
186
+ vertical-align: var(--xh-glyph-baseline-shift);
187
+ background-color: currentColor;
188
+ -webkit-mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
189
+ mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
190
+ }
191
+
192
+ [data-scope='dynamic-input'][data-part='move-down-trigger']:empty::before {
193
+ content: '';
194
+ display: inline-block;
195
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
196
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
197
+ vertical-align: var(--xh-glyph-baseline-shift);
198
+ background-color: currentColor;
199
+ -webkit-mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
200
+ mask: var(--xh-glyph-mark-chevron-down) center / contain no-repeat;
201
+ }
202
+
203
+ [data-scope='dynamic-input'][data-part='item-delete-trigger']:empty::before {
204
+ content: '';
205
+ display: inline-block;
206
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
207
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
208
+ vertical-align: var(--xh-glyph-baseline-shift);
209
+ background-color: currentColor;
210
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
211
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
212
+ }
157
213
  }