@pindoba/react-tanstack-form 0.0.0-alpha-20260619021129 → 0.0.0-alpha-20260829223243

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -4,6 +4,8 @@ import { FormInput, FormInputProps } from "./src/FormInput.js";
4
4
  import { FormSelect, FormSelectProps } from "./src/FormSelect.js";
5
5
  import { FormCheckbox, FormCheckboxProps } from "./src/FormCheckbox.js";
6
6
  import { FormSubmit, FormSubmitProps } from "./src/FormSubmit.js";
7
+ import { useFocusInvalidOnSubmit } from "./src/useFocusInvalidOnSubmit.js";
7
8
  import { getVisibleErrors, normalizeErrors } from "./src/field-errors.js";
8
9
  import { useForm, useStore } from "@tanstack/react-form";
9
- export { type AnyFieldApi, type AnyFormApi, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldErrorMode, type FormFieldOwnProps, type FormFieldProps, FormInput, type FormInputProps, FormSelect, type FormSelectProps, FormSubmit, type FormSubmitProps, getVisibleErrors, normalizeErrors, useForm, useStore };
10
+ import { FocusInvalidOptions } from "@pindoba/core-tanstack-form";
11
+ export { type AnyFieldApi, type AnyFormApi, type FocusInvalidOptions, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldErrorMode, type FormFieldOwnProps, type FormFieldProps, FormInput, type FormInputProps, FormSelect, type FormSelectProps, FormSubmit, type FormSubmitProps, getVisibleErrors, normalizeErrors, useFocusInvalidOnSubmit, useForm, useStore };
package/dist/index.js CHANGED
@@ -4,5 +4,6 @@ import { FormInput } from "./src/FormInput.js";
4
4
  import { FormSelect } from "./src/FormSelect.js";
5
5
  import { FormCheckbox } from "./src/FormCheckbox.js";
6
6
  import { FormSubmit } from "./src/FormSubmit.js";
7
+ import { useFocusInvalidOnSubmit } from "./src/useFocusInvalidOnSubmit.js";
7
8
  import { useForm, useStore } from "@tanstack/react-form";
8
- export { FormCheckbox, FormField, FormInput, FormSelect, FormSubmit, getVisibleErrors, normalizeErrors, useForm, useStore };
9
+ export { FormCheckbox, FormField, FormInput, FormSelect, FormSubmit, getVisibleErrors, normalizeErrors, useFocusInvalidOnSubmit, useForm, useStore };
@@ -1,22 +1,19 @@
1
1
  import { AnyFormApi, FormFieldOwnProps } from "./types.js";
2
- import { FieldSize } from "@pindoba/core-field";
3
2
  import { JSX, ReactNode } from "react";
4
-
3
+ import { FieldSize } from "@pindoba/core-field";
5
4
  //#region src/FormCheckbox.d.ts
6
5
  type FormCheckboxProps = Omit<FormFieldOwnProps, "size"> & {
7
- /** The TanStack form instance returned by `useForm(...)`. */form: AnyFormApi; /** Field name (a boolean key of the form's data). */
8
- name: string; /** Inline text/content rendered beside the checkbox. */
9
- children?: ReactNode; /** Size variant. Checkbox supports `sm`/`md`/`lg` (no `xs`). */
6
+ /** The TanStack form instance returned by `useForm(...)`. */
7
+ form: AnyFormApi;
8
+ /** Field name (a boolean key of the form's data). */
9
+ name: string;
10
+ /** Inline text/content rendered beside the checkbox. */
11
+ children?: ReactNode;
12
+ /** Size variant. Checkbox supports `sm`/`md`/`lg` (no `xs`). */
10
13
  size?: Exclude<FieldSize, "xs">;
11
14
  };
12
15
  /** FormCheckbox — a `<Checkbox>` bound to a boolean TanStack form field. */
13
- declare function FormCheckbox({
14
- form,
15
- name,
16
- children,
17
- size,
18
- ...fieldProps
19
- }: FormCheckboxProps): JSX.Element;
16
+ declare function FormCheckbox({ form, name, children, size, ...fieldProps }: FormCheckboxProps): JSX.Element;
20
17
  declare namespace FormCheckbox {
21
18
  var displayName: string;
22
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormCheckbox.d.ts","names":[],"sources":["../../src/FormCheckbox.tsx"],"mappings":";;;;;KAMY,iBAAA,GAAoB,IAAA,CAAK,iBAAA;+DAEnC,IAAA,EAAM,UAAA,EAFqB;EAI3B,IAAA,UAJmC;EAMnC,QAAA,GAAW,SAAA,EAJL;EAMN,IAAA,GAAO,OAAA,CAAQ,SAAA;AAAA;;iBAID,YAAA;EACd,IAAA;EACA,IAAA;EACA,QAAA;EACA,IAAA;EAAA,GACG;AAAA,GACF,iBAAA,GAAoB,GAAA,CAAI,OAAA;AAAA,kBANX,YAAA;EAAA,IAAY,WAAA;AAAA"}
1
+ {"version":3,"file":"FormCheckbox.d.ts","names":[],"sources":["../../src/FormCheckbox.tsx"],"mappings":";;;;KAMY,oBAAoB,KAAK;;EAEnC,MAAM;;EAEN;;EAEA,WAAW;;EAEX,OAAO,QAAQ;;;iBAID,eACd,MACA,MACA,UACA,SACG,cACF,oBAAoB,IAAI;kBANX;MAAA"}
@@ -1,10 +1,11 @@
1
1
  import { AnyFieldApi, AnyFormApi, FormFieldOwnProps } from "./types.js";
2
- import { FieldControlProps } from "@pindoba/core-field";
3
2
  import { JSX, ReactNode } from "react";
4
-
3
+ import { FieldControlProps } from "@pindoba/core-field";
5
4
  //#region src/FormField.d.ts
6
5
  type FormFieldProps = FormFieldOwnProps & {
7
- /** The TanStack form instance returned by `useForm(...)`. */form: AnyFormApi; /** Field name (a key of the form's data). */
6
+ /** The TanStack form instance returned by `useForm(...)`. */
7
+ form: AnyFormApi;
8
+ /** Field name (a key of the form's data). */
8
9
  name: string;
9
10
  /**
10
11
  * Render-prop for the control. Receives the props bag to spread onto the
@@ -19,13 +20,7 @@ type FormFieldProps = FormFieldOwnProps & {
19
20
  * control via the `control` render-prop, which receives the Field's `controlProps`
20
21
  * bag plus the raw `field` API.
21
22
  */
22
- declare function FormField({
23
- form,
24
- name,
25
- control,
26
- errorMode,
27
- ...fieldProps
28
- }: FormFieldProps): JSX.Element;
23
+ declare function FormField({ form, name, control, errorMode, ...fieldProps }: FormFieldProps): JSX.Element;
29
24
  declare namespace FormField {
30
25
  var displayName: string;
31
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormField.d.ts","names":[],"sources":["../../src/FormField.tsx"],"mappings":";;;;;KAOY,cAAA,GAAiB,iBAAA;+DAE3B,IAAA,EAAM,UAAA,EAFkB;EAIxB,IAAA;EAJ2B;;;;EAS3B,OAAA,GAAU,YAAA,EAAc,iBAAA,EAAmB,KAAA,EAAO,WAAA,KAAgB,SAAA;AAAA;;;;;;;;iBAUpD,SAAA;EACd,IAAA;EACA,IAAA;EACA,OAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,cAAA,GAAiB,GAAA,CAAI,OAAA;AAAA,kBANR,SAAA;EAAA,IAAS,WAAA;AAAA"}
1
+ {"version":3,"file":"FormField.d.ts","names":[],"sources":["../../src/FormField.tsx"],"mappings":";;;;KAOY,iBAAiB;;EAE3B,MAAM;;EAEN;;;;;EAKA,UAAU,cAAc,mBAAmB,OAAO,gBAAgB;;;;;;;;;iBAUpD,YACd,MACA,MACA,SACA,cACG,cACF,iBAAiB,IAAI;kBANR;MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"FormField.js","names":["TanStackField","Field"],"sources":["../../src/FormField.tsx"],"sourcesContent":["import type { FieldControlProps } from \"@pindoba/core-field\";\nimport Field from \"@pindoba/react-field\";\nimport { Field as TanStackField } from \"@tanstack/react-form\";\nimport type { JSX, ReactNode } from \"react\";\nimport { getVisibleErrors } from \"./field-errors\";\nimport type { AnyFieldApi, AnyFormApi, FormFieldOwnProps } from \"./types\";\n\nexport type FormFieldProps = FormFieldOwnProps & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /** Field name (a key of the form's data). */\n name: string;\n /**\n * Render-prop for the control. Receives the props bag to spread onto the\n * control plus the raw TanStack field API for value/handler binding.\n */\n control: (controlProps: FieldControlProps, field: AnyFieldApi) => ReactNode;\n};\n\n/**\n * FormField. Binds a TanStack React Form field to the presentational `<Field>`\n * wrapper. Errors are surfaced through the shared `getVisibleErrors` helper\n * (same visibility logic as the Svelte/Astro blocks); the consumer supplies the\n * control via the `control` render-prop, which receives the Field's `controlProps`\n * bag plus the raw `field` API.\n */\nexport function FormField({\n form,\n name,\n control,\n errorMode = \"touched\",\n ...fieldProps\n}: FormFieldProps): JSX.Element {\n return (\n <TanStackField form={form} name={name}>\n {(field) => (\n <Field\n {...fieldProps}\n error={getVisibleErrors(field, errorMode)}\n control={(controlProps) => control(controlProps, field)}\n />\n )}\n </TanStackField>\n );\n}\n\nFormField.displayName = \"FormField\";\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,MACA,SACA,YAAY,WACZ,GAAG,cAC2B;CAC9B,OACE,oBAACA,OAAD;EAAqB;EAAY;aAC7B,UACA,oBAACC,SAAD;GACE,GAAI;GACJ,OAAO,iBAAiB,OAAO,SAAS;GACxC,UAAU,iBAAiB,QAAQ,cAAc,KAAK;EACvD,CAAA;CAEU,CAAA;AAEnB;AAEA,UAAU,cAAc"}
1
+ {"version":3,"file":"FormField.js","names":["TanStackField","Field"],"sources":["../../src/FormField.tsx"],"sourcesContent":["import type { FieldControlProps } from \"@pindoba/core-field\";\nimport Field from \"@pindoba/react-field\";\nimport { Field as TanStackField } from \"@tanstack/react-form\";\nimport type { JSX, ReactNode } from \"react\";\nimport { getVisibleErrors } from \"./field-errors\";\nimport type { AnyFieldApi, AnyFormApi, FormFieldOwnProps } from \"./types\";\n\nexport type FormFieldProps = FormFieldOwnProps & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /** Field name (a key of the form's data). */\n name: string;\n /**\n * Render-prop for the control. Receives the props bag to spread onto the\n * control plus the raw TanStack field API for value/handler binding.\n */\n control: (controlProps: FieldControlProps, field: AnyFieldApi) => ReactNode;\n};\n\n/**\n * FormField. Binds a TanStack React Form field to the presentational `<Field>`\n * wrapper. Errors are surfaced through the shared `getVisibleErrors` helper\n * (same visibility logic as the Svelte/Astro blocks); the consumer supplies the\n * control via the `control` render-prop, which receives the Field's `controlProps`\n * bag plus the raw `field` API.\n */\nexport function FormField({\n form,\n name,\n control,\n errorMode = \"touched\",\n ...fieldProps\n}: FormFieldProps): JSX.Element {\n return (\n <TanStackField form={form} name={name}>\n {(field) => (\n <Field\n {...fieldProps}\n error={getVisibleErrors(field, errorMode)}\n control={(controlProps) => control(controlProps, field)}\n />\n )}\n </TanStackField>\n );\n}\n\nFormField.displayName = \"FormField\";\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,UAAU,EACxB,MACA,MACA,SACA,YAAY,WACZ,GAAG,cAC2B;CAC9B,OACE,oBAACA,OAAD;EAAqB;EAAY;EAC7B,WAAA,UACA,oBAACC,SAAD;GACE,GAAI;GACJ,OAAO,iBAAiB,OAAO,SAAS;GACxC,UAAU,iBAAiB,QAAQ,cAAc,KAAK;EACvD,CAAA;CAEU,CAAA;AAEnB;AAEA,UAAU,cAAc"}
@@ -1,23 +1,19 @@
1
1
  import { AnyFormApi, FormFieldOwnProps } from "./types.js";
2
2
  import { InputProps } from "@pindoba/react-input";
3
3
  import { JSX } from "react";
4
-
5
4
  //#region src/FormInput.d.ts
6
5
  type FormInputProps = FormFieldOwnProps & {
7
- /** The TanStack form instance returned by `useForm(...)`. */form: AnyFormApi; /** Field name (a key of the form's data). */
8
- name: string; /** HTML input type forwarded to the underlying `<Input>`. */
9
- type?: InputProps["type"]; /** Placeholder forwarded to the underlying `<Input>`. */
6
+ /** The TanStack form instance returned by `useForm(...)`. */
7
+ form: AnyFormApi;
8
+ /** Field name (a key of the form's data). */
9
+ name: string;
10
+ /** HTML input type forwarded to the underlying `<Input>`. */
11
+ type?: InputProps["type"];
12
+ /** Placeholder forwarded to the underlying `<Input>`. */
10
13
  placeholder?: string;
11
14
  };
12
15
  /** FormInput — a text `<Input>` bound to a TanStack form field. */
13
- declare function FormInput({
14
- form,
15
- name,
16
- type,
17
- placeholder,
18
- size,
19
- ...fieldProps
20
- }: FormInputProps): JSX.Element;
16
+ declare function FormInput({ form, name, type, placeholder, size, ...fieldProps }: FormInputProps): JSX.Element;
21
17
  declare namespace FormInput {
22
18
  var displayName: string;
23
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormInput.d.ts","names":[],"sources":["../../src/FormInput.tsx"],"mappings":";;;;;KAKY,cAAA,GAAiB,iBAAA;+DAE3B,IAAA,EAAM,UAAA,EAFkB;EAIxB,IAAA,UAJ2B;EAM3B,IAAA,GAAO,UAAA,UAAA;EAEP,WAAA;AAAA;;iBAIc,SAAA;EACd,IAAA;EACA,IAAA;EACA,IAAA;EACA,WAAA;EACA,IAAA;EAAA,GACG;AAAA,GACF,cAAA,GAAiB,GAAA,CAAI,OAAA;AAAA,kBAPR,SAAA;EAAA,IAAS,WAAA;AAAA"}
1
+ {"version":3,"file":"FormInput.d.ts","names":[],"sources":["../../src/FormInput.tsx"],"mappings":";;;;KAKY,iBAAiB;;EAE3B,MAAM;;EAEN;;EAEA,OAAO;;EAEP;;;iBAIc,YACd,MACA,MACA,MACA,aACA,SACG,cACF,iBAAiB,IAAI;kBAPR;MAAA"}
@@ -1,25 +1,22 @@
1
1
  import { AnyFormApi, FormFieldOwnProps } from "./types.js";
2
- import { FieldSize } from "@pindoba/core-field";
3
2
  import { JSX } from "react";
3
+ import { FieldSize } from "@pindoba/core-field";
4
4
  import { ListBoxNodeInput } from "@pindoba/core-listbox";
5
-
6
5
  //#region src/FormSelect.d.ts
7
6
  type FormSelectProps = Omit<FormFieldOwnProps, "size"> & {
8
- /** The TanStack form instance returned by `useForm(...)`. */form: AnyFormApi; /** Field name (a key of the form's data holding the selected option key). */
9
- name: string; /** Options to choose from. */
10
- items: ListBoxNodeInput[]; /** Placeholder shown when nothing is selected. */
11
- placeholder?: string; /** Size variant. Select supports `sm`/`md`/`lg` (no `xs`). */
7
+ /** The TanStack form instance returned by `useForm(...)`. */
8
+ form: AnyFormApi;
9
+ /** Field name (a key of the form's data holding the selected option key). */
10
+ name: string;
11
+ /** Options to choose from. */
12
+ items: ListBoxNodeInput[];
13
+ /** Placeholder shown when nothing is selected. */
14
+ placeholder?: string;
15
+ /** Size variant. Select supports `sm`/`md`/`lg` (no `xs`). */
12
16
  size?: Exclude<FieldSize, "xs">;
13
17
  };
14
18
  /** FormSelect — a single-select `<Select>` bound to a TanStack form field. */
15
- declare function FormSelect({
16
- form,
17
- name,
18
- items,
19
- placeholder,
20
- size,
21
- ...fieldProps
22
- }: FormSelectProps): JSX.Element;
19
+ declare function FormSelect({ form, name, items, placeholder, size, ...fieldProps }: FormSelectProps): JSX.Element;
23
20
  declare namespace FormSelect {
24
21
  var displayName: string;
25
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormSelect.d.ts","names":[],"sources":["../../src/FormSelect.tsx"],"mappings":";;;;;;KAOY,eAAA,GAAkB,IAAA,CAAK,iBAAA;+DAEjC,IAAA,EAAM,UAAA,EAFmB;EAIzB,IAAA,UAJiC;EAMjC,KAAA,EAAO,gBAAA,IAJD;EAMN,WAAA,WAEe;EAAf,IAAA,GAAO,OAAA,CAAQ,SAAA;AAAA;;iBAID,UAAA;EACd,IAAA;EACA,IAAA;EACA,KAAA;EACA,WAAA;EACA,IAAA;EAAA,GACG;AAAA,GACF,eAAA,GAAkB,GAAA,CAAI,OAAA;AAAA,kBAPT,UAAA;EAAA,IAAU,WAAA;AAAA"}
1
+ {"version":3,"file":"FormSelect.d.ts","names":[],"sources":["../../src/FormSelect.tsx"],"mappings":";;;;;KAOY,kBAAkB,KAAK;;EAEjC,MAAM;;EAEN;;EAEA,OAAO;;EAEP;;EAEA,OAAO,QAAQ;;;iBAID,aACd,MACA,MACA,OACA,aACA,SACG,cACF,kBAAkB,IAAI;kBAPT;MAAA"}
@@ -1,19 +1,22 @@
1
1
  import { AnyFormApi } from "./types.js";
2
2
  import { ButtonProps } from "@pindoba/react-button";
3
3
  import { JSX, ReactNode } from "react";
4
-
5
4
  //#region src/FormSubmit.d.ts
6
5
  type FormSubmitProps = {
7
- /** The TanStack form instance returned by `useForm(...)`. */form: AnyFormApi;
6
+ /** The TanStack form instance returned by `useForm(...)`. */
7
+ form: AnyFormApi;
8
8
  /**
9
9
  * Also disable while the form is invalid (not just while submitting). Off by
10
10
  * default — the button stays clickable so submitting an invalid form surfaces
11
11
  * its errors instead of leaving the user stuck on a disabled control.
12
12
  * @default false
13
13
  */
14
- disableWhenInvalid?: boolean; /** Emphasis forwarded to the underlying `<Button>`. */
15
- emphasis?: ButtonProps["emphasis"]; /** Size forwarded to the underlying `<Button>`. */
16
- size?: ButtonProps["size"]; /** Button label content. Falls back to "Submit". */
14
+ disableWhenInvalid?: boolean;
15
+ /** Emphasis forwarded to the underlying `<Button>`. */
16
+ emphasis?: ButtonProps["emphasis"];
17
+ /** Size forwarded to the underlying `<Button>`. */
18
+ size?: ButtonProps["size"];
19
+ /** Button label content. Falls back to "Submit". */
17
20
  children?: ReactNode;
18
21
  };
19
22
  /**
@@ -21,13 +24,7 @@ type FormSubmitProps = {
21
24
  * the `onSubmit` promise is in flight the label is blurred with a corner spinner
22
25
  * (`Loading variant="busy"`) and the button is disabled + `aria-busy`.
23
26
  */
24
- declare function FormSubmit({
25
- form,
26
- disableWhenInvalid,
27
- emphasis,
28
- size,
29
- children
30
- }: FormSubmitProps): JSX.Element;
27
+ declare function FormSubmit({ form, disableWhenInvalid, emphasis, size, children }: FormSubmitProps): JSX.Element;
31
28
  declare namespace FormSubmit {
32
29
  var displayName: string;
33
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormSubmit.d.ts","names":[],"sources":["../../src/FormSubmit.tsx"],"mappings":";;;;;KAMY,eAAA;+DAEV,IAAA,EAAM,UAAA;EAFmB;;;;;;EASzB,kBAAA,YAMoB;EAJpB,QAAA,GAAW,WAAA,cATL;EAWN,IAAA,GAAO,WAAA,UAFP;EAIA,QAAA,GAAW,SAAA;AAAA;;;;;AAAS;iBAQN,UAAA;EACd,IAAA;EACA,kBAAA;EACA,QAAA;EACA,IAAA;EACA;AAAA,GACC,eAAA,GAAkB,GAAA,CAAI,OAAA;AAAA,kBANT,UAAA;EAAA,IAAU,WAAA;AAAA"}
1
+ {"version":3,"file":"FormSubmit.d.ts","names":[],"sources":["../../src/FormSubmit.tsx"],"mappings":";;;;KAMY;;EAEV,MAAM;;;;;;;EAON;;EAEA,WAAW;;EAEX,OAAO;;EAEP,WAAW;;;;;;;iBAQG,aACd,MACA,oBACA,UACA,MACA,YACC,kBAAkB,IAAI;kBANT;MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"FormSubmit.js","names":[],"sources":["../../src/FormSubmit.tsx"],"sourcesContent":["import Button, { type ButtonProps } from \"@pindoba/react-button\";\nimport Loading from \"@pindoba/react-loading\";\nimport { useStore } from \"@tanstack/react-form\";\nimport type { JSX, ReactNode } from \"react\";\nimport type { AnyFormApi } from \"./types\";\n\nexport type FormSubmitProps = {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Also disable while the form is invalid (not just while submitting). Off by\n * default — the button stays clickable so submitting an invalid form surfaces\n * its errors instead of leaving the user stuck on a disabled control.\n * @default false\n */\n disableWhenInvalid?: boolean;\n /** Emphasis forwarded to the underlying `<Button>`. */\n emphasis?: ButtonProps[\"emphasis\"];\n /** Size forwarded to the underlying `<Button>`. */\n size?: ButtonProps[\"size\"];\n /** Button label content. Falls back to \"Submit\". */\n children?: ReactNode;\n};\n\n/**\n * FormSubmit — a submit `<Button>` wired to the form's submit-readiness. While\n * the `onSubmit` promise is in flight the label is blurred with a corner spinner\n * (`Loading variant=\"busy\"`) and the button is disabled + `aria-busy`.\n */\nexport function FormSubmit({\n form,\n disableWhenInvalid = false,\n emphasis = \"primary\",\n size,\n children,\n}: FormSubmitProps): JSX.Element {\n const { canSubmit, isSubmitting } = useStore(form.store, (state) => ({\n canSubmit: state.canSubmit,\n isSubmitting: state.isSubmitting,\n }));\n\n return (\n <Loading loading={isSubmitting} variant=\"busy\" indicator>\n <Button\n type=\"submit\"\n emphasis={emphasis}\n size={size}\n disabled={isSubmitting || (disableWhenInvalid && !canSubmit)}\n aria-busy={isSubmitting ? \"true\" : undefined}\n >\n {children ?? \"Submit\"}\n </Button>\n </Loading>\n );\n}\n\nFormSubmit.displayName = \"FormSubmit\";\n"],"mappings":";;;;;;;;;;AA6BA,SAAgB,WAAW,EACzB,MACA,qBAAqB,OACrB,WAAW,WACX,MACA,YAC+B;CAC/B,MAAM,EAAE,WAAW,iBAAiB,SAAS,KAAK,QAAQ,WAAW;EACnE,WAAW,MAAM;EACjB,cAAc,MAAM;CACtB,EAAE;CAEF,OACE,oBAAC,SAAD;EAAS,SAAS;EAAc,SAAQ;EAAO,WAAA;YAC7C,oBAAC,QAAD;GACE,MAAK;GACK;GACJ;GACN,UAAU,gBAAiB,sBAAsB,CAAC;GAClD,aAAW,eAAe,SAAS,KAAA;aAElC,YAAY;EACP,CAAA;CACD,CAAA;AAEb;AAEA,WAAW,cAAc"}
1
+ {"version":3,"file":"FormSubmit.js","names":[],"sources":["../../src/FormSubmit.tsx"],"sourcesContent":["import Button, { type ButtonProps } from \"@pindoba/react-button\";\nimport Loading from \"@pindoba/react-loading\";\nimport { useStore } from \"@tanstack/react-form\";\nimport type { JSX, ReactNode } from \"react\";\nimport type { AnyFormApi } from \"./types\";\n\nexport type FormSubmitProps = {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Also disable while the form is invalid (not just while submitting). Off by\n * default — the button stays clickable so submitting an invalid form surfaces\n * its errors instead of leaving the user stuck on a disabled control.\n * @default false\n */\n disableWhenInvalid?: boolean;\n /** Emphasis forwarded to the underlying `<Button>`. */\n emphasis?: ButtonProps[\"emphasis\"];\n /** Size forwarded to the underlying `<Button>`. */\n size?: ButtonProps[\"size\"];\n /** Button label content. Falls back to \"Submit\". */\n children?: ReactNode;\n};\n\n/**\n * FormSubmit — a submit `<Button>` wired to the form's submit-readiness. While\n * the `onSubmit` promise is in flight the label is blurred with a corner spinner\n * (`Loading variant=\"busy\"`) and the button is disabled + `aria-busy`.\n */\nexport function FormSubmit({\n form,\n disableWhenInvalid = false,\n emphasis = \"primary\",\n size,\n children,\n}: FormSubmitProps): JSX.Element {\n const { canSubmit, isSubmitting } = useStore(form.store, (state) => ({\n canSubmit: state.canSubmit,\n isSubmitting: state.isSubmitting,\n }));\n\n return (\n <Loading loading={isSubmitting} variant=\"busy\" indicator>\n <Button\n type=\"submit\"\n emphasis={emphasis}\n size={size}\n disabled={isSubmitting || (disableWhenInvalid && !canSubmit)}\n aria-busy={isSubmitting ? \"true\" : undefined}\n >\n {children ?? \"Submit\"}\n </Button>\n </Loading>\n );\n}\n\nFormSubmit.displayName = \"FormSubmit\";\n"],"mappings":";;;;;;;;;;AA6BA,SAAgB,WAAW,EACzB,MACA,qBAAqB,OACrB,WAAW,WACX,MACA,YAC+B;CAC/B,MAAM,EAAE,WAAW,iBAAiB,SAAS,KAAK,QAAQ,WAAW;EACnE,WAAW,MAAM;EACjB,cAAc,MAAM;CACtB,EAAE;CAEF,OACE,oBAAC,SAAD;EAAS,SAAS;EAAc,SAAQ;EAAO,WAAA;EAC7C,UAAA,oBAAC,QAAD;GACE,MAAK;GACK;GACJ;GACN,UAAU,gBAAiB,sBAAsB,CAAC;GAClD,aAAW,eAAe,SAAS,KAAA;GAElC,UAAA,YAAY;EACP,CAAA;CACD,CAAA;AAEb;AAEA,WAAW,cAAc"}
@@ -1,35 +1,16 @@
1
1
  import { AnyFieldApi, AnyFormApi } from "@tanstack/react-form";
2
- import { FormFieldErrorMode, FormFieldErrorMode as FormFieldErrorMode$1 } from "@pindoba/core-tanstack-form";
3
- import { FieldFeedback, FieldOrientation, FieldPassThrough, FieldSize } from "@pindoba/core-field";
2
+ import { FormFieldBaseProps, FormFieldErrorMode } from "@pindoba/core-tanstack-form";
4
3
  import { ReactNode } from "react";
5
-
4
+ import { FieldPassThrough } from "@pindoba/core-field";
6
5
  //#region src/types.d.ts
7
6
  /**
8
7
  * Field-level presentation props shared by `<FormField>` and every convenience
9
8
  * wrapper (`<FormInput>`, `<FormSelect>`, `<FormCheckbox>`). These mirror the
10
9
  * presentational `<Field>` props; the adapter supplies `error` from TanStack.
11
10
  */
12
- interface FormFieldOwnProps {
13
- /** Label text shown above (or beside) the control. */
14
- label?: string;
15
- /** Help text rendered under the control. */
16
- description?: string;
17
- /** Renders a required `*` after the label. */
18
- required?: boolean;
19
- /** Optional-hint text after the label when not required. */
20
- optionalText?: string;
21
- /** Disables the field and forwards `disabled` to the control. */
22
- disabled?: boolean;
23
- /** Size variant, kept in sync with the control. */
24
- size?: FieldSize;
25
- /** Label/control layout direction. */
26
- orientation?: FieldOrientation;
27
- /** Explicit feedback override; defaults to error-derived danger / neutral. */
28
- feedback?: FieldFeedback;
11
+ interface FormFieldOwnProps extends Omit<FormFieldBaseProps, "form" | "name" | "labelTooltip" | "passThrough"> {
29
12
  /** Tooltip attached to an info trigger next to the label. */
30
13
  labelTooltip?: ReactNode;
31
- /** When the field's errors become visible. @default "touched" */
32
- errorMode?: FormFieldErrorMode$1;
33
14
  /** Per-slot escape hatch for styling and attributes. */
34
15
  passThrough?: FieldPassThrough;
35
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;;AAmBA;;;;UAAiB,iBAAA;EAgBJ;EAdX,KAAA;EAkBY;EAhBZ,WAAA;EAkB8B;EAhB9B,QAAA;EAJA;EAMA,YAAA;EAFA;EAIA,QAAA;EAAA;EAEA,IAAA,GAAO,SAAA;EAAA;EAEP,WAAA,GAAc,gBAAA;EAAA;EAEd,QAAA,GAAW,aAAA;EAAA;EAEX,YAAA,GAAe,SAAA;EAAA;EAEf,SAAA,GAAY,oBAAA;EAAA;EAEZ,WAAA,GAAc,gBAAA;AAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;;;;;UAciB,0BAA0B,KACzC;;EAIA,eAAe;;EAEf,cAAc"}
@@ -0,0 +1,27 @@
1
+ import { AnyFormApi } from "./types.js";
2
+ import { FocusInvalidOptions } from "@pindoba/core-tanstack-form";
3
+ //#region src/useFocusInvalidOnSubmit.d.ts
4
+ /**
5
+ * Returns a ref to attach to your `<form>` that moves focus to the first
6
+ * invalid control after a failed submit:
7
+ *
8
+ * ```tsx
9
+ * const formRef = useFocusInvalidOnSubmit(form);
10
+ * return (
11
+ * <form ref={formRef} onSubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>
12
+ * …
13
+ * </form>
14
+ * );
15
+ * ```
16
+ *
17
+ * It reads the form's submit-attempt / validation state, and once an attempt
18
+ * ends invalid (after async validators settle) focuses the first control marked
19
+ * `aria-invalid="true"` inside the form. The state is read via `useStore`, so
20
+ * the focus effect runs after React has committed the error render and the
21
+ * markers are in the DOM. TanStack Form does no DOM focus itself, so without
22
+ * this a keyboard user is stranded on the submit button (WCAG 3.3.1).
23
+ */
24
+ declare function useFocusInvalidOnSubmit(form: AnyFormApi, options?: FocusInvalidOptions): React.RefObject<HTMLFormElement | null>;
25
+ //#endregion
26
+ export { useFocusInvalidOnSubmit };
27
+ //# sourceMappingURL=useFocusInvalidOnSubmit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusInvalidOnSubmit.d.ts","names":[],"sources":["../../src/useFocusInvalidOnSubmit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;iBA6BgB,wBACd,MAAM,YACN,UAAU,sBACT,MAAM,UAAU"}
@@ -0,0 +1,48 @@
1
+ import { useStore } from "@tanstack/react-form";
2
+ import { createSubmitFocusTracker, focusFirstInvalidControl } from "@pindoba/core-tanstack-form";
3
+ import { useEffect, useRef } from "react";
4
+ //#region src/useFocusInvalidOnSubmit.ts
5
+ /**
6
+ * Returns a ref to attach to your `<form>` that moves focus to the first
7
+ * invalid control after a failed submit:
8
+ *
9
+ * ```tsx
10
+ * const formRef = useFocusInvalidOnSubmit(form);
11
+ * return (
12
+ * <form ref={formRef} onSubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>
13
+ * …
14
+ * </form>
15
+ * );
16
+ * ```
17
+ *
18
+ * It reads the form's submit-attempt / validation state, and once an attempt
19
+ * ends invalid (after async validators settle) focuses the first control marked
20
+ * `aria-invalid="true"` inside the form. The state is read via `useStore`, so
21
+ * the focus effect runs after React has committed the error render and the
22
+ * markers are in the DOM. TanStack Form does no DOM focus itself, so without
23
+ * this a keyboard user is stranded on the submit button (WCAG 3.3.1).
24
+ */
25
+ function useFocusInvalidOnSubmit(form, options) {
26
+ const formRef = useRef(null);
27
+ const submissionAttempts = useStore(form.store, (s) => s.submissionAttempts);
28
+ const isValidating = useStore(form.store, (s) => s.isValidating);
29
+ const isValid = useStore(form.store, (s) => s.isValid);
30
+ const trackerRef = useRef(null);
31
+ if (trackerRef.current === null) trackerRef.current = createSubmitFocusTracker(() => focusFirstInvalidControl(formRef.current, options), submissionAttempts);
32
+ useEffect(() => {
33
+ trackerRef.current?.({
34
+ submissionAttempts,
35
+ isValidating,
36
+ isValid
37
+ });
38
+ }, [
39
+ submissionAttempts,
40
+ isValidating,
41
+ isValid
42
+ ]);
43
+ return formRef;
44
+ }
45
+ //#endregion
46
+ export { useFocusInvalidOnSubmit };
47
+
48
+ //# sourceMappingURL=useFocusInvalidOnSubmit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusInvalidOnSubmit.js","names":[],"sources":["../../src/useFocusInvalidOnSubmit.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useStore } from \"@tanstack/react-form\";\nimport {\n createSubmitFocusTracker,\n focusFirstInvalidControl,\n type FocusInvalidOptions,\n} from \"@pindoba/core-tanstack-form\";\nimport type { AnyFormApi } from \"./types\";\n\n/**\n * Returns a ref to attach to your `<form>` that moves focus to the first\n * invalid control after a failed submit:\n *\n * ```tsx\n * const formRef = useFocusInvalidOnSubmit(form);\n * return (\n * <form ref={formRef} onSubmit={(e) => { e.preventDefault(); form.handleSubmit(); }}>\n * …\n * </form>\n * );\n * ```\n *\n * It reads the form's submit-attempt / validation state, and once an attempt\n * ends invalid (after async validators settle) focuses the first control marked\n * `aria-invalid=\"true\"` inside the form. The state is read via `useStore`, so\n * the focus effect runs after React has committed the error render and the\n * markers are in the DOM. TanStack Form does no DOM focus itself, so without\n * this a keyboard user is stranded on the submit button (WCAG 3.3.1).\n */\nexport function useFocusInvalidOnSubmit(\n form: AnyFormApi,\n options?: FocusInvalidOptions,\n): React.RefObject<HTMLFormElement | null> {\n const formRef = useRef<HTMLFormElement>(null);\n\n const submissionAttempts = useStore(form.store, (s) => s.submissionAttempts);\n const isValidating = useStore(form.store, (s) => s.isValidating);\n const isValid = useStore(form.store, (s) => s.isValid);\n\n // The tracker is stateful (it remembers the last attempt count), so it must\n // survive re-renders. Seed it once with the current attempt count so a form\n // mounted mid-flight doesn't focus spuriously.\n const trackerRef = useRef<\n | ((s: {\n submissionAttempts: number;\n isValidating: boolean;\n isValid: boolean;\n }) => void)\n | null\n >(null);\n if (trackerRef.current === null) {\n trackerRef.current = createSubmitFocusTracker(\n () => focusFirstInvalidControl(formRef.current, options),\n submissionAttempts,\n );\n }\n\n // Runs after commit → aria-invalid markers are in the DOM.\n useEffect(() => {\n trackerRef.current?.({ submissionAttempts, isValidating, isValid });\n }, [submissionAttempts, isValidating, isValid]);\n\n return formRef;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,wBACd,MACA,SACyC;CACzC,MAAM,UAAU,OAAwB,IAAI;CAE5C,MAAM,qBAAqB,SAAS,KAAK,QAAQ,MAAM,EAAE,kBAAkB;CAC3E,MAAM,eAAe,SAAS,KAAK,QAAQ,MAAM,EAAE,YAAY;CAC/D,MAAM,UAAU,SAAS,KAAK,QAAQ,MAAM,EAAE,OAAO;CAKrD,MAAM,aAAa,OAOjB,IAAI;CACN,IAAI,WAAW,YAAY,MACzB,WAAW,UAAU,+BACb,yBAAyB,QAAQ,SAAS,OAAO,GACvD,kBACF;CAIF,gBAAgB;EACd,WAAW,UAAU;GAAE;GAAoB;GAAc;EAAQ,CAAC;CACpE,GAAG;EAAC;EAAoB;EAAc;CAAO,CAAC;CAE9C,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pindoba/react-tanstack-form",
3
- "version": "0.0.0-alpha-20260619021129",
3
+ "version": "0.0.0-alpha-20260829223243",
4
4
  "homepage": "https://github.com/EduardoLopes/pindoba/tree/main/packages/blocks/react/tanstack-form#README.md",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,31 +26,31 @@
26
26
  "./demos/generic-field": "./src/demos/generic-field.tsx"
27
27
  },
28
28
  "devDependencies": {
29
- "@types/react": "^19.2.17",
30
- "@types/react-dom": "^19.2.3",
31
- "react": "^19.2.7",
32
- "react-dom": "^19.2.7",
33
- "tsdown": "^0.22.2",
29
+ "@pindoba/typescript-config": "0.0.0-alpha-20260320034942",
30
+ "@types/react": "^19.2.18",
31
+ "@types/react-dom": "^19.2.5",
32
+ "react": "^19.2.8",
33
+ "react-dom": "^19.2.8",
34
+ "tsdown": "^0.22.14",
34
35
  "typescript": "^6.0.3",
35
- "zod": "^4.4.3",
36
- "@repo/typescript-config": "0.0.0-alpha-20260320034942"
36
+ "zod": "^4.5.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": "^18.3.1 || ^19.0.0"
40
40
  },
41
41
  "dependencies": {
42
- "@tanstack/react-form": "^1.33.0",
43
- "@pindoba/core-field": "0.0.0-alpha-20260619021129",
44
- "@pindoba/core-listbox": "0.0.0-alpha-20260619021129",
45
- "@pindoba/core-tanstack-form": "0.0.0-alpha-20260617191010",
46
- "@pindoba/react-button": "0.0.0-alpha-20260619021129",
47
- "@pindoba/react-affix": "0.0.0-alpha-20260619021129",
48
- "@pindoba/react-checkbox": "0.0.0-alpha-20260619021129",
49
- "@pindoba/react-field": "0.0.0-alpha-20260619021129",
50
- "@pindoba/styled-system": "0.0.0-alpha-20260619021129",
51
- "@pindoba/react-input": "0.0.0-alpha-20260619021129",
52
- "@pindoba/react-loading": "0.0.0-alpha-20260619021129",
53
- "@pindoba/react-select": "0.0.0-alpha-20260619021129"
42
+ "@pindoba/core-field": "0.0.0-alpha-20260829223243",
43
+ "@pindoba/core-listbox": "0.0.0-alpha-20260829223243",
44
+ "@pindoba/core-tanstack-form": "0.0.0-alpha-20260829223243",
45
+ "@pindoba/react-affix": "0.0.0-alpha-20260829223243",
46
+ "@pindoba/react-button": "0.0.0-alpha-20260829223243",
47
+ "@pindoba/react-checkbox": "0.0.0-alpha-20260829223243",
48
+ "@pindoba/react-field": "0.0.0-alpha-20260829223243",
49
+ "@pindoba/react-input": "0.0.0-alpha-20260829223243",
50
+ "@pindoba/react-loading": "0.0.0-alpha-20260829223243",
51
+ "@pindoba/react-select": "0.0.0-alpha-20260829223243",
52
+ "@pindoba/styled-system": "0.0.0-alpha-20260829223243",
53
+ "@tanstack/react-form": "^1.33.5"
54
54
  },
55
55
  "publishConfig": {
56
56
  "access": "public"