@rokkit/forms 1.6.0 → 1.8.0
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 +4 -2
- package/dist/lib/builder.svelte.d.ts +100 -248
- package/dist/lib/builder.svelte.js +182 -1047
- package/dist/lib/elements.d.ts +81 -0
- package/dist/lib/elements.js +196 -0
- package/dist/lib/schema.d.ts +13 -0
- package/dist/lib/schema.js +27 -0
- package/dist/lib/state/FormDefinition.svelte.d.ts +32 -0
- package/dist/lib/state/FormDefinition.svelte.js +83 -0
- package/dist/lib/state/FormLookups.svelte.d.ts +39 -0
- package/dist/lib/state/FormLookups.svelte.js +93 -0
- package/dist/lib/state/FormSteps.svelte.d.ts +32 -0
- package/dist/lib/state/FormSteps.svelte.js +80 -0
- package/dist/lib/state/FormValidation.svelte.d.ts +52 -0
- package/dist/lib/state/FormValidation.svelte.js +140 -0
- package/dist/lib/state/FormValues.svelte.d.ts +29 -0
- package/dist/lib/state/FormValues.svelte.js +69 -0
- package/dist/lib/validation.js +5 -28
- package/dist/lib/values.d.ts +42 -0
- package/dist/lib/values.js +90 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,10 +73,12 @@ import { FormBuilder } from '@rokkit/forms'
|
|
|
73
73
|
const form = new FormBuilder(data, schema, layout)
|
|
74
74
|
|
|
75
75
|
// form.elements → [{ scope, type, value, props }, ...]
|
|
76
|
+
// A field path is a JSON Forms scope ('#/address/city') or the bare path ('address/city')
|
|
76
77
|
form.updateField('#/name', 'Alice')
|
|
77
78
|
form.validateField('#/name')
|
|
78
|
-
form.
|
|
79
|
-
form.
|
|
79
|
+
form.validate() // every visible field, including those inside groups
|
|
80
|
+
form.isFieldDirty('#/name') // true if the value differs from the initial snapshot
|
|
81
|
+
form.isDirty // any field changed
|
|
80
82
|
```
|
|
81
83
|
|
|
82
84
|
### Validation
|
|
@@ -1,280 +1,132 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The state behind a schema-driven form — a COMPOSITION of job classes (`./state/`), each
|
|
3
|
+
* owning one concern:
|
|
4
|
+
*
|
|
5
|
+
* values → definition → steps → validation → lookups, and `elements` derived from them all
|
|
6
|
+
* by the pure `buildElements` (`./elements.js`).
|
|
7
|
+
*
|
|
8
|
+
* It holds almost no logic itself: `next()` (validate the step, then advance), `updateField()`
|
|
9
|
+
* (write, drop hidden messages, re-fetch dependent lookups) and `getVisibleData()` are the only
|
|
10
|
+
* methods that span two jobs. Everything else is the public API FormRenderer, MultiStep and
|
|
11
|
+
* consumers use, kept as delegations so none of them changed when the class was taken apart.
|
|
3
12
|
*/
|
|
4
13
|
export class FormBuilder {
|
|
5
14
|
/**
|
|
6
|
-
* Create a new FormBuilder instance
|
|
7
15
|
* @param {Record<string, unknown>} [data={}] - Initial data object
|
|
8
|
-
* @param {Object|null} [schema=null] -
|
|
9
|
-
* @param {Object|null} [layout=null] -
|
|
16
|
+
* @param {Object|null} [schema=null] - Schema; derived from the data when omitted
|
|
17
|
+
* @param {Object|null} [layout=null] - Layout; derived from the schema, else the data, when omitted
|
|
10
18
|
* @param {Object<string, import('./lookup.svelte.js').LookupConfig>} [lookups={}] - Lookup configurations
|
|
11
19
|
*/
|
|
12
20
|
constructor(data?: Record<string, unknown>, schema?: Object | null, layout?: Object | null, lookups?: {
|
|
13
21
|
[x: string]: import("./lookup.svelte.js").LookupConfig;
|
|
14
22
|
});
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
/**
|
|
23
|
+
/** The form's data and its dirty baseline. */
|
|
24
|
+
values: FormValues;
|
|
25
|
+
/** Schema and layout, and how each derives from the other. */
|
|
26
|
+
definition: FormDefinition;
|
|
27
|
+
/** Multi-step navigation. */
|
|
28
|
+
steps: FormSteps;
|
|
29
|
+
/** Validation messages, and the ways of producing them. Suffixed: `validation` is the public map. */
|
|
30
|
+
validationState: FormValidation;
|
|
31
|
+
/** Fields whose options come from elsewhere, and what they depend on. */
|
|
32
|
+
lookups: FormLookups;
|
|
33
|
+
/** @type {import('./elements.js').FormElement[]} */
|
|
34
|
+
elements: import("./elements.js").FormElement[];
|
|
35
|
+
set data(value: {});
|
|
36
|
+
get data(): {};
|
|
37
|
+
/**
|
|
38
|
+
* Every method taking a field path accepts a bare slash path (`'settings/distance'`) or a
|
|
39
|
+
* JSON Forms scope (`'#/settings/distance'`) — see `toFieldPath`.
|
|
40
|
+
*/
|
|
41
|
+
getValue(path: any): any;
|
|
42
|
+
/**
|
|
43
|
+
* Write a field, then drop messages of fields a `showWhen` just hid, then clear and re-fetch
|
|
44
|
+
* the lookups that depend on it.
|
|
45
|
+
* @param {string} path
|
|
46
|
+
* @param {any} value
|
|
47
|
+
* @param {boolean} [triggerLookups=true]
|
|
48
|
+
*/
|
|
49
|
+
updateField(scopeOrPath: any, value: any, triggerLookups?: boolean): void;
|
|
50
|
+
/** The data without hidden fields' values. Does not mutate the data. */
|
|
51
|
+
getVisibleData(): {
|
|
52
|
+
[k: string]: any;
|
|
53
|
+
};
|
|
54
|
+
get isDirty(): boolean;
|
|
55
|
+
/** Top-level fields that differ from the initial snapshot. */
|
|
56
|
+
get dirtyFields(): SvelteSet<string>;
|
|
57
|
+
isFieldDirty(fieldPath: any): boolean;
|
|
58
|
+
/** Make the current data the baseline — after a successful save. */
|
|
59
|
+
snapshot(): void;
|
|
60
|
+
/** Restore the baseline and clear every message. */
|
|
61
|
+
reset(): void;
|
|
62
|
+
set schema(value: {});
|
|
63
|
+
/** Setting it may re-derive the layout — see FormDefinition. */
|
|
64
|
+
get schema(): {};
|
|
65
|
+
set layout(value: {});
|
|
66
|
+
/** A null layout derives from the schema, else the data. */
|
|
67
|
+
get layout(): {};
|
|
68
|
+
/** Schema merged with the scoped layout elements. */
|
|
20
69
|
get combined(): any;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
set data(value: Record<string, unknown>);
|
|
26
|
-
/**
|
|
27
|
-
* Get the current data
|
|
28
|
-
* @returns {Record<string, unknown>} Current data object
|
|
29
|
-
*/
|
|
30
|
-
get data(): Record<string, unknown>;
|
|
31
|
-
/**
|
|
32
|
-
* Set the schema
|
|
33
|
-
* @param {Object} value - New schema object
|
|
34
|
-
*
|
|
35
|
-
* When the caller explicitly provides a schema, that schema is the source
|
|
36
|
-
* of truth for which fields exist — the layout may have been derived
|
|
37
|
-
* earlier from empty/partial data and would silently hide those fields.
|
|
38
|
-
* Re-derive the layout from the new schema so the two stay consistent,
|
|
39
|
-
* unless the caller has already installed an explicit non-empty layout.
|
|
40
|
-
*/
|
|
41
|
-
set schema(value: Object);
|
|
42
|
-
/**
|
|
43
|
-
* Get the current schema
|
|
44
|
-
* @returns {Object} Current schema object
|
|
45
|
-
*/
|
|
46
|
-
get schema(): Object;
|
|
47
|
-
/**
|
|
48
|
-
* Set the layout
|
|
49
|
-
* @param {Object} value - New layout object
|
|
50
|
-
*/
|
|
51
|
-
set layout(value: Object);
|
|
52
|
-
/**
|
|
53
|
-
* Get the current layout
|
|
54
|
-
* @returns {Object} Current layout object
|
|
55
|
-
*/
|
|
56
|
-
get layout(): Object;
|
|
57
|
-
/**
|
|
58
|
-
* Set validation messages for fields
|
|
59
|
-
* @param {Object} value - Validation object with field paths as keys
|
|
60
|
-
*/
|
|
61
|
-
set validation(value: Object);
|
|
62
|
-
/**
|
|
63
|
-
* Get the current validation state
|
|
64
|
-
* @returns {Object} Current validation object
|
|
65
|
-
*/
|
|
66
|
-
get validation(): Object;
|
|
67
|
-
/**
|
|
68
|
-
* Get the lookup manager
|
|
69
|
-
* @returns {ReturnType<typeof createLookupManager>|null}
|
|
70
|
-
*/
|
|
71
|
-
get lookupManager(): ReturnType<typeof createLookupManager> | null;
|
|
72
|
-
/**
|
|
73
|
-
* Configure lookups for the form
|
|
74
|
-
* @param {Object<string, import('./lookup.svelte.js').LookupConfig>} lookups - Lookup configurations
|
|
75
|
-
*/
|
|
76
|
-
setLookups(lookups: {
|
|
77
|
-
[x: string]: import("./lookup.svelte.js").LookupConfig;
|
|
78
|
-
}): void;
|
|
79
|
-
/**
|
|
80
|
-
* Get lookup state for a field
|
|
81
|
-
* @param {string} fieldPath - Field path
|
|
82
|
-
* @returns {{ options: any[], loading: boolean, error: string|null, fields: Object, disabled: boolean }|null}
|
|
83
|
-
*/
|
|
84
|
-
getLookupState(fieldPath: string): {
|
|
85
|
-
options: any[];
|
|
86
|
-
loading: boolean;
|
|
87
|
-
error: string | null;
|
|
88
|
-
fields: Object;
|
|
89
|
-
disabled: boolean;
|
|
90
|
-
} | null;
|
|
91
|
-
/**
|
|
92
|
-
* Check if a field is disabled due to unmet lookup dependencies
|
|
93
|
-
* @param {string} path - Field path
|
|
94
|
-
* @returns {boolean}
|
|
95
|
-
*/
|
|
96
|
-
isFieldDisabled(path: string): boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Manually refresh a field's lookup with the current form data
|
|
99
|
-
* @param {string} path - Field path
|
|
100
|
-
* @returns {Promise<void>}
|
|
101
|
-
*/
|
|
102
|
-
refreshLookup(path: string): Promise<void>;
|
|
103
|
-
/**
|
|
104
|
-
* Check if a field has a lookup configured
|
|
105
|
-
* @param {string} fieldPath - Field path
|
|
106
|
-
* @returns {boolean}
|
|
107
|
-
*/
|
|
108
|
-
hasLookup(fieldPath: string): boolean;
|
|
109
|
-
/**
|
|
110
|
-
* Initialize all lookups
|
|
111
|
-
* @returns {Promise<void>}
|
|
112
|
-
*/
|
|
113
|
-
initializeLookups(): Promise<void>;
|
|
114
|
-
/**
|
|
115
|
-
* Update a specific field value
|
|
116
|
-
* @param {string} path - Field path (e.g., 'count', 'settings/distance')
|
|
117
|
-
* @param {any} value - New value
|
|
118
|
-
* @param {boolean} [triggerLookups=true] - Whether to trigger dependent lookups
|
|
119
|
-
*/
|
|
120
|
-
updateField(path: string, value: any, triggerLookups?: boolean): void;
|
|
121
|
-
/**
|
|
122
|
-
* Get a field value by path
|
|
123
|
-
* @param {string} path - Field path
|
|
124
|
-
* @returns {any} Field value
|
|
125
|
-
*/
|
|
126
|
-
getValue(path: string): any;
|
|
127
|
-
/**
|
|
128
|
-
* Set validation message for a specific field
|
|
129
|
-
* @param {string} fieldPath - Field path (without '#/' prefix)
|
|
130
|
-
* @param {Object|null} message - Validation message object or null to clear
|
|
131
|
-
* @param {string} message.state - Message state: 'error', 'warning', 'info', 'success'
|
|
132
|
-
* @param {string} message.text - Message text content
|
|
133
|
-
*/
|
|
70
|
+
set validation(value: {});
|
|
71
|
+
/** The validation messages, by field path. */
|
|
72
|
+
get validation(): {};
|
|
73
|
+
/** @param {string} fieldPath @param {Object|null} message - null clears it */
|
|
134
74
|
setFieldValidation(fieldPath: string, message: Object | null): void;
|
|
135
|
-
/**
|
|
136
|
-
* Clear all validation messages
|
|
137
|
-
*/
|
|
138
75
|
clearValidation(): void;
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
* @returns {import('./validation.js').ValidationMessage|null} Validation result
|
|
143
|
-
*/
|
|
144
|
-
validateField(fieldPath: string): import("./validation.js").ValidationMessage | null;
|
|
145
|
-
/**
|
|
146
|
-
* Validate all fields, populate validation state
|
|
147
|
-
* @returns {Object} Validation results keyed by field path
|
|
148
|
-
*/
|
|
76
|
+
/** @returns {import('./validation.js').ValidationMessage|null} */
|
|
77
|
+
validateField(fieldPath: any): import("./validation.js").ValidationMessage | null;
|
|
78
|
+
/** Validate the whole form (every step of a wizard; the visible fields of a flat form). */
|
|
149
79
|
validate(): Object;
|
|
150
|
-
/**
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
* Does not mutate this.#data
|
|
154
|
-
* @returns {Record<string, unknown>} Filtered data containing only visible field keys
|
|
155
|
-
*/
|
|
156
|
-
getVisibleData(): Record<string, unknown>;
|
|
157
|
-
/**
|
|
158
|
-
* Whether all fields pass validation (no error-state messages)
|
|
159
|
-
* @returns {boolean}
|
|
160
|
-
*/
|
|
80
|
+
/** Validate one step's fields. */
|
|
81
|
+
validateStep(index: any): boolean;
|
|
82
|
+
isStepValid(index?: number): boolean;
|
|
161
83
|
get isValid(): boolean;
|
|
162
|
-
/**
|
|
163
|
-
* Array of current error messages with paths
|
|
164
|
-
* @returns {Array<{path: string, state: string, text: string}>}
|
|
165
|
-
*/
|
|
84
|
+
/** @returns {Array<{path: string, state: string, text: string}>} */
|
|
166
85
|
get errors(): Array<{
|
|
167
86
|
path: string;
|
|
168
87
|
state: string;
|
|
169
88
|
text: string;
|
|
170
89
|
}>;
|
|
171
|
-
/**
|
|
172
|
-
* Array of all validation messages with paths, ordered by severity
|
|
173
|
-
* @returns {Array<{path: string, state: string, text: string}>}
|
|
174
|
-
*/
|
|
90
|
+
/** @returns {Array<{path: string, state: string, text: string}>} most severe first */
|
|
175
91
|
get messages(): Array<{
|
|
176
92
|
path: string;
|
|
177
93
|
state: string;
|
|
178
94
|
text: string;
|
|
179
95
|
}>;
|
|
180
|
-
/**
|
|
181
|
-
* Whether any field has been modified from its initial value
|
|
182
|
-
* @returns {boolean}
|
|
183
|
-
*/
|
|
184
|
-
get isDirty(): boolean;
|
|
185
|
-
/**
|
|
186
|
-
* Set of field paths that differ from their initial values
|
|
187
|
-
* @returns {Set<string>}
|
|
188
|
-
*/
|
|
189
|
-
get dirtyFields(): Set<string>;
|
|
190
|
-
/**
|
|
191
|
-
* Check if a single field has been modified from its initial value
|
|
192
|
-
* @param {string} fieldPath - Field path (without '#/' prefix)
|
|
193
|
-
* @returns {boolean}
|
|
194
|
-
*/
|
|
195
|
-
isFieldDirty(fieldPath: string): boolean;
|
|
196
|
-
/**
|
|
197
|
-
* Update the initial data snapshot to the current data.
|
|
198
|
-
* Call after a successful save to clear dirty state.
|
|
199
|
-
*/
|
|
200
|
-
snapshot(): void;
|
|
201
|
-
/**
|
|
202
|
-
* Reset form data to initial snapshot and clear validation
|
|
203
|
-
*/
|
|
204
|
-
reset(): void;
|
|
205
|
-
/** True when the layout contains step elements */
|
|
206
96
|
get isMultiStep(): any;
|
|
207
|
-
/** Number of step elements in the layout */
|
|
208
97
|
get totalSteps(): any;
|
|
209
|
-
/** Zero-based index of the active step */
|
|
210
98
|
get currentStep(): number;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
* @returns {boolean} true if advanced, false if validation failed
|
|
214
|
-
*/
|
|
99
|
+
get canAdvance(): boolean;
|
|
100
|
+
/** Validate the current step, and advance only if it passes. */
|
|
215
101
|
next(): boolean;
|
|
216
|
-
/**
|
|
217
|
-
* Move to the previous step without validation.
|
|
218
|
-
* @returns {boolean} true if moved, false if already on first step
|
|
219
|
-
*/
|
|
102
|
+
/** Back one step, without validating. */
|
|
220
103
|
prev(): boolean;
|
|
221
|
-
/**
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
104
|
+
/** Return to a visited step. */
|
|
105
|
+
goToStep(index: any): void;
|
|
106
|
+
/** The underlying lookup manager, or null for a form without lookups. */
|
|
107
|
+
get lookupManager(): Object | null;
|
|
108
|
+
/** @param {Object<string, import('./lookup.svelte.js').LookupConfig>} lookups */
|
|
109
|
+
setLookups(lookups: {
|
|
110
|
+
[x: string]: import("./lookup.svelte.js").LookupConfig;
|
|
111
|
+
}): void;
|
|
112
|
+
/** @returns {{ options: any[], loading: boolean, error: string|null, fields: Object, disabled: boolean }|null} */
|
|
113
|
+
getLookupState(fieldPath: any): {
|
|
114
|
+
options: any[];
|
|
115
|
+
loading: boolean;
|
|
116
|
+
error: string | null;
|
|
117
|
+
fields: Object;
|
|
118
|
+
disabled: boolean;
|
|
119
|
+
} | null;
|
|
120
|
+
/** Disabled because a field its lookup depends on is not set yet. */
|
|
121
|
+
isFieldDisabled(path: any): any;
|
|
122
|
+
refreshLookup(path: any): Promise<void>;
|
|
123
|
+
hasLookup(fieldPath: any): any;
|
|
124
|
+
initializeLookups(): Promise<void>;
|
|
238
125
|
#private;
|
|
239
126
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
* - Input type (text, number, range, checkbox, select, etc.)
|
|
247
|
-
*/
|
|
248
|
-
type: string;
|
|
249
|
-
/**
|
|
250
|
-
* - Current value from data
|
|
251
|
-
*/
|
|
252
|
-
value: any;
|
|
253
|
-
/**
|
|
254
|
-
* - Whether to use custom child snippet (from layout)
|
|
255
|
-
*/
|
|
256
|
-
override: boolean;
|
|
257
|
-
/**
|
|
258
|
-
* - Merged properties from schema + layout + validation
|
|
259
|
-
*/
|
|
260
|
-
props: {
|
|
261
|
-
label?: string | undefined;
|
|
262
|
-
description?: string | undefined;
|
|
263
|
-
placeholder?: string | undefined;
|
|
264
|
-
required?: boolean | undefined;
|
|
265
|
-
min?: number | undefined;
|
|
266
|
-
max?: number | undefined;
|
|
267
|
-
message?: {
|
|
268
|
-
/**
|
|
269
|
-
* - Message state: 'error', 'warning', 'info', 'success'
|
|
270
|
-
*/
|
|
271
|
-
state?: string | undefined;
|
|
272
|
-
/**
|
|
273
|
-
* - Message text content
|
|
274
|
-
*/
|
|
275
|
-
text?: string | undefined;
|
|
276
|
-
} | undefined;
|
|
277
|
-
dirty?: boolean | undefined;
|
|
278
|
-
};
|
|
279
|
-
};
|
|
280
|
-
import { createLookupManager } from './lookup.svelte.js';
|
|
127
|
+
import { FormValues } from './state/FormValues.svelte.js';
|
|
128
|
+
import { FormDefinition } from './state/FormDefinition.svelte.js';
|
|
129
|
+
import { FormSteps } from './state/FormSteps.svelte.js';
|
|
130
|
+
import { FormValidation } from './state/FormValidation.svelte.js';
|
|
131
|
+
import { FormLookups } from './state/FormLookups.svelte.js';
|
|
132
|
+
import { SvelteSet } from 'svelte/reactivity';
|