@fogpipe/forma-react 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{FormRenderer-D_ZVK44t.d.ts → FormRenderer-B7qwG4to.d.ts} +9 -1
- package/dist/{chunk-5K4QITFH.js → chunk-CFX3T5WK.js} +25 -3
- package/dist/chunk-CFX3T5WK.js.map +1 -0
- package/dist/defaults/index.d.ts +1 -1
- package/dist/defaults/index.js +7 -3
- package/dist/defaults/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/FieldRenderer.tsx +33 -1
- package/src/FormRenderer.tsx +35 -1
- package/src/__tests__/defaults/components.test.tsx +256 -0
- package/src/__tests__/defaults/integration.test.tsx +132 -0
- package/src/__tests__/test-utils.tsx +4 -2
- package/src/defaults/components/ComputedDisplay.tsx +2 -1
- package/src/defaults/components/DisplayField.tsx +8 -1
- package/src/types.ts +7 -0
- package/dist/chunk-5K4QITFH.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
|
-
import { FieldError, SelectOption, FieldDefinition, Forma, MatrixColumn, ValidationResult } from '@fogpipe/forma-core';
|
|
2
|
+
import { FieldError, SelectOption, FieldDefinition, Forma, FormatOptions, MatrixColumn, ValidationResult } from '@fogpipe/forma-core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Type definitions for forma-react components
|
|
@@ -223,6 +223,10 @@ interface ComputedFieldProps extends Omit<BaseFieldProps, "onChange"> {
|
|
|
223
223
|
fieldType: "computed";
|
|
224
224
|
value: unknown;
|
|
225
225
|
expression: string;
|
|
226
|
+
/** Display format string (e.g., "currency", "percent", "decimal(2)") */
|
|
227
|
+
format?: string;
|
|
228
|
+
/** Resolved format options (locale, currency) for number/date formatting */
|
|
229
|
+
formatOptions?: FormatOptions;
|
|
226
230
|
onChange?: never;
|
|
227
231
|
}
|
|
228
232
|
/**
|
|
@@ -251,6 +255,8 @@ interface DisplayFieldProps extends Omit<BaseFieldProps, "value" | "onChange"> {
|
|
|
251
255
|
sourceValue?: unknown;
|
|
252
256
|
/** Display format string */
|
|
253
257
|
format?: string;
|
|
258
|
+
/** Resolved format options (locale, currency) for number/date formatting */
|
|
259
|
+
formatOptions?: FormatOptions;
|
|
254
260
|
/** No onChange - display fields are read-only */
|
|
255
261
|
onChange?: never;
|
|
256
262
|
value?: never;
|
|
@@ -535,6 +541,8 @@ interface FormRendererProps {
|
|
|
535
541
|
validateOn?: "change" | "blur" | "submit";
|
|
536
542
|
/** Current page for controlled wizard */
|
|
537
543
|
page?: number;
|
|
544
|
+
/** Format options for number/currency/date display (overrides spec.meta.locale/currency) */
|
|
545
|
+
formatOptions?: FormatOptions;
|
|
538
546
|
}
|
|
539
547
|
/**
|
|
540
548
|
* Imperative handle for FormRenderer
|
|
@@ -973,6 +973,14 @@ var FormRenderer = forwardRef(
|
|
|
973
973
|
pageWrapper: PageWrapper = DefaultPageWrapper,
|
|
974
974
|
validateOn = "blur"
|
|
975
975
|
} = props;
|
|
976
|
+
const resolvedFormatOptions = useMemo2(() => {
|
|
977
|
+
var _a, _b, _c;
|
|
978
|
+
return {
|
|
979
|
+
locale: ((_a = props.formatOptions) == null ? void 0 : _a.locale) ?? spec.meta.locale,
|
|
980
|
+
currency: ((_b = props.formatOptions) == null ? void 0 : _b.currency) ?? spec.meta.currency,
|
|
981
|
+
nullDisplay: ((_c = props.formatOptions) == null ? void 0 : _c.nullDisplay) ?? "\u2014"
|
|
982
|
+
};
|
|
983
|
+
}, [props.formatOptions, spec.meta.locale, spec.meta.currency]);
|
|
976
984
|
const forma = useForma({
|
|
977
985
|
spec,
|
|
978
986
|
initialData,
|
|
@@ -1034,7 +1042,7 @@ var FormRenderer = forwardRef(
|
|
|
1034
1042
|
}, [spec.pages, spec.fieldOrder, forma.wizard]);
|
|
1035
1043
|
const renderField = useCallback2(
|
|
1036
1044
|
(fieldPath) => {
|
|
1037
|
-
var _a;
|
|
1045
|
+
var _a, _b, _c, _d;
|
|
1038
1046
|
const fieldDef = spec.fields[fieldPath];
|
|
1039
1047
|
if (!fieldDef) return null;
|
|
1040
1048
|
const isVisible = formaVisibility[fieldPath] !== false;
|
|
@@ -1169,6 +1177,7 @@ var FormRenderer = forwardRef(
|
|
|
1169
1177
|
};
|
|
1170
1178
|
} else if (fieldType === "display" && fieldDef.type === "display") {
|
|
1171
1179
|
const sourceValue = fieldDef.source ? formaData[fieldDef.source] ?? formaComputed[fieldDef.source] : void 0;
|
|
1180
|
+
const format = fieldDef.format ?? (fieldDef.source ? (_c = (_b = spec.computed) == null ? void 0 : _b[fieldDef.source]) == null ? void 0 : _c.format : void 0);
|
|
1172
1181
|
const {
|
|
1173
1182
|
onChange: _onChange,
|
|
1174
1183
|
value: _value,
|
|
@@ -1179,7 +1188,19 @@ var FormRenderer = forwardRef(
|
|
|
1179
1188
|
fieldType: "display",
|
|
1180
1189
|
content: fieldDef.content,
|
|
1181
1190
|
sourceValue,
|
|
1182
|
-
format
|
|
1191
|
+
format,
|
|
1192
|
+
formatOptions: resolvedFormatOptions
|
|
1193
|
+
};
|
|
1194
|
+
} else if (fieldType === "computed" && fieldDef.type === "computed") {
|
|
1195
|
+
const computedDef = (_d = spec.computed) == null ? void 0 : _d[fieldPath];
|
|
1196
|
+
const { onChange: _onChangeC, ...computedBaseProps } = baseProps;
|
|
1197
|
+
fieldProps = {
|
|
1198
|
+
...computedBaseProps,
|
|
1199
|
+
fieldType: "computed",
|
|
1200
|
+
value: formaComputed[fieldPath],
|
|
1201
|
+
expression: (computedDef == null ? void 0 : computedDef.expression) ?? "",
|
|
1202
|
+
format: computedDef == null ? void 0 : computedDef.format,
|
|
1203
|
+
formatOptions: resolvedFormatOptions
|
|
1183
1204
|
};
|
|
1184
1205
|
} else {
|
|
1185
1206
|
fieldProps = {
|
|
@@ -1222,6 +1243,7 @@ var FormRenderer = forwardRef(
|
|
|
1222
1243
|
formaErrors,
|
|
1223
1244
|
formaIsSubmitted,
|
|
1224
1245
|
validateOn,
|
|
1246
|
+
resolvedFormatOptions,
|
|
1225
1247
|
setFieldValue,
|
|
1226
1248
|
setFieldTouched,
|
|
1227
1249
|
getArrayHelpers
|
|
@@ -1273,4 +1295,4 @@ export {
|
|
|
1273
1295
|
useFormaContext,
|
|
1274
1296
|
FormRenderer
|
|
1275
1297
|
};
|
|
1276
|
-
//# sourceMappingURL=chunk-
|
|
1298
|
+
//# sourceMappingURL=chunk-CFX3T5WK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/useForma.ts","../src/events.ts","../src/context.ts","../src/FormRenderer.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 {\n useCallback,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from \"react\";\nimport type {\n Forma,\n FieldError,\n ValidationResult,\n SelectOption,\n} from \"@fogpipe/forma-core\";\nimport { isAdornableField } from \"@fogpipe/forma-core\";\nimport type {\n GetFieldPropsResult,\n GetSelectFieldPropsResult,\n GetArrayHelpersResult,\n} from \"./types.js\";\nimport { FormaEventEmitter } from \"./events.js\";\nimport type { FormaEventMap, FormaEvents } from \"./events.js\";\nimport {\n getVisibility,\n getRequired,\n getEnabled,\n getReadonly,\n validate,\n calculate,\n getPageVisibility,\n getOptionsVisibility,\n} from \"@fogpipe/forma-core\";\nimport type { OptionsVisibilityResult } 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?: (\n data: Record<string, unknown>,\n computed?: Record<string, unknown>,\n ) => 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 * Declarative event listeners for form lifecycle events.\n * Listeners are stable for the lifetime of the hook — the latest\n * callback is always invoked via refs, without causing dependency changes.\n */\n on?: FormaEvents;\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 /**\n * Safe \"Next\" handler for wizard navigation.\n * Advances to the next page if one exists. Never triggers submission.\n * Use this instead of conditionally calling nextPage/onSubmit in a single button.\n */\n handleNext: () => 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 readonly state map */\n readonly: Record<string, boolean>;\n /** Visible options for select/multiselect fields, keyed by field path */\n optionsVisibility: OptionsVisibilityResult;\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 /**\n * Register an imperative event listener. Returns an unsubscribe function.\n * Multiple listeners per event are supported; they fire in registration order.\n */\n on: <K extends keyof FormaEventMap>(\n event: K,\n listener: (payload: FormaEventMap[K]) => void | Promise<void>,\n ) => () => void;\n\n // Helper methods for getting field props\n /** Get props for any field */\n getFieldProps: (path: string) => GetFieldPropsResult;\n /** Get props for select field (includes options) */\n getSelectFieldProps: (path: string) => GetSelectFieldPropsResult;\n /** Get array helpers for array field */\n getArrayHelpers: (path: string) => GetArrayHelpersResult;\n}\n\n/**\n * State reducer\n */\nfunction formReducer(state: FormState, action: FormAction): FormState {\n switch (action.type) {\n case \"SET_FIELD_VALUE\":\n return {\n ...state,\n data: { ...state.data, [action.field]: action.value },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_FIELD_TOUCHED\":\n return {\n ...state,\n touched: { ...state.touched, [action.field]: action.touched },\n };\n case \"SET_VALUES\":\n return {\n ...state,\n data: { ...state.data, ...action.values },\n isDirty: true,\n isSubmitted: false, // Clear on data change\n };\n case \"SET_SUBMITTING\":\n return { ...state, isSubmitting: action.isSubmitting };\n case \"SET_SUBMITTED\":\n return { ...state, isSubmitted: action.isSubmitted };\n case \"SET_PAGE\":\n return { ...state, currentPage: action.page };\n case \"RESET\":\n return {\n data: action.initialData,\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n };\n default:\n return state;\n }\n}\n\n/**\n * Get default initial values for boolean fields.\n * Boolean fields default to false to avoid undefined state,\n * which provides better UX since false is a valid answer.\n */\nfunction getDefaultBooleanValues(spec: Forma): Record<string, boolean> {\n const defaults: Record<string, boolean> = {};\n for (const fieldPath of spec.fieldOrder) {\n const schemaProperty = spec.schema.properties?.[fieldPath];\n const fieldDef = spec.fields[fieldPath];\n if (schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\") {\n defaults[fieldPath] = false;\n }\n }\n return defaults;\n}\n\n/**\n * Get default values from field definitions.\n * Collects `defaultValue` from each field that specifies one.\n * These are applied after boolean defaults but before initialData,\n * so explicit defaults override type-implicit defaults,\n * and runtime initialData overrides everything.\n */\nfunction getFieldDefaults(spec: Forma): Record<string, unknown> {\n const defaults: Record<string, unknown> = {};\n for (const [fieldPath, fieldDef] of Object.entries(spec.fields)) {\n if (fieldDef.defaultValue !== undefined) {\n defaults[fieldPath] = fieldDef.defaultValue;\n }\n }\n return defaults;\n}\n\n/**\n * Main Forma hook\n */\nexport function useForma(options: UseFormaOptions): UseFormaReturn {\n const {\n spec: inputSpec,\n initialData = {},\n onSubmit,\n onChange,\n validateOn = \"blur\",\n referenceData,\n validationDebounceMs = 0,\n on: onEvents,\n } = 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: {\n ...getDefaultBooleanValues(spec),\n ...getFieldDefaults(spec),\n ...initialData,\n },\n touched: {},\n isSubmitting: false,\n isSubmitted: false,\n isDirty: false,\n currentPage: 0,\n });\n\n // Keep a ref to current state.data to avoid stale closures in cached handlers\n const stateDataRef = useRef(state.data);\n stateDataRef.current = state.data;\n\n // Track if we've initialized (to avoid calling onChange on first render)\n const hasInitialized = useRef(false);\n\n // ── Event system ──────────────────────────────────────────────────────\n const emitterRef = useRef(new FormaEventEmitter());\n const onEventsRef = useRef(onEvents);\n onEventsRef.current = onEvents;\n const pendingEventsRef = useRef<\n Array<{ event: keyof FormaEventMap; payload: unknown }>\n >([]);\n const isFiringEventsRef = useRef(false);\n\n // Cleanup emitter on unmount\n useEffect(() => {\n const emitter = emitterRef.current;\n return () => {\n emitter.clear();\n };\n }, []);\n\n // Helper: fire an event to both declarative `on` handlers and imperative listeners\n const fireEvent = useCallback(\n <K extends keyof FormaEventMap>(event: K, payload: FormaEventMap[K]) => {\n // Declarative handler (via ref for latest callback)\n try {\n const handler = onEventsRef.current?.[event];\n if (handler) (handler as (p: FormaEventMap[K]) => void)(payload);\n } catch (error) {\n console.error(`[forma] Error in \"${event}\" event handler:`, error);\n }\n // Imperative listeners\n emitterRef.current.fire(event, payload);\n },\n [],\n );\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 // Calculate readonly state\n const readonly = useMemo(\n () => getReadonly(state.data, spec, { computed }),\n [state.data, spec, computed],\n );\n\n // Calculate visible options for all select/multiselect fields (memoized)\n const optionsVisibility = useMemo(\n () => getOptionsVisibility(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] =\n 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 =\n 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(\n (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 = (\n data: Record<string, unknown>,\n pathParts: string[],\n val: unknown,\n ): 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({\n type: \"SET_VALUES\",\n values: buildNestedObject(state.data, parts, value),\n });\n },\n [state.data],\n );\n\n // Helper to get value at nested path\n // Uses stateDataRef to always access current state, avoiding stale closure issues\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 = stateDataRef.current;\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 }, []); // No dependencies - uses ref for current state\n\n // Queue a fieldChanged event (captures previousValue from current state ref)\n const queueFieldChangedEvent = useCallback(\n (path: string, value: unknown, source: \"user\" | \"reset\" | \"setValues\") => {\n if (isFiringEventsRef.current) return; // recursion guard\n const previousValue = getValueAtPath(path);\n if (previousValue === value) return; // no actual change\n pendingEventsRef.current.push({\n event: \"fieldChanged\",\n payload: { path, value, previousValue, source },\n });\n },\n [getValueAtPath],\n );\n\n // Actions\n const setFieldValue = useCallback(\n (path: string, value: unknown) => {\n queueFieldChangedEvent(path, value, \"user\");\n setNestedValue(path, value);\n if (validateOn === \"change\") {\n dispatch({ type: \"SET_FIELD_TOUCHED\", field: path, touched: true });\n }\n },\n [validateOn, setNestedValue, queueFieldChangedEvent],\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(\n (values: Record<string, unknown>) => {\n for (const [key, value] of Object.entries(values)) {\n queueFieldChangedEvent(key, value, \"setValues\");\n }\n dispatch({ type: \"SET_VALUES\", values });\n },\n [queueFieldChangedEvent],\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\n const submissionData = { ...state.data };\n let postSubmitPayload: FormaEventMap[\"postSubmit\"] | undefined;\n\n try {\n // Fire preSubmit (async, inline — listeners can mutate submissionData)\n const preSubmitPayload = {\n data: submissionData,\n computed: { ...computed },\n };\n // Declarative handler\n const declarativePreSubmit = onEventsRef.current?.preSubmit;\n if (declarativePreSubmit) {\n await declarativePreSubmit(preSubmitPayload);\n }\n // Imperative listeners\n if (emitterRef.current.hasListeners(\"preSubmit\")) {\n await emitterRef.current.fireAsync(\"preSubmit\", preSubmitPayload);\n }\n\n // Always use immediate validation on submit to ensure accurate result\n if (!immediateValidation.valid) {\n postSubmitPayload = {\n data: submissionData,\n success: false,\n validationErrors: immediateValidation.errors,\n };\n } else if (onSubmit) {\n try {\n await onSubmit(submissionData);\n postSubmitPayload = { data: submissionData, success: true };\n } catch (error) {\n postSubmitPayload = {\n data: submissionData,\n success: false,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n } else {\n postSubmitPayload = { data: submissionData, success: true };\n }\n\n dispatch({ type: \"SET_SUBMITTED\", isSubmitted: true });\n } finally {\n dispatch({ type: \"SET_SUBMITTING\", isSubmitting: false });\n // Fire postSubmit after state updates\n if (postSubmitPayload) {\n fireEvent(\"postSubmit\", postSubmitPayload);\n }\n }\n }, [immediateValidation, onSubmit, state.data, computed, fireEvent]);\n\n const resetForm = useCallback(() => {\n const resetData = {\n ...getDefaultBooleanValues(spec),\n ...getFieldDefaults(spec),\n ...initialData,\n };\n\n // Queue fieldChanged for each field that actually changes\n if (!isFiringEventsRef.current) {\n const currentData = stateDataRef.current;\n const allKeys = new Set([\n ...Object.keys(currentData),\n ...Object.keys(resetData),\n ]);\n for (const key of allKeys) {\n const currentVal = currentData[key];\n const resetVal = resetData[key];\n if (currentVal !== resetVal) {\n pendingEventsRef.current.push({\n event: \"fieldChanged\",\n payload: {\n path: key,\n value: resetVal,\n previousValue: currentVal,\n source: \"reset\" as const,\n },\n });\n }\n }\n // Queue formReset (fires after fieldChanged events)\n pendingEventsRef.current.push({\n event: \"formReset\",\n payload: {} as FormaEventMap[\"formReset\"],\n });\n }\n\n dispatch({ type: \"RESET\", initialData: resetData });\n }, [spec, 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(\n Math.max(0, state.currentPage),\n maxPageIndex,\n );\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 const advanceToNextPage = () => {\n if (hasNextPage) {\n const toIndex = clampedPageIndex + 1;\n dispatch({ type: \"SET_PAGE\", page: toIndex });\n const newPage = visiblePages[toIndex];\n if (newPage) {\n fireEvent(\"pageChanged\", {\n fromIndex: clampedPageIndex,\n toIndex,\n page: newPage,\n });\n }\n }\n };\n\n return {\n pages,\n currentPageIndex: clampedPageIndex,\n currentPage,\n goToPage: (index: number) => {\n const validIndex = Math.min(Math.max(0, index), maxPageIndex);\n if (validIndex !== clampedPageIndex) {\n dispatch({ type: \"SET_PAGE\", page: validIndex });\n const newPage = visiblePages[validIndex];\n if (newPage) {\n fireEvent(\"pageChanged\", {\n fromIndex: clampedPageIndex,\n toIndex: validIndex,\n page: newPage,\n });\n }\n }\n },\n nextPage: advanceToNextPage,\n previousPage: () => {\n if (hasPreviousPage) {\n const toIndex = clampedPageIndex - 1;\n dispatch({ type: \"SET_PAGE\", page: toIndex });\n const newPage = visiblePages[toIndex];\n if (newPage) {\n fireEvent(\"pageChanged\", {\n fromIndex: clampedPageIndex,\n toIndex,\n page: newPage,\n });\n }\n }\n },\n // Same function as nextPage — exposed as a separate name so consumers can\n // bind a single \"Next\" button without risk of accidentally triggering submission.\n // nextPage is already a no-op on the last page.\n handleNext: advanceToNextPage,\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 =\n 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 }, [\n spec,\n state.data,\n state.currentPage,\n computed,\n validation,\n visibility,\n fireEvent,\n ]);\n\n // Flush pending events after render (fieldChanged, formReset)\n useEffect(() => {\n const events = pendingEventsRef.current;\n if (events.length === 0) return;\n pendingEventsRef.current = [];\n\n isFiringEventsRef.current = true;\n try {\n for (const pending of events) {\n fireEvent(\n pending.event as keyof FormaEventMap,\n pending.payload as FormaEventMap[keyof FormaEventMap],\n );\n }\n } finally {\n isFiringEventsRef.current = false;\n }\n });\n\n // Helper to set value at nested path\n // Uses stateDataRef to always access current state, avoiding stale closure issues\n const setValueAtPath = useCallback(\n (path: string, value: unknown): void => {\n queueFieldChangedEvent(path, value, \"user\");\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 from CURRENT state via ref (not stale closure)\n const newData = { ...stateDataRef.current };\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 },\n [queueFieldChangedEvent],\n );\n\n // Memoized onChange/onBlur handlers for fields\n const fieldHandlers = useRef<\n Map<string, { onChange: (value: unknown) => void; onBlur: () => void }>\n >(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?.type === \"array\" && 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(\n (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 },\n [setValueAtPath, setFieldTouched],\n );\n\n // Get field props for any field\n const getFieldProps = useCallback(\n (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)\n fieldType = \"select\";\n else if (\"format\" in schemaProperty) {\n if (schemaProperty.format === \"date\") fieldType = \"date\";\n else if (schemaProperty.format === \"date-time\")\n 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 shouldShowErrors =\n validateOn === \"change\" ||\n (validateOn === \"blur\" && isTouched) ||\n state.isSubmitted;\n const visibleFieldErrors = shouldShowErrors ? fieldErrors : [];\n const hasVisibleErrors = visibleFieldErrors.length > 0;\n const isRequired = required[path] ?? false;\n\n // Boolean fields: hide asterisk unless they have validation rules (consent pattern)\n // - Binary question (\"Do you smoke?\"): no validation → false is valid → hide asterisk\n // - Consent checkbox (\"I accept terms\"): has validation rule → show asterisk\n const schemaProperty = spec.schema.properties[path];\n const isBooleanField =\n schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\";\n const hasValidationRules = (fieldDef?.validations?.length ?? 0) > 0;\n const showRequiredIndicator =\n isRequired && (!isBooleanField || hasValidationRules);\n\n // Pass through adorner props for adornable field types\n const adornerProps =\n fieldDef && isAdornableField(fieldDef)\n ? { prefix: fieldDef.prefix, suffix: fieldDef.suffix }\n : {};\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 readonly: readonly[path] ?? false,\n required: isRequired,\n showRequiredIndicator,\n touched: isTouched,\n errors: fieldErrors,\n visibleErrors: visibleFieldErrors,\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n // ARIA accessibility attributes (driven by visibleErrors, not all errors)\n \"aria-invalid\": hasVisibleErrors || undefined,\n \"aria-describedby\": hasVisibleErrors ? `${path}-error` : undefined,\n \"aria-required\": isRequired || undefined,\n // Adorner props (only for adornable field types)\n ...adornerProps,\n // Presentation variant\n variant: fieldDef?.variant,\n variantConfig: fieldDef?.variantConfig,\n };\n },\n [\n spec,\n state.touched,\n state.isSubmitted,\n visibility,\n enabled,\n readonly,\n required,\n validation.errors,\n validateOn,\n getValueAtPath,\n getFieldHandlers,\n ],\n );\n\n // Get select field props - uses pre-computed optionsVisibility map\n const getSelectFieldProps = useCallback(\n (path: string): GetSelectFieldPropsResult => {\n const baseProps = getFieldProps(path);\n\n // Look up pre-computed visible options from memoized map\n const visibleOptions = optionsVisibility[path] ?? [];\n\n return {\n ...baseProps,\n options: visibleOptions as SelectOption[],\n };\n },\n [getFieldProps, optionsVisibility],\n );\n\n // Get array helpers\n const getArrayHelpers = useCallback(\n (path: string): GetArrayHelpersResult => {\n const fieldDef = spec.fields[path];\n const currentValue = (getValueAtPath(path) as unknown[]) ?? [];\n const arrayDef = fieldDef?.type === \"array\" ? fieldDef : undefined;\n const minItems = arrayDef?.minItems ?? 0;\n const maxItems = arrayDef?.maxItems ?? Infinity;\n\n const canAdd = currentValue.length < maxItems;\n const canRemove = currentValue.length > minItems;\n\n const getItemFieldProps = (\n index: number,\n fieldName: string,\n ): GetFieldPropsResult => {\n const itemPath = `${path}[${index}].${fieldName}`;\n const itemFieldDef = arrayDef?.itemFields?.[fieldName];\n const handlers = getFieldHandlers(itemPath);\n\n // Get item value\n const item = (currentValue[index] as Record<string, unknown>) ?? {};\n const itemValue = item[fieldName];\n\n const fieldErrors = validation.errors.filter(\n (e) => e.field === itemPath,\n );\n const isTouched = state.touched[itemPath] ?? false;\n const showErrors =\n validateOn === \"change\" ||\n (validateOn === \"blur\" && isTouched) ||\n state.isSubmitted;\n\n // Look up pre-computed visible options from memoized map\n const visibleOptions = optionsVisibility[itemPath] as\n | SelectOption[]\n | undefined;\n\n return {\n name: itemPath,\n value: itemValue,\n type: itemFieldDef?.type || \"text\",\n label:\n itemFieldDef?.label ||\n fieldName.charAt(0).toUpperCase() + fieldName.slice(1),\n description: itemFieldDef?.description,\n placeholder: itemFieldDef?.placeholder,\n visible: true,\n enabled: enabled[path] !== false,\n readonly: readonly[itemPath] ?? false,\n required: false, // TODO: Evaluate item field required\n showRequiredIndicator: false, // Item fields don't show required indicator\n touched: isTouched,\n errors: fieldErrors,\n visibleErrors: showErrors ? fieldErrors : [],\n onChange: handlers.onChange,\n onBlur: handlers.onBlur,\n options: visibleOptions,\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]] = [\n newArray[indexB],\n newArray[indexA],\n ];\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 },\n [\n spec.fields,\n getValueAtPath,\n setValueAtPath,\n getFieldHandlers,\n enabled,\n readonly,\n state.touched,\n state.isSubmitted,\n validation.errors,\n validateOn,\n optionsVisibility,\n ],\n );\n\n // Stable reference for imperative event subscription — only depends on the\n // emitter ref, so consumers can safely use it as a useEffect dependency.\n const on = useCallback(\n <K extends keyof FormaEventMap>(\n event: K,\n listener: (payload: FormaEventMap[K]) => void | Promise<void>,\n ) => emitterRef.current.on(event, listener),\n [],\n );\n\n return useMemo(\n (): UseFormaReturn => ({\n data: state.data,\n computed,\n visibility,\n required,\n enabled,\n readonly,\n optionsVisibility,\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 on,\n getFieldProps,\n getSelectFieldProps,\n getArrayHelpers,\n }),\n [\n state.data,\n state.touched,\n state.isSubmitting,\n state.isSubmitted,\n state.isDirty,\n computed,\n visibility,\n required,\n enabled,\n readonly,\n optionsVisibility,\n validation.errors,\n validation.valid,\n spec,\n wizard,\n setFieldValue,\n setFieldTouched,\n setValues,\n validateField,\n validateForm,\n submitForm,\n resetForm,\n on,\n getFieldProps,\n getSelectFieldProps,\n getArrayHelpers,\n ],\n );\n}\n","/**\n * Event system for forma-react\n *\n * Lightweight event emitter for form lifecycle events.\n * Events are for side effects (analytics, data injection, external state sync)\n * — they do not trigger React re-renders.\n */\n\nimport type { FieldError } from \"@fogpipe/forma-core\";\nimport type { PageState } from \"./useForma.js\";\n\n// ============================================================================\n// Event Type Definitions\n// ============================================================================\n\n/**\n * Map of all forma event names to their payload types.\n */\nexport interface FormaEventMap {\n /**\n * Fires after a field value changes via user input, setFieldValue, setValues, or resetForm.\n * Does NOT fire for computed/calculated field changes or on initial mount.\n */\n fieldChanged: {\n /** Field path (e.g., \"age\" or \"medications[0].dosage\") */\n path: string;\n /** New value */\n value: unknown;\n /** Value before the change */\n previousValue: unknown;\n /** What triggered the change */\n source: \"user\" | \"reset\" | \"setValues\";\n };\n\n /**\n * Fires at the start of submitForm(), before validation.\n * The `data` object is mutable — consumers can inject extra fields.\n * Async handlers are awaited before proceeding to validation.\n */\n preSubmit: {\n /** Mutable form data — add/modify fields here */\n data: Record<string, unknown>;\n /** Read-only snapshot of computed values */\n computed: Record<string, unknown>;\n };\n\n /**\n * Fires after onSubmit resolves/rejects or after validation failure.\n */\n postSubmit: {\n /** The submitted data (reflects any preSubmit mutations) */\n data: Record<string, unknown>;\n /** Whether submission succeeded */\n success: boolean;\n /** Present when onSubmit threw an error */\n error?: Error;\n /** Present when validation failed (onSubmit was never called) */\n validationErrors?: FieldError[];\n };\n\n /**\n * Fires when the wizard page changes via nextPage, previousPage, or goToPage.\n * Does NOT fire on initial render or automatic page clamping.\n */\n pageChanged: {\n /** Previous page index */\n fromIndex: number;\n /** New page index */\n toIndex: number;\n /** The new current page */\n page: PageState;\n };\n\n /**\n * Fires after resetForm() completes and state is back to initial values.\n */\n formReset: Record<string, never>;\n}\n\n// ============================================================================\n// Helper Types\n// ============================================================================\n\n/**\n * Listener function type for a specific event.\n */\nexport type FormaEventListener<K extends keyof FormaEventMap> = (\n event: FormaEventMap[K],\n) => void | Promise<void>;\n\n/**\n * Declarative event listener map for useForma `on` option.\n */\nexport type FormaEvents = Partial<{\n [K in keyof FormaEventMap]: FormaEventListener<K>;\n}>;\n\n// ============================================================================\n// Event Emitter\n// ============================================================================\n\n/**\n * Lightweight event emitter for forma lifecycle events.\n * Uses Map<string, Set<listener>> internally — no external dependencies.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyListener = (...args: any[]) => void | Promise<void>;\n\nexport class FormaEventEmitter {\n private listeners = new Map<string, Set<AnyListener>>();\n\n /**\n * Register a listener for an event. Returns an unsubscribe function.\n */\n on<K extends keyof FormaEventMap>(\n event: K,\n listener: FormaEventListener<K>,\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n return () => {\n const set = this.listeners.get(event);\n if (set) {\n set.delete(listener);\n if (set.size === 0) {\n this.listeners.delete(event);\n }\n }\n };\n }\n\n /**\n * Fire an event synchronously. Listener errors are caught and logged\n * to prevent one listener from breaking others.\n */\n fire<K extends keyof FormaEventMap>(\n event: K,\n payload: FormaEventMap[K],\n ): void {\n const set = this.listeners.get(event);\n if (!set || set.size === 0) return;\n\n for (const listener of set) {\n try {\n listener(payload);\n } catch (error) {\n console.error(`[forma] Error in \"${event}\" event listener:`, error);\n }\n }\n }\n\n /**\n * Fire an event and await all async listeners sequentially.\n * Used for preSubmit where handlers can be async.\n */\n async fireAsync<K extends keyof FormaEventMap>(\n event: K,\n payload: FormaEventMap[K],\n ): Promise<void> {\n const set = this.listeners.get(event);\n if (!set || set.size === 0) return;\n\n for (const listener of set) {\n try {\n await listener(payload);\n } catch (error) {\n console.error(`[forma] Error in \"${event}\" event listener:`, error);\n }\n }\n }\n\n /**\n * Check if any listeners are registered for an event.\n */\n hasListeners(event: keyof FormaEventMap): boolean {\n const set = this.listeners.get(event);\n return set !== undefined && set.size > 0;\n }\n\n /**\n * Remove all listeners. Called on cleanup.\n */\n clear(): void {\n this.listeners.clear();\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(\n \"useFormaContext must be used within a FormaContext.Provider\",\n );\n }\n return context;\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, {\n forwardRef,\n useImperativeHandle,\n useRef,\n useMemo,\n useCallback,\n} from \"react\";\nimport type {\n Forma,\n FieldDefinition,\n ValidationResult,\n JSONSchemaProperty,\n SelectOption,\n FormatOptions,\n} from \"@fogpipe/forma-core\";\nimport { isAdornableField, isSelectionField } from \"@fogpipe/forma-core\";\nimport { useForma } from \"./useForma.js\";\nimport { FormaContext } from \"./context.js\";\nimport type {\n ComponentMap,\n LayoutProps,\n FieldWrapperProps,\n PageWrapperProps,\n BaseFieldProps,\n TextFieldProps,\n NumberFieldProps,\n SelectFieldProps,\n ArrayFieldProps,\n ArrayHelpers,\n DisplayFieldProps,\n ComputedFieldProps,\n MatrixFieldProps,\n} 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?: (\n data: Record<string, unknown>,\n computed?: Record<string, unknown>,\n ) => 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 /** Format options for number/currency/date display (overrides spec.meta.locale/currency) */\n formatOptions?: FormatOptions;\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 onSubmit={onSubmit}>\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({\n fieldPath,\n field,\n children,\n errors,\n showRequiredIndicator,\n visible,\n}: FieldWrapperProps) {\n if (!visible) return null;\n\n const errorId = `${fieldPath}-error`;\n const descriptionId = field.description\n ? `${fieldPath}-description`\n : undefined;\n const hasErrors = errors.length > 0;\n\n return (\n <div className=\"field-wrapper\" data-field-path={fieldPath}>\n {field.label && (\n <label htmlFor={fieldPath}>\n {field.label}\n {showRequiredIndicator && (\n <span className=\"required\" aria-hidden=\"true\">\n *\n </span>\n )}\n {showRequiredIndicator && (\n <span className=\"sr-only\"> (required)</span>\n )}\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({\n title,\n description,\n children,\n}: 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): {\n min?: number;\n max?: number;\n step?: number;\n} {\n if (!schema) return {};\n if (schema.type !== \"number\" && schema.type !== \"integer\") return {};\n\n // Extract min/max from schema\n const min =\n \"minimum\" in schema && typeof schema.minimum === \"number\"\n ? schema.minimum\n : undefined;\n const max =\n \"maximum\" in schema && typeof schema.maximum === \"number\"\n ? schema.maximum\n : 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(\n itemFields: Record<string, FieldDefinition>,\n): Record<string, unknown> {\n const item: Record<string, unknown> = {};\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n if (fieldDef.defaultValue !== undefined) {\n item[fieldName] = fieldDef.defaultValue;\n } else 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 = \"blur\",\n } = props;\n\n // Resolve format options: prop override > spec.meta > defaults\n const resolvedFormatOptions = useMemo<FormatOptions>(() => ({\n locale: props.formatOptions?.locale ?? spec.meta.locale,\n currency: props.formatOptions?.currency ?? spec.meta.currency,\n nullDisplay: props.formatOptions?.nullDisplay ?? \"—\",\n }), [props.formatOptions, spec.meta.locale, spec.meta.currency]);\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 // 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 // Destructure only the values renderField needs from forma.\n // This prevents renderField from recreating when unrelated state changes\n // (isSubmitting, isDirty, wizard page navigation, etc.)\n const {\n data: formaData,\n computed: formaComputed,\n visibility: formaVisibility,\n required: formaRequired,\n enabled: formaEnabled,\n readonly: formaReadonly,\n optionsVisibility: formaOptionsVisibility,\n touched: formaTouched,\n errors: formaErrors,\n isSubmitted: formaIsSubmitted,\n setFieldValue,\n setFieldTouched,\n getArrayHelpers,\n } = forma;\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(\n (fieldPath: string) => {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) return null;\n\n const isVisible = formaVisibility[fieldPath] !== false;\n if (!isVisible) {\n return <div key={fieldPath} data-field-path={fieldPath} hidden />;\n }\n\n // Get field type (type is required on all field definitions)\n const fieldType = fieldDef.type;\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 = formaErrors.filter((e) => e.field === fieldPath);\n const touched = formaTouched[fieldPath] ?? false;\n const showErrors =\n validateOn === \"change\" ||\n (validateOn === \"blur\" && touched) ||\n formaIsSubmitted;\n const visibleErrors = showErrors ? errors : [];\n const required = formaRequired[fieldPath] ?? false;\n const disabled = formaEnabled[fieldPath] === false;\n\n // Get schema property for additional constraints\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Boolean fields: hide asterisk unless they have validation rules (consent pattern)\n // - Binary question (\"Do you smoke?\"): no validation → false is valid → hide asterisk\n // - Consent checkbox (\"I accept terms\"): has validation rule → show asterisk\n const isBooleanField =\n schemaProperty?.type === \"boolean\" || fieldDef?.type === \"boolean\";\n const hasValidationRules = (fieldDef?.validations?.length ?? 0) > 0;\n const showRequiredIndicator =\n required && (!isBooleanField || hasValidationRules);\n\n // Base field props\n const isReadonly = formaReadonly[fieldPath] ?? false;\n const baseProps: BaseFieldProps = {\n name: fieldPath,\n field: fieldDef,\n value: formaData[fieldPath],\n touched,\n required,\n disabled,\n errors,\n visibleErrors,\n onChange: (value: unknown) => setFieldValue(fieldPath, value),\n onBlur: () => setFieldTouched(fieldPath),\n // Convenience properties\n visible: true, // Always true since we already filtered for visibility\n enabled: !disabled,\n readonly: isReadonly,\n label: fieldDef.label ?? fieldPath,\n description: fieldDef.description,\n placeholder: fieldDef.placeholder,\n // Adorner properties (only for adornable field types)\n ...(isAdornableField(fieldDef) && {\n prefix: fieldDef.prefix,\n suffix: fieldDef.suffix,\n }),\n // Presentation variant\n variant: fieldDef.variant,\n variantConfig: fieldDef.variantConfig,\n };\n\n // Build type-specific props\n let fieldProps:\n | BaseFieldProps\n | TextFieldProps\n | NumberFieldProps\n | SelectFieldProps\n | ArrayFieldProps\n | DisplayFieldProps\n | ComputedFieldProps\n | MatrixFieldProps = 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 const selectOptions = isSelectionField(fieldDef)\n ? fieldDef.options\n : [];\n fieldProps = {\n ...baseProps,\n fieldType,\n value: baseProps.value as string | string[] | null,\n onChange: baseProps.onChange as (\n value: string | string[] | null,\n ) => void,\n options: formaOptionsVisibility[fieldPath] ?? selectOptions ?? [],\n } as SelectFieldProps;\n } else if (\n fieldType === \"array\" &&\n fieldDef.type === \"array\" &&\n fieldDef.itemFields\n ) {\n const arrayValue = Array.isArray(baseProps.value)\n ? baseProps.value\n : [];\n const minItems = fieldDef.minItems ?? 0;\n const maxItems = fieldDef.maxItems ?? Infinity;\n const itemFieldDefs = fieldDef.itemFields;\n\n // Get helpers from useForma - these are fresh on each render, avoiding stale closures\n const baseHelpers = getArrayHelpers(fieldPath);\n\n // Wrap push to add default item creation when called without arguments\n const pushWithDefault = (item?: unknown): void => {\n const newItem = item ?? createDefaultItem(itemFieldDefs);\n baseHelpers.push(newItem);\n };\n\n // Extend getItemFieldProps to include additional metadata (itemIndex, fieldName, options)\n const getItemFieldPropsExtended = (\n index: number,\n fieldName: string,\n ) => {\n const baseProps = baseHelpers.getItemFieldProps(index, fieldName);\n const itemFieldDef = itemFieldDefs[fieldName];\n const itemPath = `${fieldPath}[${index}].${fieldName}`;\n return {\n ...baseProps,\n itemIndex: index,\n fieldName,\n options:\n (formaOptionsVisibility[itemPath] as\n | SelectOption[]\n | undefined) ??\n (itemFieldDef && isSelectionField(itemFieldDef)\n ? itemFieldDef.options\n : undefined),\n };\n };\n\n const helpers: ArrayHelpers = {\n items: arrayValue,\n push: pushWithDefault,\n insert: baseHelpers.insert,\n remove: baseHelpers.remove,\n move: baseHelpers.move,\n swap: baseHelpers.swap,\n getItemFieldProps: getItemFieldPropsExtended,\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 itemFieldOrder: fieldDef.itemFieldOrder,\n minItems,\n maxItems,\n } as ArrayFieldProps;\n } else if (fieldType === \"matrix\" && fieldDef.type === \"matrix\") {\n const matrixValue =\n (baseProps.value as Record<\n string,\n string | number | string[] | number[]\n > | null) ?? null;\n const rows = fieldDef.rows.map((row) => ({\n id: row.id,\n label: row.label,\n visible: formaVisibility[`${fieldPath}.${row.id}`] !== false,\n }));\n fieldProps = {\n ...baseProps,\n fieldType: \"matrix\",\n value: matrixValue,\n onChange: baseProps.onChange as (\n value: Record<string, string | number | string[] | number[]>,\n ) => void,\n rows,\n columns: fieldDef.columns,\n multiSelect: fieldDef.multiSelect ?? false,\n } as MatrixFieldProps;\n } else if (fieldType === \"display\" && fieldDef.type === \"display\") {\n // Display fields (read-only presentation content)\n // Resolve source value if the display field has a source property\n const sourceValue = fieldDef.source\n ? (formaData[fieldDef.source] ?? formaComputed[fieldDef.source])\n : undefined;\n // Resolve format: display field's own format takes priority,\n // fall back to the source computed field's format\n const format =\n fieldDef.format ??\n (fieldDef.source\n ? spec.computed?.[fieldDef.source]?.format\n : undefined);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n onChange: _onChange,\n value: _value,\n ...displayBaseProps\n } = baseProps;\n fieldProps = {\n ...displayBaseProps,\n fieldType: \"display\",\n content: fieldDef.content,\n sourceValue,\n format,\n formatOptions: resolvedFormatOptions,\n } as DisplayFieldProps;\n } else if (fieldType === \"computed\" && fieldDef.type === \"computed\") {\n // Computed fields (read-only calculated values)\n const computedDef = spec.computed?.[fieldPath];\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { onChange: _onChangeC, ...computedBaseProps } = baseProps;\n fieldProps = {\n ...computedBaseProps,\n fieldType: \"computed\",\n value: formaComputed[fieldPath],\n expression: computedDef?.expression ?? \"\",\n format: computedDef?.format,\n formatOptions: resolvedFormatOptions,\n } as ComputedFieldProps;\n } else {\n // Text-based fields\n fieldProps = {\n ...baseProps,\n fieldType: fieldType as\n | \"text\"\n | \"phone\"\n | \"email\"\n | \"password\"\n | \"url\"\n | \"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 <div key={fieldPath} data-field-path={fieldPath}>\n <FieldWrapper\n fieldPath={fieldPath}\n field={fieldDef}\n errors={errors}\n touched={touched}\n required={required}\n showRequiredIndicator={showRequiredIndicator}\n visible={isVisible}\n >\n {React.createElement(\n Component as React.ComponentType<typeof componentProps>,\n componentProps,\n )}\n </FieldWrapper>\n </div>\n );\n },\n [\n spec,\n components,\n FieldWrapper,\n formaData,\n formaComputed,\n formaVisibility,\n formaRequired,\n formaEnabled,\n formaReadonly,\n formaOptionsVisibility,\n formaTouched,\n formaErrors,\n formaIsSubmitted,\n validateOn,\n resolvedFormatOptions,\n setFieldValue,\n setFieldTouched,\n getArrayHelpers,\n ],\n );\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 // Wrap submitForm to always call preventDefault when invoked from a form event.\n // This prevents page refreshes when consumers put onSubmit on a <form> element.\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n forma.submitForm();\n },\n [forma.submitForm],\n );\n\n return (\n <FormaContext.Provider value={forma}>\n <Layout\n onSubmit={handleSubmit}\n isSubmitting={forma.isSubmitting}\n isValid={forma.isValid}\n >\n {content}\n </Layout>\n </FormaContext.Provider>\n );\n },\n);\n"],"mappings":"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","names":["schemaProperty","useRef","useMemo","useCallback","isAdornableField","FormRenderer","useMemo","useRef","useCallback","isAdornableField","baseProps"]}
|
package/dist/defaults/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
|
-
import { c as FormRendererProps, d as FormRendererHandle, K as FieldWrapperProps, J as LayoutProps, P as PageWrapperProps, C as ComponentMap, n as TextComponentProps, o as NumberComponentProps, p as IntegerComponentProps, q as BooleanComponentProps, r as DateComponentProps, s as DateTimeComponentProps, t as SelectComponentProps, u as MultiSelectComponentProps, v as ArrayComponentProps, w as ObjectComponentProps, x as ComputedComponentProps, z as DisplayComponentProps, H as MatrixComponentProps, m as FieldComponentProps } from '../FormRenderer-
|
|
2
|
+
import { c as FormRendererProps, d as FormRendererHandle, K as FieldWrapperProps, J as LayoutProps, P as PageWrapperProps, C as ComponentMap, n as TextComponentProps, o as NumberComponentProps, p as IntegerComponentProps, q as BooleanComponentProps, r as DateComponentProps, s as DateTimeComponentProps, t as SelectComponentProps, u as MultiSelectComponentProps, v as ArrayComponentProps, w as ObjectComponentProps, x as ComputedComponentProps, z as DisplayComponentProps, H as MatrixComponentProps, m as FieldComponentProps } from '../FormRenderer-B7qwG4to.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import '@fogpipe/forma-core';
|
|
5
5
|
|
package/dist/defaults/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FormRenderer,
|
|
3
3
|
useFormaContext
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-CFX3T5WK.js";
|
|
5
5
|
|
|
6
6
|
// src/defaults/DefaultFormRenderer.tsx
|
|
7
7
|
import { forwardRef } from "react";
|
|
@@ -477,6 +477,7 @@ function ObjectField({ field }) {
|
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
// src/defaults/components/ComputedDisplay.tsx
|
|
480
|
+
import { formatValue } from "@fogpipe/forma-core";
|
|
480
481
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
481
482
|
function ComputedDisplay({ field }) {
|
|
482
483
|
let displayValue;
|
|
@@ -489,7 +490,7 @@ function ComputedDisplay({ field }) {
|
|
|
489
490
|
displayValue = String(field.value);
|
|
490
491
|
}
|
|
491
492
|
} else {
|
|
492
|
-
displayValue =
|
|
493
|
+
displayValue = formatValue(field.value, field.format, field.formatOptions);
|
|
493
494
|
}
|
|
494
495
|
return /* @__PURE__ */ jsx10(
|
|
495
496
|
"output",
|
|
@@ -502,9 +503,12 @@ function ComputedDisplay({ field }) {
|
|
|
502
503
|
}
|
|
503
504
|
|
|
504
505
|
// src/defaults/components/DisplayField.tsx
|
|
506
|
+
import { formatValue as formatValue2 } from "@fogpipe/forma-core";
|
|
505
507
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
508
|
+
var FORMAT_DEFAULTS = { nullDisplay: "\u2014" };
|
|
506
509
|
function DisplayField({ field }) {
|
|
507
|
-
const
|
|
510
|
+
const options = field.formatOptions ? { ...FORMAT_DEFAULTS, ...field.formatOptions } : FORMAT_DEFAULTS;
|
|
511
|
+
const content = field.sourceValue !== void 0 ? formatValue2(field.sourceValue, field.format, options) : field.content;
|
|
508
512
|
return /* @__PURE__ */ jsx11("div", { className: "forma-display", children: content && /* @__PURE__ */ jsx11("p", { className: "forma-display__content", children: content }) });
|
|
509
513
|
}
|
|
510
514
|
|