@studiocms/ui 0.3.2 → 0.4.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/dist/components/Accordion/Accordion.astro +23 -0
- package/dist/components/Accordion/Item.astro +21 -0
- package/dist/components/Accordion/accordion.css +64 -0
- package/dist/components/Accordion/accordion.d.ts +1 -0
- package/dist/components/Accordion/accordion.js +70 -0
- package/dist/components/Badge/Badge.astro +49 -0
- package/dist/components/Badge/badge.css +111 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.astro +31 -0
- package/dist/components/Breadcrumbs/breadcrumbs.css +15 -0
- package/dist/components/Button/Button.astro +75 -0
- package/dist/components/Button/button.css +292 -0
- package/{src/components → dist/components/Card}/Card.astro +1 -48
- package/dist/components/Card/card.css +38 -0
- package/dist/components/Center/Center.astro +7 -0
- package/dist/components/Center/center.css +8 -0
- package/dist/components/Checkbox/Checkbox.astro +95 -0
- package/dist/components/Checkbox/checkbox.css +119 -0
- package/dist/components/Checkbox/checkbox.d.ts +2 -0
- package/dist/components/Checkbox/checkbox.js +20 -0
- package/{src/components → dist/components/Divider}/Divider.astro +2 -25
- package/dist/components/Divider/divider.css +21 -0
- package/dist/components/Dropdown/Dropdown.astro +116 -0
- package/dist/components/Dropdown/dropdown.css +180 -0
- package/dist/components/Dropdown/dropdown.d.ts +48 -0
- package/dist/components/Dropdown/dropdown.js +201 -0
- package/dist/components/Footer/Footer.astro +58 -0
- package/dist/components/Footer/footer.css +68 -0
- package/dist/components/Group/Group.astro +7 -0
- package/dist/components/Group/group.css +19 -0
- package/{src/utils → dist/components/Icon}/Icon.astro +1 -1
- package/{src/utils/iconType.ts → dist/components/Icon/iconType.d.ts} +0 -1
- package/dist/components/Icon/iconType.js +0 -0
- package/{src/components → dist/components/Input}/Input.astro +2 -48
- package/dist/components/Input/input.css +38 -0
- package/{src → dist}/components/Modal/Modal.astro +4 -122
- package/dist/components/Modal/modal.css +100 -0
- package/dist/components/Modal/modal.d.ts +48 -0
- package/dist/components/Modal/modal.js +129 -0
- package/dist/components/Progress/Progress.astro +21 -0
- package/dist/components/Progress/helper.d.ts +13 -0
- package/dist/components/Progress/helper.js +32 -0
- package/dist/components/Progress/progress.css +29 -0
- package/dist/components/Progress/progress.d.ts +1 -0
- package/dist/components/Progress/progress.js +10 -0
- package/dist/components/RadioGroup/RadioGroup.astro +124 -0
- package/dist/components/RadioGroup/radiogroup.css +96 -0
- package/dist/components/RadioGroup/radiogroup.d.ts +1 -0
- package/dist/components/RadioGroup/radiogroup.js +48 -0
- package/{src/components → dist/components/Row}/Row.astro +1 -24
- package/dist/components/Row/row.css +18 -0
- package/dist/components/SearchSelect/SearchSelect.astro +135 -0
- package/dist/components/SearchSelect/searchselect.css +95 -0
- package/dist/components/SearchSelect/searchselect.d.ts +6 -0
- package/dist/components/SearchSelect/searchselect.js +166 -0
- package/dist/components/Select/Select.astro +147 -0
- package/dist/components/Select/select.css +110 -0
- package/dist/components/Select/select.d.ts +1 -0
- package/dist/components/Select/select.js +143 -0
- package/dist/components/Sidebar/helpers.d.ts +76 -0
- package/dist/components/Sidebar/helpers.js +160 -0
- package/{src → dist}/components/Tabs/TabItem.astro +3 -3
- package/dist/components/Tabs/Tabs.astro +150 -0
- package/dist/components/Tabs/tabs.css +121 -0
- package/dist/components/Tabs/tabs.d.ts +1 -0
- package/dist/components/Tabs/tabs.js +82 -0
- package/{src/components → dist/components/Textarea}/Textarea.astro +2 -61
- package/dist/components/Textarea/textarea.css +49 -0
- package/dist/components/ThemeToggle/ThemeToggle.astro +21 -0
- package/dist/components/ThemeToggle/themetoggle.css +17 -0
- package/dist/components/ThemeToggle/themetoggle.d.ts +1 -0
- package/dist/components/ThemeToggle/themetoggle.js +4 -0
- package/dist/components/Toast/Toaster.astro +69 -0
- package/dist/components/Toast/toast.d.ts +8 -0
- package/dist/components/Toast/toast.js +9 -0
- package/dist/components/Toast/toaster.css +168 -0
- package/dist/components/Toast/toaster.d.ts +1 -0
- package/dist/components/Toast/toaster.js +160 -0
- package/dist/components/Toggle/Toggle.astro +84 -0
- package/dist/components/Toggle/toggle.css +93 -0
- package/dist/components/Toggle/toggle.d.ts +2 -0
- package/dist/components/Toggle/toggle.js +20 -0
- package/{src/components → dist/components/User}/User.astro +3 -43
- package/dist/components/User/user.css +35 -0
- package/dist/css/colors.css +95 -0
- package/dist/css/global.css +3 -0
- package/dist/css/radii.css +6 -0
- package/dist/css/resets.css +46 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +379 -0
- package/dist/toolbar/ColorPicker.d.ts +7 -0
- package/dist/toolbar/ColorPicker.js +85 -0
- package/dist/toolbar/icon.d.ts +1 -0
- package/dist/toolbar/icon.js +4 -0
- package/dist/toolbar/index.d.ts +2 -0
- package/dist/toolbar/index.js +292 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.js +0 -0
- package/dist/utils/ThemeHelper.d.ts +49 -0
- package/dist/utils/ThemeHelper.js +113 -0
- package/{src/utils/colors.ts → dist/utils/colors.d.ts} +1 -1
- package/dist/utils/colors.js +0 -0
- package/dist/utils/generateID.d.ts +2 -0
- package/dist/utils/generateID.js +6 -0
- package/dist/utils/headers.d.ts +43 -0
- package/dist/utils/headers.js +129 -0
- package/dist/utils/iconStrings.d.ts +4 -0
- package/dist/utils/iconStrings.js +13 -0
- package/dist/utils/integration-utils.d.ts +130 -0
- package/dist/utils/integration-utils.js +161 -0
- package/package.json +25 -9
- package/src/components/BaseHead.astro +0 -22
- package/src/components/Button.astro +0 -372
- package/src/components/Center.astro +0 -16
- package/src/components/Checkbox.astro +0 -250
- package/src/components/Dropdown/Dropdown.astro +0 -314
- package/src/components/Dropdown/dropdown.ts +0 -258
- package/src/components/Dropdown/index.ts +0 -2
- package/src/components/Footer.astro +0 -137
- package/src/components/Modal/index.ts +0 -2
- package/src/components/Modal/modal.ts +0 -163
- package/src/components/RadioGroup.astro +0 -299
- package/src/components/SearchSelect.astro +0 -486
- package/src/components/Select.astro +0 -467
- package/src/components/Sidebar/helpers.ts +0 -179
- package/src/components/Sidebar/index.ts +0 -3
- package/src/components/Tabs/Tabs.astro +0 -393
- package/src/components/Tabs/index.ts +0 -2
- package/src/components/ThemeToggle.astro +0 -46
- package/src/components/Toast/Toaster.astro +0 -470
- package/src/components/Toast/index.ts +0 -2
- package/src/components/Toast/toast.ts +0 -16
- package/src/components/Toggle.astro +0 -214
- package/src/components/index.ts +0 -27
- package/src/components.ts +0 -26
- package/src/css/colors.css +0 -106
- package/src/css/global.css +0 -2
- package/src/css/resets.css +0 -54
- package/src/env.d.ts +0 -15
- package/src/integration.ts +0 -31
- package/src/layouts/RootLayout.astro +0 -33
- package/src/layouts/index.ts +0 -2
- package/src/layouts.ts +0 -1
- package/src/types/index.ts +0 -11
- package/src/utils/ThemeHelper.ts +0 -145
- package/src/utils/create-resolver.ts +0 -30
- package/src/utils/generateID.ts +0 -5
- package/src/utils/headers.ts +0 -190
- package/src/utils/iconStrings.ts +0 -29
- package/src/utils/index.ts +0 -1
- package/src/utils/virtual-module-plugin-builder.ts +0 -37
- /package/{src → dist}/components/Sidebar/Double.astro +0 -0
- /package/{src → dist}/components/Sidebar/Single.astro +0 -0
- /package/{src → dist}/icons/Checkmark.astro +0 -0
- /package/{src → dist}/icons/ChevronUpDown.astro +0 -0
- /package/{src → dist}/icons/User.astro +0 -0
- /package/{src → dist}/icons/X-Mark.astro +0 -0
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Icon from '../../utils/Icon.astro';
|
|
3
|
-
import type { StudioCMSColorway } from '../../utils/colors';
|
|
4
|
-
import type { HeroIconName } from '../../utils/iconType';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* An option in the dropdown.
|
|
8
|
-
*/
|
|
9
|
-
interface Option {
|
|
10
|
-
/**
|
|
11
|
-
* The label of the option.
|
|
12
|
-
*/
|
|
13
|
-
label: string;
|
|
14
|
-
/**
|
|
15
|
-
* The value of the option, returned by the helper when listened for.
|
|
16
|
-
*/
|
|
17
|
-
value: string;
|
|
18
|
-
/**
|
|
19
|
-
* Whether the option is disabled.
|
|
20
|
-
*/
|
|
21
|
-
disabled?: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* The color of the option.
|
|
24
|
-
*/
|
|
25
|
-
color?: StudioCMSColorway;
|
|
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
|
-
*/
|
|
39
|
-
interface Props {
|
|
40
|
-
/**
|
|
41
|
-
* The options to display in the dropdown.
|
|
42
|
-
*/
|
|
43
|
-
options: Option[];
|
|
44
|
-
/**
|
|
45
|
-
* Whether the dropdown is disabled.
|
|
46
|
-
*/
|
|
47
|
-
disabled?: boolean;
|
|
48
|
-
/**
|
|
49
|
-
* The ID of the dropdown. Required because of the helper.
|
|
50
|
-
*/
|
|
51
|
-
id: string;
|
|
52
|
-
/**
|
|
53
|
-
* The alignment of the dropdown, defaults to `center`. Will not work on mobile due to size constraints.
|
|
54
|
-
*/
|
|
55
|
-
align?: 'start' | 'center' | 'end';
|
|
56
|
-
/**
|
|
57
|
-
* The type of click with which the dropdown is clicked. Defaults to `left`.
|
|
58
|
-
*/
|
|
59
|
-
triggerOn?: 'left' | 'right' | 'both';
|
|
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;
|
|
74
|
-
---
|
|
75
|
-
<div
|
|
76
|
-
class="sui-dropdown-container"
|
|
77
|
-
class:list={[disabled && 'disabled']}
|
|
78
|
-
data-align={align}
|
|
79
|
-
id={`${id}-container`}
|
|
80
|
-
data-trigger={triggerOn}
|
|
81
|
-
transition:persist
|
|
82
|
-
transition:persist-props
|
|
83
|
-
>
|
|
84
|
-
<div class="sui-dropdown-toggle" id={`${id}-toggle-btn`}>
|
|
85
|
-
<slot />
|
|
86
|
-
</div>
|
|
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
|
-
>
|
|
95
|
-
{options.map(({ value, disabled, color, label, icon, href }) => (
|
|
96
|
-
<li
|
|
97
|
-
class="sui-dropdown-option"
|
|
98
|
-
data-value={value}
|
|
99
|
-
class:list={[disabled && "disabled", icon && "has-icon", color, href && "has-href"]}
|
|
100
|
-
role="option"
|
|
101
|
-
aria-selected="false"
|
|
102
|
-
>
|
|
103
|
-
{icon && (
|
|
104
|
-
<Icon width={24} height={24} name={icon} />
|
|
105
|
-
)}
|
|
106
|
-
{href ? (
|
|
107
|
-
<a href={href} class="sui-dropdown-link">{label}</a>
|
|
108
|
-
) : (
|
|
109
|
-
<span>{label}</span>
|
|
110
|
-
)}
|
|
111
|
-
</li>
|
|
112
|
-
))}
|
|
113
|
-
</ul>
|
|
114
|
-
</div>
|
|
115
|
-
<style define:vars={{ offset: `${offset}px` }}>
|
|
116
|
-
.sui-dropdown-toggle {
|
|
117
|
-
width: fit-content;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.sui-dropdown-container {
|
|
121
|
-
position: relative;
|
|
122
|
-
display: flex;
|
|
123
|
-
flex-direction: column;
|
|
124
|
-
gap: .25rem;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.sui-dropdown {
|
|
128
|
-
position: absolute;
|
|
129
|
-
list-style: none;
|
|
130
|
-
margin: 0;
|
|
131
|
-
padding: 0;
|
|
132
|
-
flex-direction: column;
|
|
133
|
-
border-radius: .5rem;
|
|
134
|
-
background-color: hsl(var(--background-step-2));
|
|
135
|
-
overflow: hidden;
|
|
136
|
-
left: 0;
|
|
137
|
-
z-index: 90;
|
|
138
|
-
min-width: 200px;
|
|
139
|
-
max-width: min-content;
|
|
140
|
-
|
|
141
|
-
height: 0;
|
|
142
|
-
border: none;
|
|
143
|
-
pointer-events: none;
|
|
144
|
-
user-select: none;
|
|
145
|
-
|
|
146
|
-
box-shadow: 0px 4px 8px hsl(var(--shadow), 0.5);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@keyframes pop-up {
|
|
150
|
-
0% {
|
|
151
|
-
scale: 0.9;
|
|
152
|
-
opacity: 0;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
100% {
|
|
156
|
-
scale: 1;
|
|
157
|
-
opacity: 1;
|
|
158
|
-
user-select: all;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@keyframes pop-down {
|
|
163
|
-
0% {
|
|
164
|
-
scale: 1;
|
|
165
|
-
height: auto;
|
|
166
|
-
border: initial;
|
|
167
|
-
pointer-events: all;
|
|
168
|
-
top: auto;
|
|
169
|
-
bottom: auto;
|
|
170
|
-
border: 1px solid hsl(var(--border));
|
|
171
|
-
opacity: 1;
|
|
172
|
-
user-select: all;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
99.9999% {
|
|
176
|
-
scale: 0.9;
|
|
177
|
-
height: auto;
|
|
178
|
-
border: initial;
|
|
179
|
-
pointer-events: all;
|
|
180
|
-
bottom: initial;
|
|
181
|
-
top: auto;
|
|
182
|
-
bottom: auto;
|
|
183
|
-
border: 1px solid hsl(var(--border));
|
|
184
|
-
opacity: 0;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
100% {
|
|
188
|
-
height: 0;
|
|
189
|
-
border: none;
|
|
190
|
-
pointer-events: none;
|
|
191
|
-
user-select: none;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.sui-dropdown.initialized {
|
|
196
|
-
animation: pop-down .15s ease forwards;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.sui-dropdown.initialized.active {
|
|
200
|
-
display: flex;
|
|
201
|
-
border: 1px solid hsl(var(--border));
|
|
202
|
-
height: auto;
|
|
203
|
-
pointer-events: all;
|
|
204
|
-
|
|
205
|
-
animation: pop-up .15s ease forwards;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.sui-dropdown.initialized.below {
|
|
209
|
-
top: calc(100% + .25rem + var(--offset)) !important;
|
|
210
|
-
bottom: auto;
|
|
211
|
-
|
|
212
|
-
transform-origin: top center;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.sui-dropdown.below.start {
|
|
216
|
-
transform-origin: top left;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.sui-dropdown.below.end {
|
|
220
|
-
transform-origin: top right;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.sui-dropdown.above {
|
|
224
|
-
top: auto;
|
|
225
|
-
bottom: calc(100% + .25rem + var(--offset)) !important;
|
|
226
|
-
transform-origin: bottom center;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.sui-dropdown.above.start {
|
|
230
|
-
transform-origin: bottom left;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.sui-dropdown.above.end {
|
|
234
|
-
transform-origin: bottom right;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.sui-dropdown-option {
|
|
238
|
-
padding: .5rem .75rem;
|
|
239
|
-
cursor: pointer;
|
|
240
|
-
font-size: .975em;
|
|
241
|
-
transition: all .15s ease;
|
|
242
|
-
display: flex;
|
|
243
|
-
flex-direction: row;
|
|
244
|
-
gap: .5rem;
|
|
245
|
-
align-items: center;
|
|
246
|
-
width: 100%;
|
|
247
|
-
white-space: normal;
|
|
248
|
-
user-select: none;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.sui-dropdown-option:hover, .sui-dropdown-option:focus, .sui-dropdown-option.focused {
|
|
252
|
-
background-color: hsl(var(--background-step-3));
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.sui-dropdown-option.has-href {
|
|
256
|
-
padding: 0;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.sui-dropdown-link {
|
|
260
|
-
padding: .5rem .75rem;
|
|
261
|
-
width: 100%;
|
|
262
|
-
text-decoration: none;
|
|
263
|
-
color: hsl(var(--text-normal));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.sui-dropdown-option.primary {
|
|
267
|
-
color: hsl(var(--primary-base));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.sui-dropdown-option.primary:hover {
|
|
271
|
-
background-color: hsl(var(--primary-base));
|
|
272
|
-
color: hsl(var(--text-inverted));
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.sui-dropdown-option.success {
|
|
276
|
-
color: hsl(var(--success-base));
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
.sui-dropdown-option.success:hover {
|
|
280
|
-
background-color: hsl(var(--success-base));
|
|
281
|
-
color: hsl(var(--text-dark));
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
.sui-dropdown-option.warning {
|
|
285
|
-
color: hsl(var(--warning-base));
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
.sui-dropdown-option.warning:hover {
|
|
289
|
-
background-color: hsl(var(--warning-base));
|
|
290
|
-
color: hsl(var(--text-dark));
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.sui-dropdown-option.danger {
|
|
294
|
-
color: hsl(var(--danger-base));
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.sui-dropdown-option.danger:hover {
|
|
298
|
-
background-color: hsl(var(--danger-base));
|
|
299
|
-
color: hsl(var(--text-light));
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.sui-dropdown-option.disabled {
|
|
303
|
-
pointer-events: none;
|
|
304
|
-
color: hsl(var(--text-muted));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
.sui-dropdown-option.end {
|
|
308
|
-
justify-content: space-between;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.sui-dropdown-option.has-icon {
|
|
312
|
-
padding-left: .5rem;
|
|
313
|
-
}
|
|
314
|
-
</style>
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
class DropdownHelper {
|
|
2
|
-
private container: HTMLDivElement;
|
|
3
|
-
private toggleEl: HTMLDivElement;
|
|
4
|
-
private dropdown: HTMLUListElement;
|
|
5
|
-
|
|
6
|
-
private alignment: 'start' | 'center' | 'end';
|
|
7
|
-
private triggerOn: 'left' | 'right' | 'both';
|
|
8
|
-
private fullWidth = false;
|
|
9
|
-
private focusIndex = -1;
|
|
10
|
-
|
|
11
|
-
active = false;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* A helper function to interact with dropdowns.
|
|
15
|
-
* @param id The ID of the dropdown.
|
|
16
|
-
* @param fullWidth Whether the dropdown should be full width. Not needed normally.
|
|
17
|
-
*/
|
|
18
|
-
constructor(id: string, fullWidth?: boolean) {
|
|
19
|
-
this.container = document.getElementById(`${id}-container`) as HTMLDivElement;
|
|
20
|
-
|
|
21
|
-
if (!this.container) {
|
|
22
|
-
throw new Error(`Unable to find dropdown with ID ${id}.`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this.alignment = this.container.dataset.align as 'start' | 'center' | 'end';
|
|
26
|
-
this.triggerOn = this.container.dataset.trigger as 'left' | 'right' | 'both';
|
|
27
|
-
|
|
28
|
-
this.toggleEl = document.getElementById(`${id}-toggle-btn`) as HTMLDivElement;
|
|
29
|
-
this.dropdown = document.getElementById(`${id}-dropdown`) as HTMLUListElement;
|
|
30
|
-
|
|
31
|
-
if (fullWidth) this.fullWidth = true;
|
|
32
|
-
|
|
33
|
-
this.hideOnClickOutside(this.container);
|
|
34
|
-
|
|
35
|
-
this.initialBehaviorRegistration();
|
|
36
|
-
this.initialOptClickRegistration();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Registers a click callback for the dropdown options. Whenever one of the options
|
|
41
|
-
* is clicked, the callback will be called with the value of the option.
|
|
42
|
-
* @param func The callback function.
|
|
43
|
-
*/
|
|
44
|
-
public registerClickCallback = (func: (value: string) => void) => {
|
|
45
|
-
const dropdownOpts = this.dropdown.querySelectorAll('li');
|
|
46
|
-
|
|
47
|
-
for (const opt of dropdownOpts) {
|
|
48
|
-
opt.removeEventListener('click', this.hide);
|
|
49
|
-
|
|
50
|
-
opt.addEventListener('click', () => {
|
|
51
|
-
func(opt.dataset.value || '');
|
|
52
|
-
this.hide();
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Sets up all listeners for the dropdown.
|
|
59
|
-
*/
|
|
60
|
-
private initialBehaviorRegistration = () => {
|
|
61
|
-
window.addEventListener('scroll', this.hide);
|
|
62
|
-
document.addEventListener('keydown', (e) => {
|
|
63
|
-
if (e.key === 'Escape') this.hide();
|
|
64
|
-
});
|
|
65
|
-
document.addEventListener('astro:before-preparation', () => {
|
|
66
|
-
this.dropdown.classList.remove('initialized');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (this.triggerOn === 'left') {
|
|
70
|
-
this.toggleEl.addEventListener('click', this.toggle);
|
|
71
|
-
} else if (this.triggerOn === 'both') {
|
|
72
|
-
this.toggleEl.addEventListener('click', this.toggle);
|
|
73
|
-
this.toggleEl.addEventListener('contextmenu', (e) => {
|
|
74
|
-
e.preventDefault();
|
|
75
|
-
this.toggle();
|
|
76
|
-
});
|
|
77
|
-
} else {
|
|
78
|
-
this.toggleEl.addEventListener('contextmenu', (e) => {
|
|
79
|
-
e.preventDefault();
|
|
80
|
-
this.toggle();
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
this.toggleEl.addEventListener('keydown', (e) => {
|
|
85
|
-
if (!this.active) return;
|
|
86
|
-
|
|
87
|
-
if (e.key === 'Enter') {
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
|
|
90
|
-
const focused = this.dropdown.querySelector('li.focused') as HTMLLIElement;
|
|
91
|
-
|
|
92
|
-
if (!focused) {
|
|
93
|
-
this.hide();
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
focused.click();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (e.key === 'ArrowDown') {
|
|
101
|
-
e.preventDefault();
|
|
102
|
-
|
|
103
|
-
this.focusIndex =
|
|
104
|
-
this.focusIndex === this.dropdown.children.length - 1 ? 0 : this.focusIndex + 1;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (e.key === 'ArrowUp') {
|
|
108
|
-
e.preventDefault();
|
|
109
|
-
|
|
110
|
-
this.focusIndex =
|
|
111
|
-
this.focusIndex === 0 ? this.dropdown.children.length - 1 : this.focusIndex - 1;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
115
|
-
if (this.focusIndex > this.dropdown.children.length - 1) {
|
|
116
|
-
this.focusIndex = 0;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.dropdown.querySelector('li.focused')?.classList.remove('focused');
|
|
120
|
-
|
|
121
|
-
const newFocus = this.dropdown.children[this.focusIndex] as HTMLLIElement;
|
|
122
|
-
|
|
123
|
-
if (!newFocus) return;
|
|
124
|
-
|
|
125
|
-
newFocus.classList.add('focused');
|
|
126
|
-
newFocus.focus();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Registers callbacks to hide the dropdown when an option is clicked.
|
|
133
|
-
*/
|
|
134
|
-
private initialOptClickRegistration = () => {
|
|
135
|
-
const dropdownOpts = this.dropdown.querySelectorAll('li');
|
|
136
|
-
|
|
137
|
-
for (const opt of dropdownOpts) {
|
|
138
|
-
opt.addEventListener('click', this.hide);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* A function to toggle the dropdown.
|
|
144
|
-
*/
|
|
145
|
-
public toggle = () => {
|
|
146
|
-
if (this.active) {
|
|
147
|
-
this.hide();
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.show();
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* A function to hide the dropdown.
|
|
156
|
-
*/
|
|
157
|
-
public hide = () => {
|
|
158
|
-
this.dropdown.classList.remove('active');
|
|
159
|
-
this.active = false;
|
|
160
|
-
this.focusIndex = -1;
|
|
161
|
-
|
|
162
|
-
this.dropdown.querySelector('li.focused')?.classList.remove('focused');
|
|
163
|
-
|
|
164
|
-
setTimeout(() => this.dropdown.classList.remove('above', 'below'), 200);
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* A function to show the dropdown.
|
|
169
|
-
*/
|
|
170
|
-
public show = () => {
|
|
171
|
-
const isMobile = window.matchMedia('screen and (max-width: 840px)').matches;
|
|
172
|
-
|
|
173
|
-
const {
|
|
174
|
-
bottom,
|
|
175
|
-
left,
|
|
176
|
-
right,
|
|
177
|
-
width: parentWidth,
|
|
178
|
-
x,
|
|
179
|
-
y,
|
|
180
|
-
height,
|
|
181
|
-
} = this.toggleEl.getBoundingClientRect();
|
|
182
|
-
const { width: dropdownWidth } = this.dropdown.getBoundingClientRect();
|
|
183
|
-
|
|
184
|
-
const optionHeight = 43.28;
|
|
185
|
-
const totalBorderSize = 2;
|
|
186
|
-
const margin = 4;
|
|
187
|
-
|
|
188
|
-
const dropdownHeight = this.dropdown.children.length * optionHeight + totalBorderSize + margin;
|
|
189
|
-
|
|
190
|
-
const CustomRect = {
|
|
191
|
-
top: bottom + margin,
|
|
192
|
-
left,
|
|
193
|
-
right,
|
|
194
|
-
bottom: bottom + margin + dropdownHeight,
|
|
195
|
-
width: isMobile || this.fullWidth ? parentWidth : dropdownWidth, // Account for scaling of animation
|
|
196
|
-
height: dropdownHeight,
|
|
197
|
-
x,
|
|
198
|
-
y: y + height + margin,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
this.active = true;
|
|
202
|
-
|
|
203
|
-
if (isMobile || this.fullWidth) {
|
|
204
|
-
this.dropdown.style.maxWidth = `${parentWidth}px`;
|
|
205
|
-
this.dropdown.style.minWidth = 'unset';
|
|
206
|
-
this.dropdown.style.width = `${parentWidth}px`;
|
|
207
|
-
this.dropdown.style.left = `calc(${parentWidth / 2}px - ${CustomRect.width / 2}px)`;
|
|
208
|
-
} else {
|
|
209
|
-
if (this.alignment === 'end') {
|
|
210
|
-
this.dropdown.style.left = `calc(${parentWidth}px - ${CustomRect.width}px)`;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (this.alignment === 'center') {
|
|
214
|
-
this.dropdown.style.left = `calc(${parentWidth / 2}px - ${CustomRect.width / 2}px)`;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (!this.dropdown.classList.contains('initialized')) {
|
|
219
|
-
this.dropdown.classList.add('initialized');
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
CustomRect.top >= 0 &&
|
|
224
|
-
CustomRect.left >= 0 &&
|
|
225
|
-
CustomRect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
226
|
-
CustomRect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
227
|
-
) {
|
|
228
|
-
this.dropdown.classList.add('active', 'below');
|
|
229
|
-
this.focusIndex = -1;
|
|
230
|
-
} else {
|
|
231
|
-
this.dropdown.classList.add('active', 'above');
|
|
232
|
-
this.focusIndex = this.dropdown.children.length;
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* A jQuery-like function to hide the dropdown when clicking outside of it.
|
|
238
|
-
* @param element The element to hide when clicking outside of it.
|
|
239
|
-
*/
|
|
240
|
-
private hideOnClickOutside = (element: HTMLElement) => {
|
|
241
|
-
const outsideClickListener = (event: MouseEvent) => {
|
|
242
|
-
if (!event.target) return;
|
|
243
|
-
|
|
244
|
-
if (!element.contains(event.target as Node) && isVisible(element) && this.active === true) {
|
|
245
|
-
// or use: event.target.closest(selector) === null
|
|
246
|
-
this.hide();
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
document.addEventListener('click', outsideClickListener);
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export { DropdownHelper };
|
|
255
|
-
|
|
256
|
-
// source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
|
|
257
|
-
const isVisible = (elem: HTMLElement) =>
|
|
258
|
-
!!elem && !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
-
|
|
4
|
-
interface FooterLink {
|
|
5
|
-
/**
|
|
6
|
-
* The label of the link.
|
|
7
|
-
*/
|
|
8
|
-
label: string;
|
|
9
|
-
/**
|
|
10
|
-
* The href of the link.
|
|
11
|
-
*/
|
|
12
|
-
href: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* The props for the footer component.
|
|
17
|
-
*/
|
|
18
|
-
interface Props extends HTMLAttributes<'footer'> {
|
|
19
|
-
/**
|
|
20
|
-
* The links to display in the footer.
|
|
21
|
-
*/
|
|
22
|
-
links: {
|
|
23
|
-
[label: string]: FooterLink[];
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* The copyright text to display in the footer.
|
|
27
|
-
*/
|
|
28
|
-
copyright: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const { copyright, links, ...props } = Astro.props;
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
<footer {...props}>
|
|
35
|
-
<div class="upper">
|
|
36
|
-
<div>
|
|
37
|
-
<slot name="brand" />
|
|
38
|
-
</div>
|
|
39
|
-
<div class="links">
|
|
40
|
-
{Object.keys(links).map((groupLabel) => (
|
|
41
|
-
<ul>
|
|
42
|
-
<li class="sui-footer-link-label">{groupLabel}</li>
|
|
43
|
-
{links[groupLabel]!.map((item) => (
|
|
44
|
-
<li>
|
|
45
|
-
<a href={item.href}>{item.label}</a>
|
|
46
|
-
</li>
|
|
47
|
-
))}
|
|
48
|
-
</ul>
|
|
49
|
-
))}
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
<hr class="separator" />
|
|
53
|
-
<div class="lower">
|
|
54
|
-
<span class="copyright-span">{copyright}</span>
|
|
55
|
-
<slot name="socials" />
|
|
56
|
-
</div>
|
|
57
|
-
</footer>
|
|
58
|
-
<style>
|
|
59
|
-
footer {
|
|
60
|
-
display: flex;
|
|
61
|
-
flex-direction: column;
|
|
62
|
-
gap: 2rem;
|
|
63
|
-
background-color: hsl(var(--background-step-1));
|
|
64
|
-
padding: 2rem 10vw;
|
|
65
|
-
color: hsl(var(--text-normal)) !important;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.upper, .lower {
|
|
69
|
-
display: flex;
|
|
70
|
-
flex-direction: row;
|
|
71
|
-
justify-content: space-between;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.links {
|
|
75
|
-
display: flex;
|
|
76
|
-
justify-content: flex-end;
|
|
77
|
-
flex-direction: row;
|
|
78
|
-
flex-wrap: wrap;
|
|
79
|
-
gap: 2rem;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.links ul {
|
|
83
|
-
list-style-type: none;
|
|
84
|
-
margin: 0 !important;
|
|
85
|
-
padding: 0 !important;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.links ul li, .links ul li * {
|
|
89
|
-
color: hsl(var(--text-normal)) !important;
|
|
90
|
-
width: fit-content;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.links ul li:has(a):hover {
|
|
94
|
-
text-decoration: underline;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.sui-footer-link-label {
|
|
98
|
-
font-size: 1.125em;
|
|
99
|
-
font-weight: 700;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.separator {
|
|
103
|
-
height: 1px;
|
|
104
|
-
width: 100%;
|
|
105
|
-
border: none;
|
|
106
|
-
background: hsl(var(--border));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
.lower {
|
|
110
|
-
align-items: center;
|
|
111
|
-
flex-wrap: wrap;
|
|
112
|
-
gap: 1rem;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
@media screen and (max-width: 1440px) {
|
|
116
|
-
footer {
|
|
117
|
-
padding: 2rem;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
@media screen and (max-width: 1280px) {
|
|
122
|
-
.upper {
|
|
123
|
-
flex-direction: column;
|
|
124
|
-
gap: 2rem;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.links {
|
|
128
|
-
justify-content: flex-start;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
@media screen and (max-width: 640px) {
|
|
133
|
-
.links ul {
|
|
134
|
-
width: calc(50% - 1rem);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
</style>
|