sveltacular 1.0.5 → 1.0.7

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.
Files changed (47) hide show
  1. package/README.md +232 -28
  2. package/dist/forms/bool-box/bool-box.svelte +21 -2
  3. package/dist/forms/bool-box/bool-box.svelte.d.ts +5 -0
  4. package/dist/forms/check-box/check-box-group.svelte +1 -0
  5. package/dist/forms/check-box/check-box.svelte +73 -31
  6. package/dist/forms/check-box/check-box.svelte.d.ts +7 -0
  7. package/dist/forms/date-box/date-box.svelte +7 -3
  8. package/dist/forms/date-box/date-box.svelte.d.ts +3 -0
  9. package/dist/forms/file-box/file-box.svelte +33 -7
  10. package/dist/forms/form-field/form-field.svelte +128 -33
  11. package/dist/forms/form-field/form-field.svelte.d.ts +9 -3
  12. package/dist/forms/form-label/form-label.svelte +4 -2
  13. package/dist/forms/form-label/form-label.svelte.d.ts +2 -2
  14. package/dist/forms/index.d.ts +6 -2
  15. package/dist/forms/index.js +6 -3
  16. package/dist/forms/info-box/info-box.svelte +9 -7
  17. package/dist/forms/list-box/list-box.svelte +270 -89
  18. package/dist/forms/list-box/list-box.svelte.d.ts +3 -0
  19. package/dist/forms/money-box/money-box.svelte +20 -16
  20. package/dist/forms/number-box/number-box.svelte +16 -3
  21. package/dist/forms/number-box/number-box.svelte.d.ts +6 -0
  22. package/dist/forms/number-range-box/number-range-box.svelte +218 -0
  23. package/dist/forms/number-range-box/number-range-box.svelte.d.ts +21 -0
  24. package/dist/forms/phone-box/phone-box.svelte +17 -3
  25. package/dist/forms/phone-box/phone-box.svelte.d.ts +5 -0
  26. package/dist/forms/radio-group/radio-box.svelte +11 -2
  27. package/dist/forms/radio-group/radio-box.svelte.d.ts +1 -0
  28. package/dist/forms/radio-group/radio-group.svelte +10 -4
  29. package/dist/forms/radio-group/radio-group.svelte.d.ts +4 -0
  30. package/dist/forms/switch-box/switch-box.svelte +33 -13
  31. package/dist/forms/switch-box/switch-box.svelte.d.ts +6 -0
  32. package/dist/forms/tag-input-box/tag-input-box.svelte +204 -0
  33. package/dist/forms/tag-input-box/tag-input-box.svelte.d.ts +18 -0
  34. package/dist/forms/text-area/text-area.svelte +19 -3
  35. package/dist/forms/text-area/text-area.svelte.d.ts +7 -0
  36. package/dist/forms/text-box/text-box.svelte +18 -15
  37. package/dist/forms/text-box/text-box.svelte.d.ts +2 -2
  38. package/dist/forms/time-box/time-box.svelte +7 -3
  39. package/dist/forms/time-box/time-box.svelte.d.ts +3 -0
  40. package/dist/forms/url-box/url-box.svelte +31 -1
  41. package/dist/forms/url-box/url-box.svelte.d.ts +10 -0
  42. package/dist/generic/avatar/avatar.svelte +2 -0
  43. package/dist/generic/chip/chip.svelte +2 -0
  44. package/dist/generic/menu/menu.svelte +2 -3
  45. package/dist/navigation/context-menu/README.md +2 -0
  46. package/dist/navigation/context-menu/context-menu-divider.svelte +2 -0
  47. package/package.json +1 -1
@@ -0,0 +1,218 @@
1
+ <script lang="ts">
2
+ import { roundToDecimals } from '../../helpers/round-to-decimals.js';
3
+ import { uniqueId } from '../../helpers/unique-id.js';
4
+ import FormField from '../form-field/form-field.svelte';
5
+ import type { FormFieldSizeOptions } from '../../types/form.js';
6
+
7
+ const minId = uniqueId();
8
+ const maxId = uniqueId();
9
+
10
+ let {
11
+ minValue = $bindable(null as number | null),
12
+ maxValue = $bindable(null as number | null),
13
+ minAllowed = 0,
14
+ maxAllowed = 99999,
15
+ step = 1,
16
+ allowDecimals = false,
17
+ minPlaceholder = '0',
18
+ maxPlaceholder = 'No limit',
19
+ prefix = null as string | null,
20
+ suffix = null as string | null,
21
+ stickyEnd = false,
22
+ required = false,
23
+ size = 'full' as FormFieldSizeOptions,
24
+ label = undefined as string | undefined,
25
+ onChange = undefined as ((minValue: number | null, maxValue: number | null) => void) | undefined
26
+ }: {
27
+ minValue?: number | null;
28
+ maxValue?: number | null;
29
+ minAllowed?: number;
30
+ maxAllowed?: number;
31
+ step?: number;
32
+ allowDecimals?: boolean;
33
+ minPlaceholder?: string;
34
+ maxPlaceholder?: string;
35
+ prefix?: string | null;
36
+ suffix?: string | null;
37
+ stickyEnd?: boolean;
38
+ required?: boolean;
39
+ size?: FormFieldSizeOptions;
40
+ label?: string;
41
+ onChange?: ((minValue: number | null, maxValue: number | null) => void) | undefined;
42
+ } = $props();
43
+
44
+ const handleChange = () => {
45
+ // Calculate decimal places from step (e.g., step 0.1 = 1 decimal, step 0.01 = 2 decimals)
46
+ const decimalPlaces = step < 1 ? Math.abs(Math.log10(step)) : 0;
47
+
48
+ // If no decimals, must round to integer
49
+ if (!allowDecimals) {
50
+ if (minValue !== null) minValue = Math.round(minValue);
51
+ if (maxValue !== null) maxValue = Math.round(maxValue);
52
+ }
53
+ // If decimals, must round to step precision
54
+ else {
55
+ if (minValue !== null) minValue = roundToDecimals(minValue, decimalPlaces);
56
+ if (maxValue !== null) maxValue = roundToDecimals(maxValue, decimalPlaces);
57
+ }
58
+
59
+ // Ensure min value is not less than minAllowed
60
+ if (minValue !== null && minValue < minAllowed) {
61
+ minValue = minAllowed;
62
+ }
63
+
64
+ // Ensure max value is not greater than maxAllowed
65
+ if (maxValue !== null && maxValue > maxAllowed) {
66
+ maxValue = maxAllowed;
67
+ }
68
+
69
+ // Ensure max value is greater than or equal to min value
70
+ if (minValue !== null && maxValue !== null && minValue > maxValue) {
71
+ maxValue = minValue;
72
+ }
73
+
74
+ onChange?.(minValue, maxValue);
75
+ };
76
+
77
+ const handleMinChange = () => {
78
+ if (stickyEnd) {
79
+ maxValue = minValue;
80
+ }
81
+ handleChange();
82
+ };
83
+
84
+ const onInput = (e: Event, isMin: boolean) => {
85
+ const input = e.target as HTMLInputElement;
86
+ const newValue = parseFloat(input.value);
87
+ if (isNaN(newValue)) {
88
+ if (isMin) minValue = null;
89
+ else maxValue = null;
90
+ return;
91
+ }
92
+ if (isMin) minValue = newValue;
93
+ else maxValue = newValue;
94
+ };
95
+
96
+ // Don't allow certain characters to be typed into the input
97
+ const onKeyPress = (e: KeyboardEvent, isMin: boolean) => {
98
+ const isNumber = !isNaN(Number(e.key));
99
+ const isDecimal = e.key === '.';
100
+ const isAllowed =
101
+ isNumber ||
102
+ isDecimal ||
103
+ ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', '-'].includes(e.key);
104
+ if (!isAllowed) return e.preventDefault();
105
+ if (isDecimal && !allowDecimals) return e.preventDefault();
106
+ };
107
+ </script>
108
+
109
+ <FormField {size} {label} id={minId} {required}>
110
+ <div class="number-range-inputs">
111
+ <div class="input-group">
112
+ <div class="input">
113
+ {#if prefix}
114
+ <span class="prefix">{prefix}</span>
115
+ {/if}
116
+ <input
117
+ id={minId}
118
+ type="number"
119
+ placeholder={minPlaceholder}
120
+ min={minAllowed}
121
+ max={maxAllowed}
122
+ {step}
123
+ bind:value={minValue}
124
+ onchange={handleMinChange}
125
+ oninput={(e) => onInput(e, true)}
126
+ onkeypress={(e) => onKeyPress(e, true)}
127
+ {required}
128
+ />
129
+ {#if suffix}
130
+ <span class="suffix">{suffix}</span>
131
+ {/if}
132
+ </div>
133
+ </div>
134
+ <div class="input-group">
135
+ <div class="input">
136
+ {#if prefix}
137
+ <span class="prefix">{prefix}</span>
138
+ {/if}
139
+ <input
140
+ id={maxId}
141
+ type="number"
142
+ placeholder={maxPlaceholder}
143
+ min={minAllowed}
144
+ max={maxAllowed}
145
+ {step}
146
+ bind:value={maxValue}
147
+ onchange={handleChange}
148
+ oninput={(e) => onInput(e, false)}
149
+ onkeypress={(e) => onKeyPress(e, false)}
150
+ {required}
151
+ />
152
+ {#if suffix}
153
+ <span class="suffix">{suffix}</span>
154
+ {/if}
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </FormField>
159
+
160
+ <style>.number-range-inputs {
161
+ display: flex;
162
+ gap: var(--spacing-md);
163
+ width: 100%;
164
+ }
165
+
166
+ .input-group {
167
+ flex: 1;
168
+ }
169
+
170
+ .input {
171
+ display: flex;
172
+ align-items: center;
173
+ justify-content: flex-start;
174
+ position: relative;
175
+ width: 100%;
176
+ height: 100%;
177
+ border-radius: var(--radius-md);
178
+ border: var(--border-thin) solid var(--form-input-border);
179
+ background-color: var(--form-input-bg);
180
+ color: var(--form-input-fg);
181
+ font-size: var(--font-md);
182
+ font-weight: 500;
183
+ line-height: 2rem;
184
+ transition: background-color var(--transition-base) var(--ease-in-out), border-color var(--transition-base) var(--ease-in-out), color var(--transition-base) var(--ease-in-out), fill var(--transition-base) var(--ease-in-out), stroke var(--transition-base) var(--ease-in-out);
185
+ user-select: none;
186
+ white-space: nowrap;
187
+ }
188
+ .input input {
189
+ background-color: transparent;
190
+ border: none;
191
+ line-height: 2rem;
192
+ font-size: var(--font-md);
193
+ width: 100%;
194
+ flex-grow: 1;
195
+ padding-left: var(--spacing-base);
196
+ padding-right: var(--spacing-base);
197
+ }
198
+ .input input:focus {
199
+ outline: none;
200
+ }
201
+ .input input::placeholder {
202
+ color: var(--form-input-placeholder);
203
+ }
204
+ .input .prefix,
205
+ .input .suffix {
206
+ font-size: var(--font-md);
207
+ line-height: 2rem;
208
+ padding-left: var(--spacing-base);
209
+ padding-right: var(--spacing-base);
210
+ background-color: var(--form-input-accent-bg);
211
+ color: var(--form-input-accent-fg);
212
+ }
213
+ .input .prefix {
214
+ border-right: var(--border-thin) solid var(--form-input-border);
215
+ }
216
+ .input .suffix {
217
+ border-left: var(--border-thin) solid var(--form-input-border);
218
+ }</style>
@@ -0,0 +1,21 @@
1
+ import type { FormFieldSizeOptions } from '../../types/form.js';
2
+ type $$ComponentProps = {
3
+ minValue?: number | null;
4
+ maxValue?: number | null;
5
+ minAllowed?: number;
6
+ maxAllowed?: number;
7
+ step?: number;
8
+ allowDecimals?: boolean;
9
+ minPlaceholder?: string;
10
+ maxPlaceholder?: string;
11
+ prefix?: string | null;
12
+ suffix?: string | null;
13
+ stickyEnd?: boolean;
14
+ required?: boolean;
15
+ size?: FormFieldSizeOptions;
16
+ label?: string;
17
+ onChange?: ((minValue: number | null, maxValue: number | null) => void) | undefined;
18
+ };
19
+ declare const NumberRangeBox: import("svelte").Component<$$ComponentProps, {}, "minValue" | "maxValue">;
20
+ type NumberRangeBox = ReturnType<typeof NumberRangeBox>;
21
+ export default NumberRangeBox;
@@ -1,18 +1,26 @@
1
1
  <script lang="ts">
2
2
  import { untrack } from 'svelte';
3
3
  import { uniqueId, type FormFieldSizeOptions } from '../../index.js';
4
- import FormField from '../form-field/form-field.svelte';
4
+ import FormField, { type FormFieldFeedback } from '../form-field/form-field.svelte';
5
5
 
6
6
  let {
7
7
  value = $bindable('' as string | null),
8
8
  size = 'md' as FormFieldSizeOptions,
9
9
  onChange = undefined,
10
- label = undefined
10
+ label = undefined,
11
+ helperText = undefined,
12
+ feedback = undefined,
13
+ disabled = false,
14
+ required = false
11
15
  }: {
12
16
  value?: string | null;
13
17
  size?: FormFieldSizeOptions;
14
18
  onChange?: ((value: string) => void) | undefined;
15
19
  label?: string;
20
+ helperText?: string;
21
+ feedback?: FormFieldFeedback;
22
+ disabled?: boolean;
23
+ required?: boolean;
16
24
  } = $props();
17
25
 
18
26
  const id = uniqueId();
@@ -146,7 +154,7 @@
146
154
  });
147
155
  </script>
148
156
 
149
- <FormField {size} {label} id="{id}-areaCode">
157
+ <FormField {size} {label} id="{id}-areaCode" {required} {disabled} {helperText} {feedback}>
150
158
  <div class="input">
151
159
  <span class="areaCode segment">
152
160
  <span>(</span>
@@ -159,6 +167,8 @@
159
167
  bind:value={areaCode}
160
168
  name="areaCode"
161
169
  data-maxlength="3"
170
+ {disabled}
171
+ {required}
162
172
  />
163
173
  <span>)</span>
164
174
  </span>
@@ -172,6 +182,8 @@
172
182
  bind:value={localExt}
173
183
  name="localExt"
174
184
  data-maxlength="3"
185
+ {disabled}
186
+ {required}
175
187
  />
176
188
  </span>
177
189
  <span class="lastFour segment">
@@ -185,6 +197,8 @@
185
197
  bind:value={lastFour}
186
198
  name="lastFour"
187
199
  data-maxlength="4"
200
+ {disabled}
201
+ {required}
188
202
  /></span
189
203
  >
190
204
  </div>
@@ -1,9 +1,14 @@
1
1
  import { type FormFieldSizeOptions } from '../../index.js';
2
+ import { type FormFieldFeedback } from '../form-field/form-field.svelte';
2
3
  type $$ComponentProps = {
3
4
  value?: string | null;
4
5
  size?: FormFieldSizeOptions;
5
6
  onChange?: ((value: string) => void) | undefined;
6
7
  label?: string;
8
+ helperText?: string;
9
+ feedback?: FormFieldFeedback;
10
+ disabled?: boolean;
11
+ required?: boolean;
7
12
  };
8
13
  declare const PhoneBox: import("svelte").Component<$$ComponentProps, {}, "value">;
9
14
  type PhoneBox = ReturnType<typeof PhoneBox>;
@@ -9,19 +9,28 @@
9
9
  value = undefined as RadioValue,
10
10
  group = $bindable(undefined as string | undefined),
11
11
  disabled = false,
12
- children = undefined
12
+ children = undefined,
13
+ onChange = undefined
13
14
  }: {
14
15
  value?: RadioValue;
15
16
  group?: string | undefined;
16
17
  disabled?: boolean;
17
18
  children?: Snippet;
19
+ onChange?: ((value: string) => void) | undefined;
18
20
  } = $props();
19
21
 
20
22
  const id = uniqueId();
21
23
  </script>
22
24
 
23
25
  <label>
24
- <input type="radio" bind:group {value} {disabled} {id} />
26
+ <input
27
+ type="radio"
28
+ bind:group
29
+ {value}
30
+ {disabled}
31
+ {id}
32
+ onchange={() => onChange?.(String(value || ''))}
33
+ />
25
34
  <span class="checkbox">
26
35
  <span class="checkmark"><CheckIcon /></span>
27
36
  </span>
@@ -5,6 +5,7 @@ type $$ComponentProps = {
5
5
  group?: string | undefined;
6
6
  disabled?: boolean;
7
7
  children?: Snippet;
8
+ onChange?: ((value: string) => void) | undefined;
8
9
  };
9
10
  declare const RadioBox: import("svelte").Component<$$ComponentProps, {}, "group">;
10
11
  type RadioBox = ReturnType<typeof RadioBox>;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { DropdownOption, FormFieldSizeOptions } from '../../types/form.js';
3
- import FormField from '../form-field/form-field.svelte';
3
+ import FormField, { type FormFieldFeedback } from '../form-field/form-field.svelte';
4
4
  import { uniqueId } from '../../helpers/unique-id.js';
5
5
  import RadioBox from './radio-box.svelte';
6
6
 
@@ -12,7 +12,10 @@
12
12
  size = 'full' as FormFieldSizeOptions,
13
13
  disabled = false,
14
14
  required = false,
15
- label = undefined
15
+ label = undefined,
16
+ helperText = undefined,
17
+ feedback = undefined,
18
+ onChange = undefined
16
19
  }: {
17
20
  group?: string;
18
21
  items?: DropdownOption[];
@@ -20,13 +23,16 @@
20
23
  disabled?: boolean;
21
24
  required?: boolean;
22
25
  label?: string;
26
+ helperText?: string;
27
+ feedback?: FormFieldFeedback;
28
+ onChange?: ((value: string) => void) | undefined;
23
29
  } = $props();
24
30
  </script>
25
31
 
26
- <FormField {size} {label} {id} {required} {disabled}>
32
+ <FormField {size} {label} {id} {required} {disabled} {helperText} {feedback}>
27
33
  <div>
28
34
  {#each items as item}
29
- <RadioBox bind:group {disabled} value={item.value}>{item.name}</RadioBox>
35
+ <RadioBox bind:group {disabled} value={item.value} onChange={onChange}>{item.name}</RadioBox>
30
36
  {/each}
31
37
  </div>
32
38
  </FormField>
@@ -1,4 +1,5 @@
1
1
  import type { DropdownOption, FormFieldSizeOptions } from '../../types/form.js';
2
+ import { type FormFieldFeedback } from '../form-field/form-field.svelte';
2
3
  type $$ComponentProps = {
3
4
  group?: string;
4
5
  items?: DropdownOption[];
@@ -6,6 +7,9 @@ type $$ComponentProps = {
6
7
  disabled?: boolean;
7
8
  required?: boolean;
8
9
  label?: string;
10
+ helperText?: string;
11
+ feedback?: FormFieldFeedback;
12
+ onChange?: ((value: string) => void) | undefined;
9
13
  };
10
14
  declare const RadioGroup: import("svelte").Component<$$ComponentProps, {}, "">;
11
15
  type RadioGroup = ReturnType<typeof RadioGroup>;
@@ -2,34 +2,54 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import { uniqueId } from '../../helpers/unique-id.js';
4
4
  import type { FormFieldSizeOptions } from '../../index.js';
5
+ import FormField, { type FormFieldFeedback } from '../form-field/form-field.svelte';
5
6
 
6
7
  let {
7
8
  checked = $bindable(false),
8
9
  size = 'full' as FormFieldSizeOptions,
9
10
  onChange = undefined,
10
- children
11
+ children,
12
+ label = undefined,
13
+ helperText = undefined,
14
+ feedback = undefined,
15
+ disabled = false,
16
+ required = false
11
17
  }: {
12
18
  checked?: boolean;
13
19
  size?: FormFieldSizeOptions;
14
20
  onChange?: ((checked: boolean) => void) | undefined;
15
21
  children?: Snippet;
22
+ label?: string;
23
+ helperText?: string;
24
+ feedback?: FormFieldFeedback;
25
+ disabled?: boolean;
26
+ required?: boolean;
16
27
  } = $props();
17
28
 
18
29
  const id = uniqueId();
19
30
  </script>
20
31
 
21
- <label class="switch-box {checked ? 'checked' : ''} {size}">
22
- <input type="checkbox" bind:checked onchange={() => onChange?.(checked)} {id} />
23
- <!-- svelte-ignore a11y_interactive_supports_focus -->
24
- <span class="switch">
25
- <span class="slider"></span>
26
- </span>
27
- {#if children}
28
- <div class="text">
29
- {@render children?.()}
30
- </div>
31
- {/if}
32
- </label>
32
+ <FormField {size} {label} {id} {required} {disabled} {helperText} {feedback}>
33
+ <label class="switch-box {checked ? 'checked' : ''} {size}">
34
+ <input
35
+ type="checkbox"
36
+ bind:checked
37
+ onchange={() => onChange?.(checked)}
38
+ {id}
39
+ {disabled}
40
+ {required}
41
+ />
42
+ <!-- svelte-ignore a11y_interactive_supports_focus -->
43
+ <span class="switch">
44
+ <span class="slider"></span>
45
+ </span>
46
+ {#if children}
47
+ <div class="text">
48
+ {@render children?.()}
49
+ </div>
50
+ {/if}
51
+ </label>
52
+ </FormField>
33
53
 
34
54
  <style>label {
35
55
  display: flex;
@@ -1,10 +1,16 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { FormFieldSizeOptions } from '../../index.js';
3
+ import { type FormFieldFeedback } from '../form-field/form-field.svelte';
3
4
  type $$ComponentProps = {
4
5
  checked?: boolean;
5
6
  size?: FormFieldSizeOptions;
6
7
  onChange?: ((checked: boolean) => void) | undefined;
7
8
  children?: Snippet;
9
+ label?: string;
10
+ helperText?: string;
11
+ feedback?: FormFieldFeedback;
12
+ disabled?: boolean;
13
+ required?: boolean;
8
14
  };
9
15
  declare const SwitchBox: import("svelte").Component<$$ComponentProps, {}, "checked">;
10
16
  type SwitchBox = ReturnType<typeof SwitchBox>;