@fogpipe/forma-react 0.8.1 → 0.8.2
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.js +27 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/canProceed.test.ts +874 -0
- package/src/__tests__/test-utils.tsx +1 -0
- package/src/__tests__/useForma.test.ts +111 -0
- package/src/useForma.ts +38 -10
package/dist/index.js
CHANGED
|
@@ -186,29 +186,45 @@ function useForma(options) {
|
|
|
186
186
|
fields: p.fields
|
|
187
187
|
}));
|
|
188
188
|
const visiblePages = pages.filter((p) => p.visible);
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
const maxPageIndex = Math.max(0, visiblePages.length - 1);
|
|
190
|
+
const clampedPageIndex = Math.min(Math.max(0, state.currentPage), maxPageIndex);
|
|
191
|
+
if (clampedPageIndex !== state.currentPage && visiblePages.length > 0) {
|
|
192
|
+
dispatch({ type: "SET_PAGE", page: clampedPageIndex });
|
|
193
|
+
}
|
|
194
|
+
const currentPage = visiblePages[clampedPageIndex] || null;
|
|
195
|
+
const hasNextPage = clampedPageIndex < visiblePages.length - 1;
|
|
196
|
+
const hasPreviousPage = clampedPageIndex > 0;
|
|
197
|
+
const isLastPage = clampedPageIndex === visiblePages.length - 1;
|
|
193
198
|
return {
|
|
194
199
|
pages,
|
|
195
|
-
currentPageIndex:
|
|
200
|
+
currentPageIndex: clampedPageIndex,
|
|
196
201
|
currentPage,
|
|
197
|
-
goToPage: (index) =>
|
|
202
|
+
goToPage: (index) => {
|
|
203
|
+
const validIndex = Math.min(Math.max(0, index), maxPageIndex);
|
|
204
|
+
dispatch({ type: "SET_PAGE", page: validIndex });
|
|
205
|
+
},
|
|
198
206
|
nextPage: () => {
|
|
199
207
|
if (hasNextPage) {
|
|
200
|
-
dispatch({ type: "SET_PAGE", page:
|
|
208
|
+
dispatch({ type: "SET_PAGE", page: clampedPageIndex + 1 });
|
|
201
209
|
}
|
|
202
210
|
},
|
|
203
211
|
previousPage: () => {
|
|
204
212
|
if (hasPreviousPage) {
|
|
205
|
-
dispatch({ type: "SET_PAGE", page:
|
|
213
|
+
dispatch({ type: "SET_PAGE", page: clampedPageIndex - 1 });
|
|
206
214
|
}
|
|
207
215
|
},
|
|
208
216
|
hasNextPage,
|
|
209
217
|
hasPreviousPage,
|
|
210
|
-
canProceed:
|
|
211
|
-
|
|
218
|
+
canProceed: (() => {
|
|
219
|
+
if (!currentPage) return true;
|
|
220
|
+
const pageErrors = validation.errors.filter((e) => {
|
|
221
|
+
const isOnCurrentPage = currentPage.fields.includes(e.field) || currentPage.fields.some((f) => e.field.startsWith(`${f}[`));
|
|
222
|
+
const isVisible = visibility[e.field] !== false;
|
|
223
|
+
const isError = e.severity === "error";
|
|
224
|
+
return isOnCurrentPage && isVisible && isError;
|
|
225
|
+
});
|
|
226
|
+
return pageErrors.length === 0;
|
|
227
|
+
})(),
|
|
212
228
|
isLastPage,
|
|
213
229
|
touchCurrentPageFields: () => {
|
|
214
230
|
if (currentPage) {
|
|
@@ -225,7 +241,7 @@ function useForma(options) {
|
|
|
225
241
|
return pageErrors.length === 0;
|
|
226
242
|
}
|
|
227
243
|
};
|
|
228
|
-
}, [spec, state.data, state.currentPage, computed, validation]);
|
|
244
|
+
}, [spec, state.data, state.currentPage, computed, validation, visibility]);
|
|
229
245
|
const getValueAtPath = useCallback((path) => {
|
|
230
246
|
const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
231
247
|
let value = state.data;
|
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 const currentPage = visiblePages[state.currentPage] || null;\n const hasNextPage = state.currentPage < visiblePages.length - 1;\n const hasPreviousPage = state.currentPage > 0;\n const isLastPage = state.currentPage === visiblePages.length - 1;\n\n return {\n pages,\n currentPageIndex: state.currentPage,\n currentPage,\n goToPage: (index: number) => dispatch({ type: \"SET_PAGE\", page: index }),\n nextPage: () => {\n if (hasNextPage) {\n dispatch({ type: \"SET_PAGE\", page: state.currentPage + 1 });\n }\n },\n previousPage: () => {\n if (hasPreviousPage) {\n dispatch({ type: \"SET_PAGE\", page: state.currentPage - 1 });\n }\n },\n hasNextPage,\n hasPreviousPage,\n canProceed: true, // TODO: Validate current page\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]);\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 * 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogpipe/forma-react",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
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.8.
|
|
33
|
+
"@fogpipe/forma-core": "^0.8.2"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^18.0.0 || ^19.0.0"
|