@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.
@@ -1,21 +1,2 @@
1
- export declare enum Type {
2
- Text = "text",
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 var Type;
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 { Size, Type } from './Input.js';
5
-
6
- interface Props {
7
- label?: string;
8
- id?: string;
9
- labelCss?: string;
10
- isLabelHidden?: boolean;
11
- helpText?: string;
12
- invalidText?: string;
13
- isInvalid?: boolean;
14
- isInline?: boolean;
15
- isRounded?: boolean;
16
- isDisabled?: boolean | undefined;
17
- css?: string;
18
- isSkinned?: boolean;
19
- isUnderlinedWithBackground?: boolean;
20
- isUnderlined?: boolean;
21
- size?: Size;
22
- type?: Type;
23
- value?: string;
24
- addonLeft?: Snippet;
25
- addonRight?: Snippet;
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
- size = Size.Normal,
45
- type = Type.Text,
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
- size ? `label-${size}` : '',
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
- size ? `input-${size}` : ''
87
+ labelSize ? `input-${labelSize}` : ''
74
88
  )
75
89
  );
76
90
 
77
- let invalidClasses = $derived(size ? `field-error-${size}` : 'field-error');
91
+ let invalidClasses = $derived(labelSize ? `field-error-${labelSize}` : 'field-error');
78
92
 
79
- let helpClasses = $derived(size ? `field-help-${size}` : 'field-help');
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 {id} class={inputClasses} bind:value {...restProps}></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(--agnostic-font-color, var(--agnostic-dark));
163
- font-family: var(--agnostic-font-family-body);
164
- font-weight: var(--agnostic-font-weight, 300);
165
- font-size: var(--agnostic-font-size, 1rem);
166
- line-height: var(--agnostic-line-height, var(--fluid-20, 1.25rem));
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(--agnostic-input-border-size, 1px);
178
- border-color: var(--agnostic-input-border-color, var(--agnostic-gray-light));
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(--agnostic-input-vertical-pad, 0.5rem);
182
- padding-block-end: var(--agnostic-input-vertical-pad, 0.5rem);
183
- padding-inline-start: var(--agnostic-input-side-padding, 0.75rem);
184
- padding-inline-end: var(--agnostic-input-side-padding, 0.75rem);
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(--agnostic-input-timing, var(--agnostic-timing-medium));
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 --agnostic-input-vertical-pad isn't overriden we'll get 20px
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(--agnostic-input-label-pad, 0.375rem);
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(--agnostic-font-size, 1rem) - 2px);
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(--agnostic-input-side-padding, 0.75rem);
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(--agnostic-timing-fast) ease-out;
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(--agnostic-timing-fast) ease-out;
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(--agnostic-timing-fast) ease-out;
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(--agnostic-timing-fast) ease-out;
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(--agnostic-input-underlined-color, var(--agnostic-gray-mid-dark));
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(--agnostic-input-underlined-bg-color, var(--agnostic-gray-extra-light));
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(--agnostic-radius, 0.25rem);
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(--agnostic-input-error-color, var(--agnostic-error));
315
+ color: var(--input-error-color, var(--error));
291
316
  }
292
317
 
293
318
  .input-error {
294
- border-color: var(--agnostic-input-error-color, var(--agnostic-error));
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(--agnostic-input-error-color, var(--agnostic-error));
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(--agnostic-input-help-color, var(--agnostic-gray-dark));
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(--agnostic-input-vertical-pad, 0.5rem) / 2);
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(--agnostic-font-size, 1rem) + 0.25rem);
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(--agnostic-font-size, 1rem);
357
+ font-size: var(--font-size, 1rem);
333
358
  }
334
359
 
335
360
  .label-large {
336
- font-size: calc(var(--agnostic-font-size, 1rem) + 0.25rem);
361
+ font-size: calc(var(--font-size, 1rem) + 0.25rem);
337
362
  }
338
363
 
339
364
  .input-small {
340
- font-size: calc(var(--agnostic-font-size, 1rem) - 0.25rem);
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(--agnostic-font-size, 1rem) - 0.25rem);
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(--agnostic-focus-ring-outline-width) var(--agnostic-focus-ring-color);
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(--agnostic-focus-ring-outline-width) var(--agnostic-focus-ring-outline-style)
355
- var(--agnostic-focus-ring-outline-color);
356
- transition: box-shadow var(--agnostic-timing-fast) ease-out;
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(--agnostic-input-disabled-bg, var(--agnostic-disabled-bg)) !important;
376
- color: var(--agnostic-input-disabled-color, var(--agnostic-disabled-color)) !important;
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(--agnostic-side-padding) * 3);
430
+ padding-left: calc(var(--side-padding) * 3);
406
431
  }
407
432
 
408
433
  .input-has-right-addon {
409
- padding-right: calc(var(--agnostic-side-padding) * 3);
434
+ padding-right: calc(var(--side-padding) * 3);
410
435
  }
411
436
 
412
437
  .input-addon-left {
413
- left: var(--agnostic-input-side-padding);
438
+ left: var(--input-side-padding);
414
439
  }
415
440
 
416
441
  .input-addon-right {
417
- right: var(--agnostic-input-side-padding);
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 { Size, Type } from './Input.js';
3
- interface Props {
4
- label?: string;
5
- id?: string;
6
- labelCss?: string;
7
- isLabelHidden?: boolean;
8
- helpText?: string;
9
- invalidText?: string;
10
- isInvalid?: boolean;
11
- isInline?: boolean;
12
- isRounded?: boolean;
13
- isDisabled?: boolean | undefined;
14
- css?: string;
15
- isSkinned?: boolean;
16
- isUnderlinedWithBackground?: boolean;
17
- isUnderlined?: boolean;
18
- size?: Size;
19
- type?: Type;
20
- value?: string;
21
- addonLeft?: Snippet;
22
- addonRight?: Snippet;
23
- }
24
- declare const Input: import("svelte").Component<Props, {}, "">;
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;
@@ -15,7 +15,7 @@
15
15
  robots = 'index, follow',
16
16
  charset = 'UTF-8',
17
17
  viewport = 'width=device-width, initial-scale=1.0'
18
- }: MetaProps = $props();
18
+ }: Partial<MetaProps> = $props();
19
19
  </script>
20
20
 
21
21
  <svelte:head>
@@ -1,11 +1,10 @@
1
- interface MetaProps {
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="link"
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="link"
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()}
@@ -64,6 +64,7 @@
64
64
  on:resize={resize}
65
65
  />
66
66
 
67
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
67
68
  <div
68
69
  class="container"
69
70
  {style}
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 { Type, Size } from './components/form/Input.js';
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 { Type, Size } from './components/form/Input.js';
40
+ export { default as Switch } from './components/form/Switch.svelte';
41
41
  /*
42
42
  * Content
43
43
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionalcms/svelte-components",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "watch": {
5
5
  "build": {
6
6
  "patterns": [