@rokkit/forms 1.0.0-next.125 → 1.0.0-next.127

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 (89) hide show
  1. package/README.md +251 -0
  2. package/dist/src/display/index.d.ts +5 -0
  3. package/dist/src/index.d.ts +9 -0
  4. package/dist/src/input/index.d.ts +3 -0
  5. package/dist/src/lib/builder.svelte.d.ts +114 -4
  6. package/dist/src/lib/lookup.svelte.d.ts +87 -0
  7. package/dist/src/lib/renderers.d.ts +23 -0
  8. package/package.json +6 -4
  9. package/src/FieldLayout.svelte +4 -11
  10. package/src/FormRenderer.svelte +202 -61
  11. package/src/InfoField.svelte +26 -0
  12. package/src/Input.svelte +17 -61
  13. package/src/InputField.svelte +15 -11
  14. package/src/ValidationReport.svelte +52 -0
  15. package/src/display/DisplayCardGrid.svelte +68 -0
  16. package/src/display/DisplayList.svelte +31 -0
  17. package/src/display/DisplaySection.svelte +20 -0
  18. package/src/display/DisplayTable.svelte +68 -0
  19. package/src/display/DisplayValue.svelte +44 -0
  20. package/src/display/index.js +5 -0
  21. package/src/index.js +14 -0
  22. package/src/input/ArrayEditor.svelte +108 -0
  23. package/src/input/InputCheckbox.svelte +2 -3
  24. package/src/input/InputColor.svelte +6 -1
  25. package/src/input/InputDate.svelte +6 -1
  26. package/src/input/InputDateTime.svelte +6 -1
  27. package/src/input/InputEmail.svelte +6 -1
  28. package/src/input/InputFile.svelte +6 -2
  29. package/src/input/InputMonth.svelte +6 -1
  30. package/src/input/InputNumber.svelte +6 -1
  31. package/src/input/InputPassword.svelte +6 -1
  32. package/src/input/InputRange.svelte +6 -1
  33. package/src/input/InputSelect.svelte +31 -53
  34. package/src/input/InputSwitch.svelte +4 -15
  35. package/src/input/InputTel.svelte +6 -1
  36. package/src/input/InputText.svelte +6 -1
  37. package/src/input/InputTextArea.svelte +6 -1
  38. package/src/input/InputTime.svelte +6 -1
  39. package/src/input/InputToggle.svelte +28 -0
  40. package/src/input/InputUrl.svelte +6 -1
  41. package/src/input/InputWeek.svelte +6 -1
  42. package/src/input/index.js +3 -1
  43. package/src/lib/Input.svelte +3 -3
  44. package/src/lib/builder.svelte.js +425 -30
  45. package/src/lib/fields.js +2 -2
  46. package/src/lib/layout.js +2 -2
  47. package/src/lib/lookup.svelte.js +334 -0
  48. package/src/lib/renderers.js +83 -0
  49. package/src/lib/schema.js +1 -1
  50. package/src/types.js +0 -9
  51. package/dist/src/forms-old/input/types.d.ts +0 -7
  52. package/dist/src/forms-old/lib/form.d.ts +0 -95
  53. package/dist/src/forms-old/lib/index.d.ts +0 -1
  54. package/dist/src/lib/deprecated/nested.d.ts +0 -48
  55. package/dist/src/lib/deprecated/nested.spec.d.ts +0 -1
  56. package/dist/src/lib/deprecated/validator.d.ts +0 -30
  57. package/dist/src/lib/deprecated/validator.spec.d.ts +0 -1
  58. package/src/DataEditor.svelte +0 -30
  59. package/src/ListEditor.svelte +0 -44
  60. package/src/NestedEditor.svelte +0 -85
  61. package/src/forms-old/CheckBox.svelte +0 -56
  62. package/src/forms-old/DataEditor.svelte +0 -30
  63. package/src/forms-old/FieldLayout.svelte +0 -48
  64. package/src/forms-old/Form.svelte +0 -17
  65. package/src/forms-old/Icon.svelte +0 -76
  66. package/src/forms-old/Item.svelte +0 -25
  67. package/src/forms-old/ListEditor.svelte +0 -44
  68. package/src/forms-old/Tabs.svelte +0 -57
  69. package/src/forms-old/Wrapper.svelte +0 -12
  70. package/src/forms-old/input/Input.svelte +0 -17
  71. package/src/forms-old/input/InputField.svelte +0 -70
  72. package/src/forms-old/input/InputSelect.svelte +0 -23
  73. package/src/forms-old/input/InputSwitch.svelte +0 -19
  74. package/src/forms-old/input/types.js +0 -29
  75. package/src/forms-old/lib/form.js +0 -72
  76. package/src/forms-old/lib/index.js +0 -12
  77. package/src/forms-old/mocks/CustomField.svelte +0 -7
  78. package/src/forms-old/mocks/CustomWrapper.svelte +0 -8
  79. package/src/forms-old/mocks/Register.svelte +0 -25
  80. package/src/inp/Input.svelte +0 -17
  81. package/src/inp/InputField.svelte +0 -69
  82. package/src/inp/InputSelect.svelte +0 -23
  83. package/src/inp/InputSwitch.svelte +0 -19
  84. package/src/lib/deprecated/Form.svelte +0 -17
  85. package/src/lib/deprecated/FormRenderer.svelte +0 -121
  86. package/src/lib/deprecated/nested.js +0 -192
  87. package/src/lib/deprecated/nested.spec.js +0 -512
  88. package/src/lib/deprecated/validator.js +0 -137
  89. package/src/lib/deprecated/validator.spec.js +0 -348
@@ -0,0 +1,68 @@
1
+ <script>
2
+ /**
3
+ * Wraps @rokkit/ui Table for display-only rendering from layout schema.
4
+ * Maps display columns (key/label/format) to TableColumn format.
5
+ */
6
+ import { Table } from '@rokkit/ui'
7
+
8
+ let {
9
+ data = [],
10
+ columns = [],
11
+ select,
12
+ title,
13
+ onselect,
14
+ class: className = ''
15
+ } = $props()
16
+
17
+ // Map display columns → Table columns with formatters
18
+ const tableColumns = $derived(
19
+ columns.map((col) => ({
20
+ name: col.key,
21
+ label: col.label ?? col.key,
22
+ sortable: col.sortable ?? true,
23
+ width: col.width,
24
+ align: col.align,
25
+ formatter: col.format ? createFormatter(col.format) : undefined
26
+ }))
27
+ )
28
+
29
+ /**
30
+ * Create a cell formatter function for a given display format.
31
+ * @param {string} format
32
+ * @returns {(value: unknown) => string}
33
+ */
34
+ function createFormatter(format) {
35
+ return (value) => {
36
+ if (value === null || value === undefined) return '—'
37
+ switch (format) {
38
+ case 'currency':
39
+ return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
40
+ /** @type {number} */ (value)
41
+ )
42
+ case 'datetime':
43
+ return new Date(/** @type {string|number} */ (value)).toLocaleString()
44
+ case 'duration': {
45
+ const minutes = /** @type {number} */ (value)
46
+ const h = Math.floor(minutes / 60)
47
+ const m = minutes % 60
48
+ if (h > 0 && m > 0) return `${h}h ${m}m`
49
+ if (h > 0) return `${h}h`
50
+ return `${m}m`
51
+ }
52
+ case 'number':
53
+ return new Intl.NumberFormat().format(/** @type {number} */ (value))
54
+ case 'boolean':
55
+ return value ? '✓' : '✗'
56
+ default:
57
+ return String(value)
58
+ }
59
+ }
60
+ }
61
+ </script>
62
+
63
+ <div data-display-table data-selectable={select || undefined} class={className}>
64
+ {#if title}
65
+ <div data-display-title>{title}</div>
66
+ {/if}
67
+ <Table {data} columns={tableColumns} {onselect} caption={title} />
68
+ </div>
@@ -0,0 +1,44 @@
1
+ <script>
2
+ /**
3
+ * Format-aware value display component.
4
+ * Renders a value with formatting based on the `format` hint.
5
+ */
6
+
7
+ let { value, format = 'text' } = $props()
8
+
9
+ /**
10
+ * Format a duration value (minutes) into human-readable string.
11
+ * @param {number} minutes
12
+ * @returns {string}
13
+ */
14
+ function formatDuration(minutes) {
15
+ if (typeof minutes !== 'number') return String(minutes)
16
+ const h = Math.floor(minutes / 60)
17
+ const m = minutes % 60
18
+ if (h > 0 && m > 0) return `${h}h ${m}m`
19
+ if (h > 0) return `${h}h`
20
+ return `${m}m`
21
+ }
22
+
23
+ const formatted = $derived.by(() => {
24
+ if (value === null || value === undefined) return '—'
25
+ switch (format) {
26
+ case 'currency':
27
+ return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value)
28
+ case 'datetime':
29
+ return new Date(value).toLocaleString()
30
+ case 'duration':
31
+ return formatDuration(value)
32
+ case 'number':
33
+ return new Intl.NumberFormat().format(value)
34
+ case 'boolean':
35
+ return value ? '✓' : '✗'
36
+ case 'badge':
37
+ return String(value)
38
+ default:
39
+ return String(value)
40
+ }
41
+ })
42
+ </script>
43
+
44
+ <span data-display-value data-format={format}>{formatted}</span>
@@ -0,0 +1,5 @@
1
+ export { default as DisplayValue } from './DisplayValue.svelte'
2
+ export { default as DisplaySection } from './DisplaySection.svelte'
3
+ export { default as DisplayTable } from './DisplayTable.svelte'
4
+ export { default as DisplayCardGrid } from './DisplayCardGrid.svelte'
5
+ export { default as DisplayList } from './DisplayList.svelte'
package/src/index.js CHANGED
@@ -1,7 +1,21 @@
1
1
  export { FormBuilder } from './lib/builder.svelte.js'
2
+ export { createLookup, createLookupManager, clearLookupCache } from './lib/lookup.svelte.js'
3
+ export { validateField, validateAll, createMessage, patterns } from './lib/validation.js'
4
+ export { defaultRenderers, resolveRenderer } from './lib/renderers.js'
5
+
6
+ // Schema and layout utilities
7
+ export { getSchemaWithLayout, findAttributeByPath } from './lib/fields.js'
8
+ export { deriveSchemaFromValue } from './lib/schema.js'
9
+ export { deriveLayoutFromValue } from './lib/layout.js'
10
+
2
11
  // Enhanced Input Components
3
12
  export { default as FormRenderer } from './FormRenderer.svelte'
4
13
  export { default as Input } from './Input.svelte'
5
14
  export { default as InputField } from './InputField.svelte'
15
+ export { default as InfoField } from './InfoField.svelte'
16
+ export { default as ValidationReport } from './ValidationReport.svelte'
17
+
18
+ // Display Components
19
+ export * from './display'
6
20
 
7
21
  export * from './input'
@@ -0,0 +1,108 @@
1
+ <script>
2
+ import { defaultRenderers, resolveRenderer } from '../lib/renderers.js'
3
+ import FormRenderer from '../FormRenderer.svelte'
4
+
5
+ /**
6
+ * @typedef {Object} ArrayEditorProps
7
+ * @property {Array} [value] - The array value (bindable)
8
+ * @property {Function} [onchange] - Called with new array on any change
9
+ * @property {Object} [items] - JSON Schema for each array item (from schema.items)
10
+ * @property {boolean} [disabled]
11
+ * @property {boolean} [readonly]
12
+ */
13
+
14
+ /** @type {ArrayEditorProps & { [key: string]: any }} */
15
+ let {
16
+ value = $bindable([]),
17
+ onchange,
18
+ items,
19
+ disabled = false,
20
+ readonly = false,
21
+ ..._rest
22
+ } = $props()
23
+
24
+ // Normalize: treat undefined/null as empty array
25
+ const safeValue = $derived(Array.isArray(value) ? value : [])
26
+
27
+ // Item schema — default to string if not provided
28
+ const itemSchema = $derived(items ?? { type: 'string' })
29
+
30
+ // Resolve the primitive renderer once (reused for all items)
31
+ const PrimitiveComponent = $derived(
32
+ itemSchema.type !== 'object'
33
+ ? resolveRenderer({ type: itemSchema.type }, defaultRenderers)
34
+ : null
35
+ )
36
+
37
+ function typeDefault(type) {
38
+ return { string: '', number: 0, integer: 0, boolean: false, array: [], object: {} }[type] ?? null
39
+ }
40
+
41
+ function createDefaultItem(schema) {
42
+ if (schema.type === 'object') {
43
+ return Object.fromEntries(
44
+ Object.entries(schema.properties ?? {}).map(([k, s]) => [k, s.default ?? typeDefault(s.type)])
45
+ )
46
+ }
47
+ return schema.default ?? typeDefault(schema.type)
48
+ }
49
+
50
+ function addItem() {
51
+ const newItem = createDefaultItem(itemSchema)
52
+ const newValue = [...safeValue, newItem]
53
+ value = newValue
54
+ onchange?.(newValue)
55
+ }
56
+
57
+ function removeItem(index) {
58
+ const newValue = safeValue.filter((_, i) => i !== index)
59
+ value = newValue
60
+ onchange?.(newValue)
61
+ }
62
+
63
+ function updateItem(index, newItemValue) {
64
+ const newValue = safeValue.map((item, i) => (i === index ? newItemValue : item))
65
+ value = newValue
66
+ onchange?.(newValue)
67
+ }
68
+ </script>
69
+
70
+ <div
71
+ data-array-editor
72
+ data-array-editor-empty={safeValue.length === 0 || undefined}
73
+ data-array-editor-disabled={disabled || undefined}
74
+ >
75
+ <div data-array-editor-items>
76
+ {#each safeValue as item, index (index)}
77
+ <div data-array-editor-item>
78
+ <div data-array-editor-item-content>
79
+ {#if itemSchema.type === 'object'}
80
+ <FormRenderer
81
+ data={item}
82
+ schema={itemSchema}
83
+ onupdate={(newData) => updateItem(index, newData)}
84
+ />
85
+ {:else}
86
+ <PrimitiveComponent
87
+ value={item}
88
+ onchange={(newVal) => updateItem(index, newVal)}
89
+ {disabled}
90
+ {readonly}
91
+ />
92
+ {/if}
93
+ </div>
94
+ {#if !readonly}
95
+ <button
96
+ type="button"
97
+ data-array-editor-remove
98
+ {disabled}
99
+ onclick={() => removeItem(index)}
100
+ >Remove</button>
101
+ {/if}
102
+ </div>
103
+ {/each}
104
+ </div>
105
+ {#if !readonly}
106
+ <button type="button" data-array-editor-add {disabled} onclick={addItem}>Add</button>
107
+ {/if}
108
+ </div>
@@ -1,5 +1,4 @@
1
1
  <script>
2
- import { Icon } from '@rokkit/ui'
3
2
  import { defaultStateIcons } from '@rokkit/core'
4
3
  import { isNil } from 'ramda'
5
4
 
@@ -27,7 +26,7 @@
27
26
  /** @type {InputCheckboxProps & { [key: string]: any }} */
28
27
  let {
29
28
  value = $bindable(),
30
- variant = 'default',
29
+ variant = 'custom',
31
30
  icons,
32
31
  onchange,
33
32
  onfocus,
@@ -69,6 +68,6 @@
69
68
  {...rest}
70
69
  />
71
70
  {#if variant !== 'default'}
72
- <Icon name={icon} data-checkbox-icon role="button" onclick={toggle} />
71
+ <span class={icon} data-checkbox-icon role="button" tabindex="0" onclick={toggle} onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && toggle()} aria-hidden="true"></span>
73
72
  {/if}
74
73
  </div>
@@ -25,6 +25,11 @@
25
25
  autocomplete,
26
26
  ...rest
27
27
  } = $props()
28
+
29
+ function handleChange(event) {
30
+ value = event.target.value
31
+ onchange?.(value)
32
+ }
28
33
  </script>
29
34
 
30
35
  <input
@@ -35,7 +40,7 @@
35
40
  {name}
36
41
  {id}
37
42
  {autocomplete}
38
- {onchange}
43
+ onchange={handleChange}
39
44
  {onfocus}
40
45
  {onblur}
41
46
  {...rest}
@@ -33,6 +33,11 @@
33
33
  autocomplete,
34
34
  ...rest
35
35
  } = $props()
36
+
37
+ function handleChange(event) {
38
+ value = event.target.value
39
+ onchange?.(value)
40
+ }
36
41
  </script>
37
42
 
38
43
  <input
@@ -47,7 +52,7 @@
47
52
  {name}
48
53
  {id}
49
54
  {autocomplete}
50
- {onchange}
55
+ onchange={handleChange}
51
56
  {onfocus}
52
57
  {onblur}
53
58
  {...rest}
@@ -33,6 +33,11 @@
33
33
  autocomplete,
34
34
  ...rest
35
35
  } = $props()
36
+
37
+ function handleChange(event) {
38
+ value = event.target.value
39
+ onchange?.(value)
40
+ }
36
41
  </script>
37
42
 
38
43
  <input
@@ -47,7 +52,7 @@
47
52
  {name}
48
53
  {id}
49
54
  {autocomplete}
50
- {onchange}
55
+ onchange={handleChange}
51
56
  {onfocus}
52
57
  {onblur}
53
58
  {...rest}
@@ -39,6 +39,11 @@
39
39
  multiple,
40
40
  ...rest
41
41
  } = $props()
42
+
43
+ function handleChange(event) {
44
+ value = event.target.value
45
+ onchange?.(value)
46
+ }
42
47
  </script>
43
48
 
44
49
  <input
@@ -56,7 +61,7 @@
56
61
  {pattern}
57
62
  {size}
58
63
  {multiple}
59
- {onchange}
64
+ onchange={handleChange}
60
65
  {onfocus}
61
66
  {onblur}
62
67
  {...rest}
@@ -27,10 +27,14 @@
27
27
  id,
28
28
  ...rest
29
29
  } = $props()
30
+
31
+ function handleChange(event) {
32
+ value = event.target.files
33
+ onchange?.(value)
34
+ }
30
35
  </script>
31
36
 
32
37
  <input
33
- bind:value
34
38
  type="file"
35
39
  {accept}
36
40
  {multiple}
@@ -38,7 +42,7 @@
38
42
  {disabled}
39
43
  {name}
40
44
  {id}
41
- {onchange}
45
+ onchange={handleChange}
42
46
  {onfocus}
43
47
  {onblur}
44
48
  {...rest}
@@ -33,6 +33,11 @@
33
33
  autocomplete,
34
34
  ...rest
35
35
  } = $props()
36
+
37
+ function handleChange(event) {
38
+ value = event.target.value
39
+ onchange?.(value)
40
+ }
36
41
  </script>
37
42
 
38
43
  <input
@@ -47,7 +52,7 @@
47
52
  {name}
48
53
  {id}
49
54
  {autocomplete}
50
- {onchange}
55
+ onchange={handleChange}
51
56
  {onfocus}
52
57
  {onblur}
53
58
  {...rest}
@@ -35,6 +35,11 @@
35
35
  autocomplete,
36
36
  ...rest
37
37
  } = $props()
38
+
39
+ function handleChange(event) {
40
+ value = event.target.valueAsNumber
41
+ onchange?.(value)
42
+ }
38
43
  </script>
39
44
 
40
45
  <input
@@ -50,7 +55,7 @@
50
55
  {name}
51
56
  {id}
52
57
  {autocomplete}
53
- {onchange}
58
+ onchange={handleChange}
54
59
  {onfocus}
55
60
  {onblur}
56
61
  {...rest}
@@ -37,6 +37,11 @@
37
37
  size,
38
38
  ...rest
39
39
  } = $props()
40
+
41
+ function handleChange(event) {
42
+ value = event.target.value
43
+ onchange?.(value)
44
+ }
40
45
  </script>
41
46
 
42
47
  <input
@@ -53,7 +58,7 @@
53
58
  {minlength}
54
59
  {pattern}
55
60
  {size}
56
- {onchange}
61
+ onchange={handleChange}
57
62
  {onfocus}
58
63
  {onblur}
59
64
  {...rest}
@@ -31,6 +31,11 @@
31
31
  onblur,
32
32
  ...rest
33
33
  } = $props()
34
+
35
+ function handleChange(event) {
36
+ value = event.target.valueAsNumber
37
+ onchange?.(value)
38
+ }
34
39
  </script>
35
40
 
36
41
  <input
@@ -44,7 +49,7 @@
44
49
  {disabled}
45
50
  {name}
46
51
  {id}
47
- {onchange}
52
+ onchange={handleChange}
48
53
  {onfocus}
49
54
  {onblur}
50
55
  {...rest}
@@ -1,71 +1,49 @@
1
1
  <script>
2
- import { defaultStateIcons } from '@rokkit/core'
3
- import { Proxy } from '@rokkit/states'
4
- import { equals } from 'ramda'
2
+ import { Select } from '@rokkit/ui'
5
3
 
6
4
  /**
7
5
  * @typedef {Object} InputSelectProps
8
- * @property {any} value
9
- * @property {Object} fields
10
- * @property {Array<Object>} options
11
- * @property {Function} onchange
12
- * @property {Function} onfocus
13
- * @property {Function} onblur
6
+ * @property {any} value - Selected value (bindable)
7
+ * @property {Object} [fields] - Field mapping for options
8
+ * @property {Array<Object|string>} [options] - Static options array (strings or objects)
9
+ * @property {string} [placeholder] - Placeholder text
10
+ * @property {boolean} [disabled] - Whether the select is disabled
11
+ * @property {string} [size] - Size variant
12
+ * @property {Function} [onchange] - Change callback
14
13
  */
15
14
 
16
15
  /** @type {InputSelectProps & { [key: string]: any }} */
17
16
  let {
18
- class: classes = '',
19
17
  value = $bindable(),
20
18
  fields,
21
19
  options = [],
22
- icons = defaultStateIcons['selector'],
23
- placeholder = null,
20
+ placeholder,
21
+ disabled = false,
22
+ size,
24
23
  onchange,
25
- onfocus,
26
- onblur,
27
- ...rest
24
+ ..._rest
28
25
  } = $props()
29
26
 
30
- let focused = $state(false)
31
- let icon = $derived(focused ? icons['opened'] : icons['closed'])
32
- let indexValue = $state(options.findIndex((item) => equals(item, value)))
33
- let proxiedOptions = $derived(options.map((option) => new Proxy(option, fields)))
27
+ // Check if options include an empty string (used as "none" option)
28
+ const hasEmptyOption = $derived(options.some((opt) => opt === '' || (typeof opt === 'object' && opt?.value === '')))
34
29
 
35
- function handleChange(event) {
36
- value = options[indexValue]
37
- onchange?.(options[indexValue])
38
- }
30
+ // Filter out empty strings — Select + ItemProxy handles string options natively
31
+ const filteredOptions = $derived(
32
+ hasEmptyOption
33
+ ? options.filter((opt) => opt !== '' && !(typeof opt === 'object' && opt?.value === ''))
34
+ : options
35
+ )
39
36
 
40
- function handleFocus(event) {
41
- focused = true
42
- onfocus?.(event)
43
- }
44
-
45
- function handleBlur(event) {
46
- focused = false
47
- onblur?.(event)
48
- }
37
+ // Use placeholder for empty option, or provide a default clear label
38
+ const effectivePlaceholder = $derived(hasEmptyOption ? (placeholder || 'None') : placeholder)
49
39
  </script>
50
40
 
51
- <div data-input-select class={classes}>
52
- <select
53
- bind:value={indexValue}
54
- {...rest}
55
- onchange={handleChange}
56
- onfocus={handleFocus}
57
- onblur={handleBlur}
58
- >
59
- {#if placeholder}
60
- <option value="" disabled selected>{placeholder}</option>
61
- {/if}
62
- {#each proxiedOptions as option, index (index)}
63
- <option value={index} aria-current={equals(option.value, value)}>
64
- {option.get('text')}
65
- </option>
66
- {/each}
67
- </select>
68
- <span>
69
- <i class={icon}></i>
70
- </span>
71
- </div>
41
+ <Select
42
+ options={filteredOptions}
43
+ {fields}
44
+ bind:value
45
+ placeholder={effectivePlaceholder}
46
+ {disabled}
47
+ {size}
48
+ {onchange}
49
+ />
@@ -1,29 +1,18 @@
1
1
  <script>
2
- import { getValue, defaultFields } from '@rokkit/core'
3
- import Switch from '@rokkit/bits-ui'
2
+ import { Switch } from '@rokkit/ui'
4
3
 
5
4
  /**
6
5
  * @typedef {Object} InputSwitchProps
7
6
  * @property {string} name
8
7
  * @property {any} value
9
- * @property {Array<Object>} options
8
+ * @property {[any, any]} options
10
9
  * @property {Object} fields
11
10
  * @property {Function} onchange
12
11
  */
13
12
 
14
13
  /** @type {InputSwitchProps & { [key: string]: any }} */
15
- let { name, value, options, fields, onchange, ...restProps } = $props()
16
- // let selected = $state(null)
17
- let configFields = $derived({ ...defaultFields, ...fields })
18
- function handle(data) {
19
- value = getValue(data.value, configFields)
20
- onchange?.(data.value)
21
- }
22
- let selected = $derived(options.find((option) => getValue(option, configFields) === value))
23
- // $effect(() => {
24
- // selected = options.find((option) => getValue(option, configFields) === value)
25
- // })
14
+ let { name, value = $bindable(), options, fields, onchange, ...restProps } = $props()
26
15
  </script>
27
16
 
28
17
  <input {name} type="hidden" bind:value />
29
- <Switch bind:value={selected} {options} {fields} {...restProps} onchange={handle} />
18
+ <Switch {options} {fields} bind:value {onchange} {...restProps} />
@@ -37,6 +37,11 @@
37
37
  size,
38
38
  ...rest
39
39
  } = $props()
40
+
41
+ function handleChange(event) {
42
+ value = event.target.value
43
+ onchange?.(value)
44
+ }
40
45
  </script>
41
46
 
42
47
  <input
@@ -53,7 +58,7 @@
53
58
  {minlength}
54
59
  {pattern}
55
60
  {size}
56
- {onchange}
61
+ onchange={handleChange}
57
62
  {onfocus}
58
63
  {onblur}
59
64
  {...rest}
@@ -37,6 +37,11 @@
37
37
  size,
38
38
  ...rest
39
39
  } = $props()
40
+
41
+ function handleChange(event) {
42
+ value = event.target.value
43
+ onchange?.(value)
44
+ }
40
45
  </script>
41
46
 
42
47
  <input
@@ -53,7 +58,7 @@
53
58
  {minlength}
54
59
  {pattern}
55
60
  {size}
56
- {onchange}
61
+ onchange={handleChange}
57
62
  {onfocus}
58
63
  {onblur}
59
64
  {...rest}
@@ -37,6 +37,11 @@
37
37
  wrap,
38
38
  ...rest
39
39
  } = $props()
40
+
41
+ function handleChange(event) {
42
+ value = event.target.value
43
+ onchange?.(value)
44
+ }
40
45
  </script>
41
46
 
42
47
  <textarea
@@ -52,7 +57,7 @@
52
57
  {maxlength}
53
58
  {minlength}
54
59
  {wrap}
55
- {onchange}
60
+ onchange={handleChange}
56
61
  {onfocus}
57
62
  {onblur}
58
63
  {...rest}