sveltacular 1.0.17 → 1.0.20

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 (38) hide show
  1. package/README.md +1 -2
  2. package/dist/forms/bool-box/bool-box.svelte +392 -13
  3. package/dist/forms/bool-box/bool-box.svelte.d.ts +2 -0
  4. package/dist/forms/bool-box/index.d.ts +2 -0
  5. package/dist/forms/bool-box/index.js +2 -0
  6. package/dist/forms/date-box/date-box.svelte +104 -53
  7. package/dist/forms/date-box/date-box.svelte.d.ts +8 -3
  8. package/dist/forms/dimension-box/dimension-box.svelte +15 -50
  9. package/dist/forms/file-box/file-box.svelte +7 -25
  10. package/dist/forms/form-input-wrapper/form-input-wrapper.svelte +203 -0
  11. package/dist/forms/form-input-wrapper/form-input-wrapper.svelte.d.ts +16 -0
  12. package/dist/forms/form-input-wrapper/index.d.ts +2 -0
  13. package/dist/forms/form-input-wrapper/index.js +2 -0
  14. package/dist/forms/index.d.ts +0 -1
  15. package/dist/forms/index.js +0 -1
  16. package/dist/forms/list-box/list-box.svelte +127 -29
  17. package/dist/forms/list-box/list-box.svelte.d.ts +3 -0
  18. package/dist/forms/money-box/money-box.svelte +104 -65
  19. package/dist/forms/money-box/money-box.svelte.d.ts +6 -0
  20. package/dist/forms/number-box/number-box.svelte +93 -49
  21. package/dist/forms/number-box/number-box.svelte.d.ts +6 -0
  22. package/dist/forms/number-range-box/number-range-box.svelte +22 -58
  23. package/dist/forms/phone-box/phone-box.svelte +101 -38
  24. package/dist/forms/phone-box/phone-box.svelte.d.ts +6 -1
  25. package/dist/forms/slider/slider.svelte +13 -6
  26. package/dist/forms/slider/slider.svelte.d.ts +6 -2
  27. package/dist/forms/tag-box/tag-box.svelte +332 -28
  28. package/dist/forms/tag-box/tag-box.svelte.d.ts +3 -0
  29. package/dist/forms/text-area/text-area.svelte +22 -2
  30. package/dist/forms/text-area/text-area.svelte.d.ts +4 -0
  31. package/dist/forms/text-box/text-box.svelte +88 -129
  32. package/dist/forms/text-box/text-box.svelte.d.ts +7 -2
  33. package/dist/forms/time-box/time-box.svelte +106 -37
  34. package/dist/forms/time-box/time-box.svelte.d.ts +10 -3
  35. package/dist/forms/url-box/url-box.svelte +26 -5
  36. package/dist/forms/url-box/url-box.svelte.d.ts +7 -1
  37. package/dist/generic/theme-provider/theme-provider-demo.svelte +7 -2
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -72,8 +72,7 @@ npm i sveltacular
72
72
  - **PhoneBox** - Phone number input with formatting
73
73
  - **FileBox** / **FileArea** - File upload with drag-and-drop
74
74
  - **Slider** - Range slider with tooltip and value display
75
- - **SwitchBox** - Toggle switch component
76
- - **BoolBox** - Boolean input component
75
+ - **BoolBox** - Boolean input component with multiple variants (dropdown, switch, checkbox, radio)
77
76
  - **MoneyBox** - Currency input with formatting
78
77
  - **TagBox** - Tag input with chip display
79
78
  - **UrlBox** - URL input with validation
@@ -1,8 +1,12 @@
1
1
  <script lang="ts">
2
2
  import ListBox from '../list-box/list-box.svelte';
3
+ import FormField from '../form-field/form-field.svelte';
4
+ import { uniqueId } from '../../helpers/unique-id.js';
3
5
  import type { FormFieldSizeOptions } from '../../index.js';
4
6
  import type { FormFieldFeedback } from '../form-field/form-field.svelte';
5
7
 
8
+ type BoolBoxVariant = 'dropdown' | 'switch' | 'checkbox' | 'radio';
9
+
6
10
  let {
7
11
  value = $bindable(false),
8
12
  options = ['Yes', 'No'] as [yes: string, no: string],
@@ -12,7 +16,8 @@
12
16
  helperText = undefined,
13
17
  feedback = undefined,
14
18
  disabled = false,
15
- required = false
19
+ required = false,
20
+ variant = 'dropdown'
16
21
  }: {
17
22
  value?: boolean;
18
23
  options?: [yes: string, no: string];
@@ -23,29 +28,403 @@
23
28
  feedback?: FormFieldFeedback;
24
29
  disabled?: boolean;
25
30
  required?: boolean;
31
+ variant?: BoolBoxVariant;
26
32
  } = $props();
27
33
 
34
+ const id = uniqueId();
28
35
  let stringValue = $state(value ? 'true' : 'false');
29
36
 
30
- const handleChange = () => {
37
+ // Handle dropdown changes
38
+ const handleDropdownChange = () => {
31
39
  value = stringValue == 'true';
32
40
  onChange?.(value);
33
41
  };
34
42
 
43
+ // Handle direct boolean changes (switch, checkbox)
44
+ const handleBooleanChange = () => {
45
+ onChange?.(value);
46
+ };
47
+
48
+ // Handle radio changes
49
+ const handleRadioChange = (newValue: boolean) => {
50
+ value = newValue;
51
+ onChange?.(value);
52
+ };
53
+
35
54
  let items = $derived([
36
55
  { value: 'true', name: options[0] },
37
56
  { value: 'false', name: options[1] }
38
57
  ]);
39
58
  </script>
40
59
 
41
- <ListBox
42
- {items}
43
- bind:value={stringValue}
44
- {size}
45
- onChange={handleChange}
46
- {label}
47
- {helperText}
48
- {feedback}
49
- {disabled}
50
- {required}
51
- />
60
+ {#if variant === 'dropdown'}
61
+ <ListBox
62
+ {items}
63
+ bind:value={stringValue}
64
+ {size}
65
+ onChange={handleDropdownChange}
66
+ {label}
67
+ {helperText}
68
+ {feedback}
69
+ {disabled}
70
+ {required}
71
+ />
72
+ {:else if variant === 'switch'}
73
+ <FormField {size} {label} {id} {required} {disabled} {helperText} {feedback}>
74
+ <label class="switch-box {value ? 'checked' : ''} {size}">
75
+ <input
76
+ type="checkbox"
77
+ bind:checked={value}
78
+ onchange={handleBooleanChange}
79
+ {id}
80
+ {disabled}
81
+ {required}
82
+ />
83
+ <span class="switch">
84
+ <span class="slider"></span>
85
+ </span>
86
+ {#if options[0]}
87
+ <span class="text">{value ? options[0] : options[1]}</span>
88
+ {/if}
89
+ </label>
90
+ </FormField>
91
+ {:else if variant === 'checkbox'}
92
+ <FormField {size} {label} {id} {required} {disabled} {helperText} {feedback}>
93
+ <label class="checkbox-box {size}">
94
+ <input
95
+ type="checkbox"
96
+ bind:checked={value}
97
+ onchange={handleBooleanChange}
98
+ {id}
99
+ {disabled}
100
+ {required}
101
+ />
102
+ <span class="checkmark"></span>
103
+ {#if options[0]}
104
+ <span class="text">{value ? options[0] : options[1]}</span>
105
+ {/if}
106
+ </label>
107
+ </FormField>
108
+ {:else if variant === 'radio'}
109
+ <FormField {size} {label} id={`${id}-group`} {required} {disabled} {helperText} {feedback}>
110
+ <div class="radio-group {size}">
111
+ <label class="radio-option">
112
+ <input
113
+ type="radio"
114
+ name={id}
115
+ checked={value === true}
116
+ onchange={() => handleRadioChange(true)}
117
+ {disabled}
118
+ {required}
119
+ />
120
+ <span class="radio-mark"></span>
121
+ <span class="text">{options[0]}</span>
122
+ </label>
123
+ <label class="radio-option">
124
+ <input
125
+ type="radio"
126
+ name={id}
127
+ checked={value === false}
128
+ onchange={() => handleRadioChange(false)}
129
+ {disabled}
130
+ {required}
131
+ />
132
+ <span class="radio-mark"></span>
133
+ <span class="text">{options[1]}</span>
134
+ </label>
135
+ </div>
136
+ </FormField>
137
+ {/if}
138
+
139
+ <style>/* Switch Styles */
140
+ .switch-box {
141
+ display: flex;
142
+ align-items: center;
143
+ cursor: pointer;
144
+ }
145
+ .switch-box input {
146
+ width: 0;
147
+ height: 0;
148
+ position: absolute;
149
+ opacity: 0;
150
+ }
151
+ .switch-box .switch {
152
+ background-color: var(--form-switch-unchecked-bg);
153
+ position: relative;
154
+ cursor: pointer;
155
+ transition: background-color var(--transition-base) var(--ease-in-out);
156
+ vertical-align: middle;
157
+ flex-shrink: 0;
158
+ }
159
+ .switch-box .slider {
160
+ border-radius: var(--radius-full);
161
+ position: absolute;
162
+ transition: left var(--transition-base) var(--ease-in-out);
163
+ background-color: var(--form-switch-unchecked-fg);
164
+ }
165
+ .switch-box.checked .switch {
166
+ background-color: var(--form-switch-checked-bg, #3182ce);
167
+ }
168
+ .switch-box.checked .slider {
169
+ background-color: var(--form-switch-checked-fg, white);
170
+ }
171
+ .switch-box .text {
172
+ margin-left: 0.65rem;
173
+ }
174
+ .switch-box {
175
+ /* Switch Sizes */
176
+ }
177
+ .switch-box.xl .switch {
178
+ width: 4rem;
179
+ height: 2rem;
180
+ border-radius: 1rem;
181
+ }
182
+ .switch-box.xl .slider {
183
+ width: 1.6rem;
184
+ height: 1.6rem;
185
+ top: 0.2rem;
186
+ left: 0.2rem;
187
+ }
188
+ .switch-box.xl.checked .slider {
189
+ left: 2.25rem;
190
+ }
191
+ .switch-box.xl .text {
192
+ font-size: 1.5rem;
193
+ margin-left: 1rem;
194
+ }
195
+ .switch-box.lg .switch {
196
+ width: 3rem;
197
+ height: 1.5rem;
198
+ border-radius: 0.75rem;
199
+ }
200
+ .switch-box.lg .slider {
201
+ width: 1.2rem;
202
+ height: 1.2rem;
203
+ top: 0.15rem;
204
+ left: 0.15rem;
205
+ }
206
+ .switch-box.lg.checked .slider {
207
+ left: 1.65rem;
208
+ }
209
+ .switch-box.lg .text {
210
+ font-size: 1.2rem;
211
+ margin-left: 0.8rem;
212
+ }
213
+ .switch-box.md .switch, .switch-box.full .switch {
214
+ width: 2.5rem;
215
+ height: 1.4rem;
216
+ border-radius: 0.7rem;
217
+ }
218
+ .switch-box.md .slider, .switch-box.full .slider {
219
+ width: 1.2rem;
220
+ height: 1.2rem;
221
+ top: 0.1rem;
222
+ left: 0.1rem;
223
+ }
224
+ .switch-box.md.checked .slider, .switch-box.full.checked .slider {
225
+ left: 1.2rem;
226
+ }
227
+ .switch-box.md .text, .switch-box.full .text {
228
+ font-size: 1rem;
229
+ margin-left: 0.65rem;
230
+ }
231
+ .switch-box.sm .switch {
232
+ width: 1.5rem;
233
+ height: 0.75rem;
234
+ border-radius: 0.375rem;
235
+ }
236
+ .switch-box.sm .slider {
237
+ width: 0.6rem;
238
+ height: 0.6rem;
239
+ top: 0.075rem;
240
+ left: 0.075rem;
241
+ }
242
+ .switch-box.sm.checked .slider {
243
+ left: 0.825rem;
244
+ }
245
+ .switch-box.sm .text {
246
+ font-size: 0.8rem;
247
+ margin-left: 0.5rem;
248
+ }
249
+
250
+ /* Checkbox Styles */
251
+ .checkbox-box {
252
+ display: flex;
253
+ align-items: center;
254
+ cursor: pointer;
255
+ }
256
+ .checkbox-box input {
257
+ position: absolute;
258
+ opacity: 0;
259
+ width: 0;
260
+ height: 0;
261
+ }
262
+ .checkbox-box .checkmark {
263
+ position: relative;
264
+ background-color: var(--form-input-bg, white);
265
+ border: 2px solid var(--form-input-border, #d1d5db);
266
+ border-radius: var(--radius-sm, 0.25rem);
267
+ transition: all var(--transition-base) var(--ease-in-out);
268
+ flex-shrink: 0;
269
+ }
270
+ .checkbox-box input:checked ~ .checkmark {
271
+ background-color: var(--form-switch-checked-bg, #3182ce);
272
+ border-color: var(--form-switch-checked-bg, #3182ce);
273
+ }
274
+ .checkbox-box .checkmark::after {
275
+ content: "";
276
+ position: absolute;
277
+ display: none;
278
+ left: 35%;
279
+ top: 15%;
280
+ width: 25%;
281
+ height: 50%;
282
+ border: solid white;
283
+ border-width: 0 2px 2px 0;
284
+ transform: rotate(45deg);
285
+ }
286
+ .checkbox-box input:checked ~ .checkmark::after {
287
+ display: block;
288
+ }
289
+ .checkbox-box input:disabled ~ .checkmark {
290
+ opacity: 0.5;
291
+ cursor: not-allowed;
292
+ }
293
+ .checkbox-box .text {
294
+ margin-left: 0.5rem;
295
+ }
296
+ .checkbox-box {
297
+ /* Checkbox Sizes */
298
+ }
299
+ .checkbox-box.xl .checkmark {
300
+ width: 2rem;
301
+ height: 2rem;
302
+ }
303
+ .checkbox-box.xl .text {
304
+ font-size: 1.5rem;
305
+ margin-left: 1rem;
306
+ }
307
+ .checkbox-box.lg .checkmark {
308
+ width: 1.5rem;
309
+ height: 1.5rem;
310
+ }
311
+ .checkbox-box.lg .text {
312
+ font-size: 1.2rem;
313
+ margin-left: 0.8rem;
314
+ }
315
+ .checkbox-box.md .checkmark, .checkbox-box.full .checkmark {
316
+ width: 1.25rem;
317
+ height: 1.25rem;
318
+ }
319
+ .checkbox-box.md .text, .checkbox-box.full .text {
320
+ font-size: 1rem;
321
+ }
322
+ .checkbox-box.sm .checkmark {
323
+ width: 1rem;
324
+ height: 1rem;
325
+ }
326
+ .checkbox-box.sm .text {
327
+ font-size: 0.8rem;
328
+ }
329
+
330
+ /* Radio Styles */
331
+ .radio-group {
332
+ display: flex;
333
+ gap: 1rem;
334
+ }
335
+ .radio-group .radio-option {
336
+ display: flex;
337
+ align-items: center;
338
+ cursor: pointer;
339
+ }
340
+ .radio-group .radio-option input {
341
+ position: absolute;
342
+ opacity: 0;
343
+ width: 0;
344
+ height: 0;
345
+ }
346
+ .radio-group .radio-option .radio-mark {
347
+ position: relative;
348
+ background-color: var(--form-input-bg, white);
349
+ border: 2px solid var(--form-input-border, #d1d5db);
350
+ border-radius: var(--radius-full);
351
+ transition: all var(--transition-base) var(--ease-in-out);
352
+ flex-shrink: 0;
353
+ }
354
+ .radio-group .radio-option input:checked ~ .radio-mark {
355
+ border-color: var(--form-switch-checked-bg, #3182ce);
356
+ }
357
+ .radio-group .radio-option .radio-mark::after {
358
+ content: "";
359
+ position: absolute;
360
+ display: none;
361
+ border-radius: var(--radius-full);
362
+ background-color: var(--form-switch-checked-bg, #3182ce);
363
+ }
364
+ .radio-group .radio-option input:checked ~ .radio-mark::after {
365
+ display: block;
366
+ }
367
+ .radio-group .radio-option input:disabled ~ .radio-mark {
368
+ opacity: 0.5;
369
+ cursor: not-allowed;
370
+ }
371
+ .radio-group .radio-option .text {
372
+ margin-left: 0.5rem;
373
+ }
374
+ .radio-group {
375
+ /* Radio Sizes */
376
+ }
377
+ .radio-group.xl .radio-mark {
378
+ width: 2rem;
379
+ height: 2rem;
380
+ }
381
+ .radio-group.xl .radio-mark::after {
382
+ top: 25%;
383
+ left: 25%;
384
+ width: 50%;
385
+ height: 50%;
386
+ }
387
+ .radio-group.xl .text {
388
+ font-size: 1.5rem;
389
+ margin-left: 1rem;
390
+ }
391
+ .radio-group.lg .radio-mark {
392
+ width: 1.5rem;
393
+ height: 1.5rem;
394
+ }
395
+ .radio-group.lg .radio-mark::after {
396
+ top: 25%;
397
+ left: 25%;
398
+ width: 50%;
399
+ height: 50%;
400
+ }
401
+ .radio-group.lg .text {
402
+ font-size: 1.2rem;
403
+ margin-left: 0.8rem;
404
+ }
405
+ .radio-group.md .radio-mark, .radio-group.full .radio-mark {
406
+ width: 1.25rem;
407
+ height: 1.25rem;
408
+ }
409
+ .radio-group.md .radio-mark::after, .radio-group.full .radio-mark::after {
410
+ top: 25%;
411
+ left: 25%;
412
+ width: 50%;
413
+ height: 50%;
414
+ }
415
+ .radio-group.md .text, .radio-group.full .text {
416
+ font-size: 1rem;
417
+ }
418
+ .radio-group.sm .radio-mark {
419
+ width: 1rem;
420
+ height: 1rem;
421
+ }
422
+ .radio-group.sm .radio-mark::after {
423
+ top: 25%;
424
+ left: 25%;
425
+ width: 50%;
426
+ height: 50%;
427
+ }
428
+ .radio-group.sm .text {
429
+ font-size: 0.8rem;
430
+ }</style>
@@ -1,5 +1,6 @@
1
1
  import type { FormFieldSizeOptions } from '../../index.js';
2
2
  import type { FormFieldFeedback } from '../form-field/form-field.svelte';
3
+ type BoolBoxVariant = 'dropdown' | 'switch' | 'checkbox' | 'radio';
3
4
  type $$ComponentProps = {
4
5
  value?: boolean;
5
6
  options?: [yes: string, no: string];
@@ -10,6 +11,7 @@ type $$ComponentProps = {
10
11
  feedback?: FormFieldFeedback;
11
12
  disabled?: boolean;
12
13
  required?: boolean;
14
+ variant?: BoolBoxVariant;
13
15
  };
14
16
  declare const BoolBox: import("svelte").Component<$$ComponentProps, {}, "value">;
15
17
  type BoolBox = ReturnType<typeof BoolBox>;
@@ -0,0 +1,2 @@
1
+ export { default as BoolBox } from './bool-box.svelte';
2
+ export { default } from './bool-box.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as BoolBox } from './bool-box.svelte';
2
+ export { default } from './bool-box.svelte';
@@ -9,6 +9,7 @@
9
9
  } from '../../helpers/date.js';
10
10
  import { uniqueId } from '../../helpers/unique-id.js';
11
11
  import FormField, { type FormFieldFeedback } from '../form-field/form-field.svelte';
12
+ import FormInputWrapper from '../form-input-wrapper';
12
13
  import type { DateUnit, FormFieldSizeOptions } from '../../index.js';
13
14
  import Button from '../button/button.svelte';
14
15
 
@@ -22,14 +23,19 @@
22
23
  size = 'full' as FormFieldSizeOptions,
23
24
  placeholder = '',
24
25
  nullable = false,
25
- enabled = $bindable(true),
26
+ disabled = false,
27
+ readonly = false,
26
28
  type = 'date' as 'date' | 'datetime-local',
27
29
  required = false,
28
30
  steps = [] as DateIncrementStep[],
29
31
  onChange = undefined,
30
32
  onCheckChanged = undefined,
33
+ onInput = undefined,
34
+ onFocus = undefined,
35
+ onBlur = undefined,
31
36
  label = undefined,
32
37
  helperText = undefined,
38
+ nullText = '-- / -- / ----',
33
39
  feedback = undefined
34
40
  }: {
35
41
  value?: string | undefined | null;
@@ -37,17 +43,31 @@
37
43
  size?: FormFieldSizeOptions;
38
44
  placeholder?: string;
39
45
  nullable?: boolean;
40
- enabled?: boolean;
46
+ disabled?: boolean;
47
+ readonly?: boolean;
41
48
  type?: 'date' | 'datetime-local';
42
49
  required?: boolean;
43
50
  steps?: DateIncrementStep[];
44
51
  onChange?: ((value: string | null) => void) | undefined;
45
- onCheckChanged?: ((enabled: boolean) => void) | undefined;
52
+ onCheckChanged?: ((isChecked: boolean) => void) | undefined;
53
+ onInput?: ((value: string | null) => void) | undefined;
54
+ onFocus?: ((e: FocusEvent) => void) | undefined;
55
+ onBlur?: ((e: FocusEvent) => void) | undefined;
46
56
  label?: string;
47
57
  helperText?: string;
58
+ nullText?: string;
48
59
  feedback?: FormFieldFeedback;
49
60
  } = $props();
50
61
 
62
+ // Track whether the nullable checkbox is checked (i.e., whether field has a value)
63
+ let isChecked = $state(untrack(() => !!value));
64
+
65
+ // Remember the last non-null value so we can restore it when re-checking
66
+ let lastValue = $state<string | undefined>(undefined);
67
+
68
+ // Derive the actual disabled state: disabled prop OR (nullable and unchecked)
69
+ let inputDisabled = $derived(disabled || (nullable && !isChecked));
70
+
51
71
  const getDefaultValue = () => {
52
72
  const _defaultValue = defaultValue || value || currentDateTime();
53
73
  if (type === 'date') {
@@ -58,10 +78,19 @@
58
78
 
59
79
  const checkChanged = () => {
60
80
  if (nullable) {
61
- value = enabled ? getDefaultValue() : '';
81
+ if (isChecked) {
82
+ // Restore last value if available, otherwise use default
83
+ value = lastValue || getDefaultValue();
84
+ } else {
85
+ // Store current value before clearing
86
+ if (value) {
87
+ lastValue = value;
88
+ }
89
+ value = '';
90
+ }
62
91
  }
63
- onCheckChanged?.(enabled);
64
- onInput();
92
+ onCheckChanged?.(isChecked);
93
+ handleInput();
65
94
  };
66
95
 
67
96
  const incrementValue = (step: DateIncrementStep) => {
@@ -72,32 +101,55 @@
72
101
  }
73
102
  };
74
103
 
75
- const onInput = () => {
76
- onChange?.(enabled ? value : null);
104
+ const handleInput = () => {
105
+ const currentValue = !nullable || isChecked ? value : null;
106
+ // Remember the value if it's not empty
107
+ if (isChecked && value) {
108
+ lastValue = value;
109
+ }
110
+ onChange?.(currentValue);
111
+ onInput?.(currentValue);
77
112
  };
78
113
 
79
114
  $effect(() => {
80
115
  if (!value) {
81
- // Use untrack to prevent writes to enabled/value from triggering this effect again
116
+ // Use untrack to prevent writes to isChecked/value from triggering this effect again
82
117
  untrack(() => {
83
- if (nullable) enabled = false;
118
+ if (nullable) isChecked = false;
84
119
  else value = getDefaultValue();
85
120
  });
121
+ } else {
122
+ // Initialize lastValue if we have an initial value
123
+ if (!lastValue) {
124
+ lastValue = value;
125
+ }
86
126
  }
87
127
  });
88
- let disabled = $derived(!enabled);
128
+
129
+ let showInput = $derived(!nullable || isChecked);
89
130
  </script>
90
131
 
91
132
  <FormField {size} {label} {id} {required} {disabled} {helperText} {feedback}>
92
- <div class:nullable class:disabled>
93
- <span class="input">
94
- <input {...{ type }} {id} {placeholder} {disabled} bind:value {required} oninput={onInput} />
95
- </span>
96
- {#if nullable}
97
- <span class="toggle">
98
- <input type="checkbox" bind:checked={enabled} onchange={checkChanged} />
99
- </span>
100
- {/if}
133
+ <div class="date-box-wrapper">
134
+ <FormInputWrapper
135
+ {disabled}
136
+ {nullable}
137
+ nullText={nullText || '-- / -- / ----'}
138
+ onCheckChanged={checkChanged}
139
+ >
140
+ <input
141
+ {...{ type }}
142
+ {id}
143
+ {placeholder}
144
+ disabled={inputDisabled}
145
+ {readonly}
146
+ bind:value
147
+ {required}
148
+ oninput={handleInput}
149
+ onfocus={onFocus}
150
+ onblur={onBlur}
151
+ />
152
+ </FormInputWrapper>
101
153
  {#if steps.length > 0}
102
154
  <span class="steps">
103
155
  {#each steps as step}
@@ -113,46 +165,45 @@
113
165
  </div>
114
166
  </FormField>
115
167
 
116
- <style>input {
117
- width: 100%;
118
- padding: 0.5rem 1rem;
119
- border-radius: 0.25rem;
120
- border: 1px solid var(--form-input-border, black);
121
- background-color: var(--form-input-bg, white);
122
- color: var(--form-input-fg, black);
123
- font-size: 0.875rem;
124
- font-weight: 500;
125
- line-height: 1.25rem;
126
- transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out, fill 0.2s ease-in-out, stroke 0.2s ease-in-out;
127
- user-select: none;
128
- white-space: nowrap;
129
- }
130
- input::placeholder {
131
- color: var(--form-input-placeholder, #a0aec0);
132
- }
133
-
134
- div {
168
+ <style>.date-box-wrapper {
135
169
  display: flex;
136
170
  position: relative;
137
171
  gap: 0.5rem;
138
172
  }
139
- div .input {
173
+ .date-box-wrapper :global(.input) {
140
174
  flex-grow: 1;
141
175
  }
142
- div .steps {
143
- display: flex;
144
- gap: 0.25rem;
176
+ .date-box-wrapper input {
177
+ background-color: transparent;
178
+ border: none;
179
+ color: inherit;
180
+ font-size: inherit;
181
+ font-weight: inherit;
182
+ line-height: 2rem;
183
+ height: 2rem;
184
+ width: 100%;
185
+ flex-grow: 1;
186
+ padding: 0 var(--spacing-base);
187
+ margin: 0;
188
+ box-sizing: border-box;
145
189
  }
146
- div.nullable input {
147
- padding-left: 2.5rem;
190
+ .date-box-wrapper input:focus {
191
+ outline: none;
148
192
  }
149
- div.nullable .toggle {
150
- position: absolute;
151
- top: 0.7rem;
152
- left: 0.4rem;
193
+ .date-box-wrapper input:focus-visible {
194
+ outline: 2px solid var(--focus-ring, #007bff);
195
+ outline-offset: 2px;
153
196
  }
154
- div.disabled input {
155
- background-color: #f5f5f5;
156
- border-color: #e0e0e0;
157
- color: #a0a0a0;
197
+ .date-box-wrapper input::placeholder {
198
+ color: var(--form-input-placeholder, #a0aec0);
199
+ }
200
+ .date-box-wrapper input:disabled {
201
+ cursor: not-allowed;
202
+ }
203
+ .date-box-wrapper input:read-only {
204
+ cursor: default;
205
+ }
206
+ .date-box-wrapper .steps {
207
+ display: flex;
208
+ gap: 0.25rem;
158
209
  }</style>