@rokkit/forms 1.0.1 → 1.0.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jerry Thomas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -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";
@@ -0,0 +1,15 @@
1
+ export { FormBuilder } from "./lib/builder.svelte.js";
2
+ export { deriveSchemaFromValue } from "./lib/schema.js";
3
+ export { deriveLayoutFromValue } from "./lib/layout.js";
4
+ export { default as FormRenderer } from "./FormRenderer.svelte";
5
+ export { default as Input } from "./Input.svelte";
6
+ export { default as InputField } from "./InputField.svelte";
7
+ export { default as InfoField } from "./InfoField.svelte";
8
+ export { default as StatusList } from "./StatusList.svelte";
9
+ export { default as StepIndicator } from "./StepIndicator.svelte";
10
+ export * from "./display";
11
+ export * from "./input";
12
+ export { createLookup, createLookupManager, clearLookupCache } from "./lib/lookup.svelte.js";
13
+ export { validateField, validateAll, createMessage, patterns } from "./lib/validation.js";
14
+ export { defaultRenderers, resolveRenderer } from "./lib/renderers.js";
15
+ export { getSchemaWithLayout, findAttributeByPath } from "./lib/fields.js";
@@ -0,0 +1,22 @@
1
+ export { default as ArrayEditor } from "./ArrayEditor.svelte";
2
+ export { default as InputCheckbox } from "./InputCheckbox.svelte";
3
+ export { default as InputColor } from "./InputColor.svelte";
4
+ export { default as InputDate } from "./InputDate.svelte";
5
+ export { default as InputDateTime } from "./InputDateTime.svelte";
6
+ export { default as InputEmail } from "./InputEmail.svelte";
7
+ export { default as InputFile } from "./InputFile.svelte";
8
+ export { default as InputMonth } from "./InputMonth.svelte";
9
+ export { default as InputNumber } from "./InputNumber.svelte";
10
+ export { default as InputPassword } from "./InputPassword.svelte";
11
+ export { default as InputRadio } from "./InputRadio.svelte";
12
+ export { default as InputRange } from "./InputRange.svelte";
13
+ export { default as InputSelect } from "./InputSelect.svelte";
14
+ export { default as InputSwatch } from "./InputSwatch.svelte";
15
+ export { default as InputSwitch } from "./InputSwitch.svelte";
16
+ export { default as InputTel } from "./InputTel.svelte";
17
+ export { default as InputText } from "./InputText.svelte";
18
+ export { default as InputTextArea } from "./InputTextArea.svelte";
19
+ export { default as InputTime } from "./InputTime.svelte";
20
+ export { default as InputToggle } from "./InputToggle.svelte";
21
+ export { default as InputUrl } from "./InputUrl.svelte";
22
+ export { default as InputWeek } from "./InputWeek.svelte";
@@ -0,0 +1,274 @@
1
+ /**
2
+ * FormBuilder class for dynamically generating forms from data structures
3
+ */
4
+ export class FormBuilder {
5
+ /**
6
+ * Create a new FormBuilder instance
7
+ * @param {Object} [data={}] - Initial data object
8
+ * @param {Object|null} [schema=null] - Optional schema override
9
+ * @param {Object|null} [layout=null] - Optional layout override
10
+ * @param {Object<string, import('./lookup.svelte.js').LookupConfig>} [lookups={}] - Lookup configurations
11
+ */
12
+ constructor(data?: Object, schema?: Object | null, layout?: Object | null, lookups?: {
13
+ [x: string]: import("./lookup.svelte.js").LookupConfig;
14
+ });
15
+ /** @type {FormElement[]} */
16
+ elements: FormElement[];
17
+ /** True when currentStep can advance to the next step */
18
+ canAdvance: boolean;
19
+ /** Combined schema+layout (scoped elements only) */
20
+ get combined(): any;
21
+ /**
22
+ * Set the data
23
+ * @param {Object} value - New data object
24
+ */
25
+ set data(value: Object);
26
+ /**
27
+ * Get the current data
28
+ * @returns {Object} Current data object
29
+ */
30
+ get data(): Object;
31
+ /**
32
+ * Set the schema
33
+ * @param {Object} value - New schema object
34
+ */
35
+ set schema(value: Object);
36
+ /**
37
+ * Get the current schema
38
+ * @returns {Object} Current schema object
39
+ */
40
+ get schema(): Object;
41
+ /**
42
+ * Set the layout
43
+ * @param {Object} value - New layout object
44
+ */
45
+ set layout(value: Object);
46
+ /**
47
+ * Get the current layout
48
+ * @returns {Object} Current layout object
49
+ */
50
+ get layout(): Object;
51
+ /**
52
+ * Set validation messages for fields
53
+ * @param {Object} value - Validation object with field paths as keys
54
+ */
55
+ set validation(value: Object);
56
+ /**
57
+ * Get the current validation state
58
+ * @returns {Object} Current validation object
59
+ */
60
+ get validation(): Object;
61
+ /**
62
+ * Get the lookup manager
63
+ * @returns {ReturnType<typeof createLookupManager>|null}
64
+ */
65
+ get lookupManager(): ReturnType<typeof createLookupManager> | null;
66
+ /**
67
+ * Configure lookups for the form
68
+ * @param {Object<string, import('./lookup.svelte.js').LookupConfig>} lookups - Lookup configurations
69
+ */
70
+ setLookups(lookups: {
71
+ [x: string]: import("./lookup.svelte.js").LookupConfig;
72
+ }): void;
73
+ /**
74
+ * Get lookup state for a field
75
+ * @param {string} fieldPath - Field path
76
+ * @returns {{ options: any[], loading: boolean, error: string|null, fields: Object, disabled: boolean }|null}
77
+ */
78
+ getLookupState(fieldPath: string): {
79
+ options: any[];
80
+ loading: boolean;
81
+ error: string | null;
82
+ fields: Object;
83
+ disabled: boolean;
84
+ } | null;
85
+ /**
86
+ * Check if a field is disabled due to unmet lookup dependencies
87
+ * @param {string} path - Field path
88
+ * @returns {boolean}
89
+ */
90
+ isFieldDisabled(path: string): boolean;
91
+ /**
92
+ * Manually refresh a field's lookup with the current form data
93
+ * @param {string} path - Field path
94
+ * @returns {Promise<void>}
95
+ */
96
+ refreshLookup(path: string): Promise<void>;
97
+ /**
98
+ * Check if a field has a lookup configured
99
+ * @param {string} fieldPath - Field path
100
+ * @returns {boolean}
101
+ */
102
+ hasLookup(fieldPath: string): boolean;
103
+ /**
104
+ * Initialize all lookups
105
+ * @returns {Promise<void>}
106
+ */
107
+ initializeLookups(): Promise<void>;
108
+ /**
109
+ * Update a specific field value
110
+ * @param {string} path - Field path (e.g., 'count', 'settings/distance')
111
+ * @param {any} value - New value
112
+ * @param {boolean} [triggerLookups=true] - Whether to trigger dependent lookups
113
+ */
114
+ updateField(path: string, value: any, triggerLookups?: boolean): void;
115
+ /**
116
+ * Get a field value by path
117
+ * @param {string} path - Field path
118
+ * @returns {any} Field value
119
+ */
120
+ getValue(path: string): any;
121
+ /**
122
+ * Set validation message for a specific field
123
+ * @param {string} fieldPath - Field path (without '#/' prefix)
124
+ * @param {Object|null} message - Validation message object or null to clear
125
+ * @param {string} message.state - Message state: 'error', 'warning', 'info', 'success'
126
+ * @param {string} message.text - Message text content
127
+ */
128
+ setFieldValidation(fieldPath: string, message: Object | null): void;
129
+ /**
130
+ * Clear all validation messages
131
+ */
132
+ clearValidation(): void;
133
+ /**
134
+ * Validate a single field by path
135
+ * @param {string} fieldPath - Field path (without '#/' prefix)
136
+ * @returns {import('./validation.js').ValidationMessage|null} Validation result
137
+ */
138
+ validateField(fieldPath: string): import("./validation.js").ValidationMessage | null;
139
+ /**
140
+ * Validate all fields, populate validation state
141
+ * @returns {Object} Validation results keyed by field path
142
+ */
143
+ validate(): Object;
144
+ /**
145
+ * Get form data with hidden field values stripped out
146
+ * Hidden fields are those absent from this.elements (the derived list)
147
+ * Does not mutate this.#data
148
+ * @returns {Object} Filtered data containing only visible field keys
149
+ */
150
+ getVisibleData(): Object;
151
+ /**
152
+ * Whether all fields pass validation (no error-state messages)
153
+ * @returns {boolean}
154
+ */
155
+ get isValid(): boolean;
156
+ /**
157
+ * Array of current error messages with paths
158
+ * @returns {Array<{path: string, state: string, text: string}>}
159
+ */
160
+ get errors(): Array<{
161
+ path: string;
162
+ state: string;
163
+ text: string;
164
+ }>;
165
+ /**
166
+ * Array of all validation messages with paths, ordered by severity
167
+ * @returns {Array<{path: string, state: string, text: string}>}
168
+ */
169
+ get messages(): Array<{
170
+ path: string;
171
+ state: string;
172
+ text: string;
173
+ }>;
174
+ /**
175
+ * Whether any field has been modified from its initial value
176
+ * @returns {boolean}
177
+ */
178
+ get isDirty(): boolean;
179
+ /**
180
+ * Set of field paths that differ from their initial values
181
+ * @returns {Set<string>}
182
+ */
183
+ get dirtyFields(): Set<string>;
184
+ /**
185
+ * Check if a single field has been modified from its initial value
186
+ * @param {string} fieldPath - Field path (without '#/' prefix)
187
+ * @returns {boolean}
188
+ */
189
+ isFieldDirty(fieldPath: string): boolean;
190
+ /**
191
+ * Update the initial data snapshot to the current data.
192
+ * Call after a successful save to clear dirty state.
193
+ */
194
+ snapshot(): void;
195
+ /**
196
+ * Reset form data to initial snapshot and clear validation
197
+ */
198
+ reset(): void;
199
+ /** True when the layout contains step elements */
200
+ get isMultiStep(): any;
201
+ /** Number of step elements in the layout */
202
+ get totalSteps(): any;
203
+ /** Zero-based index of the active step */
204
+ get currentStep(): number;
205
+ /**
206
+ * Validate the current step and advance if valid.
207
+ * @returns {boolean} true if advanced, false if validation failed
208
+ */
209
+ next(): boolean;
210
+ /**
211
+ * Move to the previous step without validation.
212
+ * @returns {boolean} true if moved, false if already on first step
213
+ */
214
+ prev(): boolean;
215
+ /**
216
+ * Navigate to a previously visited step (index < currentStep).
217
+ * @param {number} index - Target step index
218
+ */
219
+ goToStep(index: number): void;
220
+ /**
221
+ * Validate all fields in a given step. Defaults to currentStep.
222
+ * @param {number} [index] - Step index (defaults to currentStep)
223
+ * @returns {boolean} true if no errors
224
+ */
225
+ isStepValid(index?: number): boolean;
226
+ /**
227
+ * Validate all fields belonging to a step by index.
228
+ * @param {number} index - Step index
229
+ * @returns {boolean} true if no errors
230
+ */
231
+ validateStep(index: number): boolean;
232
+ #private;
233
+ }
234
+ export type FormElement = {
235
+ /**
236
+ * - JSON Pointer path (e.g., '#/email', '#/user/name')
237
+ */
238
+ scope: string;
239
+ /**
240
+ * - Input type (text, number, range, checkbox, select, etc.)
241
+ */
242
+ type: string;
243
+ /**
244
+ * - Current value from data
245
+ */
246
+ value: any;
247
+ /**
248
+ * - Whether to use custom child snippet (from layout)
249
+ */
250
+ override: boolean;
251
+ /**
252
+ * - Merged properties from schema + layout + validation
253
+ */
254
+ props: {
255
+ label?: string | undefined;
256
+ description?: string | undefined;
257
+ placeholder?: string | undefined;
258
+ required?: boolean | undefined;
259
+ min?: number | undefined;
260
+ max?: number | undefined;
261
+ message?: {
262
+ /**
263
+ * - Message state: 'error', 'warning', 'info', 'success'
264
+ */
265
+ state?: string | undefined;
266
+ /**
267
+ * - Message text content
268
+ */
269
+ text?: string | undefined;
270
+ } | undefined;
271
+ dirty?: boolean | undefined;
272
+ };
273
+ };
274
+ import { createLookupManager } from './lookup.svelte.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Evaluate a showWhen condition against current form data.
3
+ * Returns true if the field should be shown (condition met or absent).
4
+ *
5
+ * @param {{ field: string, equals?: unknown, notEquals?: unknown } | null | undefined} condition
6
+ * @param {Record<string, unknown>} data - Top-level form data object
7
+ * @returns {boolean}
8
+ */
9
+ export function evaluateCondition(condition: {
10
+ field: string;
11
+ equals?: unknown;
12
+ notEquals?: unknown;
13
+ } | null | undefined, data: Record<string, unknown>): boolean;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Find an attribute in a schema by path
3
+ * @param {string} scope
4
+ * @param {import('../types').DataSchema} schema
5
+ * @returns {import('../types').LayoutSchema}
6
+ * @throws {Error} Invalid path
7
+ */
8
+ export function findAttributeByPath(scope: string, schema: import("../types").DataSchema): import("../types").LayoutSchema;
9
+ /**
10
+ * Get combined schema and layout
11
+ * @param {*} data
12
+ * @param {import('../types').DataSchema} schema
13
+ * @param {import('../types').LayoutSchema} layout
14
+ * @returns {import('../types').LayoutSchema}
15
+ */
16
+ export function getSchemaWithLayout(schema: import("../types").DataSchema, layout: import("../types").LayoutSchema): import("../types").LayoutSchema;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export { FormBuilder } from "./builder.svelte.js";
2
+ export { evaluateCondition } from "./conditions.js";
3
+ export { default as FormRenderer } from "./FormRenderer.svelte";
4
+ export { default as Input } from "./Input.svelte";
5
+ export * from "./schema.js";
6
+ export * from "./layout.js";
7
+ export * from "./fields.js";
8
+ export { validateField, validateAll, createMessage, patterns } from "./validation.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Derives a layout from a given value.
3
+ * @param {any} value
4
+ * @param {string} scope
5
+ * @returns {import('../types').DataLayout}
6
+ */
7
+ export function deriveLayoutFromValue(value: any, scope?: string): import("../types").DataLayout;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Creates a lookup provider for a field
3
+ * @param {LookupConfig} config - Lookup configuration
4
+ * @returns {Object} Lookup provider with reactive state
5
+ */
6
+ export function createLookup(config: LookupConfig): Object;
7
+ /**
8
+ * Creates a lookup manager for a form with multiple lookups
9
+ * @param {Object<string, LookupConfig>} lookupConfigs - Map of field paths to lookup configs
10
+ * @returns {Object} Lookup manager
11
+ */
12
+ export function createLookupManager(lookupConfigs: {
13
+ [x: string]: LookupConfig;
14
+ }): Object;
15
+ /**
16
+ * Clears the entire lookup cache
17
+ */
18
+ export function clearLookupCache(): void;
19
+ export type HookConfig = {
20
+ fetchHook: Function;
21
+ cacheKeyFn?: Function;
22
+ cacheTime: number;
23
+ transform?: Function;
24
+ };
25
+ export type UrlConfig = {
26
+ url: string;
27
+ cacheTime: number;
28
+ transform?: Function;
29
+ };
30
+ export type LookupApi = {
31
+ state: Object;
32
+ meta: Object;
33
+ fetch: Function;
34
+ clearCache: Function;
35
+ reset: Function;
36
+ };
37
+ export type LookupConfig = {
38
+ /**
39
+ * - URL template with optional placeholders (e.g., '/api/cities?country={country}')
40
+ */
41
+ url?: string | undefined;
42
+ /**
43
+ * - Async function replacing URL template
44
+ */
45
+ fetch?: ((formData: any) => Promise<any[]>) | undefined;
46
+ /**
47
+ * - Pre-loaded array for filter pattern
48
+ */
49
+ source?: any[] | undefined;
50
+ /**
51
+ * - Client-side filter applied to source
52
+ */
53
+ filter?: ((items: any[], formData: any) => any[]) | undefined;
54
+ /**
55
+ * - Custom cache key for fetch hooks (no caching when absent)
56
+ */
57
+ cacheKey?: ((formData: any) => string) | undefined;
58
+ /**
59
+ * - Field paths this lookup depends on
60
+ */
61
+ dependsOn?: string[] | undefined;
62
+ /**
63
+ * - Field mapping for the response data
64
+ */
65
+ fields?: Object | undefined;
66
+ /**
67
+ * - Cache duration in milliseconds (default: 5 minutes)
68
+ */
69
+ cacheTime?: number | undefined;
70
+ /**
71
+ * - Transform response data to options array
72
+ */
73
+ transform?: ((data: any) => any[]) | undefined;
74
+ };
75
+ export type LookupState = {
76
+ /**
77
+ * - Current options
78
+ */
79
+ options: any[];
80
+ /**
81
+ * - Whether lookup is in progress
82
+ */
83
+ loading: boolean;
84
+ /**
85
+ * - Error message if lookup failed
86
+ */
87
+ error: string | null;
88
+ /**
89
+ * - Whether field is disabled (deps not met)
90
+ */
91
+ disabled: boolean;
92
+ };
93
+ /**
94
+ * Cache entry structure
95
+ */
96
+ export type CacheEntry = {
97
+ /**
98
+ * - Cached options
99
+ */
100
+ data: any[];
101
+ /**
102
+ * - When the cache was created
103
+ */
104
+ timestamp: number;
105
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Resolve a renderer component for a form element.
3
+ *
4
+ * Resolution order:
5
+ * 1. Explicit `renderer` name in element props → custom registry
6
+ * 2. Element type → registry lookup
7
+ * 3. Fallback → InputText
8
+ *
9
+ * @param {{ type: string, props?: { renderer?: string } }} element
10
+ * @param {Record<string, import('svelte').Component>} renderers - Merged registry
11
+ * @returns {import('svelte').Component}
12
+ */
13
+ export function resolveRenderer(element: {
14
+ type: string;
15
+ props?: {
16
+ renderer?: string;
17
+ };
18
+ }, renderers: Record<string, import("svelte").Component>): import("svelte").Component;
19
+ /**
20
+ * Default renderer registry mapping type strings to components.
21
+ * @type {Record<string, import('svelte').Component>}
22
+ */
23
+ export const defaultRenderers: Record<string, import("svelte").Component>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Derives a schema from a given value.
3
+ *
4
+ * @param {any} data
5
+ * @returns {import('../types').DataSchema}
6
+ */
7
+ export function deriveSchemaFromValue(data: any): import("../types").DataSchema;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Create validation messages for informational purposes
3
+ * @param {string} fieldPath - Field path
4
+ * @param {string} state - Message state ('info', 'warning', 'success')
5
+ * @param {string} text - Message text
6
+ * @returns {Object} Field path to message mapping
7
+ */
8
+ export function createMessage(fieldPath: string, state: string, text: string): Object;
9
+ /**
10
+ * Validate a single field value against its schema
11
+ * @param {any} value - Field value to validate
12
+ * @param {Object} fieldSchema - Field schema definition
13
+ * @param {string} [fieldLabel] - Field label for error messages
14
+ * @returns {ValidationMessage|null} Validation message or null if valid
15
+ */
16
+ export function validateField(value: any, fieldSchema: Object, fieldLabel?: string): ValidationMessage | null;
17
+ /**
18
+ * Validate all fields in a data object
19
+ * @param {Object} data - Data object to validate
20
+ * @param {Object} schema - Schema object with properties
21
+ * @param {Object} layout - Layout object with element definitions
22
+ * @returns {Object} Validation results keyed by field path
23
+ */
24
+ export function validateAll(data: Object, schema: Object, layout: Object): Object;
25
+ export namespace patterns {
26
+ let email: RegExp;
27
+ let phone: RegExp;
28
+ let url: RegExp;
29
+ let zipCode: RegExp;
30
+ let creditCard: RegExp;
31
+ }
32
+ export type ValidationMessage = {
33
+ /**
34
+ * - Message state: 'error', 'warning', 'info', 'success'
35
+ */
36
+ state: string;
37
+ /**
38
+ * - Message text content
39
+ */
40
+ text: string;
41
+ };
@@ -0,0 +1,5 @@
1
+ export namespace types {
2
+ let string: import("svelte/legacy").LegacyComponentType;
3
+ let integer: import("svelte/legacy").LegacyComponentType;
4
+ let phone: import("svelte/legacy").LegacyComponentType;
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/forms",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Form building components for Rokkit applications",
5
5
  "repository": {
6
6
  "type": "git",