@formality-ui/react 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -201,13 +201,14 @@ declare function defineInputs<T extends Record<string, ReactInputConfig>>(inputs
201
201
  *
202
202
  * `<Field>` renders your input component via React Hook Form's `<Controller>`.
203
203
  * At runtime Formality merges a `coreProps` bundle onto the component (name,
204
- * value, onChange, onBlur, and — as a React-special key — `ref`). The three
205
- * members below are the **injected-props contract**: `formState` always
206
- * reaches templates and render-prop children, and reaches plain components
207
- * that have opted into Formality state via `provideState` /
208
- * `passSubscriptions`; `state` (subscribed field state) and a top-level
209
- * `forwardRef` key are delivered at runtime by `<Field>` (see "Runtime
210
- * delivery" below).
204
+ * value, onChange, onBlur, and `forwardRef` RHF's ref callback, delivered as
205
+ * a regular enumerable top-level prop, NOT React's special `ref` key; see §20.1
206
+ * and "Runtime delivery" below). The three members below are the
207
+ * **injected-props contract**: `formState` always reaches templates and
208
+ * render-prop children, and reaches plain components that have opted into
209
+ * Formality state via `provideState` / `passSubscriptions`; `state`
210
+ * (subscribed field state) and `forwardRef` are delivered at runtime by
211
+ * `<Field>` (see "Runtime delivery" below).
211
212
  *
212
213
  * **Destructure before forwarding.** Component authors MUST destructure
213
214
  * `state`, `formState`, and `forwardRef` OUT of props before spreading the
@@ -593,6 +594,14 @@ interface FormProps<TFieldValues extends FieldValues = FieldValues> {
593
594
  * (`false` for immediate, or a number for a per-field delay).
594
595
  */
595
596
  debounce?: number | false;
597
+ /**
598
+ * React Hook Form validation trigger `mode`, forwarded to `useForm({ mode })`.
599
+ * One of `'onChange'` (default) | `'onBlur'` | `'onSubmit'` | `'onTouched'` |
600
+ * `'all'`. Honored as-is — auto-save is mode-agnostic: its validity gates
601
+ * trigger validation of the touched fields themselves via `methods.trigger`
602
+ * (which ignores `mode`), so it works under any mode. See PRD §12.
603
+ */
604
+ mode?: "onChange" | "onBlur" | "onSubmit" | "onTouched" | "all";
596
605
  /** Form-level validation */
597
606
  validate?: (values: Partial<TFieldValues>) => Record<string, string> | Promise<Record<string, string>>;
598
607
  }
@@ -644,7 +653,7 @@ interface FormRenderAPI<TFieldValues extends FieldValues = FieldValues> {
644
653
  * </Form>
645
654
  * ```
646
655
  */
647
- declare function Form<TFieldValues extends FieldValues = FieldValues>({ children, config, formConfig, onSubmit, record, autoSave, debounce: debounceMs, validate, }: FormProps<TFieldValues>): JSX.Element;
656
+ declare function Form<TFieldValues extends FieldValues = FieldValues>({ children, config, formConfig, onSubmit, record, autoSave, debounce: debounceMs, mode, validate, }: FormProps<TFieldValues>): JSX.Element;
648
657
 
649
658
  /**
650
659
  * Field component props.
@@ -714,15 +723,15 @@ interface FieldRenderAPI {
714
723
  formState: UseFormStateReturn<FieldValues>;
715
724
  }
716
725
  /**
717
- * Field component - Renders a form field with full Formality integration
726
+ * Field component - Thin wrapper over {@link useField}.
718
727
  *
719
- * Provides:
720
- * - React Hook Form Controller integration
721
- * - Props resolution (8-layer merge)
722
- * - Condition evaluation (disabled/visible/setValue)
723
- * - Value transformation (parse/format)
724
- * - Validation (field + type validators)
725
- * - Subscription management
728
+ * The RHF Controller integration (props resolution / 8-layer merge, conditions,
729
+ * parse/format, validation, forwardRef delivery, template/host rendering,
730
+ * render-prop `children` application) lives in the {@link useField} hook
731
+ * (PRD §1.3.3 / §5.3 / §20). This component owns ONLY:
732
+ * - the form-registry registration `useEffect` (`registerField`/
733
+ * `unregisterField`, gated on `shouldRegister`) contract bullet b; and
734
+ * - delegating to `useField(params)` and returning its `renderedField`.
726
735
  *
727
736
  * @example
728
737
  * ```tsx
@@ -735,7 +744,7 @@ interface FieldRenderAPI {
735
744
  * // Custom render
736
745
  * <Field name="name">
737
746
  * {({ renderedField, fieldState }) => (
738
- * <div className={fieldState.error ? 'has-error' : ''}>
747
+ * <div className={fieldState.error ? "has-error" : ""}>
739
748
  * {renderedField}
740
749
  * </div>
741
750
  * )}
@@ -1098,4 +1107,170 @@ declare function useInferredInputs(options: UseInferredInputsOptions): string[];
1098
1107
  */
1099
1108
  declare function useSubscriptions(fieldName: string, subscriptions: string[]): void;
1100
1109
 
1101
- export { ConfigContext, type ConfigContextValue, type CustomFieldState, type DebouncedFunction, type ExtendedFormState, Field, FieldGroup, type FieldGroupProps, type FieldProps, type FieldRenderAPI, Form, FormContext, type FormContextValue, type FormProps, type FormRenderAPI, type FormalityFieldComponentProps, FormalityProvider, type FormalityProviderProps, GroupContext, type GroupContextValue, type GroupState, type InputTemplateProps, type ReactFieldConfig, type ReactFormFieldsConfig, type ReactInputConfig, UnusedFields, type UnusedFieldsProps, type UseFormStateOptions, type WatcherSetterFn, defineInputs, makeDeepProxyState, makeProxyState, useConditions, useConfigContext, useFormContext, useFormState, useGroupContext, useInferredInputs, usePropsEvaluation, useSubscriptions };
1110
+ /**
1111
+ * Parameters for {@link useField}.
1112
+ *
1113
+ * Mirrors the subset of `FieldProps` (in `../components/Field`) that the hook
1114
+ * consumes as the single seam for **RHF Controller integration** (gap_analysis.md
1115
+ * **G6**; PRD §1.3.3).
1116
+ *
1117
+ * Per PRD §1.3.3, `hooks/useField` is the module that owns **RHF Controller
1118
+ * integration** for a field — "Uses Core: transform/pipeline, validation/
1119
+ * validate". This interface is the **input contract** for that module: it
1120
+ * carries the field identity + the overrides + the passthrough props threaded
1121
+ * into the parse/format pipeline (§5.3.5), change handler (§5.3.6), validation
1122
+ * wiring (§5.3.7), forwardRef delivery (§20.1), and template/host rendering
1123
+ * (§5.3.8).
1124
+ *
1125
+ * Generic over `TName` (default `string`) so a narrowed name type from
1126
+ * `FieldProps<TName>` can be threaded straight through (PRD §C.4 / T2.1). The
1127
+ * default keeps a bare `UseFieldParams` identical to `UseFieldParams<string>`.
1128
+ *
1129
+ * @template TName - Field name literal/union type (default `string`).
1130
+ */
1131
+ interface UseFieldParams<TName extends string = string> {
1132
+ /**
1133
+ * Field name (must match a key in Form's config). When `TName` is narrowed,
1134
+ * this is checked against `TName` at compile time.
1135
+ */
1136
+ name: TName;
1137
+ /** Override the input type resolved from config. */
1138
+ type?: string;
1139
+ /**
1140
+ * Override disabled state. Highest priority in the §5.3.4 disabled
1141
+ * resolution (prop > condition > config).
1142
+ */
1143
+ disabled?: boolean;
1144
+ /** Override hidden state (inverse of visible). */
1145
+ hidden?: boolean;
1146
+ /**
1147
+ * Whether to register this field in Form's field registry (default `true`).
1148
+ *
1149
+ * NOTE: the registration `useEffect` itself is OWNED by the `<Field>`
1150
+ * component (contract bullet b) — this flag is threaded through so a future
1151
+ * direct-hook consumer can opt out. `useField` does NOT call
1152
+ * `registerField`/`unregisterField`.
1153
+ */
1154
+ shouldRegister?: boolean;
1155
+ /**
1156
+ * Per-field input-config override. Merged at the highest-priority layer over
1157
+ * provider/form config (e.g. per-field debounce). See `resolveInputConfig`.
1158
+ */
1159
+ inputConfig?: Partial<InputConfig>;
1160
+ /**
1161
+ * Optional render-prop. Applied INSIDE the hook's Controller render callback
1162
+ * (§5.3.8) against {@link UseFieldReturn}, so the render-prop always sees the
1163
+ * live `fieldState`/`formState`/`fieldProps` values.
1164
+ */
1165
+ children?: ReactNode | ((api: UseFieldReturn) => ReactNode);
1166
+ /**
1167
+ * Additional props forwarded to the input component (the 8-layer
1168
+ * `componentProps` merge layer, §5.3.2). Captured by `mergeFieldProps`.
1169
+ */
1170
+ [key: string]: unknown;
1171
+ }
1172
+ /**
1173
+ * Return value of {@link useField}.
1174
+ *
1175
+ * **Structurally identical** to `FieldRenderAPI` (in `../components/Field`) —
1176
+ * the data the render layer (template / host / render-prop `children`) consumes.
1177
+ * This equivalence is enforced bidirectionally by
1178
+ * `__typechecks__/useField.test-d.ts`.
1179
+ *
1180
+ * Per PRD §1.3.3, the hook owns the RHF Controller integration, so the fields
1181
+ * below are exactly the Controller-produced state the render layer needs:
1182
+ * `fieldState` + `formState` come from the Controller render callback;
1183
+ * `renderedField` is the RAW rendered input (template/component/host) when
1184
+ * visible, `null` when hidden (the Controller mounts ONLY when visible, so
1185
+ * hidden fields are not RHF-registered — §5.3.8 / §20);
1186
+ * `fieldProps` is the final 8-layer-merged props (§5.3.2, via `mergeFieldProps`);
1187
+ * `watchers` is the map of fields currently watching this field (§5.3.1 step 3).
1188
+ */
1189
+ interface UseFieldReturn {
1190
+ /**
1191
+ * RHF field state from the Controller render callback
1192
+ * (`invalid` / `isTouched` / `isDirty` / `error` / …).
1193
+ */
1194
+ fieldState: ControllerFieldState;
1195
+ /**
1196
+ * The RAW rendered input (template / component / host element), or `null`
1197
+ * when the field is not visible. The render-prop `children` is applied
1198
+ * INSIDE the Controller render callback that produces this element.
1199
+ */
1200
+ renderedField: ReactNode;
1201
+ /**
1202
+ * Final merged props passed to the input — the output of the 8-layer
1203
+ * `mergeFieldProps` pipeline (§5.3.2).
1204
+ */
1205
+ fieldProps: Record<string, unknown>;
1206
+ /**
1207
+ * Map of fields watching this field (`true` = currently subscribed). Populated
1208
+ * via the watcher-setter registered with `useSubscriptions` (§5.3.1 step 3).
1209
+ */
1210
+ watchers: Record<string, boolean>;
1211
+ /**
1212
+ * RHF form state from the Controller. Typed as `UseFormStateReturn<FieldValues>`
1213
+ * to match `FieldRenderAPI` exactly (NOT bare `UseFormStateReturn`).
1214
+ */
1215
+ formState: UseFormStateReturn<FieldValues>;
1216
+ }
1217
+ /**
1218
+ * useField — RHF Controller integration for a single Field (PRD §1.3.3 / §20).
1219
+ *
1220
+ * This hook owns the **entire** Controller lifecycle for one field: it reads
1221
+ * the form/config/group contexts, resolves the input config, sets up watchers
1222
+ * + subscriptions + conditions, builds the setValue effect (ref pattern,
1223
+ * §7.1.1), resolves the disabled/visible/label state, builds the validation
1224
+ * rules + change handler, mounts the `<Controller>` element with its full
1225
+ * render callback (format → state injection → `mergeFieldProps` 8-layer merge →
1226
+ * forwardRef delivery §20.1/§20.4 → template/host/component → render-prop
1227
+ * `children`), and returns the {@link UseFieldReturn}.
1228
+ *
1229
+ * ## Responsibilities (PRD §1.3.3 + §5.3.x + §20)
1230
+ *
1231
+ * - **Controller integration** — wraps RHF's `<Controller>` render callback.
1232
+ * The `<Controller>` mounts ONLY when the field is visible (the
1233
+ * `renderedField` is `null` when hidden), preserving the
1234
+ * conditionally-hidden-field invariant (hidden fields are NOT RHF-registered).
1235
+ * - **Parse/format pipeline (§5.3.5)** — Core `parse` / `format` from
1236
+ * `@formality-ui/core` (`transform/pipeline`).
1237
+ * - **Change handler (§5.3.6)** — `changeField` + watcher fan-out.
1238
+ * - **Validation (§5.3.7)** — Core `runValidator` / `resolveErrorMessage`
1239
+ * (`validation/validate`).
1240
+ * - **forwardRef delivery (§20.1)** — delivers the input's ref via the merged
1241
+ * props' `forwardRef` key (the CURRENT implemented behavior — NOT the legacy
1242
+ * `ref` key shown in the stale §5.3.2 pseudo-code). The host-element path
1243
+ * (§20.4 narrow exception) translates `forwardRef` back into React's special
1244
+ * `ref` key for string components.
1245
+ * - **Props merge (§5.3.2)** — `resolveInputConfig` + `resolveLabel` +
1246
+ * `mergeFieldProps` (the 8-layer merge).
1247
+ * - **Template/host render (§5.3.8)** — produces the RAW `renderedField`.
1248
+ *
1249
+ * It consumes these context hooks (`useFormContext`, `useConfigContext`,
1250
+ * `useGroupContext`) and composed hooks (`useConditions`, `usePropsEvaluation`,
1251
+ * `useInferredInputs`, `useSubscriptions`), and the Core fns above.
1252
+ *
1253
+ * NOTE: field **registration** (`registerField`/`unregisterField`) is OWNED by
1254
+ * the `<Field>` component (contract bullet b), NOT this hook. The hook reads
1255
+ * `useFormContext()` for everything else (config, methods, changeField,
1256
+ * setFieldValidating, register/unregisterWatcherSetter).
1257
+ *
1258
+ * @param params - Field parameters (see {@link UseFieldParams}).
1259
+ * @returns The Controller-produced state + the RAW rendered input
1260
+ * (see {@link UseFieldReturn}).
1261
+ *
1262
+ * @example
1263
+ * ```tsx
1264
+ * // Direct hook usage (custom layout):
1265
+ * function MyField() {
1266
+ * const { renderedField, fieldState } = useField({ name: "email" });
1267
+ * return <div className={fieldState.error ? "has-error" : ""}>{renderedField}</div>;
1268
+ * }
1269
+ *
1270
+ * // Equivalent via the thin wrapper component:
1271
+ * <Field name="email" />;
1272
+ * ```
1273
+ */
1274
+ declare function useField<TName extends string = string>({ name, type: typeProp, disabled: disabledProp, hidden: hiddenProp, children, inputConfig: inputConfigProp, ...restProps }: UseFieldParams<TName>): UseFieldReturn;
1275
+
1276
+ export { ConfigContext, type ConfigContextValue, type CustomFieldState, type DebouncedFunction, type ExtendedFormState, Field, FieldGroup, type FieldGroupProps, type FieldProps, type FieldRenderAPI, Form, FormContext, type FormContextValue, type FormProps, type FormRenderAPI, type FormalityFieldComponentProps, FormalityProvider, type FormalityProviderProps, GroupContext, type GroupContextValue, type GroupState, type InputTemplateProps, type ReactFieldConfig, type ReactFormFieldsConfig, type ReactInputConfig, UnusedFields, type UnusedFieldsProps, type UseFieldParams, type UseFieldReturn, type UseFormStateOptions, type WatcherSetterFn, defineInputs, makeDeepProxyState, makeProxyState, useConditions, useConfigContext, useField, useFormContext, useFormState, useGroupContext, useInferredInputs, usePropsEvaluation, useSubscriptions };
package/dist/index.d.ts CHANGED
@@ -201,13 +201,14 @@ declare function defineInputs<T extends Record<string, ReactInputConfig>>(inputs
201
201
  *
202
202
  * `<Field>` renders your input component via React Hook Form's `<Controller>`.
203
203
  * At runtime Formality merges a `coreProps` bundle onto the component (name,
204
- * value, onChange, onBlur, and — as a React-special key — `ref`). The three
205
- * members below are the **injected-props contract**: `formState` always
206
- * reaches templates and render-prop children, and reaches plain components
207
- * that have opted into Formality state via `provideState` /
208
- * `passSubscriptions`; `state` (subscribed field state) and a top-level
209
- * `forwardRef` key are delivered at runtime by `<Field>` (see "Runtime
210
- * delivery" below).
204
+ * value, onChange, onBlur, and `forwardRef` RHF's ref callback, delivered as
205
+ * a regular enumerable top-level prop, NOT React's special `ref` key; see §20.1
206
+ * and "Runtime delivery" below). The three members below are the
207
+ * **injected-props contract**: `formState` always reaches templates and
208
+ * render-prop children, and reaches plain components that have opted into
209
+ * Formality state via `provideState` / `passSubscriptions`; `state`
210
+ * (subscribed field state) and `forwardRef` are delivered at runtime by
211
+ * `<Field>` (see "Runtime delivery" below).
211
212
  *
212
213
  * **Destructure before forwarding.** Component authors MUST destructure
213
214
  * `state`, `formState`, and `forwardRef` OUT of props before spreading the
@@ -593,6 +594,14 @@ interface FormProps<TFieldValues extends FieldValues = FieldValues> {
593
594
  * (`false` for immediate, or a number for a per-field delay).
594
595
  */
595
596
  debounce?: number | false;
597
+ /**
598
+ * React Hook Form validation trigger `mode`, forwarded to `useForm({ mode })`.
599
+ * One of `'onChange'` (default) | `'onBlur'` | `'onSubmit'` | `'onTouched'` |
600
+ * `'all'`. Honored as-is — auto-save is mode-agnostic: its validity gates
601
+ * trigger validation of the touched fields themselves via `methods.trigger`
602
+ * (which ignores `mode`), so it works under any mode. See PRD §12.
603
+ */
604
+ mode?: "onChange" | "onBlur" | "onSubmit" | "onTouched" | "all";
596
605
  /** Form-level validation */
597
606
  validate?: (values: Partial<TFieldValues>) => Record<string, string> | Promise<Record<string, string>>;
598
607
  }
@@ -644,7 +653,7 @@ interface FormRenderAPI<TFieldValues extends FieldValues = FieldValues> {
644
653
  * </Form>
645
654
  * ```
646
655
  */
647
- declare function Form<TFieldValues extends FieldValues = FieldValues>({ children, config, formConfig, onSubmit, record, autoSave, debounce: debounceMs, validate, }: FormProps<TFieldValues>): JSX.Element;
656
+ declare function Form<TFieldValues extends FieldValues = FieldValues>({ children, config, formConfig, onSubmit, record, autoSave, debounce: debounceMs, mode, validate, }: FormProps<TFieldValues>): JSX.Element;
648
657
 
649
658
  /**
650
659
  * Field component props.
@@ -714,15 +723,15 @@ interface FieldRenderAPI {
714
723
  formState: UseFormStateReturn<FieldValues>;
715
724
  }
716
725
  /**
717
- * Field component - Renders a form field with full Formality integration
726
+ * Field component - Thin wrapper over {@link useField}.
718
727
  *
719
- * Provides:
720
- * - React Hook Form Controller integration
721
- * - Props resolution (8-layer merge)
722
- * - Condition evaluation (disabled/visible/setValue)
723
- * - Value transformation (parse/format)
724
- * - Validation (field + type validators)
725
- * - Subscription management
728
+ * The RHF Controller integration (props resolution / 8-layer merge, conditions,
729
+ * parse/format, validation, forwardRef delivery, template/host rendering,
730
+ * render-prop `children` application) lives in the {@link useField} hook
731
+ * (PRD §1.3.3 / §5.3 / §20). This component owns ONLY:
732
+ * - the form-registry registration `useEffect` (`registerField`/
733
+ * `unregisterField`, gated on `shouldRegister`) contract bullet b; and
734
+ * - delegating to `useField(params)` and returning its `renderedField`.
726
735
  *
727
736
  * @example
728
737
  * ```tsx
@@ -735,7 +744,7 @@ interface FieldRenderAPI {
735
744
  * // Custom render
736
745
  * <Field name="name">
737
746
  * {({ renderedField, fieldState }) => (
738
- * <div className={fieldState.error ? 'has-error' : ''}>
747
+ * <div className={fieldState.error ? "has-error" : ""}>
739
748
  * {renderedField}
740
749
  * </div>
741
750
  * )}
@@ -1098,4 +1107,170 @@ declare function useInferredInputs(options: UseInferredInputsOptions): string[];
1098
1107
  */
1099
1108
  declare function useSubscriptions(fieldName: string, subscriptions: string[]): void;
1100
1109
 
1101
- export { ConfigContext, type ConfigContextValue, type CustomFieldState, type DebouncedFunction, type ExtendedFormState, Field, FieldGroup, type FieldGroupProps, type FieldProps, type FieldRenderAPI, Form, FormContext, type FormContextValue, type FormProps, type FormRenderAPI, type FormalityFieldComponentProps, FormalityProvider, type FormalityProviderProps, GroupContext, type GroupContextValue, type GroupState, type InputTemplateProps, type ReactFieldConfig, type ReactFormFieldsConfig, type ReactInputConfig, UnusedFields, type UnusedFieldsProps, type UseFormStateOptions, type WatcherSetterFn, defineInputs, makeDeepProxyState, makeProxyState, useConditions, useConfigContext, useFormContext, useFormState, useGroupContext, useInferredInputs, usePropsEvaluation, useSubscriptions };
1110
+ /**
1111
+ * Parameters for {@link useField}.
1112
+ *
1113
+ * Mirrors the subset of `FieldProps` (in `../components/Field`) that the hook
1114
+ * consumes as the single seam for **RHF Controller integration** (gap_analysis.md
1115
+ * **G6**; PRD §1.3.3).
1116
+ *
1117
+ * Per PRD §1.3.3, `hooks/useField` is the module that owns **RHF Controller
1118
+ * integration** for a field — "Uses Core: transform/pipeline, validation/
1119
+ * validate". This interface is the **input contract** for that module: it
1120
+ * carries the field identity + the overrides + the passthrough props threaded
1121
+ * into the parse/format pipeline (§5.3.5), change handler (§5.3.6), validation
1122
+ * wiring (§5.3.7), forwardRef delivery (§20.1), and template/host rendering
1123
+ * (§5.3.8).
1124
+ *
1125
+ * Generic over `TName` (default `string`) so a narrowed name type from
1126
+ * `FieldProps<TName>` can be threaded straight through (PRD §C.4 / T2.1). The
1127
+ * default keeps a bare `UseFieldParams` identical to `UseFieldParams<string>`.
1128
+ *
1129
+ * @template TName - Field name literal/union type (default `string`).
1130
+ */
1131
+ interface UseFieldParams<TName extends string = string> {
1132
+ /**
1133
+ * Field name (must match a key in Form's config). When `TName` is narrowed,
1134
+ * this is checked against `TName` at compile time.
1135
+ */
1136
+ name: TName;
1137
+ /** Override the input type resolved from config. */
1138
+ type?: string;
1139
+ /**
1140
+ * Override disabled state. Highest priority in the §5.3.4 disabled
1141
+ * resolution (prop > condition > config).
1142
+ */
1143
+ disabled?: boolean;
1144
+ /** Override hidden state (inverse of visible). */
1145
+ hidden?: boolean;
1146
+ /**
1147
+ * Whether to register this field in Form's field registry (default `true`).
1148
+ *
1149
+ * NOTE: the registration `useEffect` itself is OWNED by the `<Field>`
1150
+ * component (contract bullet b) — this flag is threaded through so a future
1151
+ * direct-hook consumer can opt out. `useField` does NOT call
1152
+ * `registerField`/`unregisterField`.
1153
+ */
1154
+ shouldRegister?: boolean;
1155
+ /**
1156
+ * Per-field input-config override. Merged at the highest-priority layer over
1157
+ * provider/form config (e.g. per-field debounce). See `resolveInputConfig`.
1158
+ */
1159
+ inputConfig?: Partial<InputConfig>;
1160
+ /**
1161
+ * Optional render-prop. Applied INSIDE the hook's Controller render callback
1162
+ * (§5.3.8) against {@link UseFieldReturn}, so the render-prop always sees the
1163
+ * live `fieldState`/`formState`/`fieldProps` values.
1164
+ */
1165
+ children?: ReactNode | ((api: UseFieldReturn) => ReactNode);
1166
+ /**
1167
+ * Additional props forwarded to the input component (the 8-layer
1168
+ * `componentProps` merge layer, §5.3.2). Captured by `mergeFieldProps`.
1169
+ */
1170
+ [key: string]: unknown;
1171
+ }
1172
+ /**
1173
+ * Return value of {@link useField}.
1174
+ *
1175
+ * **Structurally identical** to `FieldRenderAPI` (in `../components/Field`) —
1176
+ * the data the render layer (template / host / render-prop `children`) consumes.
1177
+ * This equivalence is enforced bidirectionally by
1178
+ * `__typechecks__/useField.test-d.ts`.
1179
+ *
1180
+ * Per PRD §1.3.3, the hook owns the RHF Controller integration, so the fields
1181
+ * below are exactly the Controller-produced state the render layer needs:
1182
+ * `fieldState` + `formState` come from the Controller render callback;
1183
+ * `renderedField` is the RAW rendered input (template/component/host) when
1184
+ * visible, `null` when hidden (the Controller mounts ONLY when visible, so
1185
+ * hidden fields are not RHF-registered — §5.3.8 / §20);
1186
+ * `fieldProps` is the final 8-layer-merged props (§5.3.2, via `mergeFieldProps`);
1187
+ * `watchers` is the map of fields currently watching this field (§5.3.1 step 3).
1188
+ */
1189
+ interface UseFieldReturn {
1190
+ /**
1191
+ * RHF field state from the Controller render callback
1192
+ * (`invalid` / `isTouched` / `isDirty` / `error` / …).
1193
+ */
1194
+ fieldState: ControllerFieldState;
1195
+ /**
1196
+ * The RAW rendered input (template / component / host element), or `null`
1197
+ * when the field is not visible. The render-prop `children` is applied
1198
+ * INSIDE the Controller render callback that produces this element.
1199
+ */
1200
+ renderedField: ReactNode;
1201
+ /**
1202
+ * Final merged props passed to the input — the output of the 8-layer
1203
+ * `mergeFieldProps` pipeline (§5.3.2).
1204
+ */
1205
+ fieldProps: Record<string, unknown>;
1206
+ /**
1207
+ * Map of fields watching this field (`true` = currently subscribed). Populated
1208
+ * via the watcher-setter registered with `useSubscriptions` (§5.3.1 step 3).
1209
+ */
1210
+ watchers: Record<string, boolean>;
1211
+ /**
1212
+ * RHF form state from the Controller. Typed as `UseFormStateReturn<FieldValues>`
1213
+ * to match `FieldRenderAPI` exactly (NOT bare `UseFormStateReturn`).
1214
+ */
1215
+ formState: UseFormStateReturn<FieldValues>;
1216
+ }
1217
+ /**
1218
+ * useField — RHF Controller integration for a single Field (PRD §1.3.3 / §20).
1219
+ *
1220
+ * This hook owns the **entire** Controller lifecycle for one field: it reads
1221
+ * the form/config/group contexts, resolves the input config, sets up watchers
1222
+ * + subscriptions + conditions, builds the setValue effect (ref pattern,
1223
+ * §7.1.1), resolves the disabled/visible/label state, builds the validation
1224
+ * rules + change handler, mounts the `<Controller>` element with its full
1225
+ * render callback (format → state injection → `mergeFieldProps` 8-layer merge →
1226
+ * forwardRef delivery §20.1/§20.4 → template/host/component → render-prop
1227
+ * `children`), and returns the {@link UseFieldReturn}.
1228
+ *
1229
+ * ## Responsibilities (PRD §1.3.3 + §5.3.x + §20)
1230
+ *
1231
+ * - **Controller integration** — wraps RHF's `<Controller>` render callback.
1232
+ * The `<Controller>` mounts ONLY when the field is visible (the
1233
+ * `renderedField` is `null` when hidden), preserving the
1234
+ * conditionally-hidden-field invariant (hidden fields are NOT RHF-registered).
1235
+ * - **Parse/format pipeline (§5.3.5)** — Core `parse` / `format` from
1236
+ * `@formality-ui/core` (`transform/pipeline`).
1237
+ * - **Change handler (§5.3.6)** — `changeField` + watcher fan-out.
1238
+ * - **Validation (§5.3.7)** — Core `runValidator` / `resolveErrorMessage`
1239
+ * (`validation/validate`).
1240
+ * - **forwardRef delivery (§20.1)** — delivers the input's ref via the merged
1241
+ * props' `forwardRef` key (the CURRENT implemented behavior — NOT the legacy
1242
+ * `ref` key shown in the stale §5.3.2 pseudo-code). The host-element path
1243
+ * (§20.4 narrow exception) translates `forwardRef` back into React's special
1244
+ * `ref` key for string components.
1245
+ * - **Props merge (§5.3.2)** — `resolveInputConfig` + `resolveLabel` +
1246
+ * `mergeFieldProps` (the 8-layer merge).
1247
+ * - **Template/host render (§5.3.8)** — produces the RAW `renderedField`.
1248
+ *
1249
+ * It consumes these context hooks (`useFormContext`, `useConfigContext`,
1250
+ * `useGroupContext`) and composed hooks (`useConditions`, `usePropsEvaluation`,
1251
+ * `useInferredInputs`, `useSubscriptions`), and the Core fns above.
1252
+ *
1253
+ * NOTE: field **registration** (`registerField`/`unregisterField`) is OWNED by
1254
+ * the `<Field>` component (contract bullet b), NOT this hook. The hook reads
1255
+ * `useFormContext()` for everything else (config, methods, changeField,
1256
+ * setFieldValidating, register/unregisterWatcherSetter).
1257
+ *
1258
+ * @param params - Field parameters (see {@link UseFieldParams}).
1259
+ * @returns The Controller-produced state + the RAW rendered input
1260
+ * (see {@link UseFieldReturn}).
1261
+ *
1262
+ * @example
1263
+ * ```tsx
1264
+ * // Direct hook usage (custom layout):
1265
+ * function MyField() {
1266
+ * const { renderedField, fieldState } = useField({ name: "email" });
1267
+ * return <div className={fieldState.error ? "has-error" : ""}>{renderedField}</div>;
1268
+ * }
1269
+ *
1270
+ * // Equivalent via the thin wrapper component:
1271
+ * <Field name="email" />;
1272
+ * ```
1273
+ */
1274
+ declare function useField<TName extends string = string>({ name, type: typeProp, disabled: disabledProp, hidden: hiddenProp, children, inputConfig: inputConfigProp, ...restProps }: UseFieldParams<TName>): UseFieldReturn;
1275
+
1276
+ export { ConfigContext, type ConfigContextValue, type CustomFieldState, type DebouncedFunction, type ExtendedFormState, Field, FieldGroup, type FieldGroupProps, type FieldProps, type FieldRenderAPI, Form, FormContext, type FormContextValue, type FormProps, type FormRenderAPI, type FormalityFieldComponentProps, FormalityProvider, type FormalityProviderProps, GroupContext, type GroupContextValue, type GroupState, type InputTemplateProps, type ReactFieldConfig, type ReactFormFieldsConfig, type ReactInputConfig, UnusedFields, type UnusedFieldsProps, type UseFieldParams, type UseFieldReturn, type UseFormStateOptions, type WatcherSetterFn, defineInputs, makeDeepProxyState, makeProxyState, useConditions, useConfigContext, useField, useFormContext, useFormState, useGroupContext, useInferredInputs, usePropsEvaluation, useSubscriptions };