@bluprynt/forms-viewer 4.0.1 → 4.1.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 +28 -5
- package/dist/index.cjs +217 -23
- package/dist/index.d.cts +152 -45
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +152 -45
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +218 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DocumentError, DocumentError as DocumentError$1, FormEngine, FormValuesEditor } from "@bluprynt/forms-core";
|
|
1
|
+
import { DocumentError, DocumentError as DocumentError$1, FormEngine, FormValuesEditor, applySuggestion, removeSuggestion } from "@bluprynt/forms-core";
|
|
2
2
|
import { Fragment, createContext, useCallback, useContext, useMemo, useRef } from "react";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/constants.ts
|
|
@@ -97,12 +97,15 @@ const getFieldErrors = (fieldErrors, fieldId, itemIndex) => {
|
|
|
97
97
|
* Array fields store their per-item schema in `arrayField.item` ({@link ArrayItemDef}).
|
|
98
98
|
* Components that render individual array items need a standard `FieldContentItem` shape,
|
|
99
99
|
* so this helper projects the item definition into one, preserving the parent field's `id`
|
|
100
|
-
* while adopting the item's `type`, `label`,
|
|
100
|
+
* while adopting the item's `type`, `label`, authoring metadata, `validation`, and `options`.
|
|
101
|
+
*
|
|
102
|
+
* A `static` item projects to a `StaticFieldContentItem`, so the return type is
|
|
103
|
+
* the wider {@link AnyFieldContentItem}.
|
|
101
104
|
*
|
|
102
105
|
* @param arrayField - The array field definition whose `.item` property describes the item schema.
|
|
103
106
|
* @param _index - The zero-based position of the item in the array (reserved for future use,
|
|
104
107
|
* e.g. per-item overrides).
|
|
105
|
-
* @returns
|
|
108
|
+
* @returns An `AnyFieldContentItem` that can be passed directly to a typed field component.
|
|
106
109
|
*
|
|
107
110
|
* @example
|
|
108
111
|
* ```ts
|
|
@@ -117,16 +120,79 @@ const getFieldErrors = (fieldErrors, fieldId, itemIndex) => {
|
|
|
117
120
|
*/
|
|
118
121
|
const getArrayField = (arrayField, _index) => {
|
|
119
122
|
const itemDef = arrayField.item;
|
|
123
|
+
const metadata = {
|
|
124
|
+
description: itemDef.description,
|
|
125
|
+
placeholder: itemDef.placeholder,
|
|
126
|
+
answer_guidelines: itemDef.answer_guidelines,
|
|
127
|
+
reference_id: itemDef.reference_id
|
|
128
|
+
};
|
|
129
|
+
if (itemDef.type === "static") return {
|
|
130
|
+
id: arrayField.id,
|
|
131
|
+
type: "static",
|
|
132
|
+
text: itemDef.text,
|
|
133
|
+
label: itemDef.label,
|
|
134
|
+
...metadata
|
|
135
|
+
};
|
|
120
136
|
return {
|
|
121
137
|
id: arrayField.id,
|
|
122
138
|
type: itemDef.type,
|
|
123
139
|
label: itemDef.label,
|
|
124
|
-
|
|
140
|
+
...metadata,
|
|
125
141
|
validation: itemDef.validation,
|
|
126
142
|
options: itemDef.options
|
|
127
143
|
};
|
|
128
144
|
};
|
|
129
145
|
/**
|
|
146
|
+
* Creates a {@link AnyFieldContentItem} representing one sub-field of an `array_obj` field.
|
|
147
|
+
*
|
|
148
|
+
* Unlike an `array` item, a sub-field carries its own id, so the projection keeps it:
|
|
149
|
+
* it is both the key its value is stored under inside each row and a stable React key.
|
|
150
|
+
*
|
|
151
|
+
* @param subField - The sub-field definition taken from the field's `items` list.
|
|
152
|
+
* @returns An `AnyFieldContentItem` that can be passed directly to a typed field component.
|
|
153
|
+
*/
|
|
154
|
+
const getArrayObjField = (subField) => {
|
|
155
|
+
const metadata = {
|
|
156
|
+
description: subField.description,
|
|
157
|
+
placeholder: subField.placeholder,
|
|
158
|
+
answer_guidelines: subField.answer_guidelines,
|
|
159
|
+
reference_id: subField.reference_id
|
|
160
|
+
};
|
|
161
|
+
if (subField.type === "static") return {
|
|
162
|
+
id: subField.id,
|
|
163
|
+
type: "static",
|
|
164
|
+
text: subField.text,
|
|
165
|
+
label: subField.label,
|
|
166
|
+
...metadata
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
id: subField.id,
|
|
170
|
+
type: subField.type,
|
|
171
|
+
label: subField.label,
|
|
172
|
+
...metadata,
|
|
173
|
+
validation: subField.validation,
|
|
174
|
+
options: subField.options
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Retrieves the validation errors for one sub-field of one row of an `array_obj` field.
|
|
179
|
+
*
|
|
180
|
+
* Errors for an `array_obj` are all stored under the container's id; the row is
|
|
181
|
+
* identified by `itemIndex` and the sub-field by `itemFieldId`.
|
|
182
|
+
*
|
|
183
|
+
* @param fieldErrors - Map from field id to its validation errors.
|
|
184
|
+
* @param fieldId - The numeric id of the `array_obj` field.
|
|
185
|
+
* @param index - Zero-based row index.
|
|
186
|
+
* @param subFieldId - The numeric id of the sub-field.
|
|
187
|
+
* @returns Errors for that cell. Empty array if none.
|
|
188
|
+
*/
|
|
189
|
+
const getArrayObjItemErrors = (fieldErrors, fieldId, index, subFieldId) => (fieldErrors.get(fieldId) ?? []).filter((e) => e.itemIndex === index && e.itemFieldId === subFieldId);
|
|
190
|
+
/**
|
|
191
|
+
* Retrieves the row-level validation errors for one row of an `array_obj` field --
|
|
192
|
+
* those carrying an `itemIndex` but no `itemFieldId`, such as a row that is not an object.
|
|
193
|
+
*/
|
|
194
|
+
const getArrayObjRowErrors = (fieldErrors, fieldId, index) => (fieldErrors.get(fieldId) ?? []).filter((e) => e.itemIndex === index && e.itemFieldId == null);
|
|
195
|
+
/**
|
|
130
196
|
* Recursively searches content items for a section with the given id.
|
|
131
197
|
*
|
|
132
198
|
* Walks the content tree depth-first, checking sections and their nested
|
|
@@ -154,7 +220,13 @@ const findSection = (items, sectionId) => {
|
|
|
154
220
|
};
|
|
155
221
|
//#endregion
|
|
156
222
|
//#region src/form/form-items.tsx
|
|
157
|
-
|
|
223
|
+
/** Looks up the component for a value field type. Optional map keys may be absent. */
|
|
224
|
+
const componentFor = (components, type) => components[type];
|
|
225
|
+
/** `select` and `multiselect` components are the only ones that receive injected options. */
|
|
226
|
+
const withOptions = (props, def) => {
|
|
227
|
+
if (def.type === "select" || def.type === "multiselect") props.options = def.options ?? [];
|
|
228
|
+
};
|
|
229
|
+
const FormItems = ({ items, visibilityMap, values, suggestions, fieldErrors, components, showInlineValidation, renderFieldProps, renderArrayItemProps, renderArrayObjItemProps }) => {
|
|
158
230
|
const SectionComponent = components.section;
|
|
159
231
|
const ErrorComponent = showInlineValidation ? components.error : void 0;
|
|
160
232
|
const elements = [];
|
|
@@ -166,11 +238,13 @@ const FormItems = ({ items, visibilityMap, values, fieldErrors, components, show
|
|
|
166
238
|
items: item.content,
|
|
167
239
|
visibilityMap,
|
|
168
240
|
values,
|
|
241
|
+
suggestions,
|
|
169
242
|
fieldErrors,
|
|
170
243
|
components,
|
|
171
244
|
showInlineValidation,
|
|
172
245
|
renderFieldProps,
|
|
173
|
-
renderArrayItemProps
|
|
246
|
+
renderArrayItemProps,
|
|
247
|
+
renderArrayObjItemProps
|
|
174
248
|
})
|
|
175
249
|
}, item.id));
|
|
176
250
|
else if (item.type === "array") {
|
|
@@ -179,23 +253,29 @@ const FormItems = ({ items, visibilityMap, values, fieldErrors, components, show
|
|
|
179
253
|
const ArrayComponent = components.array;
|
|
180
254
|
const arrayValue = values[String(item.id)] ?? [];
|
|
181
255
|
const itemDef = item.item;
|
|
182
|
-
const ItemComponent = components
|
|
183
|
-
|
|
256
|
+
const ItemComponent = componentFor(components, itemDef.type);
|
|
257
|
+
const arrayProps = {
|
|
184
258
|
field: item,
|
|
185
259
|
value: values[String(item.id)],
|
|
186
260
|
itemDef: item.item,
|
|
187
261
|
errors,
|
|
188
|
-
...modeProps
|
|
262
|
+
...modeProps
|
|
263
|
+
};
|
|
264
|
+
const arraySuggestion = suggestions?.[String(item.id)];
|
|
265
|
+
if (arraySuggestion) arrayProps.suggestion = arraySuggestion;
|
|
266
|
+
elements.push(/* @__PURE__ */ jsx(ArrayComponent, {
|
|
267
|
+
...arrayProps,
|
|
189
268
|
children: ItemComponent ? arrayValue.map((itemValue, index) => {
|
|
190
|
-
const itemErrors = getFieldErrors(fieldErrors, item.id, index);
|
|
191
269
|
const synthetic = getArrayField(item, index);
|
|
270
|
+
if (synthetic.type === "static") return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ItemComponent, { field: synthetic }) }, `${item.id}-${index}`);
|
|
271
|
+
const itemErrors = getFieldErrors(fieldErrors, item.id, index);
|
|
192
272
|
const baseProps = {
|
|
193
273
|
field: synthetic,
|
|
194
274
|
value: itemValue,
|
|
195
275
|
errors: itemErrors,
|
|
196
276
|
...renderArrayItemProps?.(item, index) ?? {}
|
|
197
277
|
};
|
|
198
|
-
|
|
278
|
+
withOptions(baseProps, itemDef);
|
|
199
279
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ItemComponent, { ...baseProps }), ErrorComponent && itemErrors.length > 0 && /* @__PURE__ */ jsx(ErrorComponent, {
|
|
200
280
|
errors: itemErrors,
|
|
201
281
|
field: synthetic
|
|
@@ -206,6 +286,55 @@ const FormItems = ({ items, visibilityMap, values, fieldErrors, components, show
|
|
|
206
286
|
errors,
|
|
207
287
|
field: item
|
|
208
288
|
}, `${item.id}-error`));
|
|
289
|
+
} else if (item.type === "array_obj") {
|
|
290
|
+
const ArrayObjComponent = components.array_obj;
|
|
291
|
+
if (!ArrayObjComponent) continue;
|
|
292
|
+
const itemsDef = item.items ?? [];
|
|
293
|
+
const rows = values[String(item.id)] ?? [];
|
|
294
|
+
const errors = [...getFieldErrors(fieldErrors, item.id), ...rows.flatMap((_row, index) => getArrayObjRowErrors(fieldErrors, item.id, index))];
|
|
295
|
+
const modeProps = renderFieldProps?.(item) ?? {};
|
|
296
|
+
const arrayProps = {
|
|
297
|
+
field: item,
|
|
298
|
+
value: values[String(item.id)],
|
|
299
|
+
itemsDef,
|
|
300
|
+
kind: item.kind ?? "list",
|
|
301
|
+
errors,
|
|
302
|
+
...modeProps
|
|
303
|
+
};
|
|
304
|
+
const arraySuggestion = suggestions?.[String(item.id)];
|
|
305
|
+
if (arraySuggestion) arrayProps.suggestion = arraySuggestion;
|
|
306
|
+
const children = rows.map((row, index) => itemsDef.map((subField) => {
|
|
307
|
+
const key = `${item.id}-${index}-${subField.id}`;
|
|
308
|
+
const SubComponent = componentFor(components, subField.type);
|
|
309
|
+
if (!SubComponent) return /* @__PURE__ */ jsx(Fragment, {}, key);
|
|
310
|
+
const synthetic = getArrayObjField(subField);
|
|
311
|
+
if (subField.type === "static") return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(SubComponent, { field: synthetic }) }, key);
|
|
312
|
+
const cellErrors = getArrayObjItemErrors(fieldErrors, item.id, index, subField.id);
|
|
313
|
+
const cellModeProps = renderArrayObjItemProps?.(item, index, subField.id) ?? {};
|
|
314
|
+
const cellProps = {
|
|
315
|
+
field: synthetic,
|
|
316
|
+
value: row?.[String(subField.id)],
|
|
317
|
+
errors: cellErrors,
|
|
318
|
+
...cellModeProps
|
|
319
|
+
};
|
|
320
|
+
withOptions(cellProps, subField);
|
|
321
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SubComponent, { ...cellProps }), ErrorComponent && cellErrors.length > 0 && /* @__PURE__ */ jsx(ErrorComponent, {
|
|
322
|
+
errors: cellErrors,
|
|
323
|
+
field: synthetic
|
|
324
|
+
})] }, key);
|
|
325
|
+
}));
|
|
326
|
+
elements.push(/* @__PURE__ */ jsx(ArrayObjComponent, {
|
|
327
|
+
...arrayProps,
|
|
328
|
+
children
|
|
329
|
+
}, item.id));
|
|
330
|
+
if (ErrorComponent && errors.length > 0) elements.push(/* @__PURE__ */ jsx(ErrorComponent, {
|
|
331
|
+
errors,
|
|
332
|
+
field: item
|
|
333
|
+
}, `${item.id}-error`));
|
|
334
|
+
} else if (item.type === "static") {
|
|
335
|
+
const StaticComponent = components.static;
|
|
336
|
+
if (!StaticComponent) continue;
|
|
337
|
+
elements.push(/* @__PURE__ */ jsx(StaticComponent, { field: item }, item.id));
|
|
209
338
|
} else {
|
|
210
339
|
const errors = getFieldErrors(fieldErrors, item.id);
|
|
211
340
|
const modeProps = renderFieldProps?.(item) ?? {};
|
|
@@ -215,8 +344,11 @@ const FormItems = ({ items, visibilityMap, values, fieldErrors, components, show
|
|
|
215
344
|
errors,
|
|
216
345
|
...modeProps
|
|
217
346
|
};
|
|
218
|
-
|
|
219
|
-
|
|
347
|
+
const suggestion = suggestions?.[String(item.id)];
|
|
348
|
+
if (suggestion) fieldProps.suggestion = suggestion;
|
|
349
|
+
withOptions(fieldProps, item);
|
|
350
|
+
const FieldComponent = componentFor(components, item.type);
|
|
351
|
+
if (!FieldComponent) continue;
|
|
220
352
|
elements.push(/* @__PURE__ */ jsx(FieldComponent, { ...fieldProps }, item.id));
|
|
221
353
|
if (ErrorComponent && errors.length > 0) elements.push(/* @__PURE__ */ jsx(ErrorComponent, {
|
|
222
354
|
errors,
|
|
@@ -230,18 +362,21 @@ const FormItems = ({ items, visibilityMap, values, fieldErrors, components, show
|
|
|
230
362
|
//#endregion
|
|
231
363
|
//#region src/form/form-content.tsx
|
|
232
364
|
const FormContent = (props) => {
|
|
233
|
-
const { items, visibilityMap, values, fieldErrors, section, showInlineValidation } = props;
|
|
365
|
+
const { items, visibilityMap, values, suggestions, fieldErrors, section, showInlineValidation } = props;
|
|
234
366
|
const sharedProps = props.mode === "editor" ? {
|
|
235
367
|
visibilityMap,
|
|
236
368
|
values,
|
|
369
|
+
suggestions,
|
|
237
370
|
fieldErrors,
|
|
238
371
|
components: props.components,
|
|
239
372
|
showInlineValidation,
|
|
240
373
|
renderFieldProps: props.renderFieldProps,
|
|
241
|
-
renderArrayItemProps: props.renderArrayItemProps
|
|
374
|
+
renderArrayItemProps: props.renderArrayItemProps,
|
|
375
|
+
renderArrayObjItemProps: props.renderArrayObjItemProps
|
|
242
376
|
} : {
|
|
243
377
|
visibilityMap,
|
|
244
378
|
values,
|
|
379
|
+
suggestions,
|
|
245
380
|
fieldErrors,
|
|
246
381
|
components: props.components,
|
|
247
382
|
showInlineValidation
|
|
@@ -274,19 +409,21 @@ const resolveDefaultSection = (items, visibilityMap) => {
|
|
|
274
409
|
//#region src/form-editor.tsx
|
|
275
410
|
const FormEditor = ({ components, onChange }) => {
|
|
276
411
|
const { definition, data, visibilityMap, fieldErrors, section, engine, showInlineValidation, documentErrors } = useFormContext();
|
|
277
|
-
const { renderFieldProps, renderArrayItemProps } = useEditorHandlers(engine, data, onChange);
|
|
412
|
+
const { renderFieldProps, renderArrayItemProps, renderArrayObjItemProps } = useEditorHandlers(engine, data, onChange);
|
|
278
413
|
if (!definition || !data || documentErrors && documentErrors.length > 0) return null;
|
|
279
414
|
return /* @__PURE__ */ jsx(FormContent, {
|
|
280
415
|
mode: "editor",
|
|
281
416
|
items: definition.content,
|
|
282
417
|
visibilityMap,
|
|
283
418
|
values: data.values,
|
|
419
|
+
suggestions: data.suggestions,
|
|
284
420
|
fieldErrors,
|
|
285
421
|
components,
|
|
286
422
|
section,
|
|
287
423
|
showInlineValidation,
|
|
288
424
|
renderFieldProps,
|
|
289
|
-
renderArrayItemProps
|
|
425
|
+
renderArrayItemProps,
|
|
426
|
+
renderArrayObjItemProps
|
|
290
427
|
});
|
|
291
428
|
};
|
|
292
429
|
const useEditorHandlers = (engine, data, onChange) => {
|
|
@@ -322,7 +459,7 @@ const useEditorHandlers = (engine, data, onChange) => {
|
|
|
322
459
|
return handler;
|
|
323
460
|
}, []);
|
|
324
461
|
const arrayHandlersMap = useRef(/* @__PURE__ */ new Map());
|
|
325
|
-
const getArrayHandlers = useCallback((fieldId) => {
|
|
462
|
+
const getArrayHandlers = useCallback((fieldId, newItem) => {
|
|
326
463
|
const key = String(fieldId);
|
|
327
464
|
let handlers = arrayHandlersMap.current.get(key);
|
|
328
465
|
if (!handlers) {
|
|
@@ -341,7 +478,7 @@ const useEditorHandlers = (engine, data, onChange) => {
|
|
|
341
478
|
};
|
|
342
479
|
handlers = {
|
|
343
480
|
onAddItem: () => fire((values) => {
|
|
344
|
-
values.push(
|
|
481
|
+
values.push(newItem());
|
|
345
482
|
return values;
|
|
346
483
|
}),
|
|
347
484
|
onRemoveItem: (index) => fire((values) => {
|
|
@@ -358,6 +495,26 @@ const useEditorHandlers = (engine, data, onChange) => {
|
|
|
358
495
|
}
|
|
359
496
|
return handlers;
|
|
360
497
|
}, []);
|
|
498
|
+
const suggestionHandlersMap = useRef(/* @__PURE__ */ new Map());
|
|
499
|
+
const getSuggestionHandlers = useCallback((fieldId) => {
|
|
500
|
+
const key = String(fieldId);
|
|
501
|
+
let handlers = suggestionHandlersMap.current.get(key);
|
|
502
|
+
if (!handlers) {
|
|
503
|
+
const fire = (next) => {
|
|
504
|
+
const { data, onChange, engine } = stateRef.current;
|
|
505
|
+
if (!data || !engine) return;
|
|
506
|
+
const document = next(data);
|
|
507
|
+
if (document === data) return;
|
|
508
|
+
onChange(document, engine.validate(document));
|
|
509
|
+
};
|
|
510
|
+
handlers = {
|
|
511
|
+
onAcceptSuggestion: () => fire((document) => applySuggestion(document, fieldId)),
|
|
512
|
+
onRejectSuggestion: () => fire((document) => removeSuggestion(document, fieldId))
|
|
513
|
+
};
|
|
514
|
+
suggestionHandlersMap.current.set(key, handlers);
|
|
515
|
+
}
|
|
516
|
+
return handlers;
|
|
517
|
+
}, []);
|
|
361
518
|
const arrayItemOnChangeMap = useRef(/* @__PURE__ */ new Map());
|
|
362
519
|
const getArrayItemOnChange = useCallback((fieldId, index) => {
|
|
363
520
|
const mapKey = `${fieldId}-${index}`;
|
|
@@ -382,15 +539,51 @@ const useEditorHandlers = (engine, data, onChange) => {
|
|
|
382
539
|
}
|
|
383
540
|
return handler;
|
|
384
541
|
}, []);
|
|
542
|
+
const arrayObjItemOnChangeMap = useRef(/* @__PURE__ */ new Map());
|
|
543
|
+
const getArrayObjItemOnChange = useCallback((fieldId, index, subFieldId) => {
|
|
544
|
+
const mapKey = `${fieldId}-${index}-${subFieldId}`;
|
|
545
|
+
let handler = arrayObjItemOnChangeMap.current.get(mapKey);
|
|
546
|
+
if (!handler) {
|
|
547
|
+
handler = (newValue) => {
|
|
548
|
+
const fieldKey = String(fieldId);
|
|
549
|
+
const { data, onChange, engine } = stateRef.current;
|
|
550
|
+
if (!data || !engine) return;
|
|
551
|
+
const rows = [...data.values[fieldKey] ?? []];
|
|
552
|
+
const current = rows[index];
|
|
553
|
+
rows[index] = {
|
|
554
|
+
...typeof current === "object" && current !== null && !Array.isArray(current) ? current : {},
|
|
555
|
+
[String(subFieldId)]: newValue
|
|
556
|
+
};
|
|
557
|
+
const document = {
|
|
558
|
+
...data,
|
|
559
|
+
values: {
|
|
560
|
+
...data.values,
|
|
561
|
+
[fieldKey]: rows
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
onChange(document, engine.validate(document));
|
|
565
|
+
};
|
|
566
|
+
arrayObjItemOnChangeMap.current.set(mapKey, handler);
|
|
567
|
+
}
|
|
568
|
+
return handler;
|
|
569
|
+
}, []);
|
|
385
570
|
return {
|
|
386
571
|
renderFieldProps: (field) => {
|
|
387
|
-
if (field.type === "array")
|
|
572
|
+
if (field.type === "array" || field.type === "array_obj") {
|
|
573
|
+
const newItem = field.type === "array_obj" ? () => ({}) : () => void 0;
|
|
574
|
+
return {
|
|
575
|
+
onChange: getFieldOnChange(field.id),
|
|
576
|
+
...getArrayHandlers(field.id, newItem),
|
|
577
|
+
...getSuggestionHandlers(field.id)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
388
581
|
onChange: getFieldOnChange(field.id),
|
|
389
|
-
...
|
|
582
|
+
...getSuggestionHandlers(field.id)
|
|
390
583
|
};
|
|
391
|
-
return { onChange: getFieldOnChange(field.id) };
|
|
392
584
|
},
|
|
393
|
-
renderArrayItemProps: (field, index) => ({ onChange: getArrayItemOnChange(field.id, index) })
|
|
585
|
+
renderArrayItemProps: (field, index) => ({ onChange: getArrayItemOnChange(field.id, index) }),
|
|
586
|
+
renderArrayObjItemProps: (field, index, subFieldId) => ({ onChange: getArrayObjItemOnChange(field.id, index, subFieldId) })
|
|
394
587
|
};
|
|
395
588
|
};
|
|
396
589
|
//#endregion
|
|
@@ -417,7 +610,7 @@ const FormFieldsValidation = ({ container: ContainerComponent, field: FieldCompo
|
|
|
417
610
|
if (groups.length === 0) return null;
|
|
418
611
|
return /* @__PURE__ */ jsx(ContainerComponent, { children: groups.map((group) => /* @__PURE__ */ jsx(FieldComponent, {
|
|
419
612
|
...group,
|
|
420
|
-
children: group.errors.map((error) => /* @__PURE__ */ jsx(ErrorComponent, { ...error }, `${error.fieldId}-${error.rule}-${error.itemIndex ?? ""}`))
|
|
613
|
+
children: group.errors.map((error) => /* @__PURE__ */ jsx(ErrorComponent, { ...error }, `${error.fieldId}-${error.rule}-${error.itemIndex ?? ""}-${error.itemFieldId ?? ""}`))
|
|
421
614
|
}, group.field?.id)) });
|
|
422
615
|
};
|
|
423
616
|
//#endregion
|
|
@@ -471,6 +664,7 @@ const FormViewer = ({ components }) => {
|
|
|
471
664
|
items: definition.content,
|
|
472
665
|
visibilityMap,
|
|
473
666
|
values: data.values,
|
|
667
|
+
suggestions: data.suggestions,
|
|
474
668
|
fieldErrors,
|
|
475
669
|
components,
|
|
476
670
|
section,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["DocumentError"],"sources":["../src/constants.ts","../src/form-context.tsx","../src/form-document-validation.tsx","../src/form/utils.ts","../src/form/form-items.tsx","../src/form/form-content.tsx","../src/form-editor.tsx","../src/form-fields-validation.tsx","../src/use-form-sections.ts","../src/form-sections.tsx","../src/form-viewer.tsx"],"sourcesContent":["export const ROOT: unique symbol = Symbol('ROOT')\nexport type ROOT = typeof ROOT\n\nexport const DEFAULT: unique symbol = Symbol('DEFAULT')\nexport type DEFAULT = typeof DEFAULT\n","import { createContext, type FC, type ReactNode, useContext, useMemo } from 'react'\n\nimport {\n DocumentError,\n DocumentValidationError,\n FieldValidationError,\n FormDefinition,\n FormDocument,\n FormEngine,\n FormValidationResult,\n} from '@bluprynt/forms-core'\n\nimport type { DEFAULT, ROOT } from './constants'\n\ntype FormContextValue = {\n definition: FormDefinition | undefined\n data: FormDocument | undefined\n engine: FormEngine | undefined\n visibilityMap: Map<number, boolean>\n validation: FormValidationResult | undefined\n documentErrors: readonly DocumentValidationError[] | undefined\n fieldErrors: Map<number, FieldValidationError[]>\n section: typeof ROOT | typeof DEFAULT | number | undefined\n showInlineValidation: boolean\n}\n\nconst FormContext = createContext<FormContextValue | undefined>(undefined)\n\nexport const useFormContext = (): FormContextValue => {\n const context = useContext(FormContext)\n if (!context) throw new Error('useFormContext must be used within a <Form> provider')\n\n return context\n}\n\ntype FormProps = {\n definition?: FormDefinition\n data?: FormDocument\n section?: typeof ROOT | typeof DEFAULT | number\n showInlineValidation?: boolean\n children: ReactNode\n}\n\nexport const Form: FC<FormProps> = ({ definition, data, section, showInlineValidation = true, children }) => {\n const { engine, documentErrors: definitionErrors } = useMemo(() => {\n if (!definition) return {}\n\n try {\n return { engine: new FormEngine(definition) }\n } catch (error) {\n if (error instanceof DocumentError) return { documentErrors: error.errors }\n throw error\n }\n }, [definition])\n\n const { visibilityMap, validation, documentErrors, fieldErrors } = useMemo(() => {\n const visibilityMap = engine && data ? engine.getVisibilityMap(data) : new Map<number, boolean>()\n const validation =\n engine && data\n ? engine.validate(data)\n : ({\n valid: true,\n fieldErrors: new Map<number, FieldValidationError[]>(),\n } satisfies FormValidationResult)\n\n return {\n visibilityMap,\n validation,\n documentErrors: [...(definitionErrors ?? []), ...(validation?.documentErrors ?? [])],\n fieldErrors: validation?.fieldErrors ?? new Map<number, FieldValidationError[]>(),\n } as const\n }, [engine, data, definitionErrors])\n\n const value: FormContextValue = {\n definition,\n data,\n engine,\n visibilityMap,\n validation,\n documentErrors,\n fieldErrors,\n section,\n showInlineValidation,\n } as const\n\n return <FormContext.Provider value={value}>{children}</FormContext.Provider>\n}\n","import type { ComponentType, FC, PropsWithChildren } from 'react'\n\nimport type { DocumentValidationError } from '@bluprynt/forms-core'\n\nimport { useFormContext } from './form-context'\n\ntype FormDocumentValidationProps = {\n container: ComponentType<PropsWithChildren>\n error: ComponentType<DocumentValidationError>\n}\n\nexport const FormDocumentValidation: FC<FormDocumentValidationProps> = ({\n container: ContainerComponent,\n error: ErrorComponent,\n}) => {\n const { documentErrors } = useFormContext()\n\n if (!documentErrors?.length) return null\n\n return (\n <ContainerComponent>\n {documentErrors.map((error, index) => (\n <ErrorComponent\n // biome-ignore lint/suspicious/noArrayIndexKey: index is unique in array\n key={`error-${error.code}-${error.itemId ?? ''}-${index}`}\n {...error}\n />\n ))}\n </ContainerComponent>\n )\n}\n","import type {\n ArrayItemDef,\n ContentItem,\n FieldContentItem,\n FieldType,\n FieldValidationError,\n SectionContentItem,\n} from '@bluprynt/forms-core'\n\n/**\n * Retrieves validation errors for a specific field from the pre-indexed error map.\n *\n * Uses O(1) map lookup by `fieldId`. When `itemIndex` is omitted, returns only\n * **field-level** errors (those without an `itemIndex`). When `itemIndex` is\n * provided, returns only **item-level** errors matching the given array item index.\n *\n * @param fieldErrors - Map from field id to its validation errors.\n * @param fieldId - The numeric ID of the field to retrieve errors for.\n * @param itemIndex - Optional zero-based index of the array item. When omitted, only\n * field-level errors (where `itemIndex` is `null` / `undefined`) are returned.\n * @returns Errors for the given field (and optionally item index). Empty array if none.\n *\n * @example\n * ```ts\n * // Field-level errors only (no itemIndex on the error)\n * getFieldErrors(fieldErrors, 5)\n *\n * // Errors for the third item of array field 5\n * getFieldErrors(fieldErrors, 5, 2)\n * ```\n */\nexport const getFieldErrors = (\n fieldErrors: Map<number, FieldValidationError[]>,\n fieldId: number,\n itemIndex?: number,\n): FieldValidationError[] => {\n const errors = fieldErrors.get(fieldId) ?? []\n if (itemIndex === undefined) return errors.filter((e) => e.itemIndex == null)\n return errors.filter((e) => e.itemIndex === itemIndex)\n}\n\n/**\n * Creates a synthetic {@link FieldContentItem} that represents a single item inside an array field.\n *\n * Array fields store their per-item schema in `arrayField.item` ({@link ArrayItemDef}).\n * Components that render individual array items need a standard `FieldContentItem` shape,\n * so this helper projects the item definition into one, preserving the parent field's `id`\n * while adopting the item's `type`, `label`, `description`, `validation`, and `options`.\n *\n * @param arrayField - The array field definition whose `.item` property describes the item schema.\n * @param _index - The zero-based position of the item in the array (reserved for future use,\n * e.g. per-item overrides).\n * @returns A `FieldContentItem` that can be passed directly to a typed field component.\n *\n * @example\n * ```ts\n * const arrayField: FieldContentItem = {\n * id: 10, type: 'array', label: 'Tags',\n * item: { type: 'string', label: 'Tag' },\n * }\n *\n * const itemDef = getArrayField(arrayField, 0)\n * // → { id: 10, type: 'string', label: 'Tag', ... }\n * ```\n */\nexport const getArrayField = (arrayField: FieldContentItem, _index: number): FieldContentItem => {\n const itemDef = arrayField.item as ArrayItemDef\n return {\n id: arrayField.id,\n type: itemDef.type as FieldType,\n label: itemDef.label,\n description: itemDef.description,\n validation: itemDef.validation as FieldContentItem['validation'],\n options: itemDef.options,\n }\n}\n\n/**\n * Recursively searches content items for a section with the given id.\n *\n * Walks the content tree depth-first, checking sections and their nested\n * content. Returns the first matching {@link SectionContentItem}, or\n * `undefined` if no section with that id exists.\n *\n * @param items - The content items to search through.\n * @param sectionId - The numeric id of the section to find.\n * @returns The matching section, or `undefined` if not found.\n *\n * @example\n * ```ts\n * const section = findSection(definition.content, 42)\n * if (section) {\n * // render section.content\n * }\n * ```\n */\nexport const findSection = (items: ContentItem[], sectionId: number): SectionContentItem | undefined => {\n for (const item of items) {\n if (item.type === 'section') {\n if (item.id === sectionId) return item\n const found = findSection(item.content, sectionId)\n if (found) return found\n }\n }\n return undefined\n}\n","import { type FC, Fragment } from 'react'\n\nimport type {\n ArrayItemDef,\n ContentItem,\n FieldContentItem,\n FieldValidationError,\n FormValues,\n} from '@bluprynt/forms-core'\n\nimport type { EditorArrayItemProps, EditorComponentMap, EditorFieldProps, ViewerComponentMap } from '../types'\nimport { getArrayField, getFieldErrors } from './utils'\n\ntype FormItemsProps = {\n items: ContentItem[]\n visibilityMap: Map<number, boolean>\n values: FormValues\n fieldErrors: Map<number, FieldValidationError[]>\n components: ViewerComponentMap | EditorComponentMap\n showInlineValidation: boolean\n renderFieldProps?: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps?: (arrayField: FieldContentItem, index: number) => EditorArrayItemProps\n}\n\nexport const FormItems: FC<FormItemsProps> = ({\n items,\n visibilityMap,\n values,\n fieldErrors,\n components,\n showInlineValidation,\n renderFieldProps,\n renderArrayItemProps,\n}) => {\n const SectionComponent = components.section\n const ErrorComponent = showInlineValidation ? components.error : undefined\n\n const elements: React.ReactNode[] = []\n\n for (const item of items) {\n if (!visibilityMap.get(item.id)) continue\n\n if (item.type === 'section') {\n elements.push(\n <SectionComponent key={item.id} section={item}>\n <FormItems\n items={item.content}\n visibilityMap={visibilityMap}\n values={values}\n fieldErrors={fieldErrors}\n components={components}\n showInlineValidation={showInlineValidation}\n renderFieldProps={renderFieldProps}\n renderArrayItemProps={renderArrayItemProps}\n />\n </SectionComponent>,\n )\n } else if (item.type === 'array') {\n const errors = getFieldErrors(fieldErrors, item.id)\n const modeProps = renderFieldProps?.(item) ?? {}\n\n const ArrayComponent = components.array as React.ComponentType<Record<string, unknown>>\n const arrayValue = (values[String(item.id)] as unknown[] | undefined) ?? []\n const itemDef = item.item as ArrayItemDef\n const ItemComponent = components[\n itemDef.type as keyof Omit<ViewerComponentMap, 'array' | 'section' | 'error'>\n ] as React.ComponentType<Record<string, unknown>> | undefined\n\n elements.push(\n <ArrayComponent\n key={item.id}\n field={item}\n value={values[String(item.id)]}\n itemDef={item.item}\n errors={errors}\n {...modeProps}>\n {ItemComponent\n ? arrayValue.map((itemValue, index) => {\n const itemErrors = getFieldErrors(fieldErrors, item.id, index)\n const synthetic = getArrayField(item, index)\n const itemModeProps = renderArrayItemProps?.(item, index) ?? {}\n\n const baseProps: Record<string, unknown> = {\n field: synthetic,\n value: itemValue,\n errors: itemErrors,\n ...itemModeProps,\n }\n\n if (itemDef.type === 'select') {\n baseProps.options = itemDef.options ?? []\n }\n\n return (\n // biome-ignore lint/suspicious/noArrayIndexKey: index is unique in array\n <Fragment key={`${item.id}-${index}`}>\n <ItemComponent {...baseProps} />\n {ErrorComponent && itemErrors.length > 0 && (\n <ErrorComponent errors={itemErrors} field={synthetic} />\n )}\n </Fragment>\n )\n })\n : null}\n </ArrayComponent>,\n )\n\n if (ErrorComponent && errors.length > 0) {\n elements.push(<ErrorComponent key={`${item.id}-error`} errors={errors} field={item} />)\n }\n } else {\n const errors = getFieldErrors(fieldErrors, item.id)\n const modeProps = renderFieldProps?.(item) ?? {}\n\n const fieldProps: Record<string, unknown> = {\n field: item,\n value: values[String(item.id)],\n errors,\n ...modeProps,\n }\n\n if (item.type === 'select') fieldProps.options = (item as FieldContentItem).options ?? []\n\n const fieldType = item.type as keyof Omit<ViewerComponentMap, 'array' | 'section' | 'error'>\n const FieldComponent = components[fieldType] as React.ComponentType<Record<string, unknown>>\n\n elements.push(<FieldComponent key={item.id} {...fieldProps} />)\n\n if (ErrorComponent && errors.length > 0)\n elements.push(<ErrorComponent key={`${item.id}-error`} errors={errors} field={item} />)\n }\n }\n\n if (elements.length === 0) return null\n\n return elements\n}\n","import type { FC } from 'react'\n\nimport type { ContentItem, FieldContentItem, FieldValidationError, FormValues } from '@bluprynt/forms-core'\n\nimport { DEFAULT, ROOT } from '../constants'\nimport type { EditorArrayItemProps, EditorComponentMap, EditorFieldProps, ViewerComponentMap } from '../types'\nimport { FormItems } from './form-items'\nimport { findSection } from './utils'\n\ntype FormContentBaseProps = {\n items: ContentItem[]\n visibilityMap: Map<number, boolean>\n values: FormValues\n fieldErrors: Map<number, FieldValidationError[]>\n section?: typeof ROOT | typeof DEFAULT | number\n showInlineValidation: boolean\n}\n\ntype FormContentViewerProps = FormContentBaseProps & {\n mode: 'viewer'\n components: ViewerComponentMap\n}\n\ntype FormContentEditorProps = FormContentBaseProps & {\n mode: 'editor'\n components: EditorComponentMap\n renderFieldProps: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps: (arrayField: FieldContentItem, index: number) => EditorArrayItemProps\n}\n\nexport type FormContentProps = FormContentViewerProps | FormContentEditorProps\n\nexport const FormContent: FC<FormContentProps> = (props) => {\n const { items, visibilityMap, values, fieldErrors, section, showInlineValidation } = props\n\n const sharedProps =\n props.mode === 'editor'\n ? {\n visibilityMap,\n values,\n fieldErrors,\n components: props.components,\n showInlineValidation,\n renderFieldProps: props.renderFieldProps,\n renderArrayItemProps: props.renderArrayItemProps,\n }\n : {\n visibilityMap,\n values,\n fieldErrors,\n components: props.components,\n showInlineValidation,\n }\n\n const selectedSection = section === DEFAULT ? resolveDefaultSection(items, visibilityMap) : section\n\n if (selectedSection === undefined) return <FormItems items={items} {...sharedProps} />\n\n if (selectedSection === ROOT) {\n const nonSectionItems = items.filter((item) => item.type !== 'section')\n return <FormItems items={nonSectionItems} {...sharedProps} />\n }\n\n const foundSection = findSection(items, selectedSection)\n if (!foundSection || !visibilityMap.get(foundSection.id)) return null\n\n const Section = props.components.section\n return (\n <Section key={foundSection.id} section={foundSection}>\n <FormItems items={foundSection.content} {...sharedProps} />\n </Section>\n )\n}\n\nconst resolveDefaultSection = (\n items: ContentItem[],\n visibilityMap: Map<number, boolean>,\n): typeof ROOT | number | undefined => {\n const rootFields = items.filter((item) => item.type !== 'section')\n if (rootFields.some((item) => visibilityMap.get(item.id))) return ROOT\n\n const firstVisibleSection = items.find((item) => item.type === 'section' && visibilityMap.get(item.id) !== false)\n\n return firstVisibleSection?.id\n}\n","import { type FC, useCallback, useRef } from 'react'\n\nimport { FieldContentItem, FormDocument, FormEngine, FormValidationResult } from '@bluprynt/forms-core'\n\nimport { FormContent } from './form'\nimport { useFormContext } from './form-context'\nimport type { EditorArrayItemProps, EditorComponentMap, EditorFieldProps } from './types'\n\ntype FormEditorProps = {\n components: EditorComponentMap\n onChange: (data: FormDocument, validation: FormValidationResult) => void\n}\n\nexport const FormEditor: FC<FormEditorProps> = ({ components, onChange }) => {\n const { definition, data, visibilityMap, fieldErrors, section, engine, showInlineValidation, documentErrors } =\n useFormContext()\n\n const { renderFieldProps, renderArrayItemProps } = useEditorHandlers(engine, data, onChange)\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <FormContent\n mode=\"editor\"\n items={definition.content}\n visibilityMap={visibilityMap}\n values={data.values}\n fieldErrors={fieldErrors}\n components={components}\n section={section}\n showInlineValidation={showInlineValidation}\n renderFieldProps={renderFieldProps}\n renderArrayItemProps={renderArrayItemProps}\n />\n )\n}\n\nexport const useEditorHandlers = (\n engine: FormEngine | undefined,\n data: FormDocument | undefined,\n onChange: (data: FormDocument, validation: FormValidationResult) => void,\n): {\n renderFieldProps: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps: (field: FieldContentItem, index: number) => EditorArrayItemProps\n} => {\n // Latest ref pattern\n const stateRef = useRef({ data, onChange, engine })\n stateRef.current = { data, onChange, engine }\n\n // Per-field onChange handler\n\n const fieldOnChangeMap = useRef(new Map<string, (value: unknown) => void>())\n const getFieldOnChange = useCallback((fieldId: number): ((value: unknown) => void) => {\n const key = String(fieldId)\n\n let handler = fieldOnChangeMap.current.get(key)\n if (!handler) {\n handler = (newValue: unknown) => {\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const document: FormDocument = { ...data, values: { ...data.values, [key]: newValue } }\n\n onChange(document, engine.validate(document))\n }\n fieldOnChangeMap.current.set(key, handler)\n }\n return handler\n }, [])\n\n // Array mutation handlers\n\n const arrayHandlersMap = useRef(\n new Map<\n string,\n {\n onAddItem: () => void\n onRemoveItem: (index: number) => void\n onMoveItem: (fromIndex: number, toIndex: number) => void\n }\n >(),\n )\n const getArrayHandlers = useCallback((fieldId: number) => {\n const key = String(fieldId)\n\n let handlers = arrayHandlersMap.current.get(key)\n if (!handlers) {\n const fire = (mutate: (arr: unknown[]) => unknown[]) => {\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const items = (data.values[key] as unknown[] | undefined) ?? []\n const document: FormDocument = { ...data, values: { ...data.values, [key]: mutate([...items]) } }\n\n onChange(document, engine.validate(document))\n }\n\n handlers = {\n onAddItem: () =>\n fire((values) => {\n values.push(undefined)\n return values\n }),\n onRemoveItem: (index: number) =>\n fire((values) => {\n values.splice(index, 1)\n return values\n }),\n onMoveItem: (fromIndex: number, toIndex: number) =>\n fire((values) => {\n const [moved] = values.splice(fromIndex, 1)\n values.splice(toIndex, 0, moved)\n return values\n }),\n }\n arrayHandlersMap.current.set(key, handlers)\n }\n return handlers\n }, [])\n\n // Array item onChange handler\n\n const arrayItemOnChangeMap = useRef(new Map<string, (value: unknown) => void>())\n const getArrayItemOnChange = useCallback((fieldId: number, index: number): ((value: unknown) => void) => {\n const mapKey = `${fieldId}-${index}`\n\n let handler = arrayItemOnChangeMap.current.get(mapKey)\n if (!handler) {\n handler = (newValue: unknown) => {\n const fieldKey = String(fieldId)\n\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const items = [...((data.values[fieldKey] as unknown[] | undefined) ?? [])]\n items[index] = newValue\n\n const document: FormDocument = { ...data, values: { ...data.values, [fieldKey]: items } }\n onChange(document, engine.validate(document))\n }\n arrayItemOnChangeMap.current.set(mapKey, handler)\n }\n return handler\n }, [])\n\n return {\n renderFieldProps: (field: FieldContentItem): EditorFieldProps => {\n if (field.type === 'array') {\n return {\n onChange: getFieldOnChange(field.id),\n ...getArrayHandlers(field.id),\n }\n }\n return { onChange: getFieldOnChange(field.id) }\n },\n renderArrayItemProps: (field: FieldContentItem, index: number): EditorArrayItemProps => ({\n onChange: getArrayItemOnChange(field.id, index),\n }),\n } as const\n}\n","import { type ComponentType, type FC, type PropsWithChildren, useMemo } from 'react'\n\nimport type { FieldEntry, FieldValidationError } from '@bluprynt/forms-core'\n\nimport { useFormContext } from './form-context'\n\nexport type FieldValidationFieldEntry = {\n field: FieldEntry | undefined\n errors: FieldValidationError[]\n}\n\ntype FormFieldsValidationProps = {\n container: ComponentType<PropsWithChildren>\n field: ComponentType<PropsWithChildren<FieldValidationFieldEntry>>\n error: ComponentType<FieldValidationError>\n}\n\nexport const FormFieldsValidation: FC<FormFieldsValidationProps> = ({\n container: ContainerComponent,\n field: FieldComponent,\n error: ErrorComponent,\n}) => {\n const { engine, data, fieldErrors, visibilityMap } = useFormContext()\n\n const groups = useMemo(() => {\n if (!engine || !data || fieldErrors.size === 0) return []\n\n const result: FieldValidationFieldEntry[] = []\n\n for (const [fieldId, errors] of fieldErrors) {\n if (visibilityMap.get(fieldId) === false) continue\n\n result.push({\n field: engine.getFieldDef(fieldId),\n errors,\n })\n }\n\n return result\n }, [engine, data, fieldErrors, visibilityMap])\n\n if (groups.length === 0) return null\n\n return (\n <ContainerComponent>\n {groups.map((group) => (\n <FieldComponent key={group.field?.id} {...group}>\n {group.errors.map((error) => (\n <ErrorComponent key={`${error.fieldId}-${error.rule}-${error.itemIndex ?? ''}`} {...error} />\n ))}\n </FieldComponent>\n ))}\n </ContainerComponent>\n )\n}\n","import { useMemo } from 'react'\n\nimport type { SectionContentItem } from '@bluprynt/forms-core'\n\nimport { ROOT } from './constants'\nimport { useFormContext } from './form-context'\n\nexport type FormSectionEntry = Omit<SectionContentItem, 'id' | 'type'> & {\n id: typeof ROOT | number\n}\n\nexport const useFormSections = (\n defaultSectionTitle = 'General',\n defaultSectionDescription?: string,\n): FormSectionEntry[] => {\n const { definition, visibilityMap, data } = useFormContext()\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: invalidate section list when data changes\n return useMemo(() => {\n if (!definition) return []\n\n const result: FormSectionEntry[] = []\n\n const rootFields = definition.content.filter((item) => item.type !== 'section')\n if (rootFields.some((item) => visibilityMap.get(item.id)))\n result.push({\n id: ROOT,\n title: defaultSectionTitle,\n description: defaultSectionDescription,\n content: rootFields,\n condition: undefined,\n })\n\n for (const item of definition.content) {\n if (item.type === 'section') {\n if (visibilityMap.get(item.id) === false) continue\n\n result.push(item)\n }\n }\n\n return result\n }, [definition?.content, visibilityMap, data, defaultSectionTitle, defaultSectionDescription])\n}\n","import { type ComponentType, type FC, type PropsWithChildren } from 'react'\n\nimport { DEFAULT, ROOT } from './constants'\nimport { useFormContext } from './form-context'\nimport { type FormSectionEntry, useFormSections } from './use-form-sections'\n\nexport type { FormSectionEntry }\n\nexport type FormSectionItemProps = {\n index: number\n section: FormSectionEntry\n active: boolean\n select: () => void\n}\n\ntype FormSectionsProps = {\n container: ComponentType<PropsWithChildren>\n item: ComponentType<FormSectionItemProps>\n defaultSectionTitle?: string\n defaultSectionDescription?: string\n onSelect?: (id: typeof ROOT | typeof DEFAULT | number) => void\n}\n\nexport const FormSections: FC<FormSectionsProps> = ({\n container: Container,\n item: Item,\n defaultSectionTitle,\n defaultSectionDescription,\n onSelect,\n}) => {\n const { definition, data, documentErrors, section } = useFormContext()\n const entries = useFormSections(defaultSectionTitle, defaultSectionDescription)\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <Container>\n {entries.map((entry, index) => (\n <Item\n key={entry.id === ROOT ? 'root' : String(entry.id)}\n index={index}\n section={entry}\n active={section === DEFAULT ? index === 0 : entry.id === section}\n select={() => onSelect?.(entry.id)}\n />\n ))}\n </Container>\n )\n}\n","import type { FC } from 'react'\n\nimport { FormContent } from './form'\nimport { useFormContext } from './form-context'\nimport type { ViewerComponentMap } from './types'\n\ntype FormViewerProps = {\n components: ViewerComponentMap\n}\n\nexport const FormViewer: FC<FormViewerProps> = ({ components }) => {\n const { definition, data, visibilityMap, fieldErrors, section, showInlineValidation, documentErrors } =\n useFormContext()\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <FormContent\n mode=\"viewer\"\n items={definition.content}\n visibilityMap={visibilityMap}\n values={data.values}\n fieldErrors={fieldErrors}\n components={components}\n section={section}\n showInlineValidation={showInlineValidation}\n />\n )\n}\n"],"mappings":";;;;AAAA,MAAa,OAAsB,OAAO,OAAO;AAGjD,MAAa,UAAyB,OAAO,UAAU;;;ACuBvD,MAAM,cAAc,cAA4C,KAAA,EAAU;AAE1E,MAAa,uBAAyC;CAClD,MAAM,UAAU,WAAW,YAAY;AACvC,KAAI,CAAC,QAAS,OAAM,IAAI,MAAM,uDAAuD;AAErF,QAAO;;AAWX,MAAa,QAAuB,EAAE,YAAY,MAAM,SAAS,uBAAuB,MAAM,eAAe;CACzG,MAAM,EAAE,QAAQ,gBAAgB,qBAAqB,cAAc;AAC/D,MAAI,CAAC,WAAY,QAAO,EAAE;AAE1B,MAAI;AACA,UAAO,EAAE,QAAQ,IAAI,WAAW,WAAW,EAAE;WACxC,OAAO;AACZ,OAAI,iBAAiBA,gBAAe,QAAO,EAAE,gBAAgB,MAAM,QAAQ;AAC3E,SAAM;;IAEX,CAAC,WAAW,CAAC;CAEhB,MAAM,EAAE,eAAe,YAAY,gBAAgB,gBAAgB,cAAc;EAC7E,MAAM,gBAAgB,UAAU,OAAO,OAAO,iBAAiB,KAAK,mBAAG,IAAI,KAAsB;EACjG,MAAM,aACF,UAAU,OACJ,OAAO,SAAS,KAAK,GACpB;GACG,OAAO;GACP,6BAAa,IAAI,KAAqC;GACzD;AAEX,SAAO;GACH;GACA;GACA,gBAAgB,CAAC,GAAI,oBAAoB,EAAE,EAAG,GAAI,YAAY,kBAAkB,EAAE,CAAE;GACpF,aAAa,YAAY,+BAAe,IAAI,KAAqC;GACpF;IACF;EAAC;EAAQ;EAAM;EAAiB,CAAC;CAEpC,MAAM,QAA0B;EAC5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH;AAED,QAAO,oBAAC,YAAY,UAAb;EAA6B;EAAQ;EAAgC,CAAA;;;;AC1EhF,MAAa,0BAA2D,EACpE,WAAW,oBACX,OAAO,qBACL;CACF,MAAM,EAAE,mBAAmB,gBAAgB;AAE3C,KAAI,CAAC,gBAAgB,OAAQ,QAAO;AAEpC,QACI,oBAAC,oBAAD,EAAA,UACK,eAAe,KAAK,OAAO,UACxB,oBAAC,gBAAD,EAGI,GAAI,OACN,EAFO,SAAS,MAAM,KAAK,GAAG,MAAM,UAAU,GAAG,GAAG,QAEpD,CACJ,EACe,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACG7B,MAAa,kBACT,aACA,SACA,cACyB;CACzB,MAAM,SAAS,YAAY,IAAI,QAAQ,IAAI,EAAE;AAC7C,KAAI,cAAc,KAAA,EAAW,QAAO,OAAO,QAAQ,MAAM,EAAE,aAAa,KAAK;AAC7E,QAAO,OAAO,QAAQ,MAAM,EAAE,cAAc,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;AA2B1D,MAAa,iBAAiB,YAA8B,WAAqC;CAC7F,MAAM,UAAU,WAAW;AAC3B,QAAO;EACH,IAAI,WAAW;EACf,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,aAAa,QAAQ;EACrB,YAAY,QAAQ;EACpB,SAAS,QAAQ;EACpB;;;;;;;;;;;;;;;;;;;;;AAsBL,MAAa,eAAe,OAAsB,cAAsD;AACpG,MAAK,MAAM,QAAQ,MACf,KAAI,KAAK,SAAS,WAAW;AACzB,MAAI,KAAK,OAAO,UAAW,QAAO;EAClC,MAAM,QAAQ,YAAY,KAAK,SAAS,UAAU;AAClD,MAAI,MAAO,QAAO;;;;;AC7E9B,MAAa,aAAiC,EAC1C,OACA,eACA,QACA,aACA,YACA,sBACA,kBACA,2BACE;CACF,MAAM,mBAAmB,WAAW;CACpC,MAAM,iBAAiB,uBAAuB,WAAW,QAAQ,KAAA;CAEjE,MAAM,WAA8B,EAAE;AAEtC,MAAK,MAAM,QAAQ,OAAO;AACtB,MAAI,CAAC,cAAc,IAAI,KAAK,GAAG,CAAE;AAEjC,MAAI,KAAK,SAAS,UACd,UAAS,KACL,oBAAC,kBAAD;GAAgC,SAAS;aACrC,oBAAC,WAAD;IACI,OAAO,KAAK;IACG;IACP;IACK;IACD;IACU;IACJ;IACI;IACxB,CAAA;GACa,EAXI,KAAK,GAWT,CACtB;WACM,KAAK,SAAS,SAAS;GAC9B,MAAM,SAAS,eAAe,aAAa,KAAK,GAAG;GACnD,MAAM,YAAY,mBAAmB,KAAK,IAAI,EAAE;GAEhD,MAAM,iBAAiB,WAAW;GAClC,MAAM,aAAc,OAAO,OAAO,KAAK,GAAG,KAA+B,EAAE;GAC3E,MAAM,UAAU,KAAK;GACrB,MAAM,gBAAgB,WAClB,QAAQ;AAGZ,YAAS,KACL,oBAAC,gBAAD;IAEI,OAAO;IACP,OAAO,OAAO,OAAO,KAAK,GAAG;IAC7B,SAAS,KAAK;IACN;IACR,GAAI;cACH,gBACK,WAAW,KAAK,WAAW,UAAU;KACjC,MAAM,aAAa,eAAe,aAAa,KAAK,IAAI,MAAM;KAC9D,MAAM,YAAY,cAAc,MAAM,MAAM;KAG5C,MAAM,YAAqC;MACvC,OAAO;MACP,OAAO;MACP,QAAQ;MACR,GANkB,uBAAuB,MAAM,MAAM,IAAI,EAAE;MAO9D;AAED,SAAI,QAAQ,SAAS,SACjB,WAAU,UAAU,QAAQ,WAAW,EAAE;AAG7C,YAEI,qBAAC,UAAD,EAAA,UAAA,CACI,oBAAC,eAAD,EAAe,GAAI,WAAa,CAAA,EAC/B,kBAAkB,WAAW,SAAS,KACnC,oBAAC,gBAAD;MAAgB,QAAQ;MAAY,OAAO;MAAa,CAAA,CAErD,EAAA,EALI,GAAG,KAAK,GAAG,GAAG,QAKlB;MAEjB,GACF;IACO,EAlCR,KAAK,GAkCG,CACpB;AAED,OAAI,kBAAkB,OAAO,SAAS,EAClC,UAAS,KAAK,oBAAC,gBAAD;IAAiD;IAAQ,OAAO;IAAQ,EAAnD,GAAG,KAAK,GAAG,QAAwC,CAAC;SAExF;GACH,MAAM,SAAS,eAAe,aAAa,KAAK,GAAG;GACnD,MAAM,YAAY,mBAAmB,KAAK,IAAI,EAAE;GAEhD,MAAM,aAAsC;IACxC,OAAO;IACP,OAAO,OAAO,OAAO,KAAK,GAAG;IAC7B;IACA,GAAG;IACN;AAED,OAAI,KAAK,SAAS,SAAU,YAAW,UAAW,KAA0B,WAAW,EAAE;GAGzF,MAAM,iBAAiB,WADL,KAAK;AAGvB,YAAS,KAAK,oBAAC,gBAAD,EAA8B,GAAI,YAAc,EAA3B,KAAK,GAAsB,CAAC;AAE/D,OAAI,kBAAkB,OAAO,SAAS,EAClC,UAAS,KAAK,oBAAC,gBAAD;IAAiD;IAAQ,OAAO;IAAQ,EAAnD,GAAG,KAAK,GAAG,QAAwC,CAAC;;;AAInG,KAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAO;;;;ACvGX,MAAa,eAAqC,UAAU;CACxD,MAAM,EAAE,OAAO,eAAe,QAAQ,aAAa,SAAS,yBAAyB;CAErF,MAAM,cACF,MAAM,SAAS,WACT;EACI;EACA;EACA;EACA,YAAY,MAAM;EAClB;EACA,kBAAkB,MAAM;EACxB,sBAAsB,MAAM;EAC/B,GACD;EACI;EACA;EACA;EACA,YAAY,MAAM;EAClB;EACH;CAEX,MAAM,kBAAkB,YAAY,UAAU,sBAAsB,OAAO,cAAc,GAAG;AAE5F,KAAI,oBAAoB,KAAA,EAAW,QAAO,oBAAC,WAAD;EAAkB;EAAO,GAAI;EAAe,CAAA;AAEtF,KAAI,oBAAoB,KAEpB,QAAO,oBAAC,WAAD;EAAW,OADM,MAAM,QAAQ,SAAS,KAAK,SAAS,UAAU;EAC7B,GAAI;EAAe,CAAA;CAGjE,MAAM,eAAe,YAAY,OAAO,gBAAgB;AACxD,KAAI,CAAC,gBAAgB,CAAC,cAAc,IAAI,aAAa,GAAG,CAAE,QAAO;CAEjE,MAAM,UAAU,MAAM,WAAW;AACjC,QACI,oBAAC,SAAD;EAA+B,SAAS;YACpC,oBAAC,WAAD;GAAW,OAAO,aAAa;GAAS,GAAI;GAAe,CAAA;EACrD,EAFI,aAAa,GAEjB;;AAIlB,MAAM,yBACF,OACA,kBACmC;AAEnC,KADmB,MAAM,QAAQ,SAAS,KAAK,SAAS,UAAU,CACnD,MAAM,SAAS,cAAc,IAAI,KAAK,GAAG,CAAC,CAAE,QAAO;AAIlE,QAF4B,MAAM,MAAM,SAAS,KAAK,SAAS,aAAa,cAAc,IAAI,KAAK,GAAG,KAAK,MAAM,EAErF;;;;ACtEhC,MAAa,cAAmC,EAAE,YAAY,eAAe;CACzE,MAAM,EAAE,YAAY,MAAM,eAAe,aAAa,SAAS,QAAQ,sBAAsB,mBACzF,gBAAgB;CAEpB,MAAM,EAAE,kBAAkB,yBAAyB,kBAAkB,QAAQ,MAAM,SAAS;AAE5F,KAAI,CAAC,cAAc,CAAC,QAAS,kBAAkB,eAAe,SAAS,EAAI,QAAO;AAElF,QACI,oBAAC,aAAD;EACI,MAAK;EACL,OAAO,WAAW;EACH;EACf,QAAQ,KAAK;EACA;EACD;EACH;EACa;EACJ;EACI;EACxB,CAAA;;AAIV,MAAa,qBACT,QACA,MACA,aAIC;CAED,MAAM,WAAW,OAAO;EAAE;EAAM;EAAU;EAAQ,CAAC;AACnD,UAAS,UAAU;EAAE;EAAM;EAAU;EAAQ;CAI7C,MAAM,mBAAmB,uBAAO,IAAI,KAAuC,CAAC;CAC5E,MAAM,mBAAmB,aAAa,YAAgD;EAClF,MAAM,MAAM,OAAO,QAAQ;EAE3B,IAAI,UAAU,iBAAiB,QAAQ,IAAI,IAAI;AAC/C,MAAI,CAAC,SAAS;AACV,cAAW,aAAsB;IAC7B,MAAM,EAAE,MAAM,UAAU,WAAW,SAAS;AAC5C,QAAI,CAAC,QAAQ,CAAC,OAAQ;IAEtB,MAAM,WAAyB;KAAE,GAAG;KAAM,QAAQ;MAAE,GAAG,KAAK;OAAS,MAAM;MAAU;KAAE;AAEvF,aAAS,UAAU,OAAO,SAAS,SAAS,CAAC;;AAEjD,oBAAiB,QAAQ,IAAI,KAAK,QAAQ;;AAE9C,SAAO;IACR,EAAE,CAAC;CAIN,MAAM,mBAAmB,uBACrB,IAAI,KAOD,CACN;CACD,MAAM,mBAAmB,aAAa,YAAoB;EACtD,MAAM,MAAM,OAAO,QAAQ;EAE3B,IAAI,WAAW,iBAAiB,QAAQ,IAAI,IAAI;AAChD,MAAI,CAAC,UAAU;GACX,MAAM,QAAQ,WAA0C;IACpD,MAAM,EAAE,MAAM,UAAU,WAAW,SAAS;AAC5C,QAAI,CAAC,QAAQ,CAAC,OAAQ;IAEtB,MAAM,QAAS,KAAK,OAAO,QAAkC,EAAE;IAC/D,MAAM,WAAyB;KAAE,GAAG;KAAM,QAAQ;MAAE,GAAG,KAAK;OAAS,MAAM,OAAO,CAAC,GAAG,MAAM,CAAC;MAAE;KAAE;AAEjG,aAAS,UAAU,OAAO,SAAS,SAAS,CAAC;;AAGjD,cAAW;IACP,iBACI,MAAM,WAAW;AACb,YAAO,KAAK,KAAA,EAAU;AACtB,YAAO;MACT;IACN,eAAe,UACX,MAAM,WAAW;AACb,YAAO,OAAO,OAAO,EAAE;AACvB,YAAO;MACT;IACN,aAAa,WAAmB,YAC5B,MAAM,WAAW;KACb,MAAM,CAAC,SAAS,OAAO,OAAO,WAAW,EAAE;AAC3C,YAAO,OAAO,SAAS,GAAG,MAAM;AAChC,YAAO;MACT;IACT;AACD,oBAAiB,QAAQ,IAAI,KAAK,SAAS;;AAE/C,SAAO;IACR,EAAE,CAAC;CAIN,MAAM,uBAAuB,uBAAO,IAAI,KAAuC,CAAC;CAChF,MAAM,uBAAuB,aAAa,SAAiB,UAA8C;EACrG,MAAM,SAAS,GAAG,QAAQ,GAAG;EAE7B,IAAI,UAAU,qBAAqB,QAAQ,IAAI,OAAO;AACtD,MAAI,CAAC,SAAS;AACV,cAAW,aAAsB;IAC7B,MAAM,WAAW,OAAO,QAAQ;IAEhC,MAAM,EAAE,MAAM,UAAU,WAAW,SAAS;AAC5C,QAAI,CAAC,QAAQ,CAAC,OAAQ;IAEtB,MAAM,QAAQ,CAAC,GAAK,KAAK,OAAO,aAAuC,EAAE,CAAE;AAC3E,UAAM,SAAS;IAEf,MAAM,WAAyB;KAAE,GAAG;KAAM,QAAQ;MAAE,GAAG,KAAK;OAAS,WAAW;MAAO;KAAE;AACzF,aAAS,UAAU,OAAO,SAAS,SAAS,CAAC;;AAEjD,wBAAqB,QAAQ,IAAI,QAAQ,QAAQ;;AAErD,SAAO;IACR,EAAE,CAAC;AAEN,QAAO;EACH,mBAAmB,UAA8C;AAC7D,OAAI,MAAM,SAAS,QACf,QAAO;IACH,UAAU,iBAAiB,MAAM,GAAG;IACpC,GAAG,iBAAiB,MAAM,GAAG;IAChC;AAEL,UAAO,EAAE,UAAU,iBAAiB,MAAM,GAAG,EAAE;;EAEnD,uBAAuB,OAAyB,WAAyC,EACrF,UAAU,qBAAqB,MAAM,IAAI,MAAM,EAClD;EACJ;;;;AC7IL,MAAa,wBAAuD,EAChE,WAAW,oBACX,OAAO,gBACP,OAAO,qBACL;CACF,MAAM,EAAE,QAAQ,MAAM,aAAa,kBAAkB,gBAAgB;CAErE,MAAM,SAAS,cAAc;AACzB,MAAI,CAAC,UAAU,CAAC,QAAQ,YAAY,SAAS,EAAG,QAAO,EAAE;EAEzD,MAAM,SAAsC,EAAE;AAE9C,OAAK,MAAM,CAAC,SAAS,WAAW,aAAa;AACzC,OAAI,cAAc,IAAI,QAAQ,KAAK,MAAO;AAE1C,UAAO,KAAK;IACR,OAAO,OAAO,YAAY,QAAQ;IAClC;IACH,CAAC;;AAGN,SAAO;IACR;EAAC;EAAQ;EAAM;EAAa;EAAc,CAAC;AAE9C,KAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QACI,oBAAC,oBAAD,EAAA,UACK,OAAO,KAAK,UACT,oBAAC,gBAAD;EAAsC,GAAI;YACrC,MAAM,OAAO,KAAK,UACf,oBAAC,gBAAD,EAAgF,GAAI,OAAS,EAAxE,GAAG,MAAM,QAAQ,GAAG,MAAM,KAAK,GAAG,MAAM,aAAa,KAAmB,CAC/F;EACW,EAJI,MAAM,OAAO,GAIjB,CACnB,EACe,CAAA;;;;ACzC7B,MAAa,mBACT,sBAAsB,WACtB,8BACqB;CACrB,MAAM,EAAE,YAAY,eAAe,SAAS,gBAAgB;AAG5D,QAAO,cAAc;AACjB,MAAI,CAAC,WAAY,QAAO,EAAE;EAE1B,MAAM,SAA6B,EAAE;EAErC,MAAM,aAAa,WAAW,QAAQ,QAAQ,SAAS,KAAK,SAAS,UAAU;AAC/E,MAAI,WAAW,MAAM,SAAS,cAAc,IAAI,KAAK,GAAG,CAAC,CACrD,QAAO,KAAK;GACR,IAAI;GACJ,OAAO;GACP,aAAa;GACb,SAAS;GACT,WAAW,KAAA;GACd,CAAC;AAEN,OAAK,MAAM,QAAQ,WAAW,QAC1B,KAAI,KAAK,SAAS,WAAW;AACzB,OAAI,cAAc,IAAI,KAAK,GAAG,KAAK,MAAO;AAE1C,UAAO,KAAK,KAAK;;AAIzB,SAAO;IACR;EAAC,YAAY;EAAS;EAAe;EAAM;EAAqB;EAA0B,CAAC;;;;ACnBlG,MAAa,gBAAuC,EAChD,WAAW,WACX,MAAM,MACN,qBACA,2BACA,eACE;CACF,MAAM,EAAE,YAAY,MAAM,gBAAgB,YAAY,gBAAgB;CACtE,MAAM,UAAU,gBAAgB,qBAAqB,0BAA0B;AAE/E,KAAI,CAAC,cAAc,CAAC,QAAS,kBAAkB,eAAe,SAAS,EAAI,QAAO;AAElF,QACI,oBAAC,WAAD,EAAA,UACK,QAAQ,KAAK,OAAO,UACjB,oBAAC,MAAD;EAEW;EACP,SAAS;EACT,QAAQ,YAAY,UAAU,UAAU,IAAI,MAAM,OAAO;EACzD,cAAc,WAAW,MAAM,GAAG;EACpC,EALO,MAAM,OAAO,OAAO,SAAS,OAAO,MAAM,GAAG,CAKpD,CACJ,EACM,CAAA;;;;ACpCpB,MAAa,cAAmC,EAAE,iBAAiB;CAC/D,MAAM,EAAE,YAAY,MAAM,eAAe,aAAa,SAAS,sBAAsB,mBACjF,gBAAgB;AAEpB,KAAI,CAAC,cAAc,CAAC,QAAS,kBAAkB,eAAe,SAAS,EAAI,QAAO;AAElF,QACI,oBAAC,aAAD;EACI,MAAK;EACL,OAAO,WAAW;EACH;EACf,QAAQ,KAAK;EACA;EACD;EACH;EACa;EACxB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["DocumentError"],"sources":["../src/constants.ts","../src/form-context.tsx","../src/form-document-validation.tsx","../src/form/utils.ts","../src/form/form-items.tsx","../src/form/form-content.tsx","../src/form-editor.tsx","../src/form-fields-validation.tsx","../src/use-form-sections.ts","../src/form-sections.tsx","../src/form-viewer.tsx"],"sourcesContent":["export const ROOT: unique symbol = Symbol('ROOT')\nexport type ROOT = typeof ROOT\n\nexport const DEFAULT: unique symbol = Symbol('DEFAULT')\nexport type DEFAULT = typeof DEFAULT\n","import { createContext, type FC, type ReactNode, useContext, useMemo } from 'react'\n\nimport {\n DocumentError,\n DocumentValidationError,\n FieldValidationError,\n FormDefinition,\n FormDocument,\n FormEngine,\n FormValidationResult,\n} from '@bluprynt/forms-core'\n\nimport type { DEFAULT, ROOT } from './constants'\n\ntype FormContextValue = {\n definition: FormDefinition | undefined\n data: FormDocument | undefined\n engine: FormEngine | undefined\n visibilityMap: Map<number, boolean>\n validation: FormValidationResult | undefined\n documentErrors: readonly DocumentValidationError[] | undefined\n fieldErrors: Map<number, FieldValidationError[]>\n section: typeof ROOT | typeof DEFAULT | number | undefined\n showInlineValidation: boolean\n}\n\nconst FormContext = createContext<FormContextValue | undefined>(undefined)\n\nexport const useFormContext = (): FormContextValue => {\n const context = useContext(FormContext)\n if (!context) throw new Error('useFormContext must be used within a <Form> provider')\n\n return context\n}\n\ntype FormProps = {\n definition?: FormDefinition\n data?: FormDocument\n section?: typeof ROOT | typeof DEFAULT | number\n showInlineValidation?: boolean\n children: ReactNode\n}\n\nexport const Form: FC<FormProps> = ({ definition, data, section, showInlineValidation = true, children }) => {\n const { engine, documentErrors: definitionErrors } = useMemo(() => {\n if (!definition) return {}\n\n try {\n return { engine: new FormEngine(definition) }\n } catch (error) {\n if (error instanceof DocumentError) return { documentErrors: error.errors }\n throw error\n }\n }, [definition])\n\n const { visibilityMap, validation, documentErrors, fieldErrors } = useMemo(() => {\n const visibilityMap = engine && data ? engine.getVisibilityMap(data) : new Map<number, boolean>()\n const validation =\n engine && data\n ? engine.validate(data)\n : ({\n valid: true,\n fieldErrors: new Map<number, FieldValidationError[]>(),\n } satisfies FormValidationResult)\n\n return {\n visibilityMap,\n validation,\n documentErrors: [...(definitionErrors ?? []), ...(validation?.documentErrors ?? [])],\n fieldErrors: validation?.fieldErrors ?? new Map<number, FieldValidationError[]>(),\n } as const\n }, [engine, data, definitionErrors])\n\n const value: FormContextValue = {\n definition,\n data,\n engine,\n visibilityMap,\n validation,\n documentErrors,\n fieldErrors,\n section,\n showInlineValidation,\n } as const\n\n return <FormContext.Provider value={value}>{children}</FormContext.Provider>\n}\n","import type { ComponentType, FC, PropsWithChildren } from 'react'\n\nimport type { DocumentValidationError } from '@bluprynt/forms-core'\n\nimport { useFormContext } from './form-context'\n\ntype FormDocumentValidationProps = {\n container: ComponentType<PropsWithChildren>\n error: ComponentType<DocumentValidationError>\n}\n\nexport const FormDocumentValidation: FC<FormDocumentValidationProps> = ({\n container: ContainerComponent,\n error: ErrorComponent,\n}) => {\n const { documentErrors } = useFormContext()\n\n if (!documentErrors?.length) return null\n\n return (\n <ContainerComponent>\n {documentErrors.map((error, index) => (\n <ErrorComponent\n // biome-ignore lint/suspicious/noArrayIndexKey: index is unique in array\n key={`error-${error.code}-${error.itemId ?? ''}-${index}`}\n {...error}\n />\n ))}\n </ContainerComponent>\n )\n}\n","import type {\n AnyFieldContentItem,\n ArrayItemDef,\n ArrayObjItemDef,\n ContentItem,\n FieldContentItem,\n FieldValidationError,\n SectionContentItem,\n} from '@bluprynt/forms-core'\n\n/**\n * Retrieves validation errors for a specific field from the pre-indexed error map.\n *\n * Uses O(1) map lookup by `fieldId`. When `itemIndex` is omitted, returns only\n * **field-level** errors (those without an `itemIndex`). When `itemIndex` is\n * provided, returns only **item-level** errors matching the given array item index.\n *\n * @param fieldErrors - Map from field id to its validation errors.\n * @param fieldId - The numeric ID of the field to retrieve errors for.\n * @param itemIndex - Optional zero-based index of the array item. When omitted, only\n * field-level errors (where `itemIndex` is `null` / `undefined`) are returned.\n * @returns Errors for the given field (and optionally item index). Empty array if none.\n *\n * @example\n * ```ts\n * // Field-level errors only (no itemIndex on the error)\n * getFieldErrors(fieldErrors, 5)\n *\n * // Errors for the third item of array field 5\n * getFieldErrors(fieldErrors, 5, 2)\n * ```\n */\nexport const getFieldErrors = (\n fieldErrors: Map<number, FieldValidationError[]>,\n fieldId: number,\n itemIndex?: number,\n): FieldValidationError[] => {\n const errors = fieldErrors.get(fieldId) ?? []\n if (itemIndex === undefined) return errors.filter((e) => e.itemIndex == null)\n return errors.filter((e) => e.itemIndex === itemIndex)\n}\n\n/**\n * Creates a synthetic {@link FieldContentItem} that represents a single item inside an array field.\n *\n * Array fields store their per-item schema in `arrayField.item` ({@link ArrayItemDef}).\n * Components that render individual array items need a standard `FieldContentItem` shape,\n * so this helper projects the item definition into one, preserving the parent field's `id`\n * while adopting the item's `type`, `label`, authoring metadata, `validation`, and `options`.\n *\n * A `static` item projects to a `StaticFieldContentItem`, so the return type is\n * the wider {@link AnyFieldContentItem}.\n *\n * @param arrayField - The array field definition whose `.item` property describes the item schema.\n * @param _index - The zero-based position of the item in the array (reserved for future use,\n * e.g. per-item overrides).\n * @returns An `AnyFieldContentItem` that can be passed directly to a typed field component.\n *\n * @example\n * ```ts\n * const arrayField: FieldContentItem = {\n * id: 10, type: 'array', label: 'Tags',\n * item: { type: 'string', label: 'Tag' },\n * }\n *\n * const itemDef = getArrayField(arrayField, 0)\n * // → { id: 10, type: 'string', label: 'Tag', ... }\n * ```\n */\nexport const getArrayField = (arrayField: FieldContentItem, _index: number): AnyFieldContentItem => {\n const itemDef = arrayField.item as ArrayItemDef\n const metadata = {\n description: itemDef.description,\n placeholder: itemDef.placeholder,\n answer_guidelines: itemDef.answer_guidelines,\n reference_id: itemDef.reference_id,\n }\n\n if (itemDef.type === 'static') {\n return { id: arrayField.id, type: 'static', text: itemDef.text, label: itemDef.label, ...metadata }\n }\n\n return {\n id: arrayField.id,\n type: itemDef.type,\n label: itemDef.label,\n ...metadata,\n validation: itemDef.validation as FieldContentItem['validation'],\n options: itemDef.options,\n }\n}\n\n/**\n * Creates a {@link AnyFieldContentItem} representing one sub-field of an `array_obj` field.\n *\n * Unlike an `array` item, a sub-field carries its own id, so the projection keeps it:\n * it is both the key its value is stored under inside each row and a stable React key.\n *\n * @param subField - The sub-field definition taken from the field's `items` list.\n * @returns An `AnyFieldContentItem` that can be passed directly to a typed field component.\n */\nexport const getArrayObjField = (subField: ArrayObjItemDef): AnyFieldContentItem => {\n const metadata = {\n description: subField.description,\n placeholder: subField.placeholder,\n answer_guidelines: subField.answer_guidelines,\n reference_id: subField.reference_id,\n }\n\n if (subField.type === 'static') {\n return { id: subField.id, type: 'static', text: subField.text, label: subField.label, ...metadata }\n }\n\n return {\n id: subField.id,\n type: subField.type,\n label: subField.label,\n ...metadata,\n validation: subField.validation as FieldContentItem['validation'],\n options: subField.options,\n }\n}\n\n/**\n * Retrieves the validation errors for one sub-field of one row of an `array_obj` field.\n *\n * Errors for an `array_obj` are all stored under the container's id; the row is\n * identified by `itemIndex` and the sub-field by `itemFieldId`.\n *\n * @param fieldErrors - Map from field id to its validation errors.\n * @param fieldId - The numeric id of the `array_obj` field.\n * @param index - Zero-based row index.\n * @param subFieldId - The numeric id of the sub-field.\n * @returns Errors for that cell. Empty array if none.\n */\nexport const getArrayObjItemErrors = (\n fieldErrors: Map<number, FieldValidationError[]>,\n fieldId: number,\n index: number,\n subFieldId: number,\n): FieldValidationError[] =>\n (fieldErrors.get(fieldId) ?? []).filter((e) => e.itemIndex === index && e.itemFieldId === subFieldId)\n\n/**\n * Retrieves the row-level validation errors for one row of an `array_obj` field --\n * those carrying an `itemIndex` but no `itemFieldId`, such as a row that is not an object.\n */\nexport const getArrayObjRowErrors = (\n fieldErrors: Map<number, FieldValidationError[]>,\n fieldId: number,\n index: number,\n): FieldValidationError[] =>\n (fieldErrors.get(fieldId) ?? []).filter((e) => e.itemIndex === index && e.itemFieldId == null)\n\n/**\n * Recursively searches content items for a section with the given id.\n *\n * Walks the content tree depth-first, checking sections and their nested\n * content. Returns the first matching {@link SectionContentItem}, or\n * `undefined` if no section with that id exists.\n *\n * @param items - The content items to search through.\n * @param sectionId - The numeric id of the section to find.\n * @returns The matching section, or `undefined` if not found.\n *\n * @example\n * ```ts\n * const section = findSection(definition.content, 42)\n * if (section) {\n * // render section.content\n * }\n * ```\n */\nexport const findSection = (items: ContentItem[], sectionId: number): SectionContentItem | undefined => {\n for (const item of items) {\n if (item.type === 'section') {\n if (item.id === sectionId) return item\n const found = findSection(item.content, sectionId)\n if (found) return found\n }\n }\n return undefined\n}\n","import { type FC, Fragment } from 'react'\n\nimport type {\n AnyFieldContentItem,\n ArrayItemDef,\n ArrayObjRow,\n ContentItem,\n FieldContentItem,\n FieldValidationError,\n FormSuggestions,\n FormValues,\n} from '@bluprynt/forms-core'\n\nimport type {\n EditorArrayItemProps,\n EditorArrayObjItemProps,\n EditorComponentMap,\n EditorFieldProps,\n ViewerComponentMap,\n} from '../types'\nimport { getArrayField, getArrayObjField, getArrayObjItemErrors, getArrayObjRowErrors, getFieldErrors } from './utils'\n\ntype AnyComponent = React.ComponentType<Record<string, unknown>> | undefined\n\ntype FormItemsProps = {\n items: ContentItem[]\n visibilityMap: Map<number, boolean>\n values: FormValues\n suggestions?: FormSuggestions\n fieldErrors: Map<number, FieldValidationError[]>\n components: ViewerComponentMap | EditorComponentMap\n showInlineValidation: boolean\n renderFieldProps?: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps?: (arrayField: FieldContentItem, index: number) => EditorArrayItemProps\n renderArrayObjItemProps?: (\n arrayField: FieldContentItem,\n index: number,\n subFieldId: number,\n ) => EditorArrayObjItemProps\n}\n\n/** Looks up the component for a value field type. Optional map keys may be absent. */\nconst componentFor = (components: ViewerComponentMap | EditorComponentMap, type: string): AnyComponent =>\n components[type as keyof Omit<ViewerComponentMap, 'array' | 'section' | 'error'>] as AnyComponent\n\n/** `select` and `multiselect` components are the only ones that receive injected options. */\nconst withOptions = (props: Record<string, unknown>, def: { type: string; options?: unknown }): void => {\n if (def.type === 'select' || def.type === 'multiselect') props.options = def.options ?? []\n}\n\nexport const FormItems: FC<FormItemsProps> = ({\n items,\n visibilityMap,\n values,\n suggestions,\n fieldErrors,\n components,\n showInlineValidation,\n renderFieldProps,\n renderArrayItemProps,\n renderArrayObjItemProps,\n}) => {\n const SectionComponent = components.section\n const ErrorComponent = showInlineValidation ? components.error : undefined\n\n const elements: React.ReactNode[] = []\n\n for (const item of items) {\n if (!visibilityMap.get(item.id)) continue\n\n if (item.type === 'section') {\n elements.push(\n <SectionComponent key={item.id} section={item}>\n <FormItems\n items={item.content}\n visibilityMap={visibilityMap}\n values={values}\n suggestions={suggestions}\n fieldErrors={fieldErrors}\n components={components}\n showInlineValidation={showInlineValidation}\n renderFieldProps={renderFieldProps}\n renderArrayItemProps={renderArrayItemProps}\n renderArrayObjItemProps={renderArrayObjItemProps}\n />\n </SectionComponent>,\n )\n } else if (item.type === 'array') {\n const errors = getFieldErrors(fieldErrors, item.id)\n const modeProps = renderFieldProps?.(item) ?? {}\n\n const ArrayComponent = components.array as React.ComponentType<Record<string, unknown>>\n const arrayValue = (values[String(item.id)] as unknown[] | undefined) ?? []\n const itemDef = item.item as ArrayItemDef\n const ItemComponent = componentFor(components, itemDef.type)\n\n const arrayProps: Record<string, unknown> = {\n field: item,\n value: values[String(item.id)],\n itemDef: item.item,\n errors,\n ...modeProps,\n }\n\n const arraySuggestion = suggestions?.[String(item.id)]\n if (arraySuggestion) arrayProps.suggestion = arraySuggestion\n\n elements.push(\n <ArrayComponent key={item.id} {...arrayProps}>\n {ItemComponent\n ? arrayValue.map((itemValue, index) => {\n const synthetic = getArrayField(item, index)\n\n // A static item holds no value: it gets the field and nothing else.\n if (synthetic.type === 'static') {\n return (\n // biome-ignore lint/suspicious/noArrayIndexKey: index is unique in array\n <Fragment key={`${item.id}-${index}`}>\n <ItemComponent field={synthetic} />\n </Fragment>\n )\n }\n\n const itemErrors = getFieldErrors(fieldErrors, item.id, index)\n const itemModeProps = renderArrayItemProps?.(item, index) ?? {}\n\n const baseProps: Record<string, unknown> = {\n field: synthetic,\n value: itemValue,\n errors: itemErrors,\n ...itemModeProps,\n }\n\n withOptions(baseProps, itemDef)\n\n return (\n // biome-ignore lint/suspicious/noArrayIndexKey: index is unique in array\n <Fragment key={`${item.id}-${index}`}>\n <ItemComponent {...baseProps} />\n {ErrorComponent && itemErrors.length > 0 && (\n <ErrorComponent errors={itemErrors} field={synthetic as FieldContentItem} />\n )}\n </Fragment>\n )\n })\n : null}\n </ArrayComponent>,\n )\n\n if (ErrorComponent && errors.length > 0) {\n elements.push(<ErrorComponent key={`${item.id}-error`} errors={errors} field={item} />)\n }\n } else if (item.type === 'array_obj') {\n // Optional map key, like the other late additions: render nothing rather than crash.\n const ArrayObjComponent = components.array_obj as AnyComponent\n if (!ArrayObjComponent) continue\n\n const itemsDef = item.items ?? []\n const rows = (values[String(item.id)] as ArrayObjRow[] | undefined) ?? []\n\n // Row-level errors (a row that is not an object) have no cell to land\n // on, so they join the field-level ones.\n const errors = [\n ...getFieldErrors(fieldErrors, item.id),\n ...rows.flatMap((_row, index) => getArrayObjRowErrors(fieldErrors, item.id, index)),\n ]\n const modeProps = renderFieldProps?.(item) ?? {}\n\n const arrayProps: Record<string, unknown> = {\n field: item,\n value: values[String(item.id)],\n itemsDef,\n // Resolved here so every component does not repeat the default.\n kind: item.kind ?? 'list',\n errors,\n ...modeProps,\n }\n\n const arraySuggestion = suggestions?.[String(item.id)]\n if (arraySuggestion) arrayProps.suggestion = arraySuggestion\n\n // children[rowIndex][subFieldIndex], aligned with itemsDef so a\n // component can lay the rows out as a table.\n const children = rows.map((row, index) =>\n itemsDef.map((subField) => {\n const key = `${item.id}-${index}-${subField.id}`\n const SubComponent = componentFor(components, subField.type)\n if (!SubComponent) return <Fragment key={key} />\n\n const synthetic = getArrayObjField(subField)\n\n if (subField.type === 'static') {\n return (\n <Fragment key={key}>\n <SubComponent field={synthetic} />\n </Fragment>\n )\n }\n\n const cellErrors = getArrayObjItemErrors(fieldErrors, item.id, index, subField.id)\n const cellModeProps = renderArrayObjItemProps?.(item, index, subField.id) ?? {}\n\n const cellProps: Record<string, unknown> = {\n field: synthetic,\n value: row?.[String(subField.id)],\n errors: cellErrors,\n ...cellModeProps,\n }\n\n withOptions(cellProps, subField)\n\n return (\n <Fragment key={key}>\n <SubComponent {...cellProps} />\n {ErrorComponent && cellErrors.length > 0 && (\n <ErrorComponent errors={cellErrors} field={synthetic as FieldContentItem} />\n )}\n </Fragment>\n )\n }),\n )\n\n elements.push(\n <ArrayObjComponent key={item.id} {...arrayProps}>\n {children}\n </ArrayObjComponent>,\n )\n\n if (ErrorComponent && errors.length > 0) {\n elements.push(<ErrorComponent key={`${item.id}-error`} errors={errors} field={item} />)\n }\n } else if (item.type === 'static') {\n // Static blocks hold no value: no errors, no suggestion, nothing to change.\n const StaticComponent = components.static as AnyComponent\n if (!StaticComponent) continue\n\n elements.push(<StaticComponent key={item.id} field={item} />)\n } else {\n const errors = getFieldErrors(fieldErrors, item.id)\n const modeProps = renderFieldProps?.(item) ?? {}\n\n const fieldProps: Record<string, unknown> = {\n field: item,\n value: values[String(item.id)],\n errors,\n ...modeProps,\n }\n\n const suggestion = suggestions?.[String(item.id)]\n if (suggestion) fieldProps.suggestion = suggestion\n\n withOptions(fieldProps, item as AnyFieldContentItem & { options?: unknown })\n\n const FieldComponent = componentFor(components, item.type)\n\n // Optional map keys (e.g. `multiselect`) may be absent; skip rather than crash.\n if (!FieldComponent) continue\n\n elements.push(<FieldComponent key={item.id} {...fieldProps} />)\n\n if (ErrorComponent && errors.length > 0)\n elements.push(<ErrorComponent key={`${item.id}-error`} errors={errors} field={item} />)\n }\n }\n\n if (elements.length === 0) return null\n\n return elements\n}\n","import type { FC } from 'react'\n\nimport type {\n ContentItem,\n FieldContentItem,\n FieldValidationError,\n FormSuggestions,\n FormValues,\n} from '@bluprynt/forms-core'\n\nimport { DEFAULT, ROOT } from '../constants'\nimport type {\n EditorArrayItemProps,\n EditorArrayObjItemProps,\n EditorComponentMap,\n EditorFieldProps,\n ViewerComponentMap,\n} from '../types'\nimport { FormItems } from './form-items'\nimport { findSection } from './utils'\n\ntype FormContentBaseProps = {\n items: ContentItem[]\n visibilityMap: Map<number, boolean>\n values: FormValues\n suggestions?: FormSuggestions\n fieldErrors: Map<number, FieldValidationError[]>\n section?: typeof ROOT | typeof DEFAULT | number\n showInlineValidation: boolean\n}\n\ntype FormContentViewerProps = FormContentBaseProps & {\n mode: 'viewer'\n components: ViewerComponentMap\n}\n\ntype FormContentEditorProps = FormContentBaseProps & {\n mode: 'editor'\n components: EditorComponentMap\n renderFieldProps: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps: (arrayField: FieldContentItem, index: number) => EditorArrayItemProps\n renderArrayObjItemProps: (\n arrayField: FieldContentItem,\n index: number,\n subFieldId: number,\n ) => EditorArrayObjItemProps\n}\n\nexport type FormContentProps = FormContentViewerProps | FormContentEditorProps\n\nexport const FormContent: FC<FormContentProps> = (props) => {\n const { items, visibilityMap, values, suggestions, fieldErrors, section, showInlineValidation } = props\n\n const sharedProps =\n props.mode === 'editor'\n ? {\n visibilityMap,\n values,\n suggestions,\n fieldErrors,\n components: props.components,\n showInlineValidation,\n renderFieldProps: props.renderFieldProps,\n renderArrayItemProps: props.renderArrayItemProps,\n renderArrayObjItemProps: props.renderArrayObjItemProps,\n }\n : {\n visibilityMap,\n values,\n suggestions,\n fieldErrors,\n components: props.components,\n showInlineValidation,\n }\n\n const selectedSection = section === DEFAULT ? resolveDefaultSection(items, visibilityMap) : section\n\n if (selectedSection === undefined) return <FormItems items={items} {...sharedProps} />\n\n if (selectedSection === ROOT) {\n const nonSectionItems = items.filter((item) => item.type !== 'section')\n return <FormItems items={nonSectionItems} {...sharedProps} />\n }\n\n const foundSection = findSection(items, selectedSection)\n if (!foundSection || !visibilityMap.get(foundSection.id)) return null\n\n const Section = props.components.section\n return (\n <Section key={foundSection.id} section={foundSection}>\n <FormItems items={foundSection.content} {...sharedProps} />\n </Section>\n )\n}\n\nconst resolveDefaultSection = (\n items: ContentItem[],\n visibilityMap: Map<number, boolean>,\n): typeof ROOT | number | undefined => {\n const rootFields = items.filter((item) => item.type !== 'section')\n if (rootFields.some((item) => visibilityMap.get(item.id))) return ROOT\n\n const firstVisibleSection = items.find((item) => item.type === 'section' && visibilityMap.get(item.id) !== false)\n\n return firstVisibleSection?.id\n}\n","import { type FC, useCallback, useRef } from 'react'\n\nimport {\n applySuggestion,\n FieldContentItem,\n FormDocument,\n FormEngine,\n FormValidationResult,\n removeSuggestion,\n} from '@bluprynt/forms-core'\n\nimport { FormContent } from './form'\nimport { useFormContext } from './form-context'\nimport type { EditorArrayItemProps, EditorArrayObjItemProps, EditorComponentMap, EditorFieldProps } from './types'\n\ntype FormEditorProps = {\n components: EditorComponentMap\n onChange: (data: FormDocument, validation: FormValidationResult) => void\n}\n\nexport const FormEditor: FC<FormEditorProps> = ({ components, onChange }) => {\n const { definition, data, visibilityMap, fieldErrors, section, engine, showInlineValidation, documentErrors } =\n useFormContext()\n\n const { renderFieldProps, renderArrayItemProps, renderArrayObjItemProps } = useEditorHandlers(\n engine,\n data,\n onChange,\n )\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <FormContent\n mode=\"editor\"\n items={definition.content}\n visibilityMap={visibilityMap}\n values={data.values}\n suggestions={data.suggestions}\n fieldErrors={fieldErrors}\n components={components}\n section={section}\n showInlineValidation={showInlineValidation}\n renderFieldProps={renderFieldProps}\n renderArrayItemProps={renderArrayItemProps}\n renderArrayObjItemProps={renderArrayObjItemProps}\n />\n )\n}\n\nexport const useEditorHandlers = (\n engine: FormEngine | undefined,\n data: FormDocument | undefined,\n onChange: (data: FormDocument, validation: FormValidationResult) => void,\n): {\n renderFieldProps: (field: FieldContentItem) => EditorFieldProps\n renderArrayItemProps: (field: FieldContentItem, index: number) => EditorArrayItemProps\n renderArrayObjItemProps: (field: FieldContentItem, index: number, subFieldId: number) => EditorArrayObjItemProps\n} => {\n // Latest ref pattern\n const stateRef = useRef({ data, onChange, engine })\n stateRef.current = { data, onChange, engine }\n\n // Per-field onChange handler\n\n const fieldOnChangeMap = useRef(new Map<string, (value: unknown) => void>())\n const getFieldOnChange = useCallback((fieldId: number): ((value: unknown) => void) => {\n const key = String(fieldId)\n\n let handler = fieldOnChangeMap.current.get(key)\n if (!handler) {\n handler = (newValue: unknown) => {\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const document: FormDocument = { ...data, values: { ...data.values, [key]: newValue } }\n\n onChange(document, engine.validate(document))\n }\n fieldOnChangeMap.current.set(key, handler)\n }\n return handler\n }, [])\n\n // Array mutation handlers\n\n const arrayHandlersMap = useRef(\n new Map<\n string,\n {\n onAddItem: () => void\n onRemoveItem: (index: number) => void\n onMoveItem: (fromIndex: number, toIndex: number) => void\n }\n >(),\n )\n const getArrayHandlers = useCallback((fieldId: number, newItem: () => unknown) => {\n const key = String(fieldId)\n\n let handlers = arrayHandlersMap.current.get(key)\n if (!handlers) {\n const fire = (mutate: (arr: unknown[]) => unknown[]) => {\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const items = (data.values[key] as unknown[] | undefined) ?? []\n const document: FormDocument = { ...data, values: { ...data.values, [key]: mutate([...items]) } }\n\n onChange(document, engine.validate(document))\n }\n\n handlers = {\n onAddItem: () =>\n fire((values) => {\n values.push(newItem())\n return values\n }),\n onRemoveItem: (index: number) =>\n fire((values) => {\n values.splice(index, 1)\n return values\n }),\n onMoveItem: (fromIndex: number, toIndex: number) =>\n fire((values) => {\n const [moved] = values.splice(fromIndex, 1)\n values.splice(toIndex, 0, moved)\n return values\n }),\n }\n arrayHandlersMap.current.set(key, handlers)\n }\n return handlers\n }, [])\n\n // Suggestion accept/reject handlers\n\n const suggestionHandlersMap = useRef(\n new Map<string, { onAcceptSuggestion: () => void; onRejectSuggestion: () => void }>(),\n )\n const getSuggestionHandlers = useCallback((fieldId: number) => {\n const key = String(fieldId)\n\n let handlers = suggestionHandlersMap.current.get(key)\n if (!handlers) {\n // Both helpers return the same document when the field has no\n // suggestion, which makes each handler a no-op in that case.\n const fire = (next: (document: FormDocument) => FormDocument) => {\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const document = next(data)\n if (document === data) return\n\n onChange(document, engine.validate(document))\n }\n\n handlers = {\n onAcceptSuggestion: () => fire((document) => applySuggestion(document, fieldId)),\n onRejectSuggestion: () => fire((document) => removeSuggestion(document, fieldId)),\n }\n suggestionHandlersMap.current.set(key, handlers)\n }\n return handlers\n }, [])\n\n // Array item onChange handler\n\n const arrayItemOnChangeMap = useRef(new Map<string, (value: unknown) => void>())\n const getArrayItemOnChange = useCallback((fieldId: number, index: number): ((value: unknown) => void) => {\n const mapKey = `${fieldId}-${index}`\n\n let handler = arrayItemOnChangeMap.current.get(mapKey)\n if (!handler) {\n handler = (newValue: unknown) => {\n const fieldKey = String(fieldId)\n\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const items = [...((data.values[fieldKey] as unknown[] | undefined) ?? [])]\n items[index] = newValue\n\n const document: FormDocument = { ...data, values: { ...data.values, [fieldKey]: items } }\n onChange(document, engine.validate(document))\n }\n arrayItemOnChangeMap.current.set(mapKey, handler)\n }\n return handler\n }, [])\n\n // `array_obj` cell onChange handler\n\n const arrayObjItemOnChangeMap = useRef(new Map<string, (value: unknown) => void>())\n const getArrayObjItemOnChange = useCallback(\n (fieldId: number, index: number, subFieldId: number): ((value: unknown) => void) => {\n const mapKey = `${fieldId}-${index}-${subFieldId}`\n\n let handler = arrayObjItemOnChangeMap.current.get(mapKey)\n if (!handler) {\n handler = (newValue: unknown) => {\n const fieldKey = String(fieldId)\n\n const { data, onChange, engine } = stateRef.current\n if (!data || !engine) return\n\n const rows = [...((data.values[fieldKey] as unknown[] | undefined) ?? [])]\n const current = rows[index]\n const row =\n typeof current === 'object' && current !== null && !Array.isArray(current)\n ? (current as Record<string, unknown>)\n : {}\n\n rows[index] = { ...row, [String(subFieldId)]: newValue }\n\n const document: FormDocument = { ...data, values: { ...data.values, [fieldKey]: rows } }\n onChange(document, engine.validate(document))\n }\n arrayObjItemOnChangeMap.current.set(mapKey, handler)\n }\n return handler\n },\n [],\n )\n\n return {\n renderFieldProps: (field: FieldContentItem): EditorFieldProps => {\n if (field.type === 'array' || field.type === 'array_obj') {\n const newItem = field.type === 'array_obj' ? () => ({}) : () => undefined\n return {\n onChange: getFieldOnChange(field.id),\n ...getArrayHandlers(field.id, newItem),\n ...getSuggestionHandlers(field.id),\n }\n }\n return { onChange: getFieldOnChange(field.id), ...getSuggestionHandlers(field.id) }\n },\n renderArrayItemProps: (field: FieldContentItem, index: number): EditorArrayItemProps => ({\n onChange: getArrayItemOnChange(field.id, index),\n }),\n renderArrayObjItemProps: (\n field: FieldContentItem,\n index: number,\n subFieldId: number,\n ): EditorArrayObjItemProps => ({\n onChange: getArrayObjItemOnChange(field.id, index, subFieldId),\n }),\n } as const\n}\n","import { type ComponentType, type FC, type PropsWithChildren, useMemo } from 'react'\n\nimport type { FieldEntry, FieldValidationError } from '@bluprynt/forms-core'\n\nimport { useFormContext } from './form-context'\n\nexport type FieldValidationFieldEntry = {\n field: FieldEntry | undefined\n errors: FieldValidationError[]\n}\n\ntype FormFieldsValidationProps = {\n container: ComponentType<PropsWithChildren>\n field: ComponentType<PropsWithChildren<FieldValidationFieldEntry>>\n error: ComponentType<FieldValidationError>\n}\n\nexport const FormFieldsValidation: FC<FormFieldsValidationProps> = ({\n container: ContainerComponent,\n field: FieldComponent,\n error: ErrorComponent,\n}) => {\n const { engine, data, fieldErrors, visibilityMap } = useFormContext()\n\n const groups = useMemo(() => {\n if (!engine || !data || fieldErrors.size === 0) return []\n\n const result: FieldValidationFieldEntry[] = []\n\n for (const [fieldId, errors] of fieldErrors) {\n if (visibilityMap.get(fieldId) === false) continue\n\n result.push({\n field: engine.getFieldDef(fieldId),\n errors,\n })\n }\n\n return result\n }, [engine, data, fieldErrors, visibilityMap])\n\n if (groups.length === 0) return null\n\n return (\n <ContainerComponent>\n {groups.map((group) => (\n <FieldComponent key={group.field?.id} {...group}>\n {group.errors.map((error) => (\n <ErrorComponent\n key={`${error.fieldId}-${error.rule}-${error.itemIndex ?? ''}-${error.itemFieldId ?? ''}`}\n {...error}\n />\n ))}\n </FieldComponent>\n ))}\n </ContainerComponent>\n )\n}\n","import { useMemo } from 'react'\n\nimport type { SectionContentItem } from '@bluprynt/forms-core'\n\nimport { ROOT } from './constants'\nimport { useFormContext } from './form-context'\n\nexport type FormSectionEntry = Omit<SectionContentItem, 'id' | 'type'> & {\n id: typeof ROOT | number\n}\n\nexport const useFormSections = (\n defaultSectionTitle = 'General',\n defaultSectionDescription?: string,\n): FormSectionEntry[] => {\n const { definition, visibilityMap, data } = useFormContext()\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: invalidate section list when data changes\n return useMemo(() => {\n if (!definition) return []\n\n const result: FormSectionEntry[] = []\n\n const rootFields = definition.content.filter((item) => item.type !== 'section')\n if (rootFields.some((item) => visibilityMap.get(item.id)))\n result.push({\n id: ROOT,\n title: defaultSectionTitle,\n description: defaultSectionDescription,\n content: rootFields,\n condition: undefined,\n })\n\n for (const item of definition.content) {\n if (item.type === 'section') {\n if (visibilityMap.get(item.id) === false) continue\n\n result.push(item)\n }\n }\n\n return result\n }, [definition?.content, visibilityMap, data, defaultSectionTitle, defaultSectionDescription])\n}\n","import { type ComponentType, type FC, type PropsWithChildren } from 'react'\n\nimport { DEFAULT, ROOT } from './constants'\nimport { useFormContext } from './form-context'\nimport { type FormSectionEntry, useFormSections } from './use-form-sections'\n\nexport type { FormSectionEntry }\n\nexport type FormSectionItemProps = {\n index: number\n section: FormSectionEntry\n active: boolean\n select: () => void\n}\n\ntype FormSectionsProps = {\n container: ComponentType<PropsWithChildren>\n item: ComponentType<FormSectionItemProps>\n defaultSectionTitle?: string\n defaultSectionDescription?: string\n onSelect?: (id: typeof ROOT | typeof DEFAULT | number) => void\n}\n\nexport const FormSections: FC<FormSectionsProps> = ({\n container: Container,\n item: Item,\n defaultSectionTitle,\n defaultSectionDescription,\n onSelect,\n}) => {\n const { definition, data, documentErrors, section } = useFormContext()\n const entries = useFormSections(defaultSectionTitle, defaultSectionDescription)\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <Container>\n {entries.map((entry, index) => (\n <Item\n key={entry.id === ROOT ? 'root' : String(entry.id)}\n index={index}\n section={entry}\n active={section === DEFAULT ? index === 0 : entry.id === section}\n select={() => onSelect?.(entry.id)}\n />\n ))}\n </Container>\n )\n}\n","import type { FC } from 'react'\n\nimport { FormContent } from './form'\nimport { useFormContext } from './form-context'\nimport type { ViewerComponentMap } from './types'\n\ntype FormViewerProps = {\n components: ViewerComponentMap\n}\n\nexport const FormViewer: FC<FormViewerProps> = ({ components }) => {\n const { definition, data, visibilityMap, fieldErrors, section, showInlineValidation, documentErrors } =\n useFormContext()\n\n if (!definition || !data || (documentErrors && documentErrors.length > 0)) return null\n\n return (\n <FormContent\n mode=\"viewer\"\n items={definition.content}\n visibilityMap={visibilityMap}\n values={data.values}\n suggestions={data.suggestions}\n fieldErrors={fieldErrors}\n components={components}\n section={section}\n showInlineValidation={showInlineValidation}\n />\n )\n}\n"],"mappings":"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"}
|