@functionalcms/svelte-components 4.0.0 → 4.0.1
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/form/Input.d.ts +2 -21
- package/dist/components/form/Input.js +1 -23
- package/dist/components/form/Input.svelte +99 -74
- package/dist/components/form/Input.svelte.d.ts +25 -23
- package/dist/components/form/Switch.svelte +290 -0
- package/dist/components/form/Switch.svelte.d.ts +13 -0
- package/dist/components/layouts/Meta.svelte +1 -1
- package/dist/components/layouts/Meta.svelte.d.ts +2 -3
- package/dist/components/presentation/Carousel.svelte +2 -2
- package/dist/components/presentation/ImageCompare.svelte +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,21 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
Textarea = "textarea",
|
|
4
|
-
Email = "email",
|
|
5
|
-
Search = "search",
|
|
6
|
-
Password = "password",
|
|
7
|
-
Tel = "tel",
|
|
8
|
-
Number = "number",
|
|
9
|
-
Url = "url",
|
|
10
|
-
Month = "month",
|
|
11
|
-
Time = "time",
|
|
12
|
-
Week = "week",
|
|
13
|
-
Date = "date",
|
|
14
|
-
DatetimeLocal = "datetime-local",
|
|
15
|
-
Color = "color"
|
|
16
|
-
}
|
|
17
|
-
export declare enum Size {
|
|
18
|
-
Small = "small",
|
|
19
|
-
Large = "large",
|
|
20
|
-
Normal = ""
|
|
21
|
-
}
|
|
1
|
+
export type Type = 'text' | 'textarea' | 'email' | 'search' | 'password' | 'tel' | 'number' | 'url' | 'month' | 'time' | 'week' | 'date' | 'datetime-local' | 'color';
|
|
2
|
+
export type LabelSize = 'small' | 'large' | '';
|
|
@@ -1,23 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
(function (Type) {
|
|
3
|
-
Type["Text"] = "text";
|
|
4
|
-
Type["Textarea"] = "textarea";
|
|
5
|
-
Type["Email"] = "email";
|
|
6
|
-
Type["Search"] = "search";
|
|
7
|
-
Type["Password"] = "password";
|
|
8
|
-
Type["Tel"] = "tel";
|
|
9
|
-
Type["Number"] = "number";
|
|
10
|
-
Type["Url"] = "url";
|
|
11
|
-
Type["Month"] = "month";
|
|
12
|
-
Type["Time"] = "time";
|
|
13
|
-
Type["Week"] = "week";
|
|
14
|
-
Type["Date"] = "date";
|
|
15
|
-
Type["DatetimeLocal"] = "datetime-local";
|
|
16
|
-
Type["Color"] = "color";
|
|
17
|
-
})(Type || (Type = {}));
|
|
18
|
-
export var Size;
|
|
19
|
-
(function (Size) {
|
|
20
|
-
Size["Small"] = "small";
|
|
21
|
-
Size["Large"] = "large";
|
|
22
|
-
Size["Normal"] = "";
|
|
23
|
-
})(Size || (Size = {}));
|
|
1
|
+
export {};
|
|
@@ -1,58 +1,72 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../utils.js';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
interface Props
|
|
7
|
-
label
|
|
8
|
-
|
|
9
|
-
labelCss
|
|
10
|
-
isLabelHidden
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
4
|
+
import type { LabelSize, Type } from './Input.js';
|
|
5
|
+
|
|
6
|
+
interface Props{
|
|
7
|
+
label: string;
|
|
8
|
+
labelSize: LabelSize;
|
|
9
|
+
labelCss: string;
|
|
10
|
+
isLabelHidden: boolean;
|
|
11
|
+
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
helpText: string;
|
|
15
|
+
|
|
16
|
+
isInvalid: boolean;
|
|
17
|
+
invalidText: string;
|
|
18
|
+
|
|
19
|
+
isInline: boolean;
|
|
20
|
+
isRounded: boolean;
|
|
21
|
+
isSkinned: boolean;
|
|
22
|
+
isUnderlinedWithBackground: boolean;
|
|
23
|
+
isUnderlined: boolean;
|
|
24
|
+
|
|
25
|
+
isDisabled: boolean | undefined;
|
|
26
|
+
isRequired: boolean | undefined;
|
|
27
|
+
|
|
28
|
+
css: string;
|
|
29
|
+
|
|
30
|
+
placeholder: string;
|
|
31
|
+
|
|
32
|
+
type: Type;
|
|
33
|
+
value: string;
|
|
34
|
+
addonLeft: Snippet;
|
|
35
|
+
addonRight: Snippet;
|
|
26
36
|
}
|
|
37
|
+
|
|
27
38
|
let {
|
|
28
39
|
addonLeft,
|
|
29
40
|
addonRight,
|
|
30
41
|
label = '',
|
|
31
42
|
id = '',
|
|
43
|
+
name = '',
|
|
32
44
|
labelCss = '',
|
|
33
45
|
isLabelHidden = false,
|
|
34
46
|
helpText = '',
|
|
35
|
-
invalidText = '',
|
|
36
47
|
isInvalid = false,
|
|
48
|
+
invalidText = '',
|
|
37
49
|
isInline = false,
|
|
38
50
|
isRounded = false,
|
|
39
51
|
isDisabled = undefined,
|
|
52
|
+
isRequired = undefined,
|
|
40
53
|
css = '',
|
|
41
54
|
isSkinned = true,
|
|
42
55
|
isUnderlinedWithBackground = false,
|
|
43
56
|
isUnderlined = false,
|
|
44
|
-
|
|
45
|
-
type =
|
|
57
|
+
labelSize = '',
|
|
58
|
+
type = 'text',
|
|
46
59
|
value = '',
|
|
60
|
+
placeholder= '',
|
|
47
61
|
...restProps
|
|
48
|
-
}: Props = $props();
|
|
62
|
+
}: Partial<Props> = $props();
|
|
49
63
|
|
|
50
64
|
let labelClasses = $derived(
|
|
51
65
|
cn(
|
|
52
66
|
'label',
|
|
53
67
|
isInvalid ? 'label-error' : '',
|
|
54
68
|
isInline ? 'label-inline' : '',
|
|
55
|
-
|
|
69
|
+
labelSize ? `label-${labelSize}` : '',
|
|
56
70
|
isLabelHidden ? 'screenreader-only' : '',
|
|
57
71
|
labelCss ? labelCss : ''
|
|
58
72
|
)
|
|
@@ -70,13 +84,13 @@
|
|
|
70
84
|
isInline ? 'input-inline' : '',
|
|
71
85
|
isUnderlinedWithBackground ? 'input-underlined-bg' : '',
|
|
72
86
|
css ? css : '',
|
|
73
|
-
|
|
87
|
+
labelSize ? `input-${labelSize}` : ''
|
|
74
88
|
)
|
|
75
89
|
);
|
|
76
90
|
|
|
77
|
-
let invalidClasses = $derived(
|
|
91
|
+
let invalidClasses = $derived(labelSize ? `field-error-${labelSize}` : 'field-error');
|
|
78
92
|
|
|
79
|
-
let helpClasses = $derived(
|
|
93
|
+
let helpClasses = $derived(labelSize ? `field-help-${labelSize}` : 'field-help');
|
|
80
94
|
|
|
81
95
|
let addonContainerClasses = () => 'input-addon-container';
|
|
82
96
|
|
|
@@ -88,10 +102,13 @@
|
|
|
88
102
|
{#snippet input()}
|
|
89
103
|
<input
|
|
90
104
|
{id}
|
|
105
|
+
{name}
|
|
91
106
|
{type}
|
|
107
|
+
{placeholder}
|
|
92
108
|
bind:value
|
|
93
109
|
class={inputClasses}
|
|
94
110
|
disabled={isDisabled}
|
|
111
|
+
required={isRequired}
|
|
95
112
|
oninput={handleInput}
|
|
96
113
|
{...restProps}
|
|
97
114
|
/>
|
|
@@ -100,7 +117,15 @@
|
|
|
100
117
|
<div class="w-100">
|
|
101
118
|
<label class={labelClasses} for={id}>{label}</label>
|
|
102
119
|
{#if type == 'textarea'}
|
|
103
|
-
<textarea
|
|
120
|
+
<textarea
|
|
121
|
+
{id}
|
|
122
|
+
{name}
|
|
123
|
+
{placeholder}
|
|
124
|
+
class={inputClasses}
|
|
125
|
+
bind:value
|
|
126
|
+
oninput={handleInput}
|
|
127
|
+
required={isRequired}
|
|
128
|
+
{...restProps}></textarea>
|
|
104
129
|
{:else if addonLeft || addonRight}
|
|
105
130
|
<div class={addonContainerClasses()}>
|
|
106
131
|
{#if addonLeft}
|
|
@@ -159,11 +184,11 @@
|
|
|
159
184
|
.input-underlined,
|
|
160
185
|
.input-underlined-bg,
|
|
161
186
|
.input {
|
|
162
|
-
color: var(--
|
|
163
|
-
font-family: var(--
|
|
164
|
-
font-weight: var(--
|
|
165
|
-
font-size: var(--
|
|
166
|
-
line-height: var(--
|
|
187
|
+
color: var(--font-color, var(--dark));
|
|
188
|
+
font-family: var(--font-family-body);
|
|
189
|
+
font-weight: var(--font-weight, 300);
|
|
190
|
+
font-size: var(--font-size, 1rem);
|
|
191
|
+
line-height: var(--line-height, var(--fluid-20, 1.25rem));
|
|
167
192
|
width: 100%;
|
|
168
193
|
max-width: 100%;
|
|
169
194
|
}
|
|
@@ -174,38 +199,38 @@
|
|
|
174
199
|
border-style: solid;
|
|
175
200
|
|
|
176
201
|
/* this can be overriden, but it might mess with the balance of the button heights across variants */
|
|
177
|
-
border-width: var(--
|
|
178
|
-
border-color: var(--
|
|
202
|
+
border-width: var(--input-border-size, 1px);
|
|
203
|
+
border-color: var(--input-border-color, var(--gray-light));
|
|
179
204
|
|
|
180
205
|
/* these can be overriden, but it might mess with the balance of the inputheights across variants */
|
|
181
|
-
padding-block-start: var(--
|
|
182
|
-
padding-block-end: var(--
|
|
183
|
-
padding-inline-start: var(--
|
|
184
|
-
padding-inline-end: var(--
|
|
206
|
+
padding-block-start: var(--input-vertical-pad, 0.5rem);
|
|
207
|
+
padding-block-end: var(--input-vertical-pad, 0.5rem);
|
|
208
|
+
padding-inline-start: var(--input-side-padding, 0.75rem);
|
|
209
|
+
padding-inline-end: var(--input-side-padding, 0.75rem);
|
|
185
210
|
|
|
186
211
|
/* Note we only want to set properties that we actually want
|
|
187
212
|
to transition in. For example, if we transition "all", the
|
|
188
213
|
inputs will "grow in" on page load—not a happy effect :) */
|
|
189
214
|
transition-property: box-shadow;
|
|
190
|
-
transition-duration: var(--
|
|
215
|
+
transition-duration: var(--input-timing, var(--timing-medium));
|
|
191
216
|
}
|
|
192
217
|
|
|
193
218
|
.label {
|
|
194
219
|
display: inline-block;
|
|
195
220
|
|
|
196
|
-
/* Provided --
|
|
221
|
+
/* Provided --input-vertical-pad isn't overriden we'll get 20px
|
|
197
222
|
label w/a 6px margin then a 38px input = 64 which is on the 8pt grid */
|
|
198
223
|
margin-block-start: 0;
|
|
199
224
|
margin-inline-start: 0;
|
|
200
225
|
margin-inline-end: 0;
|
|
201
|
-
margin-block-end: var(--
|
|
226
|
+
margin-block-end: var(--input-label-pad, 0.375rem);
|
|
202
227
|
vertical-align: initial;
|
|
203
228
|
}
|
|
204
229
|
|
|
205
230
|
/* Reset field errors and help text to be 2px less then input font size */
|
|
206
231
|
.field-help,
|
|
207
232
|
.field-error {
|
|
208
|
-
font-size: calc(var(--
|
|
233
|
+
font-size: calc(var(--font-size, 1rem) - 2px);
|
|
209
234
|
}
|
|
210
235
|
|
|
211
236
|
.label-inline,
|
|
@@ -218,7 +243,7 @@
|
|
|
218
243
|
margin-block-start: 0;
|
|
219
244
|
margin-block-end: 0;
|
|
220
245
|
margin-inline-start: 0;
|
|
221
|
-
margin-inline-end: var(--
|
|
246
|
+
margin-inline-end: var(--input-side-padding, 0.75rem);
|
|
222
247
|
}
|
|
223
248
|
|
|
224
249
|
/**
|
|
@@ -229,28 +254,28 @@
|
|
|
229
254
|
.input::-webkit-input-placeholder {
|
|
230
255
|
color: currentColor;
|
|
231
256
|
opacity: 50%;
|
|
232
|
-
transition: opacity var(--
|
|
257
|
+
transition: opacity var(--timing-fast) ease-out;
|
|
233
258
|
}
|
|
234
259
|
|
|
235
260
|
/* stylelint-disable-next-line */
|
|
236
261
|
.input::placeholder {
|
|
237
262
|
color: currentColor;
|
|
238
263
|
opacity: 50%;
|
|
239
|
-
transition: opacity var(--
|
|
264
|
+
transition: opacity var(--timing-fast) ease-out;
|
|
240
265
|
}
|
|
241
266
|
|
|
242
267
|
/* stylelint-disable-next-line */
|
|
243
268
|
.input::-ms-placeholder {
|
|
244
269
|
color: currentColor;
|
|
245
270
|
opacity: 50%;
|
|
246
|
-
transition: opacity var(--
|
|
271
|
+
transition: opacity var(--timing-fast) ease-out;
|
|
247
272
|
}
|
|
248
273
|
|
|
249
274
|
/* stylelint-disable-next-line */
|
|
250
275
|
.input:-ms-placeholder {
|
|
251
276
|
color: currentColor;
|
|
252
277
|
opacity: 50%;
|
|
253
|
-
transition: opacity var(--
|
|
278
|
+
transition: opacity var(--timing-fast) ease-out;
|
|
254
279
|
}
|
|
255
280
|
|
|
256
281
|
/**
|
|
@@ -260,19 +285,19 @@
|
|
|
260
285
|
border-top: 0;
|
|
261
286
|
border-left: 0;
|
|
262
287
|
border-right: 0;
|
|
263
|
-
border-color: var(--
|
|
288
|
+
border-color: var(--input-underlined-color, var(--gray-mid-dark));
|
|
264
289
|
background-color: transparent;
|
|
265
290
|
}
|
|
266
291
|
|
|
267
292
|
.input-underlined-bg {
|
|
268
|
-
background-color: var(--
|
|
293
|
+
background-color: var(--input-underlined-bg-color, var(--gray-extra-light));
|
|
269
294
|
}
|
|
270
295
|
|
|
271
296
|
/**
|
|
272
297
|
* Rounded inputs
|
|
273
298
|
*/
|
|
274
299
|
.input-rounded {
|
|
275
|
-
border-radius: var(--
|
|
300
|
+
border-radius: var(--radius, 0.25rem);
|
|
276
301
|
}
|
|
277
302
|
|
|
278
303
|
/**
|
|
@@ -287,24 +312,24 @@
|
|
|
287
312
|
* implement that in the contrived example).
|
|
288
313
|
*/
|
|
289
314
|
.label-error {
|
|
290
|
-
color: var(--
|
|
315
|
+
color: var(--input-error-color, var(--error));
|
|
291
316
|
}
|
|
292
317
|
|
|
293
318
|
.input-error {
|
|
294
|
-
border-color: var(--
|
|
319
|
+
border-color: var(--input-error-color, var(--error));
|
|
295
320
|
}
|
|
296
321
|
|
|
297
322
|
.label-error,
|
|
298
323
|
.field-error,
|
|
299
324
|
.field-error-small,
|
|
300
325
|
.field-error-large {
|
|
301
|
-
color: var(--
|
|
326
|
+
color: var(--input-error-color, var(--error));
|
|
302
327
|
}
|
|
303
328
|
|
|
304
329
|
.field-help,
|
|
305
330
|
.field-help-small,
|
|
306
331
|
.field-help-large {
|
|
307
|
-
color: var(--
|
|
332
|
+
color: var(--input-help-color, var(--gray-dark));
|
|
308
333
|
}
|
|
309
334
|
|
|
310
335
|
.field-help,
|
|
@@ -315,45 +340,45 @@
|
|
|
315
340
|
.field-error-large {
|
|
316
341
|
display: inline-block;
|
|
317
342
|
width: 100%;
|
|
318
|
-
margin-block-start: calc(var(--
|
|
343
|
+
margin-block-start: calc(var(--input-vertical-pad, 0.5rem) / 2);
|
|
319
344
|
}
|
|
320
345
|
|
|
321
346
|
/**
|
|
322
347
|
* Sizes
|
|
323
348
|
*/
|
|
324
349
|
.input-large {
|
|
325
|
-
font-size: calc(var(--
|
|
350
|
+
font-size: calc(var(--font-size, 1rem) + 0.25rem);
|
|
326
351
|
line-height: 1.6rem;
|
|
327
352
|
}
|
|
328
353
|
|
|
329
354
|
.field-help-large,
|
|
330
355
|
.field-error-large {
|
|
331
356
|
/* We initially remove -2px from font-size so setting to font-size essentially adds the 2px back */
|
|
332
|
-
font-size: var(--
|
|
357
|
+
font-size: var(--font-size, 1rem);
|
|
333
358
|
}
|
|
334
359
|
|
|
335
360
|
.label-large {
|
|
336
|
-
font-size: calc(var(--
|
|
361
|
+
font-size: calc(var(--font-size, 1rem) + 0.25rem);
|
|
337
362
|
}
|
|
338
363
|
|
|
339
364
|
.input-small {
|
|
340
|
-
font-size: calc(var(--
|
|
365
|
+
font-size: calc(var(--font-size, 1rem) - 0.25rem);
|
|
341
366
|
line-height: 1rem;
|
|
342
367
|
}
|
|
343
368
|
|
|
344
369
|
.field-help-small,
|
|
345
370
|
.field-error-small,
|
|
346
371
|
.label-small {
|
|
347
|
-
font-size: calc(var(--
|
|
372
|
+
font-size: calc(var(--font-size, 1rem) - 0.25rem);
|
|
348
373
|
}
|
|
349
374
|
|
|
350
375
|
.input:focus {
|
|
351
|
-
box-shadow: 0 0 0 var(--
|
|
376
|
+
box-shadow: 0 0 0 var(--focus-ring-outline-width) var(--focus-ring-color);
|
|
352
377
|
|
|
353
378
|
/* Needed for High Contrast mode */
|
|
354
|
-
outline: var(--
|
|
355
|
-
var(--
|
|
356
|
-
transition: box-shadow var(--
|
|
379
|
+
outline: var(--focus-ring-outline-width) var(--focus-ring-outline-style)
|
|
380
|
+
var(--focus-ring-outline-color);
|
|
381
|
+
transition: box-shadow var(--timing-fast) ease-out;
|
|
357
382
|
}
|
|
358
383
|
|
|
359
384
|
/* Set the focus to transparent when there's an error since we use
|
|
@@ -372,8 +397,8 @@
|
|
|
372
397
|
*/
|
|
373
398
|
.input.disabled, /* DEPRECATED -- TODO remove class based disabled */
|
|
374
399
|
.input:disabled {
|
|
375
|
-
background: var(--
|
|
376
|
-
color: var(--
|
|
400
|
+
background: var(--input-disabled-bg, var(--disabled-bg)) !important;
|
|
401
|
+
color: var(--input-disabled-color, var(--disabled-color)) !important;
|
|
377
402
|
appearance: none !important;
|
|
378
403
|
box-shadow: none !important;
|
|
379
404
|
cursor: not-allowed !important;
|
|
@@ -402,19 +427,19 @@
|
|
|
402
427
|
}
|
|
403
428
|
|
|
404
429
|
.input-has-left-addon {
|
|
405
|
-
padding-left: calc(var(--
|
|
430
|
+
padding-left: calc(var(--side-padding) * 3);
|
|
406
431
|
}
|
|
407
432
|
|
|
408
433
|
.input-has-right-addon {
|
|
409
|
-
padding-right: calc(var(--
|
|
434
|
+
padding-right: calc(var(--side-padding) * 3);
|
|
410
435
|
}
|
|
411
436
|
|
|
412
437
|
.input-addon-left {
|
|
413
|
-
left: var(--
|
|
438
|
+
left: var(--input-side-padding);
|
|
414
439
|
}
|
|
415
440
|
|
|
416
441
|
.input-addon-right {
|
|
417
|
-
right: var(--
|
|
442
|
+
right: var(--input-side-padding);
|
|
418
443
|
}
|
|
419
444
|
|
|
420
445
|
@media (prefers-reduced-motion), (update: slow) {
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
label
|
|
5
|
-
|
|
6
|
-
labelCss
|
|
7
|
-
isLabelHidden
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
isSkinned
|
|
16
|
-
isUnderlinedWithBackground
|
|
17
|
-
isUnderlined
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
2
|
+
import type { LabelSize, Type } from './Input.js';
|
|
3
|
+
declare const Input: import("svelte").Component<Partial<{
|
|
4
|
+
label: string;
|
|
5
|
+
labelSize: LabelSize;
|
|
6
|
+
labelCss: string;
|
|
7
|
+
isLabelHidden: boolean;
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
helpText: string;
|
|
11
|
+
isInvalid: boolean;
|
|
12
|
+
invalidText: string;
|
|
13
|
+
isInline: boolean;
|
|
14
|
+
isRounded: boolean;
|
|
15
|
+
isSkinned: boolean;
|
|
16
|
+
isUnderlinedWithBackground: boolean;
|
|
17
|
+
isUnderlined: boolean;
|
|
18
|
+
isDisabled: boolean | undefined;
|
|
19
|
+
isRequired: boolean | undefined;
|
|
20
|
+
css: string;
|
|
21
|
+
placeholder: string;
|
|
22
|
+
type: Type;
|
|
23
|
+
value: string;
|
|
24
|
+
addonLeft: Snippet;
|
|
25
|
+
addonRight: Snippet;
|
|
26
|
+
}>, {}, "">;
|
|
25
27
|
type Input = ReturnType<typeof Input>;
|
|
26
28
|
export default Input;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../utils.js';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
css: string;
|
|
8
|
+
labelPosition: string;
|
|
9
|
+
size: string;
|
|
10
|
+
isChecked: boolean;
|
|
11
|
+
isBordered: boolean;
|
|
12
|
+
isAction: boolean;
|
|
13
|
+
isDisabled: boolean;
|
|
14
|
+
}
|
|
15
|
+
let {
|
|
16
|
+
id = '',
|
|
17
|
+
label = '',
|
|
18
|
+
css = '',
|
|
19
|
+
labelPosition = 'left',
|
|
20
|
+
size = '',
|
|
21
|
+
isChecked = false,
|
|
22
|
+
isBordered = false,
|
|
23
|
+
isAction = false,
|
|
24
|
+
isDisabled = false
|
|
25
|
+
}: Partial<Props> = $props();
|
|
26
|
+
|
|
27
|
+
let switchContainer = $derived(
|
|
28
|
+
cn(
|
|
29
|
+
'switch-container',
|
|
30
|
+
labelPosition === 'right' ? 'switch-right' : '',
|
|
31
|
+
css ? css : '',
|
|
32
|
+
isDisabled ? 'disabled' : ''
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const switchSpan = () => {
|
|
37
|
+
let klasses = [
|
|
38
|
+
'switch',
|
|
39
|
+
isBordered ? 'switch-border' : '',
|
|
40
|
+
isAction ? 'switch-action' : '',
|
|
41
|
+
size ? `switch-${size}` : ''
|
|
42
|
+
];
|
|
43
|
+
klasses = klasses.filter((klass) => klass.length);
|
|
44
|
+
return klasses.join(' ');
|
|
45
|
+
};
|
|
46
|
+
const handleClick = (evt: any) => {
|
|
47
|
+
const el = evt.target;
|
|
48
|
+
if (el.getAttribute('aria-checked') == 'true') {
|
|
49
|
+
el.setAttribute('aria-checked', 'false');
|
|
50
|
+
} else {
|
|
51
|
+
el.setAttribute('aria-checked', 'true');
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const handleKeypress = (evt: any) => {
|
|
55
|
+
const keyCode = evt.keyCode || evt.which;
|
|
56
|
+
switch (keyCode) {
|
|
57
|
+
case 13:
|
|
58
|
+
evt.preventDefault();
|
|
59
|
+
evt.target.click();
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<label class={switchContainer} for={id}>
|
|
66
|
+
{#if labelPosition === 'left'}<span class="switch-label">{label}</span>{/if}
|
|
67
|
+
<input
|
|
68
|
+
type="checkbox"
|
|
69
|
+
class="switch-input"
|
|
70
|
+
{id}
|
|
71
|
+
bind:checked={isChecked}
|
|
72
|
+
disabled={isDisabled}
|
|
73
|
+
onclick={handleClick}
|
|
74
|
+
onkeypress={handleKeypress}
|
|
75
|
+
role="switch"
|
|
76
|
+
/>
|
|
77
|
+
<span class={switchSpan()} aria-hidden="true"></span>
|
|
78
|
+
{#if labelPosition === 'right'}<span class="switch-label">{label}</span>{/if}
|
|
79
|
+
</label>
|
|
80
|
+
|
|
81
|
+
<style>
|
|
82
|
+
/**
|
|
83
|
+
* Switch
|
|
84
|
+
*
|
|
85
|
+
* This switch is inspired by Scott Ohara's checkbox switch:
|
|
86
|
+
* https://scottaohara.github.io/a11y_styled_form_controls/src/checkbox--switch/
|
|
87
|
+
*/
|
|
88
|
+
.switch-container {
|
|
89
|
+
display: block;
|
|
90
|
+
|
|
91
|
+
/* TODO: Hopefully this doesn't become a problem but since we use absolute
|
|
92
|
+
positioning extensively, we need some way to have adjacent spaced lines */
|
|
93
|
+
min-height: 2.25rem;
|
|
94
|
+
width: 100%;
|
|
95
|
+
padding: 0.5rem;
|
|
96
|
+
position: relative;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.switch-container:hover {
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* using the before/after pseudo elements of the span to create the "switch" */
|
|
104
|
+
.switch::before,
|
|
105
|
+
.switch::after {
|
|
106
|
+
border: 1px solid var(--gray-mid-dark);
|
|
107
|
+
content: '';
|
|
108
|
+
position: absolute;
|
|
109
|
+
top: 50%;
|
|
110
|
+
transform: translateY(-50%);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* styling specific to the knob of the switch */
|
|
114
|
+
.switch::after {
|
|
115
|
+
background: #fff;
|
|
116
|
+
border-radius: 100%;
|
|
117
|
+
width: 1.4rem;
|
|
118
|
+
height: 1.4rem;
|
|
119
|
+
right: 1.4rem;
|
|
120
|
+
transition: right var(--timing-fast) ease-in-out;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* styling specific to the knob "container" */
|
|
124
|
+
.switch::before {
|
|
125
|
+
background: #eee;
|
|
126
|
+
border-radius: 1.75rem;
|
|
127
|
+
width: 2.75rem;
|
|
128
|
+
height: 1.75rem;
|
|
129
|
+
right: 0.25rem;
|
|
130
|
+
transition: background var(--timing-medium) ease-in-out;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Sizes */
|
|
134
|
+
.switch-small::after {
|
|
135
|
+
width: 1.25rem;
|
|
136
|
+
height: 1.25rem;
|
|
137
|
+
right: 1.125rem;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.switch-small::before {
|
|
141
|
+
width: 2.25rem;
|
|
142
|
+
height: 1.5rem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.switch-large::after {
|
|
146
|
+
width: 1.65rem;
|
|
147
|
+
height: 1.65rem;
|
|
148
|
+
right: 1.65rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.switch-large::before {
|
|
152
|
+
width: 3.25rem;
|
|
153
|
+
height: 2rem;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.switch-border::before {
|
|
157
|
+
border: 1px solid var(--primary);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.switch-action.switch-border::before {
|
|
161
|
+
border: 1px solid var(--action);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Switch label on right */
|
|
165
|
+
|
|
166
|
+
/* We have to flip the positioning when the label is on the right of switch */
|
|
167
|
+
.switch-right .switch::before {
|
|
168
|
+
right: initial;
|
|
169
|
+
left: 0.25rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.switch-right .switch::after {
|
|
173
|
+
right: initial;
|
|
174
|
+
left: 1.4rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Switch sizes w/label on right -- I expect SMACSS so .switch .switch-small
|
|
178
|
+
classes should both exist so the right: initial was taken care of above :) */
|
|
179
|
+
.switch-right .switch-small::after {
|
|
180
|
+
left: 1.125rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.switch-right .switch-large::after {
|
|
184
|
+
left: 1.65rem;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* ---- CHECKED STATE ----- */
|
|
188
|
+
|
|
189
|
+
/* change the position of the knob to indicate it has been checked */
|
|
190
|
+
|
|
191
|
+
.switch-input:checked + .switch-small::after {
|
|
192
|
+
right: 0.425rem;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.switch-input:checked + .switch::after {
|
|
196
|
+
right: 0.5em;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.switch-right .switch-label {
|
|
200
|
+
position: absolute;
|
|
201
|
+
right: 0;
|
|
202
|
+
|
|
203
|
+
/* Flips transition target to left to preserve our smooth transitions */
|
|
204
|
+
transition: left var(--timing-fast) ease-in-out;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.switch-right .switch-input:checked + .switch::after {
|
|
208
|
+
right: initial;
|
|
209
|
+
left: 0.5em;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.switch-right .switch-input:checked + .switch-small::after {
|
|
213
|
+
right: initial;
|
|
214
|
+
left: 0.425rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* From: https://scottaohara.github.io/a11y_styled_form_controls/src/checkbox--switch/
|
|
218
|
+
hide the actual checkbox from view, but not from keyboards or ATs.
|
|
219
|
+
Instead of standard visually hidden styling, instead set opacity to
|
|
220
|
+
almost 0 (not zero for ChomeVox legacy bug), pointer-events none, and
|
|
221
|
+
then set to full height/width of container element so that VO focus
|
|
222
|
+
ring outlines the component, instead of a tiny box within the component
|
|
223
|
+
*/
|
|
224
|
+
.switch-input {
|
|
225
|
+
margin: 0;
|
|
226
|
+
opacity: 0.01%;
|
|
227
|
+
position: absolute;
|
|
228
|
+
left: 0;
|
|
229
|
+
top: 0;
|
|
230
|
+
width: 100%;
|
|
231
|
+
height: 100%;
|
|
232
|
+
pointer-events: none;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.switch-input:focus + .switch::before {
|
|
236
|
+
box-shadow: 0 0 0 var(--focus-ring-outline-width) var(--focus-ring-color);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* update the color of the "container" to further visually indicate state */
|
|
240
|
+
.switch-input:checked + .switch:not(.switch-border)::before {
|
|
241
|
+
background: var(--primary);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.switch-input:checked + .switch-action:not(.switch-border)::before {
|
|
245
|
+
background: var(--action);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Border switch on checked the thumb gets primary or action bg respectively */
|
|
249
|
+
.switch-input:checked + .switch-border::after {
|
|
250
|
+
background: var(--primary);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.switch-input:checked + .switch-action.switch-border::after {
|
|
254
|
+
background: var(--action);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Disabled aka :disabled is not actually supported for <label>
|
|
258
|
+
element so we use attribute selector for that:
|
|
259
|
+
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled#:~:text=The%20disabled%20attribute%20is%20supported,control%20or%20its%20descendant%20controls.
|
|
260
|
+
*/
|
|
261
|
+
.switch-input[disabled] + .switch,
|
|
262
|
+
.switch-input[disabled] + .switch-label,
|
|
263
|
+
.switch-container.disabled {
|
|
264
|
+
color: var(--input-disabled-color, var(--disabled-color)) !important;
|
|
265
|
+
appearance: none !important;
|
|
266
|
+
box-shadow: none !important;
|
|
267
|
+
cursor: not-allowed !important;
|
|
268
|
+
opacity: 80% !important;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@media screen and (-ms-high-contrast: active) {
|
|
272
|
+
.switch::after {
|
|
273
|
+
background-color: windowText;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* High contrast mode outline hacks */
|
|
277
|
+
.switch-input[disabled] + .switch-label,
|
|
278
|
+
.switch-container.disabled {
|
|
279
|
+
outline: 2px solid transparent;
|
|
280
|
+
outline-offset: -2px;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@media (prefers-reduced-motion), (update: slow) {
|
|
285
|
+
.switch::after,
|
|
286
|
+
.switch::before {
|
|
287
|
+
transition-duration: 0.001ms !important;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const Switch: import("svelte").Component<Partial<{
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
css: string;
|
|
5
|
+
labelPosition: string;
|
|
6
|
+
size: string;
|
|
7
|
+
isChecked: boolean;
|
|
8
|
+
isBordered: boolean;
|
|
9
|
+
isAction: boolean;
|
|
10
|
+
isDisabled: boolean;
|
|
11
|
+
}>, {}, "">;
|
|
12
|
+
type Switch = ReturnType<typeof Switch>;
|
|
13
|
+
export default Switch;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
declare const Meta: import("svelte").Component<Partial<{
|
|
2
2
|
title: string;
|
|
3
3
|
description: string;
|
|
4
4
|
keywords: string;
|
|
5
5
|
robots: string;
|
|
6
6
|
charset: string;
|
|
7
7
|
viewport: string;
|
|
8
|
-
}
|
|
9
|
-
declare const Meta: import("svelte").Component<MetaProps, {}, "">;
|
|
8
|
+
}>, {}, "">;
|
|
10
9
|
type Meta = ReturnType<typeof Meta>;
|
|
11
10
|
export default Meta;
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
48
48
|
<Button
|
|
49
|
-
type="
|
|
49
|
+
type="button"
|
|
50
50
|
css="carousel__prev"
|
|
51
51
|
style="order: -1 !important;width: 50px;height: 100%;background: none;border: none !important;align-self: center;"
|
|
52
52
|
onclick={() => embla.scrollPrev()}
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
{/if}
|
|
70
70
|
</Button>
|
|
71
71
|
<Button
|
|
72
|
-
type="
|
|
72
|
+
type="button"
|
|
73
73
|
css="carousel__next"
|
|
74
74
|
style="order: 1000 !important;width: 50px;height: 100%;background: none; border: none !important;align-self: center;"
|
|
75
75
|
onclick={() => embla.scrollNext()}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,6 @@ export { default as DynamicMenu } from './components/menu/DynamicMenu.svelte';
|
|
|
20
20
|
export { default as HamburgerMenu } from './components/menu/HamburgerMenu.svelte';
|
|
21
21
|
export { default as Button } from './components/form/Button.svelte';
|
|
22
22
|
export { default as Input } from './components/form/Input.svelte';
|
|
23
|
-
export {
|
|
23
|
+
export { default as Switch } from './components/form/Switch.svelte';
|
|
24
24
|
export { default as Markdown } from './components/content/Markdown.svelte';
|
|
25
25
|
export { type BlogPost, listAllPosts, importPost } from './components/blog/blog.js';
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ export { default as HamburgerMenu } from './components/menu/HamburgerMenu.svelte
|
|
|
37
37
|
*/
|
|
38
38
|
export { default as Button } from './components/form/Button.svelte';
|
|
39
39
|
export { default as Input } from './components/form/Input.svelte';
|
|
40
|
-
export {
|
|
40
|
+
export { default as Switch } from './components/form/Switch.svelte';
|
|
41
41
|
/*
|
|
42
42
|
* Content
|
|
43
43
|
*/
|