@studiocms/ui 0.0.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -544
- package/package.json +11 -6
- package/src/components/Button.astro +303 -269
- package/src/components/Card.astro +37 -13
- package/src/components/Center.astro +2 -2
- package/src/components/Checkbox.astro +99 -29
- package/src/components/Divider.astro +15 -8
- package/src/components/Dropdown/Dropdown.astro +102 -41
- package/src/components/Dropdown/dropdown.ts +111 -23
- package/src/components/Footer.astro +137 -0
- package/src/components/Input.astro +42 -14
- package/src/components/Modal/Modal.astro +84 -30
- package/src/components/Modal/modal.ts +43 -9
- package/src/components/RadioGroup.astro +153 -29
- package/src/components/Row.astro +16 -7
- package/src/components/SearchSelect.astro +278 -222
- package/src/components/Select.astro +260 -127
- package/src/components/Sidebar/Double.astro +12 -12
- package/src/components/Sidebar/Single.astro +6 -6
- package/src/components/Sidebar/helpers.ts +53 -7
- package/src/components/Tabs/TabItem.astro +47 -0
- package/src/components/Tabs/Tabs.astro +376 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Textarea.astro +56 -15
- package/src/components/ThemeToggle.astro +14 -8
- package/src/components/Toast/Toaster.astro +171 -31
- package/src/components/Toggle.astro +89 -21
- package/src/components/User.astro +34 -15
- package/src/components/index.ts +24 -22
- package/src/components.ts +2 -0
- package/src/css/colors.css +65 -65
- package/src/css/resets.css +0 -1
- package/src/integration.ts +18 -0
- package/src/layouts/RootLayout.astro +1 -2
- package/src/types/index.ts +1 -1
- package/src/utils/ThemeHelper.ts +135 -117
- package/src/utils/create-resolver.ts +30 -0
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLTag, Polymorphic } from 'astro/types';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Props for the card component.
|
|
6
|
+
*/
|
|
4
7
|
type Props<As extends HTMLTag = 'div'> = Omit<Polymorphic<{ as: As }>, 'as'> & {
|
|
8
|
+
/**
|
|
9
|
+
* The polymorphic component to render the card as. Defaults to `div`.
|
|
10
|
+
*/
|
|
5
11
|
as?: As;
|
|
6
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Whether the card should be full width. Defaults to `false`.
|
|
14
|
+
*/
|
|
7
15
|
fullWidth?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the card should be full height. Defaults to `false`.
|
|
18
|
+
*/
|
|
8
19
|
fullHeight?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The variant of the card. Defaults to `default`.
|
|
22
|
+
*/
|
|
23
|
+
variant?: 'default' | 'filled';
|
|
9
24
|
};
|
|
10
25
|
|
|
11
|
-
const { as: As = 'div',
|
|
26
|
+
const { as: As = 'div', fullWidth, fullHeight, variant = 'default', ...props } = Astro.props;
|
|
12
27
|
---
|
|
13
|
-
<As class="card" class:list={[fullWidth && "full-w", fullHeight && "full-h",
|
|
14
|
-
<div class="card-header">
|
|
28
|
+
<As class="sui-card" class:list={[fullWidth && "full-w", fullHeight && "full-h", variant]} {...props}>
|
|
29
|
+
<div class="sui-card-header">
|
|
15
30
|
<slot name="header" />
|
|
16
31
|
</div>
|
|
17
|
-
<div class="card-body">
|
|
32
|
+
<div class="sui-card-body">
|
|
18
33
|
<slot />
|
|
19
34
|
</div>
|
|
20
|
-
<div class="card-footer">
|
|
35
|
+
<div class="sui-card-footer">
|
|
21
36
|
<slot name="footer" />
|
|
22
37
|
</div>
|
|
23
38
|
</As>
|
|
24
39
|
<style>
|
|
25
|
-
.card {
|
|
40
|
+
.sui-card {
|
|
26
41
|
border: 1px solid hsl(var(--border));
|
|
27
42
|
background-color: hsl(var(--background-base));
|
|
28
43
|
border-radius: .5rem;
|
|
@@ -30,32 +45,41 @@ const { as: As = 'div', class: className, fullWidth, fullHeight, ...props } = As
|
|
|
30
45
|
height: fit-content;
|
|
31
46
|
}
|
|
32
47
|
|
|
33
|
-
.card.
|
|
48
|
+
.sui-card.filled {
|
|
49
|
+
background-color: hsl(var(--background-step-3));
|
|
50
|
+
border: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sui-card.full-w {
|
|
34
54
|
width: 100%;
|
|
35
55
|
}
|
|
36
56
|
|
|
37
|
-
.card.full-h {
|
|
57
|
+
.sui-card.full-h {
|
|
38
58
|
height: 100%;
|
|
39
59
|
}
|
|
40
60
|
|
|
41
|
-
.card-header:has(*) {
|
|
61
|
+
.sui-card-header:has(*) {
|
|
42
62
|
padding: 1rem 1rem 0rem 1rem;
|
|
43
63
|
* {
|
|
44
64
|
margin: 0;
|
|
45
65
|
}
|
|
46
66
|
}
|
|
47
67
|
|
|
48
|
-
.card-body {
|
|
68
|
+
.sui-card-body {
|
|
49
69
|
padding: 1rem;
|
|
50
70
|
}
|
|
51
71
|
|
|
52
|
-
.card-footer:has(*) {
|
|
72
|
+
.sui-card-footer:has(*) {
|
|
53
73
|
border-top: 1px solid hsl(var(--border));
|
|
54
74
|
padding: 1rem;
|
|
55
75
|
}
|
|
56
76
|
|
|
77
|
+
.filled .sui-card-footer {
|
|
78
|
+
border: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
@media screen and (max-width: 840px) {
|
|
58
|
-
.card {
|
|
82
|
+
.sui-card {
|
|
59
83
|
width: 100%;
|
|
60
84
|
}
|
|
61
85
|
}
|
|
@@ -3,15 +3,39 @@ import Checkmark from '../icons/Checkmark.astro';
|
|
|
3
3
|
import type { StudioCMSColorway } from '../utils/colors';
|
|
4
4
|
import { generateID } from '../utils/generateID';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* The props for the Checkbox component.
|
|
8
|
+
*/
|
|
6
9
|
interface Props {
|
|
10
|
+
/**
|
|
11
|
+
* The label of the checkbox.
|
|
12
|
+
*/
|
|
7
13
|
label: string;
|
|
14
|
+
/**
|
|
15
|
+
* The size of the checkbox. Defaults to `md`.
|
|
16
|
+
*/
|
|
8
17
|
size?: 'sm' | 'md' | 'lg';
|
|
18
|
+
/**
|
|
19
|
+
* The color of the checkbox. Defaults to `default`.
|
|
20
|
+
*/
|
|
9
21
|
color?: StudioCMSColorway;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the checkbox is checked by default.
|
|
24
|
+
*/
|
|
10
25
|
defaultChecked?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether the checkbox is disabled.
|
|
28
|
+
*/
|
|
11
29
|
disabled?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The name of the checkbox.
|
|
32
|
+
*/
|
|
12
33
|
name?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the checkbox is required.
|
|
36
|
+
*/
|
|
13
37
|
isRequired?: boolean;
|
|
14
|
-
}
|
|
38
|
+
}
|
|
15
39
|
|
|
16
40
|
const {
|
|
17
41
|
size = 'md',
|
|
@@ -30,7 +54,7 @@ const iconSizes = {
|
|
|
30
54
|
};
|
|
31
55
|
---
|
|
32
56
|
<label
|
|
33
|
-
class="checkmark-label"
|
|
57
|
+
class="sui-checkmark-label"
|
|
34
58
|
for={name}
|
|
35
59
|
class:list={[
|
|
36
60
|
disabled && "disabled",
|
|
@@ -38,9 +62,15 @@ const iconSizes = {
|
|
|
38
62
|
size,
|
|
39
63
|
]}
|
|
40
64
|
>
|
|
41
|
-
<div
|
|
65
|
+
<div
|
|
66
|
+
class="sui-checkmark-container"
|
|
67
|
+
tabindex="0"
|
|
68
|
+
role="checkbox"
|
|
69
|
+
aria-checked={defaultChecked}
|
|
70
|
+
aria-labelledby={`label-${name}`}
|
|
71
|
+
>
|
|
42
72
|
<Checkmark
|
|
43
|
-
class={'checkmark'}
|
|
73
|
+
class={'sui-checkmark'}
|
|
44
74
|
width={iconSizes[size]}
|
|
45
75
|
height={iconSizes[size]}
|
|
46
76
|
/>
|
|
@@ -51,15 +81,48 @@ const iconSizes = {
|
|
|
51
81
|
checked={defaultChecked}
|
|
52
82
|
disabled={disabled}
|
|
53
83
|
required={isRequired}
|
|
54
|
-
class="checkbox"
|
|
84
|
+
class="sui-checkbox"
|
|
85
|
+
hidden
|
|
55
86
|
/>
|
|
56
87
|
</div>
|
|
57
|
-
<span>
|
|
88
|
+
<span id={`label-${name}`}>
|
|
58
89
|
{label} <span class="req-star">{isRequired && "*"}</span>
|
|
59
90
|
</span>
|
|
60
91
|
</label>
|
|
92
|
+
<script>
|
|
93
|
+
const elements = document.querySelectorAll<HTMLDivElement>('.sui-checkmark-container');
|
|
94
|
+
const checkbox = document.querySelectorAll<HTMLInputElement>('.sui-checkbox');
|
|
95
|
+
|
|
96
|
+
for (const element of elements) {
|
|
97
|
+
if (element.dataset.initialized) continue;
|
|
98
|
+
|
|
99
|
+
element.dataset.initialized = 'true';
|
|
100
|
+
|
|
101
|
+
element.addEventListener('keydown', (e) => {
|
|
102
|
+
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
103
|
+
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
|
|
106
|
+
const checkbox = element.querySelector<HTMLInputElement>('.sui-checkbox');
|
|
107
|
+
|
|
108
|
+
if (!checkbox) return;
|
|
109
|
+
|
|
110
|
+
checkbox.click();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (const box of checkbox) {
|
|
115
|
+
if (box.dataset.initialized) continue;
|
|
116
|
+
|
|
117
|
+
box.dataset.initialized = 'true';
|
|
118
|
+
|
|
119
|
+
box.addEventListener('change', (e) => {
|
|
120
|
+
box.parentElement!.ariaChecked = (e.target as HTMLInputElement).checked ? 'true' : 'false';
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
</script>
|
|
61
124
|
<style>
|
|
62
|
-
.checkmark-label {
|
|
125
|
+
.sui-checkmark-label {
|
|
63
126
|
display: flex;
|
|
64
127
|
flex-direction: row;
|
|
65
128
|
align-items: center;
|
|
@@ -68,13 +131,13 @@ const iconSizes = {
|
|
|
68
131
|
margin: .25rem 0;
|
|
69
132
|
}
|
|
70
133
|
|
|
71
|
-
.checkmark-label.disabled {
|
|
134
|
+
.sui-checkmark-label.disabled {
|
|
72
135
|
opacity: 0.5;
|
|
73
136
|
pointer-events: none;
|
|
74
137
|
color: hsl(var(--text-muted));
|
|
75
138
|
}
|
|
76
139
|
|
|
77
|
-
.checkmark-container {
|
|
140
|
+
.sui-checkmark-container {
|
|
78
141
|
display: flex;
|
|
79
142
|
align-items: center;
|
|
80
143
|
justify-content: center;
|
|
@@ -82,57 +145,64 @@ const iconSizes = {
|
|
|
82
145
|
border: 2px solid hsl(var(--default-base));
|
|
83
146
|
border-radius: .5rem;
|
|
84
147
|
cursor: pointer;
|
|
85
|
-
transition:
|
|
148
|
+
transition: background-color .15s, border .15s, transform .15s;
|
|
149
|
+
transition-timing-function: ease;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.sui-checkmark-container:focus-visible {
|
|
153
|
+
outline: 2px solid hsl(var(--text-normal));
|
|
154
|
+
outline-offset: 2px;
|
|
86
155
|
}
|
|
87
156
|
|
|
88
|
-
.checkmark-label:hover .checkmark-container {
|
|
157
|
+
.sui-checkmark-label:hover .sui-checkmark-container {
|
|
89
158
|
background-color: hsl(var(--default-hover));
|
|
90
159
|
}
|
|
91
160
|
|
|
92
|
-
.checkmark-label:active .checkmark-container {
|
|
161
|
+
.sui-checkmark-label:active .sui-checkmark-container {
|
|
93
162
|
background-color: hsl(var(--default-active));
|
|
94
163
|
scale: 0.9;
|
|
95
164
|
}
|
|
96
165
|
|
|
97
|
-
.checkmark-label.sm {
|
|
166
|
+
.sui-checkmark-label.sm {
|
|
98
167
|
font-size: .875em;
|
|
99
168
|
}
|
|
100
169
|
|
|
101
|
-
.checkmark-label.sm .checkmark-container {
|
|
170
|
+
.sui-checkmark-label.sm .sui-checkmark-container {
|
|
102
171
|
width: 1.25rem;
|
|
103
172
|
height: 1.25rem;
|
|
104
173
|
}
|
|
105
174
|
|
|
106
|
-
.checkmark-label.md .checkmark-container {
|
|
175
|
+
.sui-checkmark-label.md .sui-checkmark-container {
|
|
107
176
|
width: 1.5rem;
|
|
108
177
|
height: 1.5rem;
|
|
109
178
|
}
|
|
110
179
|
|
|
111
|
-
.checkmark-label.lg {
|
|
180
|
+
.sui-checkmark-label.lg {
|
|
112
181
|
font-size: 1.125em;
|
|
113
182
|
}
|
|
114
183
|
|
|
115
|
-
.checkmark-label.lg .checkmark-container {
|
|
184
|
+
.sui-checkmark-label.lg .sui-checkmark-container {
|
|
116
185
|
width: 1.75rem;
|
|
117
186
|
height: 1.75rem;
|
|
187
|
+
padding: .125rem;
|
|
118
188
|
}
|
|
119
189
|
|
|
120
|
-
.primary .checkmark-container:has(.checkbox:checked) {
|
|
190
|
+
.primary .sui-checkmark-container:has(.sui-checkbox:checked) {
|
|
121
191
|
border-color: hsl(var(--primary-base));
|
|
122
192
|
background-color: hsl(var(--primary-base));
|
|
123
193
|
}
|
|
124
194
|
|
|
125
|
-
.success .checkmark-container:has(.checkbox:checked) {
|
|
195
|
+
.success .sui-checkmark-container:has(.sui-checkbox:checked) {
|
|
126
196
|
border-color: hsl(var(--success-base));
|
|
127
197
|
background-color: hsl(var(--success-base));
|
|
128
198
|
}
|
|
129
199
|
|
|
130
|
-
.warning .checkmark-container:has(.checkbox:checked) {
|
|
200
|
+
.warning .sui-checkmark-container:has(.sui-checkbox:checked) {
|
|
131
201
|
border-color: hsl(var(--warning-base));
|
|
132
202
|
background-color: hsl(var(--warning-base));
|
|
133
203
|
}
|
|
134
204
|
|
|
135
|
-
.danger .checkmark-container:has(.checkbox:checked) {
|
|
205
|
+
.danger .sui-checkmark-container:has(.sui-checkbox:checked) {
|
|
136
206
|
border-color: hsl(var(--danger-base));
|
|
137
207
|
background-color: hsl(var(--danger-base));
|
|
138
208
|
}
|
|
@@ -142,7 +212,7 @@ const iconSizes = {
|
|
|
142
212
|
font-weight: 700;
|
|
143
213
|
}
|
|
144
214
|
|
|
145
|
-
.checkbox {
|
|
215
|
+
.sui-checkbox {
|
|
146
216
|
width: 0;
|
|
147
217
|
height: 0;
|
|
148
218
|
visibility: hidden;
|
|
@@ -151,29 +221,29 @@ const iconSizes = {
|
|
|
151
221
|
}
|
|
152
222
|
</style>
|
|
153
223
|
<style is:global>
|
|
154
|
-
.checkmark polyline {
|
|
224
|
+
.sui-checkmark polyline {
|
|
155
225
|
transition: all .15s ease;
|
|
156
226
|
color: hsl(var(--text-normal));
|
|
157
227
|
}
|
|
158
228
|
|
|
159
|
-
.primary .checkmark polyline {
|
|
229
|
+
.primary .sui-checkmark polyline {
|
|
160
230
|
color: hsl(var(--text-inverted));
|
|
161
231
|
}
|
|
162
232
|
|
|
163
|
-
.success .checkmark polyline {
|
|
233
|
+
.success .sui-checkmark polyline {
|
|
164
234
|
color: hsl(var(--text-dark));
|
|
165
235
|
}
|
|
166
236
|
|
|
167
|
-
.warning .checkmark polyline {
|
|
237
|
+
.warning .sui-checkmark polyline {
|
|
168
238
|
color: hsl(var(--text-dark));
|
|
169
239
|
}
|
|
170
240
|
|
|
171
|
-
.danger .checkmark polyline {
|
|
241
|
+
.danger .sui-checkmark polyline {
|
|
172
242
|
color: hsl(var(--text-light));
|
|
173
243
|
}
|
|
174
244
|
|
|
175
|
-
.checkmark-container:has(.checkbox:checked) {
|
|
176
|
-
.checkmark polyline {
|
|
245
|
+
.sui-checkmark-container:has(.sui-checkbox:checked) {
|
|
246
|
+
.sui-checkmark polyline {
|
|
177
247
|
stroke-dashoffset: 44;
|
|
178
248
|
}
|
|
179
249
|
}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* Props for the divider component.
|
|
4
|
+
*/
|
|
2
5
|
interface Props {
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The background color of the divider, used to "hide" content behind the slot. Defaults to `background-base`.
|
|
8
|
+
*/
|
|
9
|
+
background?: 'background-base' | 'background-step-1' | 'background-step-2' | 'background-step-3';
|
|
10
|
+
}
|
|
5
11
|
|
|
6
12
|
const { background = 'background-base' } = Astro.props;
|
|
7
13
|
---
|
|
8
|
-
<div class="
|
|
9
|
-
<
|
|
10
|
-
<div class="content" style={`background-color: hsl(var(--${background}));`}>
|
|
14
|
+
<div class="sui-divider-container">
|
|
15
|
+
<hr class="sui-divider-line" />
|
|
16
|
+
<div class="sui-divider-content" style={`background-color: hsl(var(--${background}));`}>
|
|
11
17
|
<slot />
|
|
12
18
|
</div>
|
|
13
19
|
</div>
|
|
14
20
|
<style>
|
|
15
|
-
.
|
|
21
|
+
.sui-divider-container {
|
|
16
22
|
display: flex;
|
|
17
23
|
width: 100%;
|
|
18
24
|
align-items: center;
|
|
@@ -20,7 +26,7 @@ const { background = 'background-base' } = Astro.props;
|
|
|
20
26
|
position: relative;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
.line {
|
|
29
|
+
.sui-divider-line {
|
|
24
30
|
position: absolute;
|
|
25
31
|
top: 50%;
|
|
26
32
|
left: 50%;
|
|
@@ -29,9 +35,10 @@ const { background = 'background-base' } = Astro.props;
|
|
|
29
35
|
height: 1px;
|
|
30
36
|
background-color: hsl(var(--border));
|
|
31
37
|
z-index: 1;
|
|
38
|
+
border: none;
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
.content {
|
|
41
|
+
.sui-divider-content {
|
|
35
42
|
padding: .25rem .5rem;
|
|
36
43
|
z-index: 2;
|
|
37
44
|
color: hsl(var(--text-muted));
|
|
@@ -3,50 +3,108 @@ import Icon from '../../utils/Icon.astro';
|
|
|
3
3
|
import type { StudioCMSColorway } from '../../utils/colors';
|
|
4
4
|
import type { HeroIconName } from '../../utils/iconType';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* An option in the dropdown.
|
|
8
|
+
*/
|
|
6
9
|
interface Option {
|
|
10
|
+
/**
|
|
11
|
+
* The label of the option.
|
|
12
|
+
*/
|
|
7
13
|
label: string;
|
|
14
|
+
/**
|
|
15
|
+
* The value of the option, returned by the helper when listened for.
|
|
16
|
+
*/
|
|
8
17
|
value: string;
|
|
18
|
+
/**
|
|
19
|
+
* Whether the option is disabled.
|
|
20
|
+
*/
|
|
9
21
|
disabled?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* The color of the option.
|
|
24
|
+
*/
|
|
10
25
|
color?: StudioCMSColorway;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The icon to display next to the option.
|
|
28
|
+
*/
|
|
29
|
+
icon?: HeroIconName;
|
|
30
|
+
/**
|
|
31
|
+
* The href to link to when the option is clicked. When given, the option will be rendered as an anchor tag.
|
|
32
|
+
*/
|
|
33
|
+
href?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The props for the Dropdown component.
|
|
38
|
+
*/
|
|
15
39
|
interface Props {
|
|
40
|
+
/**
|
|
41
|
+
* The options to display in the dropdown.
|
|
42
|
+
*/
|
|
16
43
|
options: Option[];
|
|
44
|
+
/**
|
|
45
|
+
* Whether the dropdown is disabled.
|
|
46
|
+
*/
|
|
17
47
|
disabled?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The ID of the dropdown. Required because of the helper.
|
|
50
|
+
*/
|
|
18
51
|
id: string;
|
|
52
|
+
/**
|
|
53
|
+
* The alignment of the dropdown, defaults to `center`. Will not work on mobile due to size constraints.
|
|
54
|
+
*/
|
|
19
55
|
align?: 'start' | 'center' | 'end';
|
|
56
|
+
/**
|
|
57
|
+
* The type of click with which the dropdown is clicked. Defaults to `left`.
|
|
58
|
+
*/
|
|
20
59
|
triggerOn?: 'left' | 'right' | 'both';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
60
|
+
/**
|
|
61
|
+
* The offset of the dropdown from the trigger element in pixels.
|
|
62
|
+
*/
|
|
63
|
+
offset?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
options,
|
|
68
|
+
disabled = false,
|
|
69
|
+
align = 'center',
|
|
70
|
+
id,
|
|
71
|
+
triggerOn = 'left',
|
|
72
|
+
offset = 0,
|
|
73
|
+
} = Astro.props;
|
|
25
74
|
---
|
|
26
75
|
<div
|
|
27
|
-
class="dropdown-container"
|
|
76
|
+
class="sui-dropdown-container"
|
|
28
77
|
class:list={[disabled && 'disabled']}
|
|
29
78
|
data-align={align}
|
|
30
79
|
id={`${id}-container`}
|
|
31
80
|
data-trigger={triggerOn}
|
|
32
|
-
transition:persist
|
|
81
|
+
transition:persist
|
|
82
|
+
transition:persist-props
|
|
33
83
|
>
|
|
34
|
-
<div class="dropdown-toggle" id={`${id}-toggle-btn`}>
|
|
84
|
+
<div class="sui-dropdown-toggle" id={`${id}-toggle-btn`}>
|
|
35
85
|
<slot />
|
|
36
86
|
</div>
|
|
37
|
-
<ul
|
|
87
|
+
<ul
|
|
88
|
+
class="sui-dropdown"
|
|
89
|
+
class:list={[align]}
|
|
90
|
+
role="listbox" id={`${id}-dropdown`}
|
|
91
|
+
transition:persist
|
|
92
|
+
transition:persist-props
|
|
93
|
+
aria-labelledby={`${id}-toggle-btn`}
|
|
94
|
+
>
|
|
38
95
|
{options.map(({ value, disabled, color, label, icon, href }) => (
|
|
39
96
|
<li
|
|
40
|
-
class="dropdown-option"
|
|
41
|
-
role="option"
|
|
97
|
+
class="sui-dropdown-option"
|
|
42
98
|
data-value={value}
|
|
43
99
|
class:list={[disabled && "disabled", icon && "has-icon", color, href && "has-href"]}
|
|
100
|
+
role="option"
|
|
101
|
+
aria-selected="false"
|
|
44
102
|
>
|
|
45
103
|
{icon && (
|
|
46
104
|
<Icon width={24} height={24} name={icon} />
|
|
47
105
|
)}
|
|
48
106
|
{href ? (
|
|
49
|
-
<a href={href} class="dropdown-link">{label}</a>
|
|
107
|
+
<a href={href} class="sui-dropdown-link">{label}</a>
|
|
50
108
|
) : (
|
|
51
109
|
<span>{label}</span>
|
|
52
110
|
)}
|
|
@@ -55,18 +113,18 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
55
113
|
</ul>
|
|
56
114
|
</div>
|
|
57
115
|
<style define:vars={{ offset: `${offset}px` }}>
|
|
58
|
-
.dropdown-toggle {
|
|
116
|
+
.sui-dropdown-toggle {
|
|
59
117
|
width: fit-content;
|
|
60
118
|
}
|
|
61
119
|
|
|
62
|
-
.dropdown-container {
|
|
120
|
+
.sui-dropdown-container {
|
|
63
121
|
position: relative;
|
|
64
122
|
display: flex;
|
|
65
123
|
flex-direction: column;
|
|
66
124
|
gap: .25rem;
|
|
67
125
|
}
|
|
68
126
|
|
|
69
|
-
.dropdown {
|
|
127
|
+
.sui-dropdown {
|
|
70
128
|
position: absolute;
|
|
71
129
|
list-style: none;
|
|
72
130
|
margin: 0;
|
|
@@ -134,11 +192,11 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
134
192
|
}
|
|
135
193
|
}
|
|
136
194
|
|
|
137
|
-
.dropdown.initialized {
|
|
195
|
+
.sui-dropdown.initialized {
|
|
138
196
|
animation: pop-down .15s ease forwards;
|
|
139
197
|
}
|
|
140
198
|
|
|
141
|
-
.dropdown.initialized.active {
|
|
199
|
+
.sui-dropdown.initialized.active {
|
|
142
200
|
display: flex;
|
|
143
201
|
border: 1px solid hsl(var(--border));
|
|
144
202
|
height: auto;
|
|
@@ -147,36 +205,36 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
147
205
|
animation: pop-up .15s ease forwards;
|
|
148
206
|
}
|
|
149
207
|
|
|
150
|
-
.dropdown.initialized.below {
|
|
208
|
+
.sui-dropdown.initialized.below {
|
|
151
209
|
top: calc(100% + .25rem + var(--offset)) !important;
|
|
152
210
|
bottom: auto;
|
|
153
211
|
|
|
154
212
|
transform-origin: top center;
|
|
155
213
|
}
|
|
156
214
|
|
|
157
|
-
.dropdown.below.start {
|
|
215
|
+
.sui-dropdown.below.start {
|
|
158
216
|
transform-origin: top left;
|
|
159
217
|
}
|
|
160
218
|
|
|
161
|
-
.dropdown.below.end {
|
|
219
|
+
.sui-dropdown.below.end {
|
|
162
220
|
transform-origin: top right;
|
|
163
221
|
}
|
|
164
222
|
|
|
165
|
-
.dropdown.above {
|
|
223
|
+
.sui-dropdown.above {
|
|
166
224
|
top: auto;
|
|
167
225
|
bottom: calc(100% + .25rem + var(--offset)) !important;
|
|
168
226
|
transform-origin: bottom center;
|
|
169
227
|
}
|
|
170
228
|
|
|
171
|
-
.dropdown.above.start {
|
|
229
|
+
.sui-dropdown.above.start {
|
|
172
230
|
transform-origin: bottom left;
|
|
173
231
|
}
|
|
174
232
|
|
|
175
|
-
.dropdown.above.end {
|
|
233
|
+
.sui-dropdown.above.end {
|
|
176
234
|
transform-origin: bottom right;
|
|
177
235
|
}
|
|
178
236
|
|
|
179
|
-
.dropdown-option {
|
|
237
|
+
.sui-dropdown-option {
|
|
180
238
|
padding: .5rem .75rem;
|
|
181
239
|
cursor: pointer;
|
|
182
240
|
font-size: .975em;
|
|
@@ -187,67 +245,70 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
187
245
|
align-items: center;
|
|
188
246
|
width: 100%;
|
|
189
247
|
white-space: normal;
|
|
248
|
+
user-select: none;
|
|
190
249
|
}
|
|
191
250
|
|
|
192
|
-
.dropdown-option:hover {
|
|
251
|
+
.sui-dropdown-option:hover, .sui-dropdown-option:focus, .sui-dropdown-option.focused {
|
|
193
252
|
background-color: hsl(var(--background-step-3));
|
|
194
253
|
}
|
|
195
254
|
|
|
196
|
-
.dropdown-option.has-href {
|
|
255
|
+
.sui-dropdown-option.has-href {
|
|
197
256
|
padding: 0;
|
|
198
257
|
}
|
|
199
258
|
|
|
200
|
-
.dropdown-link {
|
|
259
|
+
.sui-dropdown-link {
|
|
201
260
|
padding: .5rem .75rem;
|
|
202
261
|
width: 100%;
|
|
262
|
+
text-decoration: none;
|
|
263
|
+
color: hsl(var(--text-normal));
|
|
203
264
|
}
|
|
204
265
|
|
|
205
|
-
.dropdown-option.primary {
|
|
266
|
+
.sui-dropdown-option.primary {
|
|
206
267
|
color: hsl(var(--primary-base));
|
|
207
268
|
}
|
|
208
269
|
|
|
209
|
-
.dropdown-option.primary:hover {
|
|
270
|
+
.sui-dropdown-option.primary:hover {
|
|
210
271
|
background-color: hsl(var(--primary-base));
|
|
211
272
|
color: hsl(var(--text-inverted));
|
|
212
273
|
}
|
|
213
274
|
|
|
214
|
-
.dropdown-option.success {
|
|
275
|
+
.sui-dropdown-option.success {
|
|
215
276
|
color: hsl(var(--success-base));
|
|
216
277
|
}
|
|
217
278
|
|
|
218
|
-
.dropdown-option.success:hover {
|
|
279
|
+
.sui-dropdown-option.success:hover {
|
|
219
280
|
background-color: hsl(var(--success-base));
|
|
220
281
|
color: hsl(var(--text-dark));
|
|
221
282
|
}
|
|
222
283
|
|
|
223
|
-
.dropdown-option.warning {
|
|
284
|
+
.sui-dropdown-option.warning {
|
|
224
285
|
color: hsl(var(--warning-base));
|
|
225
286
|
}
|
|
226
287
|
|
|
227
|
-
.dropdown-option.warning:hover {
|
|
288
|
+
.sui-dropdown-option.warning:hover {
|
|
228
289
|
background-color: hsl(var(--warning-base));
|
|
229
290
|
color: hsl(var(--text-dark));
|
|
230
291
|
}
|
|
231
292
|
|
|
232
|
-
.dropdown-option.danger {
|
|
293
|
+
.sui-dropdown-option.danger {
|
|
233
294
|
color: hsl(var(--danger-base));
|
|
234
295
|
}
|
|
235
296
|
|
|
236
|
-
.dropdown-option.danger:hover {
|
|
297
|
+
.sui-dropdown-option.danger:hover {
|
|
237
298
|
background-color: hsl(var(--danger-base));
|
|
238
299
|
color: hsl(var(--text-light));
|
|
239
300
|
}
|
|
240
301
|
|
|
241
|
-
.dropdown-option.disabled {
|
|
302
|
+
.sui-dropdown-option.disabled {
|
|
242
303
|
pointer-events: none;
|
|
243
304
|
color: hsl(var(--text-muted));
|
|
244
305
|
}
|
|
245
306
|
|
|
246
|
-
.dropdown-option.end {
|
|
307
|
+
.sui-dropdown-option.end {
|
|
247
308
|
justify-content: space-between;
|
|
248
309
|
}
|
|
249
310
|
|
|
250
|
-
.dropdown-option.has-icon {
|
|
311
|
+
.sui-dropdown-option.has-icon {
|
|
251
312
|
padding-left: .5rem;
|
|
252
313
|
}
|
|
253
314
|
</style>
|