@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.
- package/CHANGELOG.md +527 -0
- package/README.md +1 -1
- package/css/accordion.css +61 -5
- package/css/affix.css +5 -0
- package/css/alert.css +35 -5
- package/css/anchor.css +12 -7
- package/css/avatar-group.css +8 -3
- package/css/avatar.css +8 -3
- package/css/back-top.css +21 -1
- package/css/badge.css +21 -2
- package/css/breadcrumb.css +29 -4
- package/css/button-group.css +19 -13
- package/css/button.css +57 -11
- package/css/calendar.css +124 -2
- package/css/card.css +10 -5
- package/css/carousel.css +41 -5
- package/css/cascader.css +188 -102
- package/css/checkbox-group.css +46 -19
- package/css/checkbox.css +59 -8
- package/css/clipboard.css +7 -1
- package/css/code-block.css +17 -7
- package/css/collapsible.css +47 -2
- package/css/color-picker.css +117 -46
- package/css/combobox.css +132 -52
- package/css/composer.css +10 -3
- package/css/context-menu.css +101 -75
- package/css/countdown.css +5 -0
- package/css/date-field.css +96 -14
- package/css/date-picker.css +281 -65
- package/css/descriptions.css +7 -2
- package/css/dialog.css +109 -22
- package/css/download-trigger.css +76 -0
- package/css/drawer.css +75 -23
- package/css/dynamic-input.css +73 -17
- package/css/editable.css +17 -10
- package/css/ellipsis.css +6 -1
- package/css/empty-state.css +12 -7
- package/css/field.css +14 -6
- package/css/fieldset.css +69 -0
- package/css/file-upload.css +50 -7
- package/css/flex.css +5 -0
- package/css/float-button.css +21 -1
- package/css/floating-panel.css +310 -0
- package/css/form.css +10 -5
- package/css/gradient-text.css +5 -0
- package/css/grid.css +5 -0
- package/css/heatmap.css +410 -0
- package/css/highlight.css +6 -1
- package/css/hotkeys.css +90 -0
- package/css/hover-card.css +58 -50
- package/css/icon-wrapper.css +5 -0
- package/css/icon.css +5 -0
- package/css/image-cropper.css +231 -0
- package/css/image-viewer.css +167 -22
- package/css/image.css +7 -2
- package/css/infinite-scroll.css +6 -1
- package/css/json-viewer.css +241 -0
- package/css/layout.css +11 -10
- package/css/list.css +13 -8
- package/css/listbox.css +25 -4
- package/css/loading-bar.css +12 -1
- package/css/log.css +6 -1
- package/css/marquee.css +14 -0
- package/css/masonry.css +63 -0
- package/css/mention.css +105 -32
- package/css/menu.css +131 -46
- package/css/menubar.css +150 -66
- package/css/navigation-menu.css +59 -29
- package/css/number-animation.css +8 -3
- package/css/number-field.css +178 -16
- package/css/overlay-arrow.css +51 -0
- package/css/page-header.css +10 -5
- package/css/pagination.css +18 -13
- package/css/password-input.css +356 -0
- package/css/pin-input.css +18 -10
- package/css/popconfirm.css +73 -16
- package/css/popover.css +88 -44
- package/css/popselect.css +201 -52
- package/css/progress.css +52 -7
- package/css/qr-code.css +6 -1
- package/css/radio-group.css +19 -8
- package/css/rating.css +7 -2
- package/css/reset.css +17 -0
- package/css/result.css +11 -6
- package/css/scroll-area.css +65 -94
- package/css/scrollbar.css +167 -0
- package/css/segmented.css +215 -0
- package/css/select.css +292 -124
- package/css/separator.css +7 -2
- package/css/side-nav.css +116 -19
- package/css/signature-pad.css +144 -0
- package/css/skeleton.css +12 -1
- package/css/slider.css +15 -10
- package/css/space.css +117 -0
- package/css/spinner.css +31 -11
- package/css/splitter.css +5 -0
- package/css/statistic.css +14 -9
- package/css/steps.css +30 -8
- package/css/switch.css +62 -13
- package/css/table.css +136 -37
- package/css/tabs.css +9 -4
- package/css/tag.css +177 -0
- package/css/tags-input.css +83 -40
- package/css/text-field.css +154 -36
- package/css/thread.css +6 -1
- package/css/time-field.css +102 -16
- package/css/time-picker.css +264 -69
- package/css/time.css +5 -0
- package/css/timeline.css +15 -10
- package/css/timer.css +119 -0
- package/css/toast.css +46 -21
- package/css/toaster.css +6 -1
- package/css/toggle-group.css +5 -0
- package/css/toggle.css +11 -6
- package/css/tone.css +10 -5
- package/css/toolbar.css +6 -1
- package/css/tooltip.css +54 -38
- package/css/tour.css +128 -63
- package/css/transfer.css +73 -17
- package/css/tree-select.css +203 -83
- package/css/tree.css +90 -1
- package/css/typography.css +9 -4
- package/css/undefined.css +11 -1
- package/css/virtualizer.css +8 -1
- package/css/watermark.css +6 -2
- package/index.css +17 -1
- package/index.unlayered.css +9394 -2883
- package/package.json +19 -4
- 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:
|
|
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-
|
|
44
|
-
padding-inline: var(--xh-dialog-px, var(--xh-
|
|
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-
|
|
111
|
+
box-shadow: var(--xh-dialog-shadow, var(--xh-elevation-sheet));
|
|
49
112
|
}
|
|
50
113
|
|
|
51
|
-
/*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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-
|
|
202
|
-
padding-inline: var(--xh-drawer-px, var(--xh-
|
|
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-
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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:
|
|
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:
|
|
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
|
}
|
package/css/dynamic-input.css
CHANGED
|
@@ -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='
|
|
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-
|
|
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:
|
|
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='
|
|
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='
|
|
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='
|
|
83
|
-
[data-scope='dynamic-input'][data-part='move-up-trigger']:
|
|
84
|
-
[data-scope='dynamic-input'][data-part='move-down-trigger']:
|
|
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='
|
|
90
|
-
color: var(--xh-dynamic-input-
|
|
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='
|
|
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='
|
|
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']:
|
|
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
|
}
|