@rokkit/forms 1.0.0-next.124 → 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.
- package/README.md +251 -0
- package/dist/src/display/index.d.ts +5 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/input/index.d.ts +3 -0
- package/dist/src/lib/builder.svelte.d.ts +114 -4
- package/dist/src/lib/lookup.svelte.d.ts +87 -0
- package/dist/src/lib/renderers.d.ts +23 -0
- package/package.json +6 -4
- package/src/FieldLayout.svelte +4 -11
- package/src/FormRenderer.svelte +202 -61
- package/src/InfoField.svelte +26 -0
- package/src/Input.svelte +17 -61
- package/src/InputField.svelte +15 -11
- package/src/ValidationReport.svelte +52 -0
- package/src/display/DisplayCardGrid.svelte +68 -0
- package/src/display/DisplayList.svelte +31 -0
- package/src/display/DisplaySection.svelte +20 -0
- package/src/display/DisplayTable.svelte +68 -0
- package/src/display/DisplayValue.svelte +44 -0
- package/src/display/index.js +5 -0
- package/src/index.js +14 -0
- package/src/input/ArrayEditor.svelte +108 -0
- package/src/input/InputCheckbox.svelte +2 -3
- package/src/input/InputColor.svelte +6 -1
- package/src/input/InputDate.svelte +6 -1
- package/src/input/InputDateTime.svelte +6 -1
- package/src/input/InputEmail.svelte +6 -1
- package/src/input/InputFile.svelte +6 -2
- package/src/input/InputMonth.svelte +6 -1
- package/src/input/InputNumber.svelte +6 -1
- package/src/input/InputPassword.svelte +6 -1
- package/src/input/InputRange.svelte +6 -1
- package/src/input/InputSelect.svelte +31 -53
- package/src/input/InputSwitch.svelte +4 -15
- package/src/input/InputTel.svelte +6 -1
- package/src/input/InputText.svelte +6 -1
- package/src/input/InputTextArea.svelte +6 -1
- package/src/input/InputTime.svelte +6 -1
- package/src/input/InputToggle.svelte +28 -0
- package/src/input/InputUrl.svelte +6 -1
- package/src/input/InputWeek.svelte +6 -1
- package/src/input/index.js +3 -1
- package/src/lib/Input.svelte +3 -3
- package/src/lib/builder.svelte.js +425 -30
- package/src/lib/fields.js +2 -2
- package/src/lib/layout.js +2 -2
- package/src/lib/lookup.svelte.js +334 -0
- package/src/lib/renderers.js +83 -0
- package/src/lib/schema.js +1 -1
- package/src/types.js +0 -9
- package/dist/src/forms-old/input/types.d.ts +0 -7
- package/dist/src/forms-old/lib/form.d.ts +0 -95
- package/dist/src/forms-old/lib/index.d.ts +0 -1
- package/dist/src/lib/deprecated/nested.d.ts +0 -48
- package/dist/src/lib/deprecated/nested.spec.d.ts +0 -1
- package/dist/src/lib/deprecated/validator.d.ts +0 -30
- package/dist/src/lib/deprecated/validator.spec.d.ts +0 -1
- package/src/DataEditor.svelte +0 -30
- package/src/ListEditor.svelte +0 -44
- package/src/NestedEditor.svelte +0 -85
- package/src/forms-old/CheckBox.svelte +0 -56
- package/src/forms-old/DataEditor.svelte +0 -30
- package/src/forms-old/FieldLayout.svelte +0 -48
- package/src/forms-old/Form.svelte +0 -17
- package/src/forms-old/Icon.svelte +0 -76
- package/src/forms-old/Item.svelte +0 -25
- package/src/forms-old/ListEditor.svelte +0 -44
- package/src/forms-old/Tabs.svelte +0 -57
- package/src/forms-old/Wrapper.svelte +0 -12
- package/src/forms-old/input/Input.svelte +0 -17
- package/src/forms-old/input/InputField.svelte +0 -70
- package/src/forms-old/input/InputSelect.svelte +0 -23
- package/src/forms-old/input/InputSwitch.svelte +0 -19
- package/src/forms-old/input/types.js +0 -29
- package/src/forms-old/lib/form.js +0 -72
- package/src/forms-old/lib/index.js +0 -12
- package/src/forms-old/mocks/CustomField.svelte +0 -7
- package/src/forms-old/mocks/CustomWrapper.svelte +0 -8
- package/src/forms-old/mocks/Register.svelte +0 -25
- package/src/inp/Input.svelte +0 -17
- package/src/inp/InputField.svelte +0 -69
- package/src/inp/InputSelect.svelte +0 -23
- package/src/inp/InputSwitch.svelte +0 -19
- package/src/lib/deprecated/Form.svelte +0 -17
- package/src/lib/deprecated/FormRenderer.svelte +0 -121
- package/src/lib/deprecated/nested.js +0 -192
- package/src/lib/deprecated/nested.spec.js +0 -512
- package/src/lib/deprecated/validator.js +0 -137
- 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 = '
|
|
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
|
-
<
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
52
|
+
onchange={handleChange}
|
|
48
53
|
{onfocus}
|
|
49
54
|
{onblur}
|
|
50
55
|
{...rest}
|
|
@@ -1,71 +1,49 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import {
|
|
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}
|
|
9
|
-
* @property {Object}
|
|
10
|
-
* @property {Array<Object>} options
|
|
11
|
-
* @property {
|
|
12
|
-
* @property {
|
|
13
|
-
* @property {
|
|
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
|
-
|
|
23
|
-
|
|
20
|
+
placeholder,
|
|
21
|
+
disabled = false,
|
|
22
|
+
size,
|
|
24
23
|
onchange,
|
|
25
|
-
|
|
26
|
-
onblur,
|
|
27
|
-
...rest
|
|
24
|
+
..._rest
|
|
28
25
|
} = $props()
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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 {
|
|
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 {
|
|
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
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
60
|
+
onchange={handleChange}
|
|
56
61
|
{onfocus}
|
|
57
62
|
{onblur}
|
|
58
63
|
{...rest}
|