@gntik-ai/ui 0.5.0 → 0.9.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/forms.js CHANGED
@@ -1,7 +1,9 @@
1
1
  'use client';
2
- import { a as FieldLabel, n as FieldDescription, r as FieldError, t as Field } from "./Field-neBukiNh.js";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
- import { FormProvider, useController, useFormContext } from "react-hook-form";
2
+ import { N as tv, P as cn, a as FieldLabel, c as FieldsetLegend, d as useAnnounce, f as useHasLiveAnnouncer, h as IconButton, m as Button, n as FieldDescription, o as Fieldset, r as FieldError, s as FieldsetDescription, t as Field, u as LiveAnnouncer, w as useI18n } from "./Field-DPYsdteY.js";
3
+ import { createContext, useContext, useId, useLayoutEffect, useRef } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { ArrowDown, ArrowUp, Copy, Plus, Trash2 } from "lucide-react";
6
+ import { FormProvider, get, useController, useFieldArray, useFormContext, useFormState, useWatch } from "react-hook-form";
5
7
  //#region src/forms/useFieldProps.ts
6
8
  /**
7
9
  * Wires one react-hook-form field (through `useController`) into the kit's Field parts.
@@ -39,23 +41,74 @@ function errorMessage(error) {
39
41
  return typeof root?.message === "string" ? root.message : void 0;
40
42
  }
41
43
  //#endregion
44
+ //#region src/forms/bindings.ts
45
+ /** Maps value/onChange controls to the kit's value/onValueChange API. Changes also touch the field. */
46
+ function toValueProps({ value, onChange, onBlur, ...props }) {
47
+ return {
48
+ ...props,
49
+ ref: focusTargetRef(props.ref),
50
+ value: value ?? null,
51
+ onValueChange: (next) => {
52
+ onChange(next);
53
+ onBlur();
54
+ }
55
+ };
56
+ }
57
+ /** Maps value/onChange controls to the kit's checked/onCheckedChange API. */
58
+ function toCheckedProps({ value, onChange, onBlur, ...props }) {
59
+ return {
60
+ ...props,
61
+ ref: focusTargetRef(props.ref),
62
+ checked: !!value,
63
+ onCheckedChange: (next) => {
64
+ onChange(next);
65
+ onBlur();
66
+ }
67
+ };
68
+ }
69
+ /** Resolve at focus time: composite controls can mount or change their tabbable child later. */
70
+ function resolveFocusTarget(element) {
71
+ const enabled = ":not(:disabled):not([aria-disabled=\"true\"])";
72
+ if (element.matches(`input:not([type="hidden"])${enabled}, button${enabled}, textarea${enabled}, select${enabled}, a[href], [tabindex]${enabled}`)) return element;
73
+ return element.querySelector(`[tabindex="0"]${enabled}`) ?? element.querySelector(`input:not([type="hidden"])${enabled}, button${enabled}`);
74
+ }
75
+ function focusTargetRef(ref) {
76
+ return (element) => ref(element ? { focus: () => resolveFocusTarget(element)?.focus() } : null);
77
+ }
78
+ //#endregion
42
79
  //#region src/forms/FormField.tsx
43
- /**
44
- * A kit `Field` bound to a react-hook-form field: label, control, description and the field's
45
- * error message, with `aria-invalid` and `aria-describedby` wired by Base UI's Field.
46
- */
47
- function FormField({ name, label, required, description, className, children, ...options }) {
48
- const state = useFieldProps(name, options);
80
+ const FieldEnhancerContext = createContext(void 0);
81
+ const widths = {
82
+ xs: "max-w-[6.5rem]",
83
+ sm: "max-w-[13.5rem]",
84
+ md: "max-w-[20.5rem]",
85
+ lg: "max-w-[27.5rem]",
86
+ xl: "max-w-[34.5rem]"
87
+ };
88
+ function FormField(props) {
89
+ const { name, label, required, description, className, width, control, rules, disabled } = props;
90
+ const enhanced = useContext(FieldEnhancerContext)?.({ name });
91
+ const fieldDisabled = enhanced?.disabled ?? disabled;
92
+ const state = useFieldProps(name, {
93
+ control,
94
+ rules,
95
+ disabled: fieldDisabled
96
+ });
97
+ const controlProps = enhanced ? {
98
+ ...state.controlProps,
99
+ ...enhanced
100
+ } : state.controlProps;
101
+ const child = props.bind === "value" ? props.children(toValueProps(controlProps), state) : props.bind === "checked" ? props.children(toCheckedProps(controlProps), state) : props.children(controlProps, state);
49
102
  return /* @__PURE__ */ jsxs(Field, {
50
103
  ...state.fieldProps,
51
- disabled: options.disabled,
52
- className,
104
+ disabled: fieldDisabled,
105
+ className: width ? cn("w-full", widths[width], className) : className,
53
106
  children: [
54
107
  label && /* @__PURE__ */ jsx(FieldLabel, {
55
108
  required,
56
109
  children: label
57
110
  }),
58
- children(state.controlProps, state),
111
+ child,
59
112
  description && /* @__PURE__ */ jsx(FieldDescription, { children: description }),
60
113
  /* @__PURE__ */ jsx(FieldError, {
61
114
  match: !!state.error,
@@ -68,14 +121,17 @@ function FormField({ name, label, required, description, className, children, ..
68
121
  * `<form noValidate>` + `FormProvider`: submits through `handleSubmit`, so a failed submit shows
69
122
  * every message and focuses the first invalid field (react-hook-form's `shouldFocusError`).
70
123
  */
71
- function Form({ form, onSubmit, onInvalid, children, ...props }) {
124
+ function Form({ form, onSubmit, onInvalid, enhanceFieldProps, children, ...props }) {
72
125
  return /* @__PURE__ */ jsx(FormProvider, {
73
126
  ...form,
74
- children: /* @__PURE__ */ jsx("form", {
75
- noValidate: true,
76
- ...props,
77
- onSubmit: form.handleSubmit(onSubmit, onInvalid),
78
- children
127
+ children: /* @__PURE__ */ jsx(FieldEnhancerContext.Provider, {
128
+ value: enhanceFieldProps,
129
+ children: /* @__PURE__ */ jsx("form", {
130
+ noValidate: true,
131
+ ...props,
132
+ onSubmit: form.handleSubmit(onSubmit, onInvalid),
133
+ children
134
+ })
79
135
  })
80
136
  });
81
137
  }
@@ -125,6 +181,253 @@ function schemaResolver(schema) {
125
181
  };
126
182
  }
127
183
  //#endregion
128
- export { Form, FormField, issuesToErrors, schemaResolver, useFieldProps };
184
+ //#region src/forms/field-array.variants.ts
185
+ const fieldArrayVariants = tv({
186
+ slots: {
187
+ root: "min-w-0",
188
+ list: "flex flex-col gap-3",
189
+ row: "flex min-w-0 gap-3",
190
+ fields: "flex min-w-0 flex-1 flex-col gap-3",
191
+ actions: "flex shrink-0 flex-wrap items-start gap-1",
192
+ footer: "flex flex-wrap items-center gap-3",
193
+ hint: "text-sm text-muted-foreground",
194
+ error: "text-sm text-destructive-text"
195
+ },
196
+ variants: { layout: {
197
+ inline: { row: "flex-col sm:flex-row" },
198
+ card: { row: "flex-col rounded-lg border border-border bg-card p-4" }
199
+ } },
200
+ defaultVariants: { layout: "inline" }
201
+ });
202
+ //#endregion
203
+ //#region src/forms/FieldArray.tsx
204
+ /** Repeatable object fields in the optional react-hook-form adapter. */
205
+ function FieldArray(props) {
206
+ return useHasLiveAnnouncer() ? /* @__PURE__ */ jsx(FieldArrayContent, { ...props }) : /* @__PURE__ */ jsx(LiveAnnouncer, { children: /* @__PURE__ */ jsx(FieldArrayContent, { ...props }) });
207
+ }
208
+ const focusable = "input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])";
209
+ function RowFields({ children, row }) {
210
+ return children(row);
211
+ }
212
+ function FieldArrayContent({ name, control: controlProp, label, description, rules, children, defaultItem, max, min = 0, emptyState, reorderable = false, duplicable = false, layout = "inline", itemLabel, addLabel, className }) {
213
+ const context = useFormContext();
214
+ const control = controlProp ?? context?.control;
215
+ const minimum = typeof rules?.minLength === "object" ? rules.minLength.value : rules?.minLength;
216
+ const arrayRules = minimum && minimum > 0 ? {
217
+ ...rules,
218
+ required: rules?.required ?? {
219
+ value: true,
220
+ message: typeof rules?.minLength === "object" ? rules.minLength.message : ""
221
+ }
222
+ } : rules;
223
+ const { fields, append, insert, remove: removeItem, move: moveItem } = useFieldArray({
224
+ name,
225
+ control,
226
+ rules: arrayRules
227
+ });
228
+ const path = name;
229
+ const values = useWatch({
230
+ control,
231
+ name: path
232
+ });
233
+ const { errors } = useFormState({
234
+ control,
235
+ name: path
236
+ });
237
+ const arrayError = get(errors, name);
238
+ const message = arrayError?.root?.message ?? arrayError?.message;
239
+ const error = typeof message === "string" ? message : void 0;
240
+ const uid = useId();
241
+ const descriptionId = `${uid}-description`;
242
+ const errorId = `${uid}-error`;
243
+ const { t } = useI18n();
244
+ const labelFor = (n) => itemLabel?.(n) ?? t("fieldArray.item", { n });
245
+ const s = fieldArrayVariants({ layout });
246
+ const announce = useAnnounce();
247
+ const rows = useRef(/* @__PURE__ */ new Map());
248
+ const addButton = useRef(null);
249
+ const pendingFocus = useRef(null);
250
+ const full = max !== void 0 && fields.length >= max;
251
+ const announceInsertion = (message) => {
252
+ const limit = max !== void 0 && fields.length + 1 >= max ? t("fieldArray.limit", { max }) : "";
253
+ announce([message, limit].filter(Boolean).join(" "));
254
+ };
255
+ useLayoutEffect(() => {
256
+ const pending = pendingFocus.current;
257
+ if (!pending) return;
258
+ pendingFocus.current = null;
259
+ if ("add" in pending) {
260
+ addButton.current?.focus();
261
+ return;
262
+ }
263
+ const id = "previousIds" in pending ? fields.find((field) => !pending.previousIds.has(field.id))?.id : pending.id;
264
+ const element = "element" in pending ? pending.element : void 0;
265
+ (element?.isConnected ? element : id ? rows.current.get(id)?.querySelector(focusable) : null)?.focus();
266
+ });
267
+ const add = () => {
268
+ if (full) {
269
+ announce(t("fieldArray.limit", { max: max ?? 0 }));
270
+ return;
271
+ }
272
+ pendingFocus.current = { previousIds: new Set(fields.map((field) => field.id)) };
273
+ append(structuredClone(typeof defaultItem === "function" ? defaultItem() : defaultItem), { shouldFocus: false });
274
+ announceInsertion(t("fieldArray.added", { item: labelFor(fields.length + 1) }));
275
+ };
276
+ const remove = (index) => {
277
+ if (fields.length <= min) return;
278
+ const neighbour = fields[index + 1] ?? fields[index - 1];
279
+ pendingFocus.current = neighbour ? { id: neighbour.id } : { add: true };
280
+ removeItem(index);
281
+ announce(t("fieldArray.removed", { item: labelFor(index + 1) }));
282
+ };
283
+ const move = (index, delta) => {
284
+ const destination = index + delta;
285
+ const field = fields[index];
286
+ if (!reorderable || !field || !Number.isInteger(delta) || destination < 0 || destination >= fields.length || delta === 0) return;
287
+ const active = document.activeElement;
288
+ pendingFocus.current = {
289
+ id: field.id,
290
+ element: active instanceof HTMLElement && rows.current.get(field.id)?.contains(active) ? active : void 0
291
+ };
292
+ moveItem(index, destination);
293
+ announce(t("fieldArray.moved", {
294
+ n: destination + 1,
295
+ total: fields.length
296
+ }));
297
+ };
298
+ const duplicate = (index) => {
299
+ if (!duplicable || full) return;
300
+ const value = values?.[index];
301
+ if (!value) return;
302
+ pendingFocus.current = { previousIds: new Set(fields.map((field) => field.id)) };
303
+ insert(index + 1, structuredClone(value), { shouldFocus: false });
304
+ announceInsertion(t("fieldArray.duplicated", { item: labelFor(index + 1) }));
305
+ };
306
+ return /* @__PURE__ */ jsxs(Fieldset, {
307
+ "data-field-array": "",
308
+ className: s.root({ className }),
309
+ "aria-describedby": [description ? descriptionId : "", error ? errorId : ""].filter(Boolean).join(" ") || void 0,
310
+ "aria-invalid": !!error || void 0,
311
+ children: [
312
+ label && /* @__PURE__ */ jsx(FieldsetLegend, { children: label }),
313
+ description && /* @__PURE__ */ jsx(FieldsetDescription, {
314
+ id: descriptionId,
315
+ children: description
316
+ }),
317
+ /* @__PURE__ */ jsx("div", {
318
+ className: s.list(),
319
+ children: fields.map((field, index) => /* @__PURE__ */ jsxs("div", {
320
+ className: s.row(),
321
+ ref: (element) => {
322
+ if (element) rows.current.set(field.id, element);
323
+ else rows.current.delete(field.id);
324
+ },
325
+ role: "group",
326
+ "aria-label": labelFor(index + 1),
327
+ onKeyDown: (event) => {
328
+ if (event.target instanceof Element && event.target.closest("[data-field-array]") !== event.currentTarget.closest("[data-field-array]")) return;
329
+ if (reorderable && event.altKey && (event.key === "ArrowUp" || event.key === "ArrowDown")) {
330
+ event.preventDefault();
331
+ event.stopPropagation();
332
+ move(index, event.key === "ArrowUp" ? -1 : 1);
333
+ }
334
+ },
335
+ children: [/* @__PURE__ */ jsx("div", {
336
+ className: s.fields(),
337
+ children: /* @__PURE__ */ jsx(RowFields, {
338
+ row: {
339
+ index,
340
+ remove: () => remove(index),
341
+ move: (delta) => move(index, delta),
342
+ duplicate: () => duplicate(index),
343
+ name: (part) => `${name}.${index}.${part}`
344
+ },
345
+ children
346
+ })
347
+ }), /* @__PURE__ */ jsxs("div", {
348
+ className: s.actions(),
349
+ children: [
350
+ reorderable && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IconButton, {
351
+ icon: ArrowUp,
352
+ label: t("fieldArray.moveUp", { item: labelFor(index + 1) }),
353
+ disabled: index === 0,
354
+ onClick: () => move(index, -1)
355
+ }), /* @__PURE__ */ jsx(IconButton, {
356
+ icon: ArrowDown,
357
+ label: t("fieldArray.moveDown", { item: labelFor(index + 1) }),
358
+ disabled: index === fields.length - 1,
359
+ onClick: () => move(index, 1)
360
+ })] }),
361
+ duplicable && /* @__PURE__ */ jsx(IconButton, {
362
+ icon: Copy,
363
+ label: t("fieldArray.duplicate", { item: labelFor(index + 1) }),
364
+ disabled: full,
365
+ onClick: () => duplicate(index)
366
+ }),
367
+ /* @__PURE__ */ jsx(IconButton, {
368
+ icon: Trash2,
369
+ label: t("fieldArray.remove", { item: labelFor(index + 1) }),
370
+ disabled: fields.length <= min,
371
+ onClick: () => remove(index)
372
+ })
373
+ ]
374
+ })]
375
+ }, field.id))
376
+ }),
377
+ !fields.length && (emptyState ?? /* @__PURE__ */ jsx("p", {
378
+ className: s.hint(),
379
+ children: t("fieldArray.empty")
380
+ })),
381
+ /* @__PURE__ */ jsxs("div", {
382
+ className: s.footer(),
383
+ children: [/* @__PURE__ */ jsx(Button, {
384
+ ref: addButton,
385
+ icon: Plus,
386
+ variant: "secondary",
387
+ disabled: full,
388
+ onClick: add,
389
+ children: addLabel ?? t("fieldArray.add")
390
+ }), full && /* @__PURE__ */ jsx("p", {
391
+ className: s.hint(),
392
+ children: t("fieldArray.limit", { max: max ?? 0 })
393
+ })]
394
+ }),
395
+ error && /* @__PURE__ */ jsx("p", {
396
+ id: errorId,
397
+ className: s.error(),
398
+ children: error
399
+ })
400
+ ]
401
+ });
402
+ }
403
+ //#endregion
404
+ //#region src/forms/FieldArray.doc.ts
405
+ const doc = {
406
+ name: "FieldArray",
407
+ group: "Forms",
408
+ status: "beta",
409
+ description: "Repeatable arbitrary fields bound to react-hook-form arrays. Import from @gntik-ai/ui/forms only; use within Form or pass control explicitly. Rows expose index, name(field), remove(), duplicate() and move(delta). Add accepts a default object or factory. Optional reorder and duplicate actions preserve row identity, and min/max gate removals and additions. Inline and card layouts support nested arrays, list-level validation, focus restoration and localized announcements. Use ListInput for standalone key/value pairs without a form library; use FieldArray for arbitrary object fields managed by react-hook-form.",
410
+ primitive: "@base-ui/react/fieldset, @base-ui/react/field, @base-ui/react/button",
411
+ pattern: "fieldset with named row groups",
412
+ keyboard: [
413
+ ["Tab / Shift+Tab", "Moves through row fields, row actions and Add in document order"],
414
+ ["Enter / Space on Add", "Appends the default item and focuses its first control"],
415
+ ["Enter / Space on Remove", "Removes the row and focuses the next row, previous row or Add"],
416
+ ["Alt+ArrowUp / Alt+ArrowDown", "With reorderable, moves the row and keeps focus on the same control; stops at either end"],
417
+ ["Enter / Space on Move up / Move down", "Moves the row by one position and preserves focus"],
418
+ ["Enter / Space on Duplicate", "With duplicable, inserts an independent deep copy below and focuses it"]
419
+ ],
420
+ tokens: [
421
+ "border",
422
+ "card",
423
+ "foreground",
424
+ "muted-foreground",
425
+ "destructive-text",
426
+ "secondary",
427
+ "focus-ring"
428
+ ]
429
+ };
430
+ //#endregion
431
+ export { FieldArray, Form, FormField, doc as fieldArrayDoc, fieldArrayVariants, issuesToErrors, schemaResolver, toCheckedProps, toValueProps, useFieldProps };
129
432
 
130
433
  //# sourceMappingURL=forms.js.map
package/dist/forms.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"forms.js","names":["provider"],"sources":["../src/forms/useFieldProps.ts","../src/forms/FormField.tsx","../src/forms/schemaResolver.ts"],"sourcesContent":["import {\n useController,\n useFormContext,\n type Control,\n type ControllerFieldState,\n type ControllerRenderProps,\n type FieldPath,\n type FieldValues,\n type RegisterOptions,\n} from 'react-hook-form';\n\nexport interface UseFieldPropsOptions<TValues extends FieldValues, TName extends FieldPath<TValues>> {\n /** The form's `control`. Defaults to the nearest `<FormProvider>` / `<Form>`. */\n control?: Control<TValues>;\n /** Field-level rules (`required`, `minLength`, `validate`…). Prefer a schema resolver for whole forms. */\n rules?: Omit<RegisterOptions<TValues, TName>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;\n /** Disables the control (and skips its validation). */\n disabled?: boolean;\n}\n\n/** Props for the kit's `<Field>`: drive its invalid / touched / dirty state from react-hook-form. */\nexport interface FormFieldStateProps {\n name: string;\n invalid: boolean;\n touched: boolean;\n dirty: boolean;\n}\n\nexport interface UseFieldPropsResult<TValues extends FieldValues, TName extends FieldPath<TValues>> {\n /** Spread on `<Field>`. Base UI then links the label, description and error to the control. */\n fieldProps: FormFieldStateProps;\n /**\n * Spread on the control (`<Input {...controlProps} />`), or map it (`value` + `onValueChange={controlProps.onChange}`).\n * `ref` must reach a focusable element so a failed submit can focus the first invalid field.\n */\n controlProps: ControllerRenderProps<TValues, TName> & { 'aria-invalid'?: true };\n /** The current error message, for `<FieldError match={!!error}>{error}</FieldError>`. */\n error: string | undefined;\n fieldState: ControllerFieldState;\n}\n\n/**\n * Wires one react-hook-form field (through `useController`) into the kit's Field parts.\n * Works with uncontrolled-looking inputs too: `Input` gets `value` / `onChange` / `onBlur` / `ref`.\n */\nexport function useFieldProps<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>(\n name: TName,\n { control, rules, disabled }: UseFieldPropsOptions<TValues, TName> = {},\n): UseFieldPropsResult<TValues, TName> {\n const context = useFormContext<TValues>();\n const { field, fieldState } = useController<TValues, TName>({\n name,\n control: control ?? context?.control,\n rules,\n disabled,\n });\n const invalid = !!fieldState.error;\n return {\n fieldProps: { name, invalid, touched: fieldState.isTouched, dirty: fieldState.isDirty },\n controlProps: { ...field, 'aria-invalid': invalid || undefined },\n error: errorMessage(fieldState.error),\n fieldState,\n };\n}\n\n/** First message of a field error (also for array / object errors that carry `root`). */\nfunction errorMessage(error: ControllerFieldState['error']): string | undefined {\n if (!error) return undefined;\n if (typeof error.message === 'string' && error.message) return error.message;\n const root = (error as { root?: { message?: unknown } }).root;\n return typeof root?.message === 'string' ? root.message : undefined;\n}\n","import type { FormHTMLAttributes, ReactNode } from 'react';\nimport type {\n FieldPath,\n FieldValues,\n FormProviderProps,\n SubmitErrorHandler,\n SubmitHandler,\n UseFormReturn,\n} from 'react-hook-form';\nimport { FormProvider } from 'react-hook-form';\nimport { Field, FieldDescription, FieldError, FieldLabel } from '../components/Field';\nimport { useFieldProps, type UseFieldPropsOptions, type UseFieldPropsResult } from './useFieldProps';\n\nexport interface FormFieldProps<\n TValues extends FieldValues,\n TName extends FieldPath<TValues>,\n> extends UseFieldPropsOptions<TValues, TName> {\n name: TName;\n label?: ReactNode;\n /** Shows the required marker on the label (validation itself comes from `rules` or the schema). */\n required?: boolean;\n description?: ReactNode;\n className?: string;\n /** Renders the control: `{(field) => <Input {...field} />}`. Gets the field's state as the second argument. */\n children: (\n control: UseFieldPropsResult<TValues, TName>['controlProps'],\n state: UseFieldPropsResult<TValues, TName>,\n ) => ReactNode;\n}\n\n/**\n * A kit `Field` bound to a react-hook-form field: label, control, description and the field's\n * error message, with `aria-invalid` and `aria-describedby` wired by Base UI's Field.\n */\nexport function FormField<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>({ name, label, required, description, className, children, ...options }: FormFieldProps<TValues, TName>) {\n const state = useFieldProps<TValues, TName>(name, options);\n return (\n <Field {...state.fieldProps} disabled={options.disabled} className={className}>\n {label && <FieldLabel required={required}>{label}</FieldLabel>}\n {children(state.controlProps, state)}\n {description && <FieldDescription>{description}</FieldDescription>}\n <FieldError match={!!state.error}>{state.error}</FieldError>\n </Field>\n );\n}\n\nexport interface FormProps<TValues extends FieldValues, TTransformed = TValues> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n 'onSubmit' | 'onInvalid'\n> {\n /** The object returned by `useForm()`. */\n form: UseFormReturn<TValues, unknown, TTransformed>;\n onSubmit: SubmitHandler<TTransformed>;\n onInvalid?: SubmitErrorHandler<TValues>;\n children?: ReactNode;\n}\n\n/**\n * `<form noValidate>` + `FormProvider`: submits through `handleSubmit`, so a failed submit shows\n * every message and focuses the first invalid field (react-hook-form's `shouldFocusError`).\n */\nexport function Form<TValues extends FieldValues, TTransformed = TValues>({\n form,\n onSubmit,\n onInvalid,\n children,\n ...props\n}: FormProps<TValues, TTransformed>) {\n const provider = form as unknown as FormProviderProps<TValues, unknown, TTransformed>;\n return (\n <FormProvider {...provider}>\n <form noValidate {...props} onSubmit={form.handleSubmit(onSubmit, onInvalid)}>\n {children}\n </form>\n </FormProvider>\n );\n}\n","import type { FieldErrors, FieldValues, Resolver } from 'react-hook-form';\n\n/** One validation issue, as zod (v3 and v4) and other Standard-Schema-style libraries report it. */\nexport interface SchemaIssue {\n path: ReadonlyArray<PropertyKey | { key: PropertyKey }>;\n message: string;\n code?: string;\n}\n\ntype SafeParseResult<Out> =\n { success: true; data: Out } | { success: false; error: { issues: readonly SchemaIssue[] } };\n\n/** Anything with zod's `safeParseAsync` / `safeParse` shape (a zod schema, or an adapter). */\nexport interface ParseableSchema<Out> {\n safeParseAsync?: (values: unknown) => Promise<SafeParseResult<Out>>;\n safeParse?: (values: unknown) => SafeParseResult<Out>;\n}\n\nfunction setPath(target: Record<string, unknown>, path: readonly string[], value: unknown) {\n let node = target;\n path.forEach((key, i) => {\n if (i === path.length - 1) {\n if (node[key] === undefined) node[key] = value; // first issue per field wins\n return;\n }\n const next = node[key];\n node[key] = next && typeof next === 'object' ? next : {};\n node = node[key] as Record<string, unknown>;\n });\n}\n\n/** Converts schema issues into react-hook-form's nested `errors` object. */\nexport function issuesToErrors<TValues extends FieldValues>(issues: readonly SchemaIssue[]): FieldErrors<TValues> {\n const errors: Record<string, unknown> = {};\n for (const issue of issues) {\n const path = issue.path.map((p) => String(typeof p === 'object' && p !== null ? p.key : p));\n setPath(errors, path.length ? path : ['root'], { type: issue.code ?? 'validate', message: issue.message });\n }\n return errors as FieldErrors<TValues>;\n}\n\n/**\n * A `zodResolver`-compatible resolver with no extra dependency: `useForm({ resolver: schemaResolver(schema) })`.\n * Accepts a zod 3/4 schema (or any object with `safeParseAsync` / `safeParse`). On success the\n * parsed (transformed) data reaches `onSubmit`. `@hookform/resolvers/zod` works the same way with `FormField`.\n */\nexport function schemaResolver<TValues extends FieldValues, TOutput = TValues>(\n schema: ParseableSchema<TOutput>,\n): Resolver<TValues, unknown, TOutput> {\n return async (values) => {\n const result = schema.safeParseAsync ? await schema.safeParseAsync(values) : schema.safeParse?.(values);\n if (!result) throw new Error('schemaResolver: the schema has neither safeParseAsync nor safeParse');\n if (result.success) return { values: result.data, errors: {} };\n return { values: {}, errors: issuesToErrors<TValues>(result.error.issues) };\n };\n}\n"],"mappings":";;;;;;;;;AA6CA,SAAgB,cAId,MACA,EAAE,SAAS,OAAO,aAAmD,CAAC,GACjC;CACrC,MAAM,UAAU,eAAwB;CACxC,MAAM,EAAE,OAAO,eAAe,cAA8B;EAC1D;EACA,SAAS,WAAW,SAAS;EAC7B;EACA;CACF,CAAC;CACD,MAAM,UAAU,CAAC,CAAC,WAAW;CAC7B,OAAO;EACL,YAAY;GAAE;GAAM;GAAS,SAAS,WAAW;GAAW,OAAO,WAAW;EAAQ;EACtF,cAAc;GAAE,GAAG;GAAO,gBAAgB,WAAW,KAAA;EAAU;EAC/D,OAAO,aAAa,WAAW,KAAK;EACpC;CACF;AACF;;AAGA,SAAS,aAAa,OAA0D;CAC9E,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,IAAI,OAAO,MAAM,YAAY,YAAY,MAAM,SAAS,OAAO,MAAM;CACrE,MAAM,OAAQ,MAA2C;CACzD,OAAO,OAAO,MAAM,YAAY,WAAW,KAAK,UAAU,KAAA;AAC5D;;;;;;;ACxCA,SAAgB,UAGd,EAAE,MAAM,OAAO,UAAU,aAAa,WAAW,UAAU,GAAG,WAA2C;CACzG,MAAM,QAAQ,cAA8B,MAAM,OAAO;CACzD,OACE,qBAAC,OAAD;EAAO,GAAI,MAAM;EAAY,UAAU,QAAQ;EAAqB;EAApE,UAAA;GACG,SAAS,oBAAC,YAAD;IAAsB;IAAW,UAAA;GAAkB,CAAA;GAC5D,SAAS,MAAM,cAAc,KAAK;GAClC,eAAe,oBAAC,kBAAD,EAAA,UAAmB,YAA8B,CAAA;GACjE,oBAAC,YAAD;IAAY,OAAO,CAAC,CAAC,MAAM;IAAQ,UAAA,MAAM;GAAkB,CAAA;EACtD;;AAEX;;;;;AAiBA,SAAgB,KAA0D,EACxE,MACA,UACA,WACA,UACA,GAAG,SACgC;CAEnC,OACE,oBAAC,cAAD;EAAc,GAAIA;EAChB,UAAA,oBAAC,QAAD;GAAM,YAAA;GAAW,GAAI;GAAO,UAAU,KAAK,aAAa,UAAU,SAAS;GACxE;EACG,CAAA;CACM,CAAA;AAElB;;;AC7DA,SAAS,QAAQ,QAAiC,MAAyB,OAAgB;CACzF,IAAI,OAAO;CACX,KAAK,SAAS,KAAK,MAAM;EACvB,IAAI,MAAM,KAAK,SAAS,GAAG;GACzB,IAAI,KAAK,SAAS,KAAA,GAAW,KAAK,OAAO;GACzC;EACF;EACA,MAAM,OAAO,KAAK;EAClB,KAAK,OAAO,QAAQ,OAAO,SAAS,WAAW,OAAO,CAAC;EACvD,OAAO,KAAK;CACd,CAAC;AACH;;AAGA,SAAgB,eAA4C,QAAsD;CAChH,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,OAAO,MAAM,YAAY,MAAM,OAAO,EAAE,MAAM,CAAC,CAAC;EAC1F,QAAQ,QAAQ,KAAK,SAAS,OAAO,CAAC,MAAM,GAAG;GAAE,MAAM,MAAM,QAAQ;GAAY,SAAS,MAAM;EAAQ,CAAC;CAC3G;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,eACd,QACqC;CACrC,OAAO,OAAO,WAAW;EACvB,MAAM,SAAS,OAAO,iBAAiB,MAAM,OAAO,eAAe,MAAM,IAAI,OAAO,YAAY,MAAM;EACtG,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,qEAAqE;EAClG,IAAI,OAAO,SAAS,OAAO;GAAE,QAAQ,OAAO;GAAM,QAAQ,CAAC;EAAE;EAC7D,OAAO;GAAE,QAAQ,CAAC;GAAG,QAAQ,eAAwB,OAAO,MAAM,MAAM;EAAE;CAC5E;AACF"}
1
+ {"version":3,"file":"forms.js","names":["provider"],"sources":["../src/forms/useFieldProps.ts","../src/forms/bindings.ts","../src/forms/FormField.tsx","../src/forms/schemaResolver.ts","../src/forms/field-array.variants.ts","../src/forms/FieldArray.tsx","../src/forms/FieldArray.doc.ts"],"sourcesContent":["import {\n useController,\n useFormContext,\n type Control,\n type ControllerFieldState,\n type ControllerRenderProps,\n type FieldPath,\n type FieldValues,\n type RegisterOptions,\n} from 'react-hook-form';\n\nexport interface UseFieldPropsOptions<TValues extends FieldValues, TName extends FieldPath<TValues>> {\n /** The form's `control`. Defaults to the nearest `<FormProvider>` / `<Form>`. */\n control?: Control<TValues>;\n /** Field-level rules (`required`, `minLength`, `validate`…). Prefer a schema resolver for whole forms. */\n rules?: Omit<RegisterOptions<TValues, TName>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;\n /** Disables the control (and skips its validation). */\n disabled?: boolean;\n}\n\n/** Props for the kit's `<Field>`: drive its invalid / touched / dirty state from react-hook-form. */\nexport interface FormFieldStateProps {\n name: string;\n invalid: boolean;\n touched: boolean;\n dirty: boolean;\n}\n\nexport interface UseFieldPropsResult<TValues extends FieldValues, TName extends FieldPath<TValues>> {\n /** Spread on `<Field>`. Base UI then links the label, description and error to the control. */\n fieldProps: FormFieldStateProps;\n /**\n * Spread on the control (`<Input {...controlProps} />`), or map it (`value` + `onValueChange={controlProps.onChange}`).\n * `ref` must reach a focusable element so a failed submit can focus the first invalid field.\n */\n controlProps: ControllerRenderProps<TValues, TName> & { 'aria-invalid'?: true };\n /** The current error message, for `<FieldError match={!!error}>{error}</FieldError>`. */\n error: string | undefined;\n fieldState: ControllerFieldState;\n}\n\n/**\n * Wires one react-hook-form field (through `useController`) into the kit's Field parts.\n * Works with uncontrolled-looking inputs too: `Input` gets `value` / `onChange` / `onBlur` / `ref`.\n */\nexport function useFieldProps<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>(\n name: TName,\n { control, rules, disabled }: UseFieldPropsOptions<TValues, TName> = {},\n): UseFieldPropsResult<TValues, TName> {\n const context = useFormContext<TValues>();\n const { field, fieldState } = useController<TValues, TName>({\n name,\n control: control ?? context?.control,\n rules,\n disabled,\n });\n const invalid = !!fieldState.error;\n return {\n fieldProps: { name, invalid, touched: fieldState.isTouched, dirty: fieldState.isDirty },\n controlProps: { ...field, 'aria-invalid': invalid || undefined },\n error: errorMessage(fieldState.error),\n fieldState,\n };\n}\n\n/** First message of a field error (also for array / object errors that carry `root`). */\nfunction errorMessage(error: ControllerFieldState['error']): string | undefined {\n if (!error) return undefined;\n if (typeof error.message === 'string' && error.message) return error.message;\n const root = (error as { root?: { message?: unknown } }).root;\n return typeof root?.message === 'string' ? root.message : undefined;\n}\n","import type { RefCallback } from 'react';\nimport type { ControllerRenderProps } from 'react-hook-form';\n\n/** The public control props returned by useFieldProps. */\nexport interface BindingControlProps<TValue> {\n name: string;\n value: TValue;\n onChange: ControllerRenderProps['onChange'];\n onBlur: () => void;\n ref: ControllerRenderProps['ref'];\n disabled?: boolean;\n readOnly?: boolean;\n 'aria-invalid'?: true;\n}\n\nexport interface ValueBindingProps<TValue> {\n name: string;\n value: NonNullable<TValue> | null;\n onValueChange: (value: TValue | null) => void;\n ref: RefCallback<HTMLElement>;\n disabled?: boolean;\n readOnly?: boolean;\n 'aria-invalid'?: true;\n}\n\nexport interface CheckedBindingProps extends Omit<ValueBindingProps<boolean>, 'value' | 'onValueChange'> {\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n}\n\n/** Maps value/onChange controls to the kit's value/onValueChange API. Changes also touch the field. */\nexport function toValueProps<TValue>({\n value,\n onChange,\n onBlur,\n ...props\n}: BindingControlProps<TValue>): ValueBindingProps<TValue> {\n return {\n ...props,\n ref: focusTargetRef(props.ref),\n value: value ?? null,\n onValueChange: (next) => {\n onChange(next);\n onBlur();\n },\n };\n}\n\n/** Maps value/onChange controls to the kit's checked/onCheckedChange API. */\nexport function toCheckedProps<TValue>({\n value,\n onChange,\n onBlur,\n ...props\n}: BindingControlProps<TValue>): CheckedBindingProps {\n return {\n ...props,\n ref: focusTargetRef(props.ref),\n checked: !!value,\n onCheckedChange: (next) => {\n onChange(next);\n onBlur();\n },\n };\n}\n\n/** Resolve at focus time: composite controls can mount or change their tabbable child later. */\nexport function resolveFocusTarget(element: HTMLElement): HTMLElement | null {\n const enabled = ':not(:disabled):not([aria-disabled=\"true\"])';\n if (\n element.matches(\n `input:not([type=\"hidden\"])${enabled}, button${enabled}, textarea${enabled}, select${enabled}, a[href], [tabindex]${enabled}`,\n )\n )\n return element;\n return (\n element.querySelector<HTMLElement>(`[tabindex=\"0\"]${enabled}`) ??\n element.querySelector<HTMLElement>(`input:not([type=\"hidden\"])${enabled}, button${enabled}`)\n );\n}\n\nfunction focusTargetRef(ref: BindingControlProps<unknown>['ref']): RefCallback<HTMLElement> {\n return (element) => ref(element ? { focus: () => resolveFocusTarget(element)?.focus() } : null);\n}\n","import { createContext, useContext, type FormHTMLAttributes, type ReactNode } from 'react';\nimport type {\n FieldPath,\n FieldPathValue,\n FieldValues,\n FormProviderProps,\n SubmitErrorHandler,\n SubmitHandler,\n UseFormReturn,\n} from 'react-hook-form';\nimport { FormProvider } from 'react-hook-form';\nimport { cn } from '../utils/cn';\nimport { toValueProps, toCheckedProps, type ValueBindingProps, type CheckedBindingProps } from './bindings';\nimport { Field, FieldDescription, FieldError, FieldLabel } from '../components/Field';\nimport { useFieldProps, type UseFieldPropsOptions, type UseFieldPropsResult } from './useFieldProps';\n\nexport interface EnhancedFieldProps {\n disabled?: boolean;\n readOnly?: boolean;\n}\n\nexport type EnhanceFieldProps = (field: { name: string }) => EnhancedFieldProps | undefined;\nconst FieldEnhancerContext = createContext<EnhanceFieldProps | undefined>(undefined);\n\nexport type FormFieldWidth = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\nconst widths: Record<FormFieldWidth, string> = {\n xs: 'max-w-[6.5rem]',\n sm: 'max-w-[13.5rem]',\n md: 'max-w-[20.5rem]',\n lg: 'max-w-[27.5rem]',\n xl: 'max-w-[34.5rem]',\n};\n\nexport type FormFieldBinding = 'input' | 'value' | 'checked';\n\ntype BoundProps<\n TValues extends FieldValues,\n TName extends FieldPath<TValues>,\n TBind extends FormFieldBinding,\n> = TBind extends 'value'\n ? ValueBindingProps<FieldPathValue<TValues, TName>>\n : TBind extends 'checked'\n ? CheckedBindingProps\n : UseFieldPropsResult<TValues, TName>['controlProps'];\n\nexport type FormFieldProps<\n TValues extends FieldValues,\n TName extends FieldPath<TValues>,\n TBind extends FormFieldBinding = 'input',\n> = UseFieldPropsOptions<TValues, TName> & {\n name: TName;\n label?: ReactNode;\n /** Shows the required marker (validation comes from rules or the schema). */\n required?: boolean;\n description?: ReactNode;\n className?: string;\n /** Optional maximum width; unset fills the available width. */\n width?: FormFieldWidth;\n children: (control: BoundProps<TValues, TName, TBind>, state: UseFieldPropsResult<TValues, TName>) => ReactNode;\n} & (TBind extends 'input' ? { bind?: 'input' } : { bind: TBind });\n\n/**\n * A kit `Field` bound to a react-hook-form field: label, control, description and the field's\n * error message, with `aria-invalid` and `aria-describedby` wired by Base UI's Field.\n */\nexport function FormField<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>(props: FormFieldProps<TValues, TName, 'value'>): ReactNode;\nexport function FormField<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>(props: FormFieldProps<TValues, TName, 'checked'>): ReactNode;\nexport function FormField<\n TValues extends FieldValues = FieldValues,\n TName extends FieldPath<TValues> = FieldPath<TValues>,\n>(props: FormFieldProps<TValues, TName>): ReactNode;\nexport function FormField<TValues extends FieldValues, TName extends FieldPath<TValues>>(\n props:\n | FormFieldProps<TValues, TName>\n | FormFieldProps<TValues, TName, 'value'>\n | FormFieldProps<TValues, TName, 'checked'>,\n) {\n const { name, label, required, description, className, width, control, rules, disabled } = props;\n const enhance = useContext(FieldEnhancerContext);\n const enhanced = enhance?.({ name });\n const fieldDisabled = enhanced?.disabled ?? disabled;\n const state = useFieldProps<TValues, TName>(name, { control, rules, disabled: fieldDisabled });\n const controlProps = enhanced ? { ...state.controlProps, ...enhanced } : state.controlProps;\n const child =\n props.bind === 'value'\n ? props.children(toValueProps(controlProps), state)\n : props.bind === 'checked'\n ? props.children(toCheckedProps(controlProps), state)\n : props.children(controlProps, state);\n return (\n <Field\n {...state.fieldProps}\n disabled={fieldDisabled}\n className={width ? cn('w-full', widths[width], className) : className}\n >\n {label && <FieldLabel required={required}>{label}</FieldLabel>}\n {child}\n {description && <FieldDescription>{description}</FieldDescription>}\n <FieldError match={!!state.error}>{state.error}</FieldError>\n </Field>\n );\n}\n\nexport interface FormProps<TValues extends FieldValues, TTransformed = TValues> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n 'onSubmit' | 'onInvalid'\n> {\n /** The object returned by `useForm()`. */\n form: UseFormReturn<TValues, unknown, TTransformed>;\n onSubmit: SubmitHandler<TTransformed>;\n onInvalid?: SubmitErrorHandler<TValues>;\n /** Adds form-wide disabled/readOnly props to fields by name. Undefined leaves props unchanged. */\n enhanceFieldProps?: EnhanceFieldProps;\n children?: ReactNode;\n}\n\n/**\n * `<form noValidate>` + `FormProvider`: submits through `handleSubmit`, so a failed submit shows\n * every message and focuses the first invalid field (react-hook-form's `shouldFocusError`).\n */\nexport function Form<TValues extends FieldValues, TTransformed = TValues>({\n form,\n onSubmit,\n onInvalid,\n enhanceFieldProps,\n children,\n ...props\n}: FormProps<TValues, TTransformed>) {\n const provider = form as unknown as FormProviderProps<TValues, unknown, TTransformed>;\n return (\n <FormProvider {...provider}>\n <FieldEnhancerContext.Provider value={enhanceFieldProps}>\n <form noValidate {...props} onSubmit={form.handleSubmit(onSubmit, onInvalid)}>\n {children}\n </form>\n </FieldEnhancerContext.Provider>\n </FormProvider>\n );\n}\n","import type { FieldErrors, FieldValues, Resolver } from 'react-hook-form';\n\n/** One validation issue, as zod (v3 and v4) and other Standard-Schema-style libraries report it. */\nexport interface SchemaIssue {\n path: ReadonlyArray<PropertyKey | { key: PropertyKey }>;\n message: string;\n code?: string;\n}\n\ntype SafeParseResult<Out> =\n { success: true; data: Out } | { success: false; error: { issues: readonly SchemaIssue[] } };\n\n/** Anything with zod's `safeParseAsync` / `safeParse` shape (a zod schema, or an adapter). */\nexport interface ParseableSchema<Out> {\n safeParseAsync?: (values: unknown) => Promise<SafeParseResult<Out>>;\n safeParse?: (values: unknown) => SafeParseResult<Out>;\n}\n\nfunction setPath(target: Record<string, unknown>, path: readonly string[], value: unknown) {\n let node = target;\n path.forEach((key, i) => {\n if (i === path.length - 1) {\n if (node[key] === undefined) node[key] = value; // first issue per field wins\n return;\n }\n const next = node[key];\n node[key] = next && typeof next === 'object' ? next : {};\n node = node[key] as Record<string, unknown>;\n });\n}\n\n/** Converts schema issues into react-hook-form's nested `errors` object. */\nexport function issuesToErrors<TValues extends FieldValues>(issues: readonly SchemaIssue[]): FieldErrors<TValues> {\n const errors: Record<string, unknown> = {};\n for (const issue of issues) {\n const path = issue.path.map((p) => String(typeof p === 'object' && p !== null ? p.key : p));\n setPath(errors, path.length ? path : ['root'], { type: issue.code ?? 'validate', message: issue.message });\n }\n return errors as FieldErrors<TValues>;\n}\n\n/**\n * A `zodResolver`-compatible resolver with no extra dependency: `useForm({ resolver: schemaResolver(schema) })`.\n * Accepts a zod 3/4 schema (or any object with `safeParseAsync` / `safeParse`). On success the\n * parsed (transformed) data reaches `onSubmit`. `@hookform/resolvers/zod` works the same way with `FormField`.\n */\nexport function schemaResolver<TValues extends FieldValues, TOutput = TValues>(\n schema: ParseableSchema<TOutput>,\n): Resolver<TValues, unknown, TOutput> {\n return async (values) => {\n const result = schema.safeParseAsync ? await schema.safeParseAsync(values) : schema.safeParse?.(values);\n if (!result) throw new Error('schemaResolver: the schema has neither safeParseAsync nor safeParse');\n if (result.success) return { values: result.data, errors: {} };\n return { values: {}, errors: issuesToErrors<TValues>(result.error.issues) };\n };\n}\n","import { tv } from '../utils/tv';\n\nexport const fieldArrayVariants = tv({\n slots: {\n root: 'min-w-0',\n list: 'flex flex-col gap-3',\n row: 'flex min-w-0 gap-3',\n fields: 'flex min-w-0 flex-1 flex-col gap-3',\n actions: 'flex shrink-0 flex-wrap items-start gap-1',\n footer: 'flex flex-wrap items-center gap-3',\n hint: 'text-sm text-muted-foreground',\n error: 'text-sm text-destructive-text',\n },\n variants: {\n layout: {\n inline: { row: 'flex-col sm:flex-row' },\n card: { row: 'flex-col rounded-lg border border-border bg-card p-4' },\n },\n },\n defaultVariants: { layout: 'inline' },\n});\n","import { ArrowDown, ArrowUp, Copy, Plus, Trash2 } from 'lucide-react';\nimport { useId, useLayoutEffect, useRef, type ReactNode } from 'react';\nimport {\n get,\n useFieldArray,\n useFormContext,\n useFormState,\n useWatch,\n type Control,\n type FieldArray as ArrayItem,\n type FieldArrayPath,\n type FieldPath,\n type FieldValues,\n type Path,\n type UseFieldArrayProps,\n} from 'react-hook-form';\nimport { Fieldset, FieldsetDescription, FieldsetLegend } from '../components/Field';\nimport { Button, IconButton } from '../components/Button';\nimport { LiveAnnouncer, useAnnounce, useHasLiveAnnouncer } from '../components/LiveAnnouncer';\nimport { useI18n } from '../i18n';\nimport { fieldArrayVariants } from './field-array.variants';\n\nexport interface FieldArrayRow<TValues extends FieldValues, TName extends FieldArrayPath<TValues>> {\n index: number;\n remove(): void;\n move(delta: number): void;\n duplicate(): void;\n name<TField extends Path<ArrayItem<TValues, TName>>>(\n field: TField,\n ): `${TName}.${number}.${TField}` & FieldPath<TValues>;\n}\n\nexport interface FieldArrayProps<\n TValues extends FieldValues,\n TName extends FieldArrayPath<TValues> = FieldArrayPath<TValues>,\n> {\n name: TName;\n control?: Control<TValues>;\n defaultItem: ArrayItem<TValues, TName> | (() => ArrayItem<TValues, TName>);\n label?: ReactNode;\n description?: ReactNode;\n rules?: UseFieldArrayProps<TValues, TName>['rules'];\n max?: number;\n min?: number;\n emptyState?: ReactNode;\n reorderable?: boolean;\n duplicable?: boolean;\n layout?: 'inline' | 'card';\n itemLabel?: (n: number) => string;\n addLabel?: ReactNode;\n className?: string;\n children: (row: FieldArrayRow<TValues, TName>) => ReactNode;\n}\n\n/** Repeatable object fields in the optional react-hook-form adapter. */\nexport function FieldArray<\n TValues extends FieldValues,\n TName extends FieldArrayPath<TValues> = FieldArrayPath<TValues>,\n>(props: FieldArrayProps<TValues, TName>) {\n const hasAnnouncer = useHasLiveAnnouncer();\n return hasAnnouncer ? (\n <FieldArrayContent {...props} />\n ) : (\n <LiveAnnouncer>\n <FieldArrayContent {...props} />\n </LiveAnnouncer>\n );\n}\n\nconst focusable =\n 'input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])';\ntype PendingFocus = { previousIds: Set<string> } | { id: string; element?: HTMLElement } | { add: true };\n\nfunction RowFields<TValues extends FieldValues, TName extends FieldArrayPath<TValues>>({\n children,\n row,\n}: {\n children: FieldArrayProps<TValues, TName>['children'];\n row: FieldArrayRow<TValues, TName>;\n}) {\n return children(row);\n}\n\nfunction FieldArrayContent<TValues extends FieldValues, TName extends FieldArrayPath<TValues>>({\n name,\n control: controlProp,\n label,\n description,\n rules,\n children,\n defaultItem,\n max,\n min = 0,\n emptyState,\n reorderable = false,\n duplicable = false,\n layout = 'inline',\n itemLabel,\n addLabel,\n className,\n}: FieldArrayProps<TValues, TName>) {\n const context = useFormContext<TValues>();\n const control = controlProp ?? context?.control;\n // RHF skips minLength for an empty array. Preserve its message for that case too.\n const minimum = typeof rules?.minLength === 'object' ? rules.minLength.value : rules?.minLength;\n const arrayRules =\n minimum && minimum > 0\n ? {\n ...rules,\n required: rules?.required ?? {\n value: true,\n message: typeof rules?.minLength === 'object' ? rules.minLength.message : '',\n },\n }\n : rules;\n const {\n fields,\n append,\n insert,\n remove: removeItem,\n move: moveItem,\n } = useFieldArray<TValues, TName>({ name, control, rules: arrayRules });\n // Every array path is also a field path; RHF's two recursive path types need a bridge.\n const path = name as string as FieldPath<TValues>;\n const values = useWatch({ control, name: path });\n const { errors } = useFormState({ control, name: path });\n const arrayError = get(errors, name) as { root?: { message?: unknown }; message?: unknown } | undefined;\n const message = arrayError?.root?.message ?? arrayError?.message;\n const error = typeof message === 'string' ? message : undefined;\n const uid = useId();\n const descriptionId = `${uid}-description`;\n const errorId = `${uid}-error`;\n const { t } = useI18n();\n const labelFor = (n: number) => itemLabel?.(n) ?? t('fieldArray.item', { n });\n const s = fieldArrayVariants({ layout });\n const announce = useAnnounce();\n const rows = useRef(new Map<string, HTMLDivElement>());\n const addButton = useRef<HTMLButtonElement>(null);\n const pendingFocus = useRef<PendingFocus | null>(null);\n const full = max !== undefined && fields.length >= max;\n const announceInsertion = (message: string) => {\n const limit = max !== undefined && fields.length + 1 >= max ? t('fieldArray.limit', { max }) : '';\n announce([message, limit].filter(Boolean).join(' '));\n };\n useLayoutEffect(() => {\n const pending = pendingFocus.current;\n if (!pending) return;\n pendingFocus.current = null;\n if ('add' in pending) {\n addButton.current?.focus();\n return;\n }\n const id = 'previousIds' in pending ? fields.find((field) => !pending.previousIds.has(field.id))?.id : pending.id;\n const element = 'element' in pending ? pending.element : undefined;\n (element?.isConnected ? element : id ? rows.current.get(id)?.querySelector<HTMLElement>(focusable) : null)?.focus();\n });\n const add = () => {\n if (full) {\n announce(t('fieldArray.limit', { max: max ?? 0 }));\n return;\n }\n pendingFocus.current = { previousIds: new Set(fields.map((field) => field.id)) };\n append(\n structuredClone(\n typeof defaultItem === 'function' ? (defaultItem as () => ArrayItem<TValues, TName>)() : defaultItem,\n ),\n { shouldFocus: false },\n );\n announceInsertion(t('fieldArray.added', { item: labelFor(fields.length + 1) }));\n };\n const remove = (index: number) => {\n if (fields.length <= min) return;\n const neighbour = fields[index + 1] ?? fields[index - 1];\n pendingFocus.current = neighbour ? { id: neighbour.id } : { add: true };\n removeItem(index);\n announce(t('fieldArray.removed', { item: labelFor(index + 1) }));\n };\n const move = (index: number, delta: number) => {\n const destination = index + delta;\n const field = fields[index];\n if (\n !reorderable ||\n !field ||\n !Number.isInteger(delta) ||\n destination < 0 ||\n destination >= fields.length ||\n delta === 0\n )\n return;\n const active = document.activeElement;\n pendingFocus.current = {\n id: field.id,\n element: active instanceof HTMLElement && rows.current.get(field.id)?.contains(active) ? active : undefined,\n };\n moveItem(index, destination);\n announce(t('fieldArray.moved', { n: destination + 1, total: fields.length }));\n };\n const duplicate = (index: number) => {\n if (!duplicable || full) return;\n const value = (values as ArrayItem<TValues, TName>[] | undefined)?.[index];\n if (!value) return;\n pendingFocus.current = { previousIds: new Set(fields.map((field) => field.id)) };\n insert(index + 1, structuredClone(value), { shouldFocus: false });\n announceInsertion(t('fieldArray.duplicated', { item: labelFor(index + 1) }));\n };\n return (\n <Fieldset\n data-field-array=\"\"\n className={s.root({ className })}\n aria-describedby={[description ? descriptionId : '', error ? errorId : ''].filter(Boolean).join(' ') || undefined}\n aria-invalid={!!error || undefined}\n >\n {label && <FieldsetLegend>{label}</FieldsetLegend>}\n {description && <FieldsetDescription id={descriptionId}>{description}</FieldsetDescription>}\n <div className={s.list()}>\n {fields.map((field, index) => (\n <div\n className={s.row()}\n key={field.id}\n ref={(element) => {\n if (element) rows.current.set(field.id, element);\n else rows.current.delete(field.id);\n }}\n role=\"group\"\n aria-label={labelFor(index + 1)}\n onKeyDown={(event) => {\n if (\n event.target instanceof Element &&\n event.target.closest('[data-field-array]') !== event.currentTarget.closest('[data-field-array]')\n )\n return;\n if (reorderable && event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {\n event.preventDefault();\n event.stopPropagation();\n move(index, event.key === 'ArrowUp' ? -1 : 1);\n }\n }}\n >\n <div className={s.fields()}>\n <RowFields\n row={{\n index,\n remove: () => remove(index),\n move: (delta) => move(index, delta),\n duplicate: () => duplicate(index),\n name: (part) =>\n `${name}.${index}.${part}` as `${TName}.${number}.${typeof part}` & FieldPath<TValues>,\n }}\n >\n {children}\n </RowFields>\n </div>\n <div className={s.actions()}>\n {reorderable && (\n <>\n <IconButton\n icon={ArrowUp}\n label={t('fieldArray.moveUp', { item: labelFor(index + 1) })}\n disabled={index === 0}\n onClick={() => move(index, -1)}\n />\n <IconButton\n icon={ArrowDown}\n label={t('fieldArray.moveDown', { item: labelFor(index + 1) })}\n disabled={index === fields.length - 1}\n onClick={() => move(index, 1)}\n />\n </>\n )}\n {duplicable && (\n <IconButton\n icon={Copy}\n label={t('fieldArray.duplicate', { item: labelFor(index + 1) })}\n disabled={full}\n onClick={() => duplicate(index)}\n />\n )}\n <IconButton\n icon={Trash2}\n label={t('fieldArray.remove', { item: labelFor(index + 1) })}\n disabled={fields.length <= min}\n onClick={() => remove(index)}\n />\n </div>\n </div>\n ))}\n </div>\n {!fields.length && (emptyState ?? <p className={s.hint()}>{t('fieldArray.empty')}</p>)}\n <div className={s.footer()}>\n <Button ref={addButton} icon={Plus} variant=\"secondary\" disabled={full} onClick={add}>\n {addLabel ?? t('fieldArray.add')}\n </Button>\n {full && <p className={s.hint()}>{t('fieldArray.limit', { max: max ?? 0 })}</p>}\n </div>\n {error && (\n <p id={errorId} className={s.error()}>\n {error}\n </p>\n )}\n </Fieldset>\n );\n}\n","import type { ComponentDoc } from '../doc';\n\nexport const doc: ComponentDoc = {\n name: 'FieldArray',\n group: 'Forms',\n status: 'beta',\n description:\n 'Repeatable arbitrary fields bound to react-hook-form arrays. Import from @gntik-ai/ui/forms only; use within Form or pass control explicitly. Rows expose index, name(field), remove(), duplicate() and move(delta). Add accepts a default object or factory. Optional reorder and duplicate actions preserve row identity, and min/max gate removals and additions. Inline and card layouts support nested arrays, list-level validation, focus restoration and localized announcements. Use ListInput for standalone key/value pairs without a form library; use FieldArray for arbitrary object fields managed by react-hook-form.',\n primitive: '@base-ui/react/fieldset, @base-ui/react/field, @base-ui/react/button',\n pattern: 'fieldset with named row groups',\n keyboard: [\n ['Tab / Shift+Tab', 'Moves through row fields, row actions and Add in document order'],\n ['Enter / Space on Add', 'Appends the default item and focuses its first control'],\n ['Enter / Space on Remove', 'Removes the row and focuses the next row, previous row or Add'],\n [\n 'Alt+ArrowUp / Alt+ArrowDown',\n 'With reorderable, moves the row and keeps focus on the same control; stops at either end',\n ],\n ['Enter / Space on Move up / Move down', 'Moves the row by one position and preserves focus'],\n ['Enter / Space on Duplicate', 'With duplicable, inserts an independent deep copy below and focuses it'],\n ],\n tokens: ['border', 'card', 'foreground', 'muted-foreground', 'destructive-text', 'secondary', 'focus-ring'],\n};\n"],"mappings":"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"}