@fogpipe/forma-react 0.8.2 → 0.10.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/dist/index.d.ts +11 -1
- package/dist/index.js +45 -19
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/FormRenderer.tsx +11 -3
- package/src/__tests__/canProceed.test.ts +11 -8
- package/src/__tests__/diabetes-trial-flow.test.ts +793 -0
- package/src/__tests__/null-handling.test.ts +439 -0
- package/src/__tests__/useForma.test.ts +129 -0
- package/src/types.ts +11 -1
- package/src/useForma.ts +28 -1
package/dist/index.d.ts
CHANGED
|
@@ -273,6 +273,11 @@ interface FieldWrapperProps {
|
|
|
273
273
|
errors: FieldError[];
|
|
274
274
|
touched: boolean;
|
|
275
275
|
required: boolean;
|
|
276
|
+
/**
|
|
277
|
+
* Whether to show the required indicator in the UI.
|
|
278
|
+
* False for boolean fields since false is a valid answer.
|
|
279
|
+
*/
|
|
280
|
+
showRequiredIndicator: boolean;
|
|
276
281
|
visible: boolean;
|
|
277
282
|
}
|
|
278
283
|
/**
|
|
@@ -362,8 +367,13 @@ interface GetFieldPropsResult {
|
|
|
362
367
|
visible: boolean;
|
|
363
368
|
/** Whether field is enabled (not disabled) */
|
|
364
369
|
enabled: boolean;
|
|
365
|
-
/** Whether field is required */
|
|
370
|
+
/** Whether field is required (for validation) */
|
|
366
371
|
required: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* Whether to show the required indicator in the UI.
|
|
374
|
+
* False for boolean fields since false is a valid answer.
|
|
375
|
+
*/
|
|
376
|
+
showRequiredIndicator: boolean;
|
|
367
377
|
/** Whether field has been touched */
|
|
368
378
|
touched: boolean;
|
|
369
379
|
/** Validation errors for this field */
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,18 @@ function formReducer(state, action) {
|
|
|
50
50
|
return state;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
function getDefaultBooleanValues(spec) {
|
|
54
|
+
var _a;
|
|
55
|
+
const defaults = {};
|
|
56
|
+
for (const fieldPath of spec.fieldOrder) {
|
|
57
|
+
const schemaProperty = (_a = spec.schema.properties) == null ? void 0 : _a[fieldPath];
|
|
58
|
+
const fieldDef = spec.fields[fieldPath];
|
|
59
|
+
if ((schemaProperty == null ? void 0 : schemaProperty.type) === "boolean" || (fieldDef == null ? void 0 : fieldDef.type) === "boolean") {
|
|
60
|
+
defaults[fieldPath] = false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return defaults;
|
|
64
|
+
}
|
|
53
65
|
function useForma(options) {
|
|
54
66
|
const { spec: inputSpec, initialData = {}, onSubmit, onChange, validateOn = "blur", referenceData, validationDebounceMs = 0 } = options;
|
|
55
67
|
const spec = useMemo(() => {
|
|
@@ -63,7 +75,8 @@ function useForma(options) {
|
|
|
63
75
|
};
|
|
64
76
|
}, [inputSpec, referenceData]);
|
|
65
77
|
const [state, dispatch] = useReducer(formReducer, {
|
|
66
|
-
data: initialData,
|
|
78
|
+
data: { ...getDefaultBooleanValues(spec), ...initialData },
|
|
79
|
+
// Boolean defaults merged UNDER initialData
|
|
67
80
|
touched: {},
|
|
68
81
|
isSubmitting: false,
|
|
69
82
|
isSubmitted: false,
|
|
@@ -305,23 +318,24 @@ function useForma(options) {
|
|
|
305
318
|
return fieldHandlers.current.get(path);
|
|
306
319
|
}, [setValueAtPath, setFieldTouched]);
|
|
307
320
|
const getFieldProps = useCallback((path) => {
|
|
321
|
+
var _a;
|
|
308
322
|
const fieldDef = spec.fields[path];
|
|
309
323
|
const handlers = getFieldHandlers(path);
|
|
310
324
|
let fieldType = (fieldDef == null ? void 0 : fieldDef.type) || "text";
|
|
311
325
|
if (!fieldType || fieldType === "computed") {
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
314
|
-
if (
|
|
315
|
-
else if (
|
|
316
|
-
else if (
|
|
317
|
-
else if (
|
|
318
|
-
else if (
|
|
319
|
-
else if ("enum" in
|
|
320
|
-
else if ("format" in
|
|
321
|
-
if (
|
|
322
|
-
else if (
|
|
323
|
-
else if (
|
|
324
|
-
else if (
|
|
326
|
+
const schemaProperty2 = spec.schema.properties[path];
|
|
327
|
+
if (schemaProperty2) {
|
|
328
|
+
if (schemaProperty2.type === "number") fieldType = "number";
|
|
329
|
+
else if (schemaProperty2.type === "integer") fieldType = "integer";
|
|
330
|
+
else if (schemaProperty2.type === "boolean") fieldType = "boolean";
|
|
331
|
+
else if (schemaProperty2.type === "array") fieldType = "array";
|
|
332
|
+
else if (schemaProperty2.type === "object") fieldType = "object";
|
|
333
|
+
else if ("enum" in schemaProperty2 && schemaProperty2.enum) fieldType = "select";
|
|
334
|
+
else if ("format" in schemaProperty2) {
|
|
335
|
+
if (schemaProperty2.format === "date") fieldType = "date";
|
|
336
|
+
else if (schemaProperty2.format === "date-time") fieldType = "datetime";
|
|
337
|
+
else if (schemaProperty2.format === "email") fieldType = "email";
|
|
338
|
+
else if (schemaProperty2.format === "uri") fieldType = "url";
|
|
325
339
|
}
|
|
326
340
|
}
|
|
327
341
|
}
|
|
@@ -331,6 +345,10 @@ function useForma(options) {
|
|
|
331
345
|
const displayedErrors = showErrors ? fieldErrors : [];
|
|
332
346
|
const hasErrors = displayedErrors.length > 0;
|
|
333
347
|
const isRequired = required[path] ?? false;
|
|
348
|
+
const schemaProperty = spec.schema.properties[path];
|
|
349
|
+
const isBooleanField = (schemaProperty == null ? void 0 : schemaProperty.type) === "boolean" || (fieldDef == null ? void 0 : fieldDef.type) === "boolean";
|
|
350
|
+
const hasValidationRules = (((_a = fieldDef == null ? void 0 : fieldDef.validations) == null ? void 0 : _a.length) ?? 0) > 0;
|
|
351
|
+
const showRequiredIndicator = isRequired && (!isBooleanField || hasValidationRules);
|
|
334
352
|
return {
|
|
335
353
|
name: path,
|
|
336
354
|
value: getValueAtPath(path),
|
|
@@ -341,6 +359,7 @@ function useForma(options) {
|
|
|
341
359
|
visible: visibility[path] !== false,
|
|
342
360
|
enabled: enabled[path] !== false,
|
|
343
361
|
required: isRequired,
|
|
362
|
+
showRequiredIndicator,
|
|
344
363
|
touched: isTouched,
|
|
345
364
|
errors: displayedErrors,
|
|
346
365
|
onChange: handlers.onChange,
|
|
@@ -387,6 +406,8 @@ function useForma(options) {
|
|
|
387
406
|
enabled: enabled[path] !== false,
|
|
388
407
|
required: false,
|
|
389
408
|
// TODO: Evaluate item field required
|
|
409
|
+
showRequiredIndicator: false,
|
|
410
|
+
// Item fields don't show required indicator
|
|
390
411
|
touched: isTouched,
|
|
391
412
|
errors: showErrors ? fieldErrors : [],
|
|
392
413
|
onChange: handlers.onChange,
|
|
@@ -490,7 +511,7 @@ function DefaultLayout({ children, onSubmit, isSubmitting }) {
|
|
|
490
511
|
}
|
|
491
512
|
);
|
|
492
513
|
}
|
|
493
|
-
function DefaultFieldWrapper({ fieldPath, field, children, errors,
|
|
514
|
+
function DefaultFieldWrapper({ fieldPath, field, children, errors, showRequiredIndicator, visible }) {
|
|
494
515
|
if (!visible) return null;
|
|
495
516
|
const errorId = `${fieldPath}-error`;
|
|
496
517
|
const descriptionId = field.description ? `${fieldPath}-description` : void 0;
|
|
@@ -498,8 +519,8 @@ function DefaultFieldWrapper({ fieldPath, field, children, errors, required, vis
|
|
|
498
519
|
return /* @__PURE__ */ jsxs("div", { className: "field-wrapper", "data-field-path": fieldPath, children: [
|
|
499
520
|
field.label && /* @__PURE__ */ jsxs("label", { htmlFor: fieldPath, children: [
|
|
500
521
|
field.label,
|
|
501
|
-
|
|
502
|
-
|
|
522
|
+
showRequiredIndicator && /* @__PURE__ */ jsx("span", { className: "required", "aria-hidden": "true", children: "*" }),
|
|
523
|
+
showRequiredIndicator && /* @__PURE__ */ jsx("span", { className: "sr-only", children: " (required)" })
|
|
503
524
|
] }),
|
|
504
525
|
children,
|
|
505
526
|
hasErrors && /* @__PURE__ */ jsx(
|
|
@@ -607,6 +628,7 @@ var FormRenderer = forwardRef(
|
|
|
607
628
|
return spec.fieldOrder;
|
|
608
629
|
}, [spec.pages, spec.fieldOrder, forma.wizard]);
|
|
609
630
|
const renderField = useCallback2((fieldPath) => {
|
|
631
|
+
var _a;
|
|
610
632
|
const fieldDef = spec.fields[fieldPath];
|
|
611
633
|
if (!fieldDef) return null;
|
|
612
634
|
const isVisible = forma.visibility[fieldPath] !== false;
|
|
@@ -623,6 +645,9 @@ var FormRenderer = forwardRef(
|
|
|
623
645
|
const required = forma.required[fieldPath] ?? false;
|
|
624
646
|
const disabled = forma.enabled[fieldPath] === false;
|
|
625
647
|
const schemaProperty = spec.schema.properties[fieldPath];
|
|
648
|
+
const isBooleanField = (schemaProperty == null ? void 0 : schemaProperty.type) === "boolean" || (fieldDef == null ? void 0 : fieldDef.type) === "boolean";
|
|
649
|
+
const hasValidationRules = (((_a = fieldDef == null ? void 0 : fieldDef.validations) == null ? void 0 : _a.length) ?? 0) > 0;
|
|
650
|
+
const showRequiredIndicator = required && (!isBooleanField || hasValidationRules);
|
|
626
651
|
const baseProps = {
|
|
627
652
|
name: fieldPath,
|
|
628
653
|
field: fieldDef,
|
|
@@ -707,10 +732,10 @@ var FormRenderer = forwardRef(
|
|
|
707
732
|
move: cachedHelpers.move,
|
|
708
733
|
swap: cachedHelpers.swap,
|
|
709
734
|
getItemFieldProps: (index, fieldName) => {
|
|
710
|
-
var
|
|
735
|
+
var _a2;
|
|
711
736
|
const itemFieldDef = itemFieldDefs[fieldName];
|
|
712
737
|
const itemPath = `${fieldPath}[${index}].${fieldName}`;
|
|
713
|
-
const itemValue = (
|
|
738
|
+
const itemValue = (_a2 = arrayValue[index]) == null ? void 0 : _a2[fieldName];
|
|
714
739
|
return {
|
|
715
740
|
name: itemPath,
|
|
716
741
|
value: itemValue,
|
|
@@ -768,6 +793,7 @@ var FormRenderer = forwardRef(
|
|
|
768
793
|
errors,
|
|
769
794
|
touched,
|
|
770
795
|
required,
|
|
796
|
+
showRequiredIndicator,
|
|
771
797
|
visible: isVisible,
|
|
772
798
|
children: React.createElement(Component, componentProps)
|
|
773
799
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useForma.ts","../src/FormRenderer.tsx","../src/context.ts","../src/FieldRenderer.tsx","../src/ErrorBoundary.tsx"],"sourcesContent":["/**\n * useForma Hook\n *\n * Main hook for managing Forma form state.\n * This is a placeholder - the full implementation will be migrated from formidable.\n */\n\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport type { Forma, FieldError, ValidationResult } from \"@fogpipe/forma-core\";\nimport type { GetFieldPropsResult, GetSelectFieldPropsResult, GetArrayHelpersResult } from \"./types.js\";\nimport {\n getVisibility,\n getRequired,\n getEnabled,\n validate,\n calculate,\n getPageVisibility,\n} from \"@fogpipe/forma-core\";\n\n/**\n * Options for useForma hook\n */\nexport interface UseFormaOptions {\n /** The Forma specification */\n spec: Forma;\n /** Initial form data */\n initialData?: Record<string, unknown>;\n /** Submit handler */\n onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;\n /** Change handler */\n onChange?: (data: Record<string, unknown>, computed?: Record<string, unknown>) => void;\n /** When to validate: on change, blur, or submit only */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Additional reference data to merge with spec.referenceData */\n referenceData?: Record<string, unknown>;\n /**\n * Debounce validation by this many milliseconds.\n * Useful for large forms to improve performance.\n * Set to 0 (default) for immediate validation.\n */\n validationDebounceMs?: number;\n}\n\n/**\n * Form state\n */\ninterface FormState {\n data: Record<string, unknown>;\n touched: Record<string, boolean>;\n isSubmitting: boolean;\n isSubmitted: boolean;\n isDirty: boolean;\n currentPage: number;\n}\n\n/**\n * State actions\n */\ntype FormAction =\n | { type: \"SET_FIELD_VALUE\"; field: string; value: unknown }\n | { type: \"SET_FIELD_TOUCHED\"; field: string; touched: boolean }\n | { type: \"SET_VALUES\"; values: Record<string, unknown> }\n | { type: \"SET_SUBMITTING\"; isSubmitting: boolean }\n | { type: \"SET_SUBMITTED\"; isSubmitted: boolean }\n | { type: \"SET_PAGE\"; page: number }\n | { type: \"RESET\"; initialData: Record<string, unknown> };\n\n/**\n * Page state for multi-page forms\n */\nexport interface PageState {\n id: string;\n title: string;\n description?: string;\n visible: boolean;\n fields: string[];\n}\n\n/**\n * Wizard navigation helpers\n */\nexport interface WizardHelpers {\n pages: PageState[];\n currentPageIndex: number;\n currentPage: PageState | null;\n goToPage: (index: number) => void;\n nextPage: () => void;\n previousPage: () => void;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n canProceed: boolean;\n isLastPage: boolean;\n touchCurrentPageFields: () => void;\n validateCurrentPage: () => boolean;\n}\n\n/**\n * Return type of useForma hook\n */\nexport interface UseFormaReturn {\n /** Current form data */\n data: Record<string, unknown>;\n /** Computed field values */\n computed: Record<string, unknown>;\n /** Field visibility map */\n visibility: Record<string, boolean>;\n /** Field required state map */\n required: Record<string, boolean>;\n /** Field enabled state map */\n enabled: Record<string, boolean>;\n /** Field touched state map */\n touched: Record<string, boolean>;\n /** Validation errors */\n errors: FieldError[];\n /** Whether form is valid */\n isValid: boolean;\n /** Whether form is submitting */\n isSubmitting: boolean;\n /** Whether form has been submitted */\n isSubmitted: boolean;\n /** Whether any field has been modified */\n isDirty: boolean;\n /** The Forma spec */\n spec: Forma;\n /** Wizard helpers (if multi-page) */\n wizard: WizardHelpers | null;\n\n /** Set a field value */\n setFieldValue: (path: string, value: unknown) => void;\n /** Set a field as touched */\n setFieldTouched: (path: string, touched?: boolean) => void;\n /** Set multiple values */\n setValues: (values: Record<string, unknown>) => void;\n /** Validate a single field */\n validateField: (path: string) => FieldError[];\n /** Validate entire form */\n validateForm: () => ValidationResult;\n /** Submit the form */\n submitForm: () => Promise<void>;\n /** Reset the form */\n resetForm: () => void;\n\n // Helper methods for getting field props\n /** Get props for any field */\n getFieldProps: (path: string) => GetFieldPropsResult;\n /** Get props for select field (includes options) */\n getSelectFieldProps: (path: string) => GetSelectFieldPropsResult;\n /** Get array helpers for array field */\n getArrayHelpers: (path: string) => GetArrayHelpersResult;\n}\n\n/**\n * State reducer\n */\nfunction formReducer(state: FormState, action: FormAction): FormState {\n switch (action.type) {\n case \"SET_FIELD_VALUE\":\n return {\n ...state,\n data: { ...state.data, [action.field]: action.value },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_FIELD_TOUCHED\":\n return {\n ...state,\n touched: { ...state.touched, [action.field]: action.touched },\n };\n case \"SET_VALUES\":\n return {\n ...state,\n data: { ...state.data, ...action.values },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_SUBMITTING\":\n return { ...state, isSubmitting: action.isSubmitting };\n case \"SET_SUBMITTED\":\n return { ...state, isSubmitted: action.isSubmitted };\n case \"SET_PAGE\":\n return { ...state, currentPage: action.page };\n case \"RESET\":\n return {\n data: action.initialData,\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n };\n default:\n return state;\n }\n}\n\n/**\n * Main Forma hook\n */\nexport function useForma(options: UseFormaOptions): UseFormaReturn {\n const { spec: inputSpec, initialData = {}, onSubmit, onChange, validateOn = \"blur\", referenceData, validationDebounceMs = 0 } = options;\n\n // Merge referenceData from options with spec.referenceData\n const spec = useMemo((): Forma => {\n if (!referenceData) return inputSpec;\n return {\n ...inputSpec,\n referenceData: {\n ...inputSpec.referenceData,\n ...referenceData,\n },\n };\n }, [inputSpec, referenceData]);\n\n const [state, dispatch] = useReducer(formReducer, {\n data: initialData,\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n });\n\n // Track if we've initialized (to avoid calling onChange on first render)\n const hasInitialized = useRef(false);\n\n // Calculate computed values\n const computed = useMemo(\n () => calculate(state.data, spec),\n [state.data, spec]\n );\n\n // Calculate visibility\n const visibility = useMemo(\n () => getVisibility(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Calculate required state\n const required = useMemo(\n () => getRequired(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Calculate enabled state\n const enabled = useMemo(\n () => getEnabled(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Validate form - compute immediate result\n const immediateValidation = useMemo(\n () => validate(state.data, spec, { computed, onlyVisible: true }),\n [state.data, spec, computed]\n );\n\n // Debounced validation state (only used when validationDebounceMs > 0)\n const [debouncedValidation, setDebouncedValidation] = useState<ValidationResult>(immediateValidation);\n\n // Apply debouncing if configured\n useEffect(() => {\n if (validationDebounceMs <= 0) {\n // No debouncing - use immediate validation\n setDebouncedValidation(immediateValidation);\n return;\n }\n\n // Debounce validation updates\n const timeoutId = setTimeout(() => {\n setDebouncedValidation(immediateValidation);\n }, validationDebounceMs);\n\n return () => clearTimeout(timeoutId);\n }, [immediateValidation, validationDebounceMs]);\n\n // Use debounced validation for display, but immediate for submit\n const validation = validationDebounceMs > 0 ? debouncedValidation : immediateValidation;\n\n // isDirty is tracked via reducer state for O(1) performance\n\n // Call onChange when data changes (not on initial render)\n useEffect(() => {\n if (hasInitialized.current) {\n onChange?.(state.data, computed);\n } else {\n hasInitialized.current = true;\n }\n }, [state.data, computed, onChange]);\n\n // Helper function to set value at nested path\n const setNestedValue = useCallback((path: string, value: unknown): void => {\n // Handle array index notation: \"items[0].name\" -> nested structure\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n\n if (parts.length === 1) {\n // Simple path - just set directly\n dispatch({ type: \"SET_FIELD_VALUE\", field: path, value });\n return;\n }\n\n // Build nested object for complex paths\n const buildNestedObject = (data: Record<string, unknown>, pathParts: string[], val: unknown): Record<string, unknown> => {\n const result = { ...data };\n let current: Record<string, unknown> = result;\n\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i];\n const nextPart = pathParts[i + 1];\n const isNextArrayIndex = /^\\d+$/.test(nextPart);\n\n if (current[part] === undefined) {\n current[part] = isNextArrayIndex ? [] : {};\n } else if (Array.isArray(current[part])) {\n current[part] = [...(current[part] as unknown[])];\n } else {\n current[part] = { ...(current[part] as Record<string, unknown>) };\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[pathParts[pathParts.length - 1]] = val;\n return result;\n };\n\n dispatch({ type: \"SET_VALUES\", values: buildNestedObject(state.data, parts, value) });\n }, [state.data]);\n\n // Actions\n const setFieldValue = useCallback(\n (path: string, value: unknown) => {\n setNestedValue(path, value);\n if (validateOn === \"change\") {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field: path, touched: true });\n }\n },\n [validateOn, setNestedValue]\n );\n\n const setFieldTouched = useCallback((path: string, touched = true) => {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field: path, touched });\n }, []);\n\n const setValues = useCallback((values: Record<string, unknown>) => {\n dispatch({ type: \"SET_VALUES\", values });\n }, []);\n\n const validateField = useCallback(\n (path: string): FieldError[] => {\n return validation.errors.filter((e) => e.field === path);\n },\n [validation]\n );\n\n const validateForm = useCallback((): ValidationResult => {\n return validation;\n }, [validation]);\n\n const submitForm = useCallback(async () => {\n dispatch({ type: \"SET_SUBMITTING\", isSubmitting: true });\n try {\n // Always use immediate validation on submit to ensure accurate result\n if (immediateValidation.valid && onSubmit) {\n await onSubmit(state.data);\n }\n dispatch({ type: \"SET_SUBMITTED\", isSubmitted: true });\n } finally {\n dispatch({ type: \"SET_SUBMITTING\", isSubmitting: false });\n }\n }, [immediateValidation, onSubmit, state.data]);\n\n const resetForm = useCallback(() => {\n dispatch({ type: \"RESET\", initialData });\n }, [initialData]);\n\n // Wizard helpers\n const wizard = useMemo((): WizardHelpers | null => {\n if (!spec.pages || spec.pages.length === 0) return null;\n\n const pageVisibility = getPageVisibility(state.data, spec, { computed });\n\n // Include all pages with their visibility status\n const pages: PageState[] = spec.pages.map((p) => ({\n id: p.id,\n title: p.title,\n description: p.description,\n visible: pageVisibility[p.id] !== false,\n fields: p.fields,\n }));\n\n // For navigation, only count visible pages\n const visiblePages = pages.filter((p) => p.visible);\n\n // Clamp currentPage to valid range (handles case where current page becomes hidden)\n const maxPageIndex = Math.max(0, visiblePages.length - 1);\n const clampedPageIndex = Math.min(Math.max(0, state.currentPage), maxPageIndex);\n\n // Auto-correct page index if it's out of bounds\n if (clampedPageIndex !== state.currentPage && visiblePages.length > 0) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex });\n }\n\n const currentPage = visiblePages[clampedPageIndex] || null;\n const hasNextPage = clampedPageIndex < visiblePages.length - 1;\n const hasPreviousPage = clampedPageIndex > 0;\n const isLastPage = clampedPageIndex === visiblePages.length - 1;\n\n return {\n pages,\n currentPageIndex: clampedPageIndex,\n currentPage,\n goToPage: (index: number) => {\n // Clamp to valid range\n const validIndex = Math.min(Math.max(0, index), maxPageIndex);\n dispatch({ type: \"SET_PAGE\", page: validIndex });\n },\n nextPage: () => {\n if (hasNextPage) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex + 1 });\n }\n },\n previousPage: () => {\n if (hasPreviousPage) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex - 1 });\n }\n },\n hasNextPage,\n hasPreviousPage,\n canProceed: (() => {\n if (!currentPage) return true;\n // Get errors only for visible fields on the current page\n const pageErrors = validation.errors.filter((e) => {\n // Check if field is on current page (including array items like \"items[0].name\")\n const isOnCurrentPage = currentPage.fields.includes(e.field) ||\n currentPage.fields.some(f => e.field.startsWith(`${f}[`));\n // Only count errors for visible fields\n const isVisible = visibility[e.field] !== false;\n // Only count actual errors, not warnings\n const isError = e.severity === 'error';\n return isOnCurrentPage && isVisible && isError;\n });\n return pageErrors.length === 0;\n })(),\n isLastPage,\n touchCurrentPageFields: () => {\n if (currentPage) {\n currentPage.fields.forEach((field) => {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field, touched: true });\n });\n }\n },\n validateCurrentPage: () => {\n if (!currentPage) return true;\n const pageErrors = validation.errors.filter((e) =>\n currentPage.fields.includes(e.field)\n );\n return pageErrors.length === 0;\n },\n };\n }, [spec, state.data, state.currentPage, computed, validation, visibility]);\n\n // Helper to get value at nested path\n const getValueAtPath = useCallback((path: string): unknown => {\n // Handle array index notation: \"items[0].name\" -> [\"items\", \"0\", \"name\"]\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n let value: unknown = state.data;\n for (const part of parts) {\n if (value === null || value === undefined) return undefined;\n value = (value as Record<string, unknown>)[part];\n }\n return value;\n }, [state.data]);\n\n // Helper to set value at nested path\n const setValueAtPath = useCallback((path: string, value: unknown): void => {\n // For nested paths, we need to build the nested structure\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n if (parts.length === 1) {\n dispatch({ type: \"SET_FIELD_VALUE\", field: path, value });\n return;\n }\n\n // Build nested object\n const newData = { ...state.data };\n let current: Record<string, unknown> = newData;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n const isNextArrayIndex = /^\\d+$/.test(nextPart);\n\n if (current[part] === undefined) {\n current[part] = isNextArrayIndex ? [] : {};\n } else if (Array.isArray(current[part])) {\n current[part] = [...(current[part] as unknown[])];\n } else {\n current[part] = { ...(current[part] as Record<string, unknown>) };\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[parts[parts.length - 1]] = value;\n dispatch({ type: \"SET_VALUES\", values: newData });\n }, [state.data]);\n\n // Memoized onChange/onBlur handlers for fields\n const fieldHandlers = useRef<Map<string, { onChange: (value: unknown) => void; onBlur: () => void }>>(new Map());\n\n // Clean up stale field handlers when spec changes to prevent memory leaks\n useEffect(() => {\n const validFields = new Set(spec.fieldOrder);\n // Also include array item field patterns\n for (const fieldId of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldId];\n if (fieldDef?.itemFields) {\n for (const key of fieldHandlers.current.keys()) {\n if (key.startsWith(`${fieldId}[`)) {\n validFields.add(key);\n }\n }\n }\n }\n // Remove handlers for fields that no longer exist\n for (const key of fieldHandlers.current.keys()) {\n const baseField = key.split('[')[0];\n if (!validFields.has(key) && !validFields.has(baseField)) {\n fieldHandlers.current.delete(key);\n }\n }\n }, [spec]);\n\n const getFieldHandlers = useCallback((path: string) => {\n if (!fieldHandlers.current.has(path)) {\n fieldHandlers.current.set(path, {\n onChange: (value: unknown) => setValueAtPath(path, value),\n onBlur: () => setFieldTouched(path),\n });\n }\n return fieldHandlers.current.get(path)!;\n }, [setValueAtPath, setFieldTouched]);\n\n // Get field props for any field\n const getFieldProps = useCallback((path: string): GetFieldPropsResult => {\n const fieldDef = spec.fields[path];\n const handlers = getFieldHandlers(path);\n\n // Determine field type from definition or infer from schema\n let fieldType = fieldDef?.type || \"text\";\n if (!fieldType || fieldType === \"computed\") {\n const schemaProperty = spec.schema.properties[path];\n if (schemaProperty) {\n if (schemaProperty.type === \"number\") fieldType = \"number\";\n else if (schemaProperty.type === \"integer\") fieldType = \"integer\";\n else if (schemaProperty.type === \"boolean\") fieldType = \"boolean\";\n else if (schemaProperty.type === \"array\") fieldType = \"array\";\n else if (schemaProperty.type === \"object\") fieldType = \"object\";\n else if (\"enum\" in schemaProperty && schemaProperty.enum) fieldType = \"select\";\n else if (\"format\" in schemaProperty) {\n if (schemaProperty.format === \"date\") fieldType = \"date\";\n else if (schemaProperty.format === \"date-time\") fieldType = \"datetime\";\n else if (schemaProperty.format === \"email\") fieldType = \"email\";\n else if (schemaProperty.format === \"uri\") fieldType = \"url\";\n }\n }\n }\n\n const fieldErrors = validation.errors.filter((e) => e.field === path);\n const isTouched = state.touched[path] ?? false;\n const showErrors = validateOn === \"change\" || (validateOn === \"blur\" && isTouched) || state.isSubmitted;\n const displayedErrors = showErrors ? fieldErrors : [];\n const hasErrors = displayedErrors.length > 0;\n const isRequired = required[path] ?? false;\n\n return {\n name: path,\n value: getValueAtPath(path),\n type: fieldType,\n label: fieldDef?.label || path.charAt(0).toUpperCase() + path.slice(1),\n description: fieldDef?.description,\n placeholder: fieldDef?.placeholder,\n visible: visibility[path] !== false,\n enabled: enabled[path] !== false,\n required: isRequired,\n touched: isTouched,\n errors: displayedErrors,\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n // ARIA accessibility attributes\n \"aria-invalid\": hasErrors || undefined,\n \"aria-describedby\": hasErrors ? `${path}-error` : undefined,\n \"aria-required\": isRequired || undefined,\n };\n }, [spec, state.touched, state.isSubmitted, visibility, enabled, required, validation.errors, validateOn, getValueAtPath, getFieldHandlers]);\n\n // Get select field props\n const getSelectFieldProps = useCallback((path: string): GetSelectFieldPropsResult => {\n const baseProps = getFieldProps(path);\n const fieldDef = spec.fields[path];\n\n return {\n ...baseProps,\n options: fieldDef?.options ?? [],\n };\n }, [getFieldProps, spec.fields]);\n\n // Get array helpers\n const getArrayHelpers = useCallback((path: string): GetArrayHelpersResult => {\n const fieldDef = spec.fields[path];\n const currentValue = (getValueAtPath(path) as unknown[]) ?? [];\n const minItems = fieldDef?.minItems ?? 0;\n const maxItems = fieldDef?.maxItems ?? Infinity;\n\n const canAdd = currentValue.length < maxItems;\n const canRemove = currentValue.length > minItems;\n\n const getItemFieldProps = (index: number, fieldName: string): GetFieldPropsResult => {\n const itemPath = `${path}[${index}].${fieldName}`;\n const itemFieldDef = fieldDef?.itemFields?.[fieldName];\n const handlers = getFieldHandlers(itemPath);\n\n // Get item value\n const item = currentValue[index] as Record<string, unknown> | undefined;\n const itemValue = item?.[fieldName];\n\n const fieldErrors = validation.errors.filter((e) => e.field === itemPath);\n const isTouched = state.touched[itemPath] ?? false;\n const showErrors = validateOn === \"change\" || (validateOn === \"blur\" && isTouched) || state.isSubmitted;\n\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type || \"text\",\n label: itemFieldDef?.label || fieldName.charAt(0).toUpperCase() + fieldName.slice(1),\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: enabled[path] !== false,\n required: false, // TODO: Evaluate item field required\n touched: isTouched,\n errors: showErrors ? fieldErrors : [],\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n };\n };\n\n return {\n items: currentValue,\n push: (item: unknown) => {\n if (canAdd) {\n setValueAtPath(path, [...currentValue, item]);\n }\n },\n remove: (index: number) => {\n if (canRemove) {\n const newArray = [...currentValue];\n newArray.splice(index, 1);\n setValueAtPath(path, newArray);\n }\n },\n move: (from: number, to: number) => {\n const newArray = [...currentValue];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n setValueAtPath(path, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const newArray = [...currentValue];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n setValueAtPath(path, newArray);\n },\n insert: (index: number, item: unknown) => {\n if (canAdd) {\n const newArray = [...currentValue];\n newArray.splice(index, 0, item);\n setValueAtPath(path, newArray);\n }\n },\n getItemFieldProps,\n minItems,\n maxItems,\n canAdd,\n canRemove,\n };\n }, [spec.fields, getValueAtPath, setValueAtPath, getFieldHandlers, enabled, state.touched, state.isSubmitted, validation.errors, validateOn]);\n\n return {\n data: state.data,\n computed,\n visibility,\n required,\n enabled,\n touched: state.touched,\n errors: validation.errors,\n isValid: validation.valid,\n isSubmitting: state.isSubmitting,\n isSubmitted: state.isSubmitted,\n isDirty: state.isDirty,\n spec,\n wizard,\n setFieldValue,\n setFieldTouched,\n setValues,\n validateField,\n validateForm,\n submitForm,\n resetForm,\n getFieldProps,\n getSelectFieldProps,\n getArrayHelpers,\n };\n}\n","/**\n * FormRenderer Component\n *\n * Renders a complete form from a Forma specification.\n * Supports single-page and multi-page (wizard) forms.\n */\n\nimport React, { forwardRef, useImperativeHandle, useRef, useMemo, useCallback } from \"react\";\nimport type { Forma, FieldDefinition, ValidationResult, JSONSchemaProperty } from \"@fogpipe/forma-core\";\nimport { useForma } from \"./useForma.js\";\nimport { FormaContext } from \"./context.js\";\nimport type { ComponentMap, LayoutProps, FieldWrapperProps, PageWrapperProps, BaseFieldProps, TextFieldProps, NumberFieldProps, SelectFieldProps, ArrayFieldProps, ArrayHelpers } from \"./types.js\";\n\n/**\n * Props for FormRenderer component\n */\nexport interface FormRendererProps {\n /** The Forma specification */\n spec: Forma;\n /** Initial form data */\n initialData?: Record<string, unknown>;\n /** Submit handler */\n onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;\n /** Change handler */\n onChange?: (data: Record<string, unknown>, computed?: Record<string, unknown>) => void;\n /** Component map for rendering fields */\n components: ComponentMap;\n /** Custom layout component */\n layout?: React.ComponentType<LayoutProps>;\n /** Custom field wrapper component */\n fieldWrapper?: React.ComponentType<FieldWrapperProps>;\n /** Custom page wrapper component */\n pageWrapper?: React.ComponentType<PageWrapperProps>;\n /** When to validate */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Current page for controlled wizard */\n page?: number;\n}\n\n/**\n * Imperative handle for FormRenderer\n */\nexport interface FormRendererHandle {\n submitForm: () => Promise<void>;\n resetForm: () => void;\n validateForm: () => ValidationResult;\n focusField: (path: string) => void;\n focusFirstError: () => void;\n getValues: () => Record<string, unknown>;\n setValues: (values: Record<string, unknown>) => void;\n isValid: boolean;\n isDirty: boolean;\n}\n\n/**\n * Default layout component\n */\nfunction DefaultLayout({ children, onSubmit, isSubmitting }: LayoutProps) {\n return (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n {children}\n <button type=\"submit\" disabled={isSubmitting}>\n {isSubmitting ? \"Submitting...\" : \"Submit\"}\n </button>\n </form>\n );\n}\n\n/**\n * Default field wrapper component with accessibility support\n */\nfunction DefaultFieldWrapper({ fieldPath, field, children, errors, required, visible }: FieldWrapperProps) {\n if (!visible) return null;\n\n const errorId = `${fieldPath}-error`;\n const descriptionId = field.description ? `${fieldPath}-description` : undefined;\n const hasErrors = errors.length > 0;\n\n return (\n <div className=\"field-wrapper\" data-field-path={fieldPath}>\n {field.label && (\n <label htmlFor={fieldPath}>\n {field.label}\n {required && <span className=\"required\" aria-hidden=\"true\">*</span>}\n {required && <span className=\"sr-only\"> (required)</span>}\n </label>\n )}\n {children}\n {hasErrors && (\n <div\n id={errorId}\n className=\"field-errors\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n {errors.map((error, i) => (\n <span key={i} className=\"error\">\n {error.message}\n </span>\n ))}\n </div>\n )}\n {field.description && (\n <p id={descriptionId} className=\"field-description\">\n {field.description}\n </p>\n )}\n </div>\n );\n}\n\n/**\n * Default page wrapper component\n */\nfunction DefaultPageWrapper({ title, description, children }: PageWrapperProps) {\n return (\n <div className=\"page-wrapper\">\n <h2>{title}</h2>\n {description && <p>{description}</p>}\n {children}\n </div>\n );\n}\n\n/**\n * Extract numeric constraints from JSON Schema property\n */\nfunction getNumberConstraints(schema?: JSONSchemaProperty): { min?: number; max?: number; step?: number } {\n if (!schema) return {};\n if (schema.type !== \"number\" && schema.type !== \"integer\") return {};\n\n // Extract min/max from schema\n const min = \"minimum\" in schema && typeof schema.minimum === \"number\" ? schema.minimum : undefined;\n const max = \"maximum\" in schema && typeof schema.maximum === \"number\" ? schema.maximum : undefined;\n\n // Use multipleOf for step if defined, otherwise default to 1 for integers\n let step: number | undefined;\n if (\"multipleOf\" in schema && typeof schema.multipleOf === \"number\") {\n step = schema.multipleOf;\n } else if (schema.type === \"integer\") {\n step = 1;\n }\n\n return { min, max, step };\n}\n\n/**\n * Create a default item for an array field based on item field definitions\n */\nfunction createDefaultItem(itemFields: Record<string, FieldDefinition>): Record<string, unknown> {\n const item: Record<string, unknown> = {};\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n if (fieldDef.type === \"boolean\") {\n item[fieldName] = false;\n } else if (fieldDef.type === \"number\" || fieldDef.type === \"integer\") {\n item[fieldName] = null;\n } else {\n item[fieldName] = \"\";\n }\n }\n return item;\n}\n\n/**\n * FormRenderer component\n */\nexport const FormRenderer = forwardRef<FormRendererHandle, FormRendererProps>(\n function FormRenderer(props, ref) {\n const {\n spec,\n initialData,\n onSubmit,\n onChange,\n components,\n layout: Layout = DefaultLayout,\n fieldWrapper: FieldWrapper = DefaultFieldWrapper,\n pageWrapper: PageWrapper = DefaultPageWrapper,\n validateOn,\n } = props;\n\n const forma = useForma({\n spec,\n initialData,\n onSubmit,\n onChange,\n validateOn,\n });\n\n const fieldRefs = useRef<Map<string, HTMLElement>>(new Map());\n\n // Cache for array helper functions to prevent recreation on every render\n const arrayHelpersCache = useRef<Map<string, {\n push: (item?: unknown) => void;\n insert: (index: number, item: unknown) => void;\n remove: (index: number) => void;\n move: (from: number, to: number) => void;\n swap: (indexA: number, indexB: number) => void;\n }>>(new Map());\n\n // Focus a specific field by path\n const focusField = useCallback((path: string) => {\n const element = fieldRefs.current.get(path);\n element?.focus();\n }, []);\n\n // Focus the first field with an error\n const focusFirstError = useCallback(() => {\n const firstError = forma.errors[0];\n if (firstError) {\n focusField(firstError.field);\n }\n }, [forma.errors, focusField]);\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n submitForm: forma.submitForm,\n resetForm: forma.resetForm,\n validateForm: forma.validateForm,\n focusField,\n focusFirstError,\n getValues: () => forma.data,\n setValues: forma.setValues,\n isValid: forma.isValid,\n isDirty: forma.isDirty,\n }),\n [forma, focusField, focusFirstError]\n );\n\n // Determine which fields to render based on pages or fieldOrder\n const fieldsToRender = useMemo(() => {\n if (spec.pages && spec.pages.length > 0 && forma.wizard) {\n // Wizard mode - render fields for the active page\n const currentPage = forma.wizard.currentPage;\n if (currentPage) {\n return currentPage.fields;\n }\n // Fallback to first page\n return spec.pages[0]?.fields ?? [];\n }\n // Single page mode - render all fields in order\n return spec.fieldOrder;\n }, [spec.pages, spec.fieldOrder, forma.wizard]);\n\n // Render a single field (memoized)\n const renderField = useCallback((fieldPath: string) => {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) return null;\n\n const isVisible = forma.visibility[fieldPath] !== false;\n if (!isVisible) return null;\n\n // Infer field type\n const fieldType = fieldDef.type || (fieldDef.itemFields ? \"array\" : \"text\");\n const componentKey = fieldType as keyof ComponentMap;\n const Component = components[componentKey] || components.fallback;\n\n if (!Component) {\n console.warn(`No component found for field type: ${fieldType}`);\n return null;\n }\n\n const errors = forma.errors.filter((e) => e.field === fieldPath);\n const touched = forma.touched[fieldPath] ?? false;\n const required = forma.required[fieldPath] ?? false;\n const disabled = forma.enabled[fieldPath] === false;\n\n // Get schema property for additional constraints\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Base field props\n const baseProps: BaseFieldProps = {\n name: fieldPath,\n field: fieldDef,\n value: forma.data[fieldPath],\n touched,\n required,\n disabled,\n errors,\n onChange: (value: unknown) => forma.setFieldValue(fieldPath, value),\n onBlur: () => forma.setFieldTouched(fieldPath),\n // Convenience properties\n visible: true, // Always true since we already filtered for visibility\n enabled: !disabled,\n label: fieldDef.label ?? fieldPath,\n description: fieldDef.description,\n placeholder: fieldDef.placeholder,\n };\n\n // Build type-specific props\n let fieldProps: BaseFieldProps | TextFieldProps | NumberFieldProps | SelectFieldProps | ArrayFieldProps = baseProps;\n\n if (fieldType === \"number\" || fieldType === \"integer\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType,\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n ...constraints,\n } as NumberFieldProps;\n } else if (fieldType === \"select\" || fieldType === \"multiselect\") {\n fieldProps = {\n ...baseProps,\n fieldType,\n value: baseProps.value as string | string[] | null,\n onChange: baseProps.onChange as (value: string | string[] | null) => void,\n options: fieldDef.options ?? [],\n } as SelectFieldProps;\n } else if (fieldType === \"array\" && fieldDef.itemFields) {\n const arrayValue = (baseProps.value as unknown[] | undefined) ?? [];\n const minItems = fieldDef.minItems ?? 0;\n const maxItems = fieldDef.maxItems ?? Infinity;\n const itemFieldDefs = fieldDef.itemFields;\n\n // Get or create cached helper functions for this array field\n // These functions read current values when called, not when created\n if (!arrayHelpersCache.current.has(fieldPath)) {\n arrayHelpersCache.current.set(fieldPath, {\n push: (item?: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newItem = item ?? createDefaultItem(itemFieldDefs);\n forma.setFieldValue(fieldPath, [...currentArray, newItem]);\n },\n insert: (index: number, item: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n newArray.splice(index, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n remove: (index: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n newArray.splice(index, 1);\n forma.setFieldValue(fieldPath, newArray);\n },\n move: (from: number, to: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n forma.setFieldValue(fieldPath, newArray);\n },\n });\n }\n const cachedHelpers = arrayHelpersCache.current.get(fieldPath)!;\n\n const helpers: ArrayHelpers = {\n items: arrayValue,\n push: cachedHelpers.push,\n insert: cachedHelpers.insert,\n remove: cachedHelpers.remove,\n move: cachedHelpers.move,\n swap: cachedHelpers.swap,\n getItemFieldProps: (index: number, fieldName: string) => {\n const itemFieldDef = itemFieldDefs[fieldName];\n const itemPath = `${fieldPath}[${index}].${fieldName}`;\n const itemValue = (arrayValue[index] as Record<string, unknown>)?.[fieldName];\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type ?? \"text\",\n label: itemFieldDef?.label ?? fieldName,\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: !disabled,\n required: itemFieldDef?.requiredWhen === \"true\",\n touched: forma.touched[itemPath] ?? false,\n errors: forma.errors.filter((e) => e.field === itemPath),\n onChange: (value: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n const item = (newArray[index] ?? {}) as Record<string, unknown>;\n newArray[index] = { ...item, [fieldName]: value };\n forma.setFieldValue(fieldPath, newArray);\n },\n onBlur: () => forma.setFieldTouched(itemPath),\n itemIndex: index,\n fieldName,\n options: itemFieldDef?.options,\n };\n },\n minItems,\n maxItems,\n canAdd: arrayValue.length < maxItems,\n canRemove: arrayValue.length > minItems,\n };\n fieldProps = {\n ...baseProps,\n fieldType: \"array\",\n value: arrayValue,\n onChange: baseProps.onChange as (value: unknown[]) => void,\n helpers,\n itemFields: itemFieldDefs,\n minItems,\n maxItems,\n } as ArrayFieldProps;\n } else {\n // Text-based fields\n fieldProps = {\n ...baseProps,\n fieldType: fieldType as \"text\" | \"email\" | \"password\" | \"url\" | \"textarea\",\n value: (baseProps.value as string) ?? \"\",\n onChange: baseProps.onChange as (value: string) => void,\n };\n }\n\n // Wrap props in { field, spec } structure for components\n const componentProps = { field: fieldProps, spec };\n\n return (\n <FieldWrapper\n key={fieldPath}\n fieldPath={fieldPath}\n field={fieldDef}\n errors={errors}\n touched={touched}\n required={required}\n visible={isVisible}\n >\n {React.createElement(Component as React.ComponentType<typeof componentProps>, componentProps)}\n </FieldWrapper>\n );\n }, [spec, forma, components, FieldWrapper]);\n\n // Render fields (memoized)\n const renderedFields = useMemo(\n () => fieldsToRender.map(renderField),\n [fieldsToRender, renderField]\n );\n\n // Render with page wrapper if using pages\n const content = useMemo(() => {\n if (spec.pages && spec.pages.length > 0 && forma.wizard) {\n const currentPage = forma.wizard.currentPage;\n if (!currentPage) return null;\n\n return (\n <PageWrapper\n title={currentPage.title}\n description={currentPage.description}\n pageIndex={forma.wizard.currentPageIndex}\n totalPages={forma.wizard.pages.length}\n >\n {renderedFields}\n </PageWrapper>\n );\n }\n\n return <>{renderedFields}</>;\n }, [spec.pages, forma.wizard, PageWrapper, renderedFields]);\n\n return (\n <FormaContext.Provider value={forma}>\n <Layout\n onSubmit={forma.submitForm}\n isSubmitting={forma.isSubmitting}\n isValid={forma.isValid}\n >\n {content}\n </Layout>\n </FormaContext.Provider>\n );\n }\n);\n","/**\n * React Context for Forma\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { UseFormaReturn } from \"./useForma.js\";\n\n/**\n * Context for sharing form state across components\n */\nexport const FormaContext = createContext<UseFormaReturn | null>(null);\n\n/**\n * Hook to access Forma context\n * @throws Error if used outside of FormaContext.Provider\n */\nexport function useFormaContext(): UseFormaReturn {\n const context = useContext(FormaContext);\n if (!context) {\n throw new Error(\"useFormaContext must be used within a FormaContext.Provider\");\n }\n return context;\n}\n","/**\n * FieldRenderer Component\n *\n * Routes a single field to the appropriate component based on its type.\n * This is useful for custom form layouts where you need field-by-field control.\n */\n\nimport React from \"react\";\nimport type { FieldDefinition, JSONSchemaProperty } from \"@fogpipe/forma-core\";\nimport { useFormaContext } from \"./context.js\";\nimport type {\n ComponentMap,\n BaseFieldProps,\n TextFieldProps,\n NumberFieldProps,\n IntegerFieldProps,\n SelectFieldProps,\n MultiSelectFieldProps,\n ArrayFieldProps,\n ArrayHelpers,\n} from \"./types.js\";\n\n/**\n * Props for FieldRenderer component\n */\nexport interface FieldRendererProps {\n /** Field path (e.g., \"firstName\" or \"address.city\") */\n fieldPath: string;\n /** Component map for rendering fields */\n components: ComponentMap;\n /** Optional class name for the wrapper */\n className?: string;\n}\n\n/**\n * Extract numeric constraints from JSON Schema property\n */\nfunction getNumberConstraints(schema?: JSONSchemaProperty): { min?: number; max?: number; step?: number } {\n if (!schema) return {};\n if (schema.type !== \"number\" && schema.type !== \"integer\") return {};\n\n // Extract min/max from schema\n const min = \"minimum\" in schema && typeof schema.minimum === \"number\" ? schema.minimum : undefined;\n const max = \"maximum\" in schema && typeof schema.maximum === \"number\" ? schema.maximum : undefined;\n\n // Use multipleOf for step if defined, otherwise default to 1 for integers\n let step: number | undefined;\n if (\"multipleOf\" in schema && typeof schema.multipleOf === \"number\") {\n step = schema.multipleOf;\n } else if (schema.type === \"integer\") {\n step = 1;\n }\n\n return { min, max, step };\n}\n\n/**\n * Create a default item for an array field based on item field definitions\n */\nfunction createDefaultItem(itemFields: Record<string, FieldDefinition>): Record<string, unknown> {\n const item: Record<string, unknown> = {};\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n if (fieldDef.type === \"boolean\") {\n item[fieldName] = false;\n } else if (fieldDef.type === \"number\" || fieldDef.type === \"integer\") {\n item[fieldName] = null;\n } else {\n item[fieldName] = \"\";\n }\n }\n return item;\n}\n\n/**\n * FieldRenderer component\n *\n * @example\n * ```tsx\n * // Render a specific field with custom components\n * <FieldRenderer fieldPath=\"email\" components={componentMap} />\n * ```\n */\nexport function FieldRenderer({ fieldPath, components, className }: FieldRendererProps) {\n const forma = useFormaContext();\n const { spec } = forma;\n\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n console.warn(`Field not found: ${fieldPath}`);\n return null;\n }\n\n const isVisible = forma.visibility[fieldPath] !== false;\n if (!isVisible) return null;\n\n // Infer field type\n const fieldType = fieldDef.type || (fieldDef.itemFields ? \"array\" : \"text\");\n const componentKey = fieldType as keyof ComponentMap;\n const Component = components[componentKey] || components.fallback;\n\n if (!Component) {\n console.warn(`No component found for field type: ${fieldType}`);\n return null;\n }\n\n const errors = forma.errors.filter((e) => e.field === fieldPath);\n const touched = forma.touched[fieldPath] ?? false;\n const required = forma.required[fieldPath] ?? false;\n const disabled = forma.enabled[fieldPath] === false;\n\n // Get schema property for additional constraints\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Base field props\n const baseProps: BaseFieldProps = {\n name: fieldPath,\n field: fieldDef,\n value: forma.data[fieldPath],\n touched,\n required,\n disabled,\n errors,\n onChange: (value: unknown) => forma.setFieldValue(fieldPath, value),\n onBlur: () => forma.setFieldTouched(fieldPath),\n // Convenience properties\n visible: true, // Always true since we already filtered for visibility\n enabled: !disabled,\n label: fieldDef.label ?? fieldPath,\n description: fieldDef.description,\n placeholder: fieldDef.placeholder,\n };\n\n // Build type-specific props\n let fieldProps: BaseFieldProps | TextFieldProps | NumberFieldProps | IntegerFieldProps | SelectFieldProps | MultiSelectFieldProps | ArrayFieldProps = baseProps;\n\n if (fieldType === \"number\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType: \"number\",\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n ...constraints,\n } as NumberFieldProps;\n } else if (fieldType === \"integer\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType: \"integer\",\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n min: constraints.min,\n max: constraints.max,\n } as IntegerFieldProps;\n } else if (fieldType === \"select\") {\n fieldProps = {\n ...baseProps,\n fieldType: \"select\",\n value: baseProps.value as string | null,\n onChange: baseProps.onChange as (value: string | null) => void,\n options: fieldDef.options ?? [],\n } as SelectFieldProps;\n } else if (fieldType === \"multiselect\") {\n fieldProps = {\n ...baseProps,\n fieldType: \"multiselect\",\n value: (baseProps.value as string[] | undefined) ?? [],\n onChange: baseProps.onChange as (value: string[]) => void,\n options: fieldDef.options ?? [],\n } as MultiSelectFieldProps;\n } else if (fieldType === \"array\" && fieldDef.itemFields) {\n const arrayValue = (baseProps.value as unknown[] | undefined) ?? [];\n const minItems = fieldDef.minItems ?? 0;\n const maxItems = fieldDef.maxItems ?? Infinity;\n const itemFieldDefs = fieldDef.itemFields;\n\n const helpers: ArrayHelpers = {\n items: arrayValue,\n push: (item?: unknown) => {\n const newItem = item ?? createDefaultItem(itemFieldDefs);\n forma.setFieldValue(fieldPath, [...arrayValue, newItem]);\n },\n insert: (index: number, item: unknown) => {\n const newArray = [...arrayValue];\n newArray.splice(index, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n remove: (index: number) => {\n const newArray = [...arrayValue];\n newArray.splice(index, 1);\n forma.setFieldValue(fieldPath, newArray);\n },\n move: (from: number, to: number) => {\n const newArray = [...arrayValue];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const newArray = [...arrayValue];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n forma.setFieldValue(fieldPath, newArray);\n },\n getItemFieldProps: (index: number, fieldName: string) => {\n const itemFieldDef = itemFieldDefs[fieldName];\n const itemPath = `${fieldPath}[${index}].${fieldName}`;\n const itemValue = (arrayValue[index] as Record<string, unknown>)?.[fieldName];\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type ?? \"text\",\n label: itemFieldDef?.label ?? fieldName,\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: !disabled,\n required: itemFieldDef?.requiredWhen === \"true\",\n touched: forma.touched[itemPath] ?? false,\n errors: forma.errors.filter((e) => e.field === itemPath),\n onChange: (value: unknown) => {\n const newArray = [...arrayValue];\n const item = (newArray[index] ?? {}) as Record<string, unknown>;\n newArray[index] = { ...item, [fieldName]: value };\n forma.setFieldValue(fieldPath, newArray);\n },\n onBlur: () => forma.setFieldTouched(itemPath),\n itemIndex: index,\n fieldName,\n options: itemFieldDef?.options,\n };\n },\n minItems,\n maxItems,\n canAdd: arrayValue.length < maxItems,\n canRemove: arrayValue.length > minItems,\n };\n fieldProps = {\n ...baseProps,\n fieldType: \"array\",\n value: arrayValue,\n onChange: baseProps.onChange as (value: unknown[]) => void,\n helpers,\n itemFields: itemFieldDefs,\n minItems,\n maxItems,\n } as ArrayFieldProps;\n } else {\n // Text-based fields\n fieldProps = {\n ...baseProps,\n fieldType: fieldType as \"text\" | \"email\" | \"password\" | \"url\" | \"textarea\",\n value: (baseProps.value as string) ?? \"\",\n onChange: baseProps.onChange as (value: string) => void,\n };\n }\n\n // Wrap props in { field, spec } structure for components\n const componentProps = { field: fieldProps, spec };\n const element = React.createElement(Component as React.ComponentType<typeof componentProps>, componentProps);\n\n if (className) {\n return <div className={className}>{element}</div>;\n }\n\n return element;\n}\n","/**\n * FormaErrorBoundary Component\n *\n * Error boundary for catching render errors in form components.\n * Provides graceful error handling and recovery options.\n */\n\nimport React from \"react\";\n\n/**\n * Props for FormaErrorBoundary component\n */\nexport interface FormaErrorBoundaryProps {\n /** Child components to render */\n children: React.ReactNode;\n /** Custom fallback UI to show when an error occurs */\n fallback?: React.ReactNode | ((error: Error, reset: () => void) => React.ReactNode);\n /** Callback when an error is caught */\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n /** Key to reset the error boundary (change this to reset) */\n resetKey?: string | number;\n}\n\n/**\n * State for FormaErrorBoundary component\n */\ninterface FormaErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * Default fallback component shown when an error occurs\n */\nfunction DefaultErrorFallback({ error, onReset }: { error: Error; onReset: () => void }) {\n return (\n <div className=\"forma-error-boundary\" role=\"alert\">\n <h3>Something went wrong</h3>\n <p>An error occurred while rendering the form.</p>\n <details>\n <summary>Error details</summary>\n <pre>{error.message}</pre>\n </details>\n <button type=\"button\" onClick={onReset}>\n Try again\n </button>\n </div>\n );\n}\n\n/**\n * Error boundary component for Forma forms\n *\n * Catches JavaScript errors in child component tree and displays\n * a fallback UI instead of crashing the entire application.\n *\n * @example\n * ```tsx\n * <FormaErrorBoundary\n * fallback={<div>Form error occurred</div>}\n * onError={(error) => logError(error)}\n * >\n * <FormRenderer spec={spec} components={components} />\n * </FormaErrorBoundary>\n * ```\n */\nexport class FormaErrorBoundary extends React.Component<\n FormaErrorBoundaryProps,\n FormaErrorBoundaryState\n> {\n constructor(props: FormaErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): FormaErrorBoundaryState {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.props.onError?.(error, errorInfo);\n }\n\n componentDidUpdate(prevProps: FormaErrorBoundaryProps): void {\n // Reset error state when resetKey changes\n if (\n this.state.hasError &&\n prevProps.resetKey !== this.props.resetKey\n ) {\n this.setState({ hasError: false, error: null });\n }\n }\n\n reset = (): void => {\n this.setState({ hasError: false, error: null });\n };\n\n render(): React.ReactNode {\n if (this.state.hasError && this.state.error) {\n const { fallback } = this.props;\n\n if (typeof fallback === \"function\") {\n return fallback(this.state.error, this.reset);\n }\n\n if (fallback) {\n return fallback;\n }\n\n return <DefaultErrorFallback error={this.state.error} onReset={this.reset} />;\n }\n\n return this.props.children;\n }\n}\n"],"mappings":"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","names":["useRef","useMemo","useCallback","FormRenderer","useRef","useCallback","useMemo","React","jsx","getNumberConstraints","createDefaultItem","React","React","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/useForma.ts","../src/FormRenderer.tsx","../src/context.ts","../src/FieldRenderer.tsx","../src/ErrorBoundary.tsx"],"sourcesContent":["/**\n * useForma Hook\n *\n * Main hook for managing Forma form state.\n * This is a placeholder - the full implementation will be migrated from formidable.\n */\n\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport type { Forma, FieldError, ValidationResult } from \"@fogpipe/forma-core\";\nimport type { GetFieldPropsResult, GetSelectFieldPropsResult, GetArrayHelpersResult } from \"./types.js\";\nimport {\n getVisibility,\n getRequired,\n getEnabled,\n validate,\n calculate,\n getPageVisibility,\n} from \"@fogpipe/forma-core\";\n\n/**\n * Options for useForma hook\n */\nexport interface UseFormaOptions {\n /** The Forma specification */\n spec: Forma;\n /** Initial form data */\n initialData?: Record<string, unknown>;\n /** Submit handler */\n onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;\n /** Change handler */\n onChange?: (data: Record<string, unknown>, computed?: Record<string, unknown>) => void;\n /** When to validate: on change, blur, or submit only */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Additional reference data to merge with spec.referenceData */\n referenceData?: Record<string, unknown>;\n /**\n * Debounce validation by this many milliseconds.\n * Useful for large forms to improve performance.\n * Set to 0 (default) for immediate validation.\n */\n validationDebounceMs?: number;\n}\n\n/**\n * Form state\n */\ninterface FormState {\n data: Record<string, unknown>;\n touched: Record<string, boolean>;\n isSubmitting: boolean;\n isSubmitted: boolean;\n isDirty: boolean;\n currentPage: number;\n}\n\n/**\n * State actions\n */\ntype FormAction =\n | { type: \"SET_FIELD_VALUE\"; field: string; value: unknown }\n | { type: \"SET_FIELD_TOUCHED\"; field: string; touched: boolean }\n | { type: \"SET_VALUES\"; values: Record<string, unknown> }\n | { type: \"SET_SUBMITTING\"; isSubmitting: boolean }\n | { type: \"SET_SUBMITTED\"; isSubmitted: boolean }\n | { type: \"SET_PAGE\"; page: number }\n | { type: \"RESET\"; initialData: Record<string, unknown> };\n\n/**\n * Page state for multi-page forms\n */\nexport interface PageState {\n id: string;\n title: string;\n description?: string;\n visible: boolean;\n fields: string[];\n}\n\n/**\n * Wizard navigation helpers\n */\nexport interface WizardHelpers {\n pages: PageState[];\n currentPageIndex: number;\n currentPage: PageState | null;\n goToPage: (index: number) => void;\n nextPage: () => void;\n previousPage: () => void;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n canProceed: boolean;\n isLastPage: boolean;\n touchCurrentPageFields: () => void;\n validateCurrentPage: () => boolean;\n}\n\n/**\n * Return type of useForma hook\n */\nexport interface UseFormaReturn {\n /** Current form data */\n data: Record<string, unknown>;\n /** Computed field values */\n computed: Record<string, unknown>;\n /** Field visibility map */\n visibility: Record<string, boolean>;\n /** Field required state map */\n required: Record<string, boolean>;\n /** Field enabled state map */\n enabled: Record<string, boolean>;\n /** Field touched state map */\n touched: Record<string, boolean>;\n /** Validation errors */\n errors: FieldError[];\n /** Whether form is valid */\n isValid: boolean;\n /** Whether form is submitting */\n isSubmitting: boolean;\n /** Whether form has been submitted */\n isSubmitted: boolean;\n /** Whether any field has been modified */\n isDirty: boolean;\n /** The Forma spec */\n spec: Forma;\n /** Wizard helpers (if multi-page) */\n wizard: WizardHelpers | null;\n\n /** Set a field value */\n setFieldValue: (path: string, value: unknown) => void;\n /** Set a field as touched */\n setFieldTouched: (path: string, touched?: boolean) => void;\n /** Set multiple values */\n setValues: (values: Record<string, unknown>) => void;\n /** Validate a single field */\n validateField: (path: string) => FieldError[];\n /** Validate entire form */\n validateForm: () => ValidationResult;\n /** Submit the form */\n submitForm: () => Promise<void>;\n /** Reset the form */\n resetForm: () => void;\n\n // Helper methods for getting field props\n /** Get props for any field */\n getFieldProps: (path: string) => GetFieldPropsResult;\n /** Get props for select field (includes options) */\n getSelectFieldProps: (path: string) => GetSelectFieldPropsResult;\n /** Get array helpers for array field */\n getArrayHelpers: (path: string) => GetArrayHelpersResult;\n}\n\n/**\n * State reducer\n */\nfunction formReducer(state: FormState, action: FormAction): FormState {\n switch (action.type) {\n case \"SET_FIELD_VALUE\":\n return {\n ...state,\n data: { ...state.data, [action.field]: action.value },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_FIELD_TOUCHED\":\n return {\n ...state,\n touched: { ...state.touched, [action.field]: action.touched },\n };\n case \"SET_VALUES\":\n return {\n ...state,\n data: { ...state.data, ...action.values },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_SUBMITTING\":\n return { ...state, isSubmitting: action.isSubmitting };\n case \"SET_SUBMITTED\":\n return { ...state, isSubmitted: action.isSubmitted };\n case \"SET_PAGE\":\n return { ...state, currentPage: action.page };\n case \"RESET\":\n return {\n data: action.initialData,\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n };\n default:\n return state;\n }\n}\n\n/**\n * Get default initial values for boolean fields.\n * Boolean fields default to false to avoid undefined state,\n * which provides better UX since false is a valid answer.\n */\nfunction getDefaultBooleanValues(spec: Forma): Record<string, boolean> {\n const defaults: Record<string, boolean> = {};\n for (const fieldPath of spec.fieldOrder) {\n const schemaProperty = spec.schema.properties?.[fieldPath];\n const fieldDef = spec.fields[fieldPath];\n if (schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\") {\n defaults[fieldPath] = false;\n }\n }\n return defaults;\n}\n\n/**\n * Main Forma hook\n */\nexport function useForma(options: UseFormaOptions): UseFormaReturn {\n const { spec: inputSpec, initialData = {}, onSubmit, onChange, validateOn = \"blur\", referenceData, validationDebounceMs = 0 } = options;\n\n // Merge referenceData from options with spec.referenceData\n const spec = useMemo((): Forma => {\n if (!referenceData) return inputSpec;\n return {\n ...inputSpec,\n referenceData: {\n ...inputSpec.referenceData,\n ...referenceData,\n },\n };\n }, [inputSpec, referenceData]);\n\n const [state, dispatch] = useReducer(formReducer, {\n data: { ...getDefaultBooleanValues(spec), ...initialData }, // Boolean defaults merged UNDER initialData\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n });\n\n // Track if we've initialized (to avoid calling onChange on first render)\n const hasInitialized = useRef(false);\n\n // Calculate computed values\n const computed = useMemo(\n () => calculate(state.data, spec),\n [state.data, spec]\n );\n\n // Calculate visibility\n const visibility = useMemo(\n () => getVisibility(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Calculate required state\n const required = useMemo(\n () => getRequired(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Calculate enabled state\n const enabled = useMemo(\n () => getEnabled(state.data, spec, { computed }),\n [state.data, spec, computed]\n );\n\n // Validate form - compute immediate result\n const immediateValidation = useMemo(\n () => validate(state.data, spec, { computed, onlyVisible: true }),\n [state.data, spec, computed]\n );\n\n // Debounced validation state (only used when validationDebounceMs > 0)\n const [debouncedValidation, setDebouncedValidation] = useState<ValidationResult>(immediateValidation);\n\n // Apply debouncing if configured\n useEffect(() => {\n if (validationDebounceMs <= 0) {\n // No debouncing - use immediate validation\n setDebouncedValidation(immediateValidation);\n return;\n }\n\n // Debounce validation updates\n const timeoutId = setTimeout(() => {\n setDebouncedValidation(immediateValidation);\n }, validationDebounceMs);\n\n return () => clearTimeout(timeoutId);\n }, [immediateValidation, validationDebounceMs]);\n\n // Use debounced validation for display, but immediate for submit\n const validation = validationDebounceMs > 0 ? debouncedValidation : immediateValidation;\n\n // isDirty is tracked via reducer state for O(1) performance\n\n // Call onChange when data changes (not on initial render)\n useEffect(() => {\n if (hasInitialized.current) {\n onChange?.(state.data, computed);\n } else {\n hasInitialized.current = true;\n }\n }, [state.data, computed, onChange]);\n\n // Helper function to set value at nested path\n const setNestedValue = useCallback((path: string, value: unknown): void => {\n // Handle array index notation: \"items[0].name\" -> nested structure\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n\n if (parts.length === 1) {\n // Simple path - just set directly\n dispatch({ type: \"SET_FIELD_VALUE\", field: path, value });\n return;\n }\n\n // Build nested object for complex paths\n const buildNestedObject = (data: Record<string, unknown>, pathParts: string[], val: unknown): Record<string, unknown> => {\n const result = { ...data };\n let current: Record<string, unknown> = result;\n\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i];\n const nextPart = pathParts[i + 1];\n const isNextArrayIndex = /^\\d+$/.test(nextPart);\n\n if (current[part] === undefined) {\n current[part] = isNextArrayIndex ? [] : {};\n } else if (Array.isArray(current[part])) {\n current[part] = [...(current[part] as unknown[])];\n } else {\n current[part] = { ...(current[part] as Record<string, unknown>) };\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[pathParts[pathParts.length - 1]] = val;\n return result;\n };\n\n dispatch({ type: \"SET_VALUES\", values: buildNestedObject(state.data, parts, value) });\n }, [state.data]);\n\n // Actions\n const setFieldValue = useCallback(\n (path: string, value: unknown) => {\n setNestedValue(path, value);\n if (validateOn === \"change\") {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field: path, touched: true });\n }\n },\n [validateOn, setNestedValue]\n );\n\n const setFieldTouched = useCallback((path: string, touched = true) => {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field: path, touched });\n }, []);\n\n const setValues = useCallback((values: Record<string, unknown>) => {\n dispatch({ type: \"SET_VALUES\", values });\n }, []);\n\n const validateField = useCallback(\n (path: string): FieldError[] => {\n return validation.errors.filter((e) => e.field === path);\n },\n [validation]\n );\n\n const validateForm = useCallback((): ValidationResult => {\n return validation;\n }, [validation]);\n\n const submitForm = useCallback(async () => {\n dispatch({ type: \"SET_SUBMITTING\", isSubmitting: true });\n try {\n // Always use immediate validation on submit to ensure accurate result\n if (immediateValidation.valid && onSubmit) {\n await onSubmit(state.data);\n }\n dispatch({ type: \"SET_SUBMITTED\", isSubmitted: true });\n } finally {\n dispatch({ type: \"SET_SUBMITTING\", isSubmitting: false });\n }\n }, [immediateValidation, onSubmit, state.data]);\n\n const resetForm = useCallback(() => {\n dispatch({ type: \"RESET\", initialData });\n }, [initialData]);\n\n // Wizard helpers\n const wizard = useMemo((): WizardHelpers | null => {\n if (!spec.pages || spec.pages.length === 0) return null;\n\n const pageVisibility = getPageVisibility(state.data, spec, { computed });\n\n // Include all pages with their visibility status\n const pages: PageState[] = spec.pages.map((p) => ({\n id: p.id,\n title: p.title,\n description: p.description,\n visible: pageVisibility[p.id] !== false,\n fields: p.fields,\n }));\n\n // For navigation, only count visible pages\n const visiblePages = pages.filter((p) => p.visible);\n\n // Clamp currentPage to valid range (handles case where current page becomes hidden)\n const maxPageIndex = Math.max(0, visiblePages.length - 1);\n const clampedPageIndex = Math.min(Math.max(0, state.currentPage), maxPageIndex);\n\n // Auto-correct page index if it's out of bounds\n if (clampedPageIndex !== state.currentPage && visiblePages.length > 0) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex });\n }\n\n const currentPage = visiblePages[clampedPageIndex] || null;\n const hasNextPage = clampedPageIndex < visiblePages.length - 1;\n const hasPreviousPage = clampedPageIndex > 0;\n const isLastPage = clampedPageIndex === visiblePages.length - 1;\n\n return {\n pages,\n currentPageIndex: clampedPageIndex,\n currentPage,\n goToPage: (index: number) => {\n // Clamp to valid range\n const validIndex = Math.min(Math.max(0, index), maxPageIndex);\n dispatch({ type: \"SET_PAGE\", page: validIndex });\n },\n nextPage: () => {\n if (hasNextPage) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex + 1 });\n }\n },\n previousPage: () => {\n if (hasPreviousPage) {\n dispatch({ type: \"SET_PAGE\", page: clampedPageIndex - 1 });\n }\n },\n hasNextPage,\n hasPreviousPage,\n canProceed: (() => {\n if (!currentPage) return true;\n // Get errors only for visible fields on the current page\n const pageErrors = validation.errors.filter((e) => {\n // Check if field is on current page (including array items like \"items[0].name\")\n const isOnCurrentPage = currentPage.fields.includes(e.field) ||\n currentPage.fields.some(f => e.field.startsWith(`${f}[`));\n // Only count errors for visible fields\n const isVisible = visibility[e.field] !== false;\n // Only count actual errors, not warnings\n const isError = e.severity === 'error';\n return isOnCurrentPage && isVisible && isError;\n });\n return pageErrors.length === 0;\n })(),\n isLastPage,\n touchCurrentPageFields: () => {\n if (currentPage) {\n currentPage.fields.forEach((field) => {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field, touched: true });\n });\n }\n },\n validateCurrentPage: () => {\n if (!currentPage) return true;\n const pageErrors = validation.errors.filter((e) =>\n currentPage.fields.includes(e.field)\n );\n return pageErrors.length === 0;\n },\n };\n }, [spec, state.data, state.currentPage, computed, validation, visibility]);\n\n // Helper to get value at nested path\n const getValueAtPath = useCallback((path: string): unknown => {\n // Handle array index notation: \"items[0].name\" -> [\"items\", \"0\", \"name\"]\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n let value: unknown = state.data;\n for (const part of parts) {\n if (value === null || value === undefined) return undefined;\n value = (value as Record<string, unknown>)[part];\n }\n return value;\n }, [state.data]);\n\n // Helper to set value at nested path\n const setValueAtPath = useCallback((path: string, value: unknown): void => {\n // For nested paths, we need to build the nested structure\n const parts = path.replace(/\\[(\\d+)\\]/g, '.$1').split('.');\n if (parts.length === 1) {\n dispatch({ type: \"SET_FIELD_VALUE\", field: path, value });\n return;\n }\n\n // Build nested object\n const newData = { ...state.data };\n let current: Record<string, unknown> = newData;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n const isNextArrayIndex = /^\\d+$/.test(nextPart);\n\n if (current[part] === undefined) {\n current[part] = isNextArrayIndex ? [] : {};\n } else if (Array.isArray(current[part])) {\n current[part] = [...(current[part] as unknown[])];\n } else {\n current[part] = { ...(current[part] as Record<string, unknown>) };\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[parts[parts.length - 1]] = value;\n dispatch({ type: \"SET_VALUES\", values: newData });\n }, [state.data]);\n\n // Memoized onChange/onBlur handlers for fields\n const fieldHandlers = useRef<Map<string, { onChange: (value: unknown) => void; onBlur: () => void }>>(new Map());\n\n // Clean up stale field handlers when spec changes to prevent memory leaks\n useEffect(() => {\n const validFields = new Set(spec.fieldOrder);\n // Also include array item field patterns\n for (const fieldId of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldId];\n if (fieldDef?.itemFields) {\n for (const key of fieldHandlers.current.keys()) {\n if (key.startsWith(`${fieldId}[`)) {\n validFields.add(key);\n }\n }\n }\n }\n // Remove handlers for fields that no longer exist\n for (const key of fieldHandlers.current.keys()) {\n const baseField = key.split('[')[0];\n if (!validFields.has(key) && !validFields.has(baseField)) {\n fieldHandlers.current.delete(key);\n }\n }\n }, [spec]);\n\n const getFieldHandlers = useCallback((path: string) => {\n if (!fieldHandlers.current.has(path)) {\n fieldHandlers.current.set(path, {\n onChange: (value: unknown) => setValueAtPath(path, value),\n onBlur: () => setFieldTouched(path),\n });\n }\n return fieldHandlers.current.get(path)!;\n }, [setValueAtPath, setFieldTouched]);\n\n // Get field props for any field\n const getFieldProps = useCallback((path: string): GetFieldPropsResult => {\n const fieldDef = spec.fields[path];\n const handlers = getFieldHandlers(path);\n\n // Determine field type from definition or infer from schema\n let fieldType = fieldDef?.type || \"text\";\n if (!fieldType || fieldType === \"computed\") {\n const schemaProperty = spec.schema.properties[path];\n if (schemaProperty) {\n if (schemaProperty.type === \"number\") fieldType = \"number\";\n else if (schemaProperty.type === \"integer\") fieldType = \"integer\";\n else if (schemaProperty.type === \"boolean\") fieldType = \"boolean\";\n else if (schemaProperty.type === \"array\") fieldType = \"array\";\n else if (schemaProperty.type === \"object\") fieldType = \"object\";\n else if (\"enum\" in schemaProperty && schemaProperty.enum) fieldType = \"select\";\n else if (\"format\" in schemaProperty) {\n if (schemaProperty.format === \"date\") fieldType = \"date\";\n else if (schemaProperty.format === \"date-time\") fieldType = \"datetime\";\n else if (schemaProperty.format === \"email\") fieldType = \"email\";\n else if (schemaProperty.format === \"uri\") fieldType = \"url\";\n }\n }\n }\n\n const fieldErrors = validation.errors.filter((e) => e.field === path);\n const isTouched = state.touched[path] ?? false;\n const showErrors = validateOn === \"change\" || (validateOn === \"blur\" && isTouched) || state.isSubmitted;\n const displayedErrors = showErrors ? fieldErrors : [];\n const hasErrors = displayedErrors.length > 0;\n const isRequired = required[path] ?? false;\n\n // Boolean fields: hide asterisk unless they have validation rules (consent pattern)\n // - Binary question (\"Do you smoke?\"): no validation → false is valid → hide asterisk\n // - Consent checkbox (\"I accept terms\"): has validation rule → show asterisk\n const schemaProperty = spec.schema.properties[path];\n const isBooleanField = schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\";\n const hasValidationRules = (fieldDef?.validations?.length ?? 0) > 0;\n const showRequiredIndicator = isRequired && (!isBooleanField || hasValidationRules);\n\n return {\n name: path,\n value: getValueAtPath(path),\n type: fieldType,\n label: fieldDef?.label || path.charAt(0).toUpperCase() + path.slice(1),\n description: fieldDef?.description,\n placeholder: fieldDef?.placeholder,\n visible: visibility[path] !== false,\n enabled: enabled[path] !== false,\n required: isRequired,\n showRequiredIndicator,\n touched: isTouched,\n errors: displayedErrors,\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n // ARIA accessibility attributes\n \"aria-invalid\": hasErrors || undefined,\n \"aria-describedby\": hasErrors ? `${path}-error` : undefined,\n \"aria-required\": isRequired || undefined,\n };\n }, [spec, state.touched, state.isSubmitted, visibility, enabled, required, validation.errors, validateOn, getValueAtPath, getFieldHandlers]);\n\n // Get select field props\n const getSelectFieldProps = useCallback((path: string): GetSelectFieldPropsResult => {\n const baseProps = getFieldProps(path);\n const fieldDef = spec.fields[path];\n\n return {\n ...baseProps,\n options: fieldDef?.options ?? [],\n };\n }, [getFieldProps, spec.fields]);\n\n // Get array helpers\n const getArrayHelpers = useCallback((path: string): GetArrayHelpersResult => {\n const fieldDef = spec.fields[path];\n const currentValue = (getValueAtPath(path) as unknown[]) ?? [];\n const minItems = fieldDef?.minItems ?? 0;\n const maxItems = fieldDef?.maxItems ?? Infinity;\n\n const canAdd = currentValue.length < maxItems;\n const canRemove = currentValue.length > minItems;\n\n const getItemFieldProps = (index: number, fieldName: string): GetFieldPropsResult => {\n const itemPath = `${path}[${index}].${fieldName}`;\n const itemFieldDef = fieldDef?.itemFields?.[fieldName];\n const handlers = getFieldHandlers(itemPath);\n\n // Get item value\n const item = currentValue[index] as Record<string, unknown> | undefined;\n const itemValue = item?.[fieldName];\n\n const fieldErrors = validation.errors.filter((e) => e.field === itemPath);\n const isTouched = state.touched[itemPath] ?? false;\n const showErrors = validateOn === \"change\" || (validateOn === \"blur\" && isTouched) || state.isSubmitted;\n\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type || \"text\",\n label: itemFieldDef?.label || fieldName.charAt(0).toUpperCase() + fieldName.slice(1),\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: enabled[path] !== false,\n required: false, // TODO: Evaluate item field required\n showRequiredIndicator: false, // Item fields don't show required indicator\n touched: isTouched,\n errors: showErrors ? fieldErrors : [],\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n };\n };\n\n return {\n items: currentValue,\n push: (item: unknown) => {\n if (canAdd) {\n setValueAtPath(path, [...currentValue, item]);\n }\n },\n remove: (index: number) => {\n if (canRemove) {\n const newArray = [...currentValue];\n newArray.splice(index, 1);\n setValueAtPath(path, newArray);\n }\n },\n move: (from: number, to: number) => {\n const newArray = [...currentValue];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n setValueAtPath(path, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const newArray = [...currentValue];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n setValueAtPath(path, newArray);\n },\n insert: (index: number, item: unknown) => {\n if (canAdd) {\n const newArray = [...currentValue];\n newArray.splice(index, 0, item);\n setValueAtPath(path, newArray);\n }\n },\n getItemFieldProps,\n minItems,\n maxItems,\n canAdd,\n canRemove,\n };\n }, [spec.fields, getValueAtPath, setValueAtPath, getFieldHandlers, enabled, state.touched, state.isSubmitted, validation.errors, validateOn]);\n\n return {\n data: state.data,\n computed,\n visibility,\n required,\n enabled,\n touched: state.touched,\n errors: validation.errors,\n isValid: validation.valid,\n isSubmitting: state.isSubmitting,\n isSubmitted: state.isSubmitted,\n isDirty: state.isDirty,\n spec,\n wizard,\n setFieldValue,\n setFieldTouched,\n setValues,\n validateField,\n validateForm,\n submitForm,\n resetForm,\n getFieldProps,\n getSelectFieldProps,\n getArrayHelpers,\n };\n}\n","/**\n * FormRenderer Component\n *\n * Renders a complete form from a Forma specification.\n * Supports single-page and multi-page (wizard) forms.\n */\n\nimport React, { forwardRef, useImperativeHandle, useRef, useMemo, useCallback } from \"react\";\nimport type { Forma, FieldDefinition, ValidationResult, JSONSchemaProperty } from \"@fogpipe/forma-core\";\nimport { useForma } from \"./useForma.js\";\nimport { FormaContext } from \"./context.js\";\nimport type { ComponentMap, LayoutProps, FieldWrapperProps, PageWrapperProps, BaseFieldProps, TextFieldProps, NumberFieldProps, SelectFieldProps, ArrayFieldProps, ArrayHelpers } from \"./types.js\";\n\n/**\n * Props for FormRenderer component\n */\nexport interface FormRendererProps {\n /** The Forma specification */\n spec: Forma;\n /** Initial form data */\n initialData?: Record<string, unknown>;\n /** Submit handler */\n onSubmit?: (data: Record<string, unknown>) => void | Promise<void>;\n /** Change handler */\n onChange?: (data: Record<string, unknown>, computed?: Record<string, unknown>) => void;\n /** Component map for rendering fields */\n components: ComponentMap;\n /** Custom layout component */\n layout?: React.ComponentType<LayoutProps>;\n /** Custom field wrapper component */\n fieldWrapper?: React.ComponentType<FieldWrapperProps>;\n /** Custom page wrapper component */\n pageWrapper?: React.ComponentType<PageWrapperProps>;\n /** When to validate */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Current page for controlled wizard */\n page?: number;\n}\n\n/**\n * Imperative handle for FormRenderer\n */\nexport interface FormRendererHandle {\n submitForm: () => Promise<void>;\n resetForm: () => void;\n validateForm: () => ValidationResult;\n focusField: (path: string) => void;\n focusFirstError: () => void;\n getValues: () => Record<string, unknown>;\n setValues: (values: Record<string, unknown>) => void;\n isValid: boolean;\n isDirty: boolean;\n}\n\n/**\n * Default layout component\n */\nfunction DefaultLayout({ children, onSubmit, isSubmitting }: LayoutProps) {\n return (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n {children}\n <button type=\"submit\" disabled={isSubmitting}>\n {isSubmitting ? \"Submitting...\" : \"Submit\"}\n </button>\n </form>\n );\n}\n\n/**\n * Default field wrapper component with accessibility support\n */\nfunction DefaultFieldWrapper({ fieldPath, field, children, errors, showRequiredIndicator, visible }: FieldWrapperProps) {\n if (!visible) return null;\n\n const errorId = `${fieldPath}-error`;\n const descriptionId = field.description ? `${fieldPath}-description` : undefined;\n const hasErrors = errors.length > 0;\n\n return (\n <div className=\"field-wrapper\" data-field-path={fieldPath}>\n {field.label && (\n <label htmlFor={fieldPath}>\n {field.label}\n {showRequiredIndicator && <span className=\"required\" aria-hidden=\"true\">*</span>}\n {showRequiredIndicator && <span className=\"sr-only\"> (required)</span>}\n </label>\n )}\n {children}\n {hasErrors && (\n <div\n id={errorId}\n className=\"field-errors\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n {errors.map((error, i) => (\n <span key={i} className=\"error\">\n {error.message}\n </span>\n ))}\n </div>\n )}\n {field.description && (\n <p id={descriptionId} className=\"field-description\">\n {field.description}\n </p>\n )}\n </div>\n );\n}\n\n/**\n * Default page wrapper component\n */\nfunction DefaultPageWrapper({ title, description, children }: PageWrapperProps) {\n return (\n <div className=\"page-wrapper\">\n <h2>{title}</h2>\n {description && <p>{description}</p>}\n {children}\n </div>\n );\n}\n\n/**\n * Extract numeric constraints from JSON Schema property\n */\nfunction getNumberConstraints(schema?: JSONSchemaProperty): { min?: number; max?: number; step?: number } {\n if (!schema) return {};\n if (schema.type !== \"number\" && schema.type !== \"integer\") return {};\n\n // Extract min/max from schema\n const min = \"minimum\" in schema && typeof schema.minimum === \"number\" ? schema.minimum : undefined;\n const max = \"maximum\" in schema && typeof schema.maximum === \"number\" ? schema.maximum : undefined;\n\n // Use multipleOf for step if defined, otherwise default to 1 for integers\n let step: number | undefined;\n if (\"multipleOf\" in schema && typeof schema.multipleOf === \"number\") {\n step = schema.multipleOf;\n } else if (schema.type === \"integer\") {\n step = 1;\n }\n\n return { min, max, step };\n}\n\n/**\n * Create a default item for an array field based on item field definitions\n */\nfunction createDefaultItem(itemFields: Record<string, FieldDefinition>): Record<string, unknown> {\n const item: Record<string, unknown> = {};\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n if (fieldDef.type === \"boolean\") {\n item[fieldName] = false;\n } else if (fieldDef.type === \"number\" || fieldDef.type === \"integer\") {\n item[fieldName] = null;\n } else {\n item[fieldName] = \"\";\n }\n }\n return item;\n}\n\n/**\n * FormRenderer component\n */\nexport const FormRenderer = forwardRef<FormRendererHandle, FormRendererProps>(\n function FormRenderer(props, ref) {\n const {\n spec,\n initialData,\n onSubmit,\n onChange,\n components,\n layout: Layout = DefaultLayout,\n fieldWrapper: FieldWrapper = DefaultFieldWrapper,\n pageWrapper: PageWrapper = DefaultPageWrapper,\n validateOn,\n } = props;\n\n const forma = useForma({\n spec,\n initialData,\n onSubmit,\n onChange,\n validateOn,\n });\n\n const fieldRefs = useRef<Map<string, HTMLElement>>(new Map());\n\n // Cache for array helper functions to prevent recreation on every render\n const arrayHelpersCache = useRef<Map<string, {\n push: (item?: unknown) => void;\n insert: (index: number, item: unknown) => void;\n remove: (index: number) => void;\n move: (from: number, to: number) => void;\n swap: (indexA: number, indexB: number) => void;\n }>>(new Map());\n\n // Focus a specific field by path\n const focusField = useCallback((path: string) => {\n const element = fieldRefs.current.get(path);\n element?.focus();\n }, []);\n\n // Focus the first field with an error\n const focusFirstError = useCallback(() => {\n const firstError = forma.errors[0];\n if (firstError) {\n focusField(firstError.field);\n }\n }, [forma.errors, focusField]);\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n submitForm: forma.submitForm,\n resetForm: forma.resetForm,\n validateForm: forma.validateForm,\n focusField,\n focusFirstError,\n getValues: () => forma.data,\n setValues: forma.setValues,\n isValid: forma.isValid,\n isDirty: forma.isDirty,\n }),\n [forma, focusField, focusFirstError]\n );\n\n // Determine which fields to render based on pages or fieldOrder\n const fieldsToRender = useMemo(() => {\n if (spec.pages && spec.pages.length > 0 && forma.wizard) {\n // Wizard mode - render fields for the active page\n const currentPage = forma.wizard.currentPage;\n if (currentPage) {\n return currentPage.fields;\n }\n // Fallback to first page\n return spec.pages[0]?.fields ?? [];\n }\n // Single page mode - render all fields in order\n return spec.fieldOrder;\n }, [spec.pages, spec.fieldOrder, forma.wizard]);\n\n // Render a single field (memoized)\n const renderField = useCallback((fieldPath: string) => {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) return null;\n\n const isVisible = forma.visibility[fieldPath] !== false;\n if (!isVisible) return null;\n\n // Infer field type\n const fieldType = fieldDef.type || (fieldDef.itemFields ? \"array\" : \"text\");\n const componentKey = fieldType as keyof ComponentMap;\n const Component = components[componentKey] || components.fallback;\n\n if (!Component) {\n console.warn(`No component found for field type: ${fieldType}`);\n return null;\n }\n\n const errors = forma.errors.filter((e) => e.field === fieldPath);\n const touched = forma.touched[fieldPath] ?? false;\n const required = forma.required[fieldPath] ?? false;\n const disabled = forma.enabled[fieldPath] === false;\n\n // Get schema property for additional constraints\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Boolean fields: hide asterisk unless they have validation rules (consent pattern)\n // - Binary question (\"Do you smoke?\"): no validation → false is valid → hide asterisk\n // - Consent checkbox (\"I accept terms\"): has validation rule → show asterisk\n const isBooleanField = schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\";\n const hasValidationRules = (fieldDef?.validations?.length ?? 0) > 0;\n const showRequiredIndicator = required && (!isBooleanField || hasValidationRules);\n\n // Base field props\n const baseProps: BaseFieldProps = {\n name: fieldPath,\n field: fieldDef,\n value: forma.data[fieldPath],\n touched,\n required,\n disabled,\n errors,\n onChange: (value: unknown) => forma.setFieldValue(fieldPath, value),\n onBlur: () => forma.setFieldTouched(fieldPath),\n // Convenience properties\n visible: true, // Always true since we already filtered for visibility\n enabled: !disabled,\n label: fieldDef.label ?? fieldPath,\n description: fieldDef.description,\n placeholder: fieldDef.placeholder,\n };\n\n // Build type-specific props\n let fieldProps: BaseFieldProps | TextFieldProps | NumberFieldProps | SelectFieldProps | ArrayFieldProps = baseProps;\n\n if (fieldType === \"number\" || fieldType === \"integer\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType,\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n ...constraints,\n } as NumberFieldProps;\n } else if (fieldType === \"select\" || fieldType === \"multiselect\") {\n fieldProps = {\n ...baseProps,\n fieldType,\n value: baseProps.value as string | string[] | null,\n onChange: baseProps.onChange as (value: string | string[] | null) => void,\n options: fieldDef.options ?? [],\n } as SelectFieldProps;\n } else if (fieldType === \"array\" && fieldDef.itemFields) {\n const arrayValue = (baseProps.value as unknown[] | undefined) ?? [];\n const minItems = fieldDef.minItems ?? 0;\n const maxItems = fieldDef.maxItems ?? Infinity;\n const itemFieldDefs = fieldDef.itemFields;\n\n // Get or create cached helper functions for this array field\n // These functions read current values when called, not when created\n if (!arrayHelpersCache.current.has(fieldPath)) {\n arrayHelpersCache.current.set(fieldPath, {\n push: (item?: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newItem = item ?? createDefaultItem(itemFieldDefs);\n forma.setFieldValue(fieldPath, [...currentArray, newItem]);\n },\n insert: (index: number, item: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n newArray.splice(index, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n remove: (index: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n newArray.splice(index, 1);\n forma.setFieldValue(fieldPath, newArray);\n },\n move: (from: number, to: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n forma.setFieldValue(fieldPath, newArray);\n },\n });\n }\n const cachedHelpers = arrayHelpersCache.current.get(fieldPath)!;\n\n const helpers: ArrayHelpers = {\n items: arrayValue,\n push: cachedHelpers.push,\n insert: cachedHelpers.insert,\n remove: cachedHelpers.remove,\n move: cachedHelpers.move,\n swap: cachedHelpers.swap,\n getItemFieldProps: (index: number, fieldName: string) => {\n const itemFieldDef = itemFieldDefs[fieldName];\n const itemPath = `${fieldPath}[${index}].${fieldName}`;\n const itemValue = (arrayValue[index] as Record<string, unknown>)?.[fieldName];\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type ?? \"text\",\n label: itemFieldDef?.label ?? fieldName,\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: !disabled,\n required: itemFieldDef?.requiredWhen === \"true\",\n touched: forma.touched[itemPath] ?? false,\n errors: forma.errors.filter((e) => e.field === itemPath),\n onChange: (value: unknown) => {\n const currentArray = (forma.data[fieldPath] as unknown[] | undefined) ?? [];\n const newArray = [...currentArray];\n const item = (newArray[index] ?? {}) as Record<string, unknown>;\n newArray[index] = { ...item, [fieldName]: value };\n forma.setFieldValue(fieldPath, newArray);\n },\n onBlur: () => forma.setFieldTouched(itemPath),\n itemIndex: index,\n fieldName,\n options: itemFieldDef?.options,\n };\n },\n minItems,\n maxItems,\n canAdd: arrayValue.length < maxItems,\n canRemove: arrayValue.length > minItems,\n };\n fieldProps = {\n ...baseProps,\n fieldType: \"array\",\n value: arrayValue,\n onChange: baseProps.onChange as (value: unknown[]) => void,\n helpers,\n itemFields: itemFieldDefs,\n minItems,\n maxItems,\n } as ArrayFieldProps;\n } else {\n // Text-based fields\n fieldProps = {\n ...baseProps,\n fieldType: fieldType as \"text\" | \"email\" | \"password\" | \"url\" | \"textarea\",\n value: (baseProps.value as string) ?? \"\",\n onChange: baseProps.onChange as (value: string) => void,\n };\n }\n\n // Wrap props in { field, spec } structure for components\n const componentProps = { field: fieldProps, spec };\n\n return (\n <FieldWrapper\n key={fieldPath}\n fieldPath={fieldPath}\n field={fieldDef}\n errors={errors}\n touched={touched}\n required={required}\n showRequiredIndicator={showRequiredIndicator}\n visible={isVisible}\n >\n {React.createElement(Component as React.ComponentType<typeof componentProps>, componentProps)}\n </FieldWrapper>\n );\n }, [spec, forma, components, FieldWrapper]);\n\n // Render fields (memoized)\n const renderedFields = useMemo(\n () => fieldsToRender.map(renderField),\n [fieldsToRender, renderField]\n );\n\n // Render with page wrapper if using pages\n const content = useMemo(() => {\n if (spec.pages && spec.pages.length > 0 && forma.wizard) {\n const currentPage = forma.wizard.currentPage;\n if (!currentPage) return null;\n\n return (\n <PageWrapper\n title={currentPage.title}\n description={currentPage.description}\n pageIndex={forma.wizard.currentPageIndex}\n totalPages={forma.wizard.pages.length}\n >\n {renderedFields}\n </PageWrapper>\n );\n }\n\n return <>{renderedFields}</>;\n }, [spec.pages, forma.wizard, PageWrapper, renderedFields]);\n\n return (\n <FormaContext.Provider value={forma}>\n <Layout\n onSubmit={forma.submitForm}\n isSubmitting={forma.isSubmitting}\n isValid={forma.isValid}\n >\n {content}\n </Layout>\n </FormaContext.Provider>\n );\n }\n);\n","/**\n * React Context for Forma\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { UseFormaReturn } from \"./useForma.js\";\n\n/**\n * Context for sharing form state across components\n */\nexport const FormaContext = createContext<UseFormaReturn | null>(null);\n\n/**\n * Hook to access Forma context\n * @throws Error if used outside of FormaContext.Provider\n */\nexport function useFormaContext(): UseFormaReturn {\n const context = useContext(FormaContext);\n if (!context) {\n throw new Error(\"useFormaContext must be used within a FormaContext.Provider\");\n }\n return context;\n}\n","/**\n * FieldRenderer Component\n *\n * Routes a single field to the appropriate component based on its type.\n * This is useful for custom form layouts where you need field-by-field control.\n */\n\nimport React from \"react\";\nimport type { FieldDefinition, JSONSchemaProperty } from \"@fogpipe/forma-core\";\nimport { useFormaContext } from \"./context.js\";\nimport type {\n ComponentMap,\n BaseFieldProps,\n TextFieldProps,\n NumberFieldProps,\n IntegerFieldProps,\n SelectFieldProps,\n MultiSelectFieldProps,\n ArrayFieldProps,\n ArrayHelpers,\n} from \"./types.js\";\n\n/**\n * Props for FieldRenderer component\n */\nexport interface FieldRendererProps {\n /** Field path (e.g., \"firstName\" or \"address.city\") */\n fieldPath: string;\n /** Component map for rendering fields */\n components: ComponentMap;\n /** Optional class name for the wrapper */\n className?: string;\n}\n\n/**\n * Extract numeric constraints from JSON Schema property\n */\nfunction getNumberConstraints(schema?: JSONSchemaProperty): { min?: number; max?: number; step?: number } {\n if (!schema) return {};\n if (schema.type !== \"number\" && schema.type !== \"integer\") return {};\n\n // Extract min/max from schema\n const min = \"minimum\" in schema && typeof schema.minimum === \"number\" ? schema.minimum : undefined;\n const max = \"maximum\" in schema && typeof schema.maximum === \"number\" ? schema.maximum : undefined;\n\n // Use multipleOf for step if defined, otherwise default to 1 for integers\n let step: number | undefined;\n if (\"multipleOf\" in schema && typeof schema.multipleOf === \"number\") {\n step = schema.multipleOf;\n } else if (schema.type === \"integer\") {\n step = 1;\n }\n\n return { min, max, step };\n}\n\n/**\n * Create a default item for an array field based on item field definitions\n */\nfunction createDefaultItem(itemFields: Record<string, FieldDefinition>): Record<string, unknown> {\n const item: Record<string, unknown> = {};\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n if (fieldDef.type === \"boolean\") {\n item[fieldName] = false;\n } else if (fieldDef.type === \"number\" || fieldDef.type === \"integer\") {\n item[fieldName] = null;\n } else {\n item[fieldName] = \"\";\n }\n }\n return item;\n}\n\n/**\n * FieldRenderer component\n *\n * @example\n * ```tsx\n * // Render a specific field with custom components\n * <FieldRenderer fieldPath=\"email\" components={componentMap} />\n * ```\n */\nexport function FieldRenderer({ fieldPath, components, className }: FieldRendererProps) {\n const forma = useFormaContext();\n const { spec } = forma;\n\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n console.warn(`Field not found: ${fieldPath}`);\n return null;\n }\n\n const isVisible = forma.visibility[fieldPath] !== false;\n if (!isVisible) return null;\n\n // Infer field type\n const fieldType = fieldDef.type || (fieldDef.itemFields ? \"array\" : \"text\");\n const componentKey = fieldType as keyof ComponentMap;\n const Component = components[componentKey] || components.fallback;\n\n if (!Component) {\n console.warn(`No component found for field type: ${fieldType}`);\n return null;\n }\n\n const errors = forma.errors.filter((e) => e.field === fieldPath);\n const touched = forma.touched[fieldPath] ?? false;\n const required = forma.required[fieldPath] ?? false;\n const disabled = forma.enabled[fieldPath] === false;\n\n // Get schema property for additional constraints\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Base field props\n const baseProps: BaseFieldProps = {\n name: fieldPath,\n field: fieldDef,\n value: forma.data[fieldPath],\n touched,\n required,\n disabled,\n errors,\n onChange: (value: unknown) => forma.setFieldValue(fieldPath, value),\n onBlur: () => forma.setFieldTouched(fieldPath),\n // Convenience properties\n visible: true, // Always true since we already filtered for visibility\n enabled: !disabled,\n label: fieldDef.label ?? fieldPath,\n description: fieldDef.description,\n placeholder: fieldDef.placeholder,\n };\n\n // Build type-specific props\n let fieldProps: BaseFieldProps | TextFieldProps | NumberFieldProps | IntegerFieldProps | SelectFieldProps | MultiSelectFieldProps | ArrayFieldProps = baseProps;\n\n if (fieldType === \"number\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType: \"number\",\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n ...constraints,\n } as NumberFieldProps;\n } else if (fieldType === \"integer\") {\n const constraints = getNumberConstraints(schemaProperty);\n fieldProps = {\n ...baseProps,\n fieldType: \"integer\",\n value: baseProps.value as number | null,\n onChange: baseProps.onChange as (value: number | null) => void,\n min: constraints.min,\n max: constraints.max,\n } as IntegerFieldProps;\n } else if (fieldType === \"select\") {\n fieldProps = {\n ...baseProps,\n fieldType: \"select\",\n value: baseProps.value as string | null,\n onChange: baseProps.onChange as (value: string | null) => void,\n options: fieldDef.options ?? [],\n } as SelectFieldProps;\n } else if (fieldType === \"multiselect\") {\n fieldProps = {\n ...baseProps,\n fieldType: \"multiselect\",\n value: (baseProps.value as string[] | undefined) ?? [],\n onChange: baseProps.onChange as (value: string[]) => void,\n options: fieldDef.options ?? [],\n } as MultiSelectFieldProps;\n } else if (fieldType === \"array\" && fieldDef.itemFields) {\n const arrayValue = (baseProps.value as unknown[] | undefined) ?? [];\n const minItems = fieldDef.minItems ?? 0;\n const maxItems = fieldDef.maxItems ?? Infinity;\n const itemFieldDefs = fieldDef.itemFields;\n\n const helpers: ArrayHelpers = {\n items: arrayValue,\n push: (item?: unknown) => {\n const newItem = item ?? createDefaultItem(itemFieldDefs);\n forma.setFieldValue(fieldPath, [...arrayValue, newItem]);\n },\n insert: (index: number, item: unknown) => {\n const newArray = [...arrayValue];\n newArray.splice(index, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n remove: (index: number) => {\n const newArray = [...arrayValue];\n newArray.splice(index, 1);\n forma.setFieldValue(fieldPath, newArray);\n },\n move: (from: number, to: number) => {\n const newArray = [...arrayValue];\n const [item] = newArray.splice(from, 1);\n newArray.splice(to, 0, item);\n forma.setFieldValue(fieldPath, newArray);\n },\n swap: (indexA: number, indexB: number) => {\n const newArray = [...arrayValue];\n [newArray[indexA], newArray[indexB]] = [newArray[indexB], newArray[indexA]];\n forma.setFieldValue(fieldPath, newArray);\n },\n getItemFieldProps: (index: number, fieldName: string) => {\n const itemFieldDef = itemFieldDefs[fieldName];\n const itemPath = `${fieldPath}[${index}].${fieldName}`;\n const itemValue = (arrayValue[index] as Record<string, unknown>)?.[fieldName];\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type ?? \"text\",\n label: itemFieldDef?.label ?? fieldName,\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: !disabled,\n required: itemFieldDef?.requiredWhen === \"true\",\n touched: forma.touched[itemPath] ?? false,\n errors: forma.errors.filter((e) => e.field === itemPath),\n onChange: (value: unknown) => {\n const newArray = [...arrayValue];\n const item = (newArray[index] ?? {}) as Record<string, unknown>;\n newArray[index] = { ...item, [fieldName]: value };\n forma.setFieldValue(fieldPath, newArray);\n },\n onBlur: () => forma.setFieldTouched(itemPath),\n itemIndex: index,\n fieldName,\n options: itemFieldDef?.options,\n };\n },\n minItems,\n maxItems,\n canAdd: arrayValue.length < maxItems,\n canRemove: arrayValue.length > minItems,\n };\n fieldProps = {\n ...baseProps,\n fieldType: \"array\",\n value: arrayValue,\n onChange: baseProps.onChange as (value: unknown[]) => void,\n helpers,\n itemFields: itemFieldDefs,\n minItems,\n maxItems,\n } as ArrayFieldProps;\n } else {\n // Text-based fields\n fieldProps = {\n ...baseProps,\n fieldType: fieldType as \"text\" | \"email\" | \"password\" | \"url\" | \"textarea\",\n value: (baseProps.value as string) ?? \"\",\n onChange: baseProps.onChange as (value: string) => void,\n };\n }\n\n // Wrap props in { field, spec } structure for components\n const componentProps = { field: fieldProps, spec };\n const element = React.createElement(Component as React.ComponentType<typeof componentProps>, componentProps);\n\n if (className) {\n return <div className={className}>{element}</div>;\n }\n\n return element;\n}\n","/**\n * FormaErrorBoundary Component\n *\n * Error boundary for catching render errors in form components.\n * Provides graceful error handling and recovery options.\n */\n\nimport React from \"react\";\n\n/**\n * Props for FormaErrorBoundary component\n */\nexport interface FormaErrorBoundaryProps {\n /** Child components to render */\n children: React.ReactNode;\n /** Custom fallback UI to show when an error occurs */\n fallback?: React.ReactNode | ((error: Error, reset: () => void) => React.ReactNode);\n /** Callback when an error is caught */\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n /** Key to reset the error boundary (change this to reset) */\n resetKey?: string | number;\n}\n\n/**\n * State for FormaErrorBoundary component\n */\ninterface FormaErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * Default fallback component shown when an error occurs\n */\nfunction DefaultErrorFallback({ error, onReset }: { error: Error; onReset: () => void }) {\n return (\n <div className=\"forma-error-boundary\" role=\"alert\">\n <h3>Something went wrong</h3>\n <p>An error occurred while rendering the form.</p>\n <details>\n <summary>Error details</summary>\n <pre>{error.message}</pre>\n </details>\n <button type=\"button\" onClick={onReset}>\n Try again\n </button>\n </div>\n );\n}\n\n/**\n * Error boundary component for Forma forms\n *\n * Catches JavaScript errors in child component tree and displays\n * a fallback UI instead of crashing the entire application.\n *\n * @example\n * ```tsx\n * <FormaErrorBoundary\n * fallback={<div>Form error occurred</div>}\n * onError={(error) => logError(error)}\n * >\n * <FormRenderer spec={spec} components={components} />\n * </FormaErrorBoundary>\n * ```\n */\nexport class FormaErrorBoundary extends React.Component<\n FormaErrorBoundaryProps,\n FormaErrorBoundaryState\n> {\n constructor(props: FormaErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): FormaErrorBoundaryState {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.props.onError?.(error, errorInfo);\n }\n\n componentDidUpdate(prevProps: FormaErrorBoundaryProps): void {\n // Reset error state when resetKey changes\n if (\n this.state.hasError &&\n prevProps.resetKey !== this.props.resetKey\n ) {\n this.setState({ hasError: false, error: null });\n }\n }\n\n reset = (): void => {\n this.setState({ hasError: false, error: null });\n };\n\n render(): React.ReactNode {\n if (this.state.hasError && this.state.error) {\n const { fallback } = this.props;\n\n if (typeof fallback === \"function\") {\n return fallback(this.state.error, this.reset);\n }\n\n if (fallback) {\n return fallback;\n }\n\n return <DefaultErrorFallback error={this.state.error} onReset={this.reset} />;\n }\n\n return this.props.children;\n }\n}\n"],"mappings":"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","names":["schemaProperty","useRef","useMemo","useCallback","FormRenderer","useRef","useCallback","useMemo","_a","React","jsx","getNumberConstraints","createDefaultItem","React","React","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogpipe/forma-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Headless React form renderer for Forma specifications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"test:coverage": "vitest run --coverage"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@fogpipe/forma-core": "^0.
|
|
33
|
+
"@fogpipe/forma-core": "^0.10.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^18.0.0 || ^19.0.0"
|