@pindoba/react-tanstack-form 0.0.0-alpha-20260907031008 → 0.0.0-alpha-20261008173743
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 +6 -5
- package/dist/index.js +2 -1
- package/dist/src/FormCheckbox.d.ts +21 -9
- package/dist/src/FormCheckbox.d.ts.map +1 -1
- package/dist/src/FormCheckbox.js +28 -11
- package/dist/src/FormCheckbox.js.map +1 -1
- package/dist/src/FormInput.d.ts +28 -10
- package/dist/src/FormInput.d.ts.map +1 -1
- package/dist/src/FormInput.js +23 -7
- package/dist/src/FormInput.js.map +1 -1
- package/dist/src/FormSelect.d.ts +27 -9
- package/dist/src/FormSelect.d.ts.map +1 -1
- package/dist/src/FormSelect.js +12 -4
- package/dist/src/FormSelect.js.map +1 -1
- package/dist/src/FormSubmit.d.ts +8 -5
- package/dist/src/FormSubmit.d.ts.map +1 -1
- package/dist/src/FormSubmit.js +4 -2
- package/dist/src/FormSubmit.js.map +1 -1
- package/dist/src/FormTextarea.d.ts +35 -0
- package/dist/src/FormTextarea.d.ts.map +1 -0
- package/dist/src/FormTextarea.js +42 -0
- package/dist/src/FormTextarea.js.map +1 -0
- package/dist/src/types.d.ts +8 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/useFocusInvalidOnSubmit.d.ts +3 -1
- package/dist/src/useFocusInvalidOnSubmit.d.ts.map +1 -1
- package/dist/src/useFocusInvalidOnSubmit.js.map +1 -1
- package/package.json +17 -14
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { AnyFieldApi, AnyFormApi, FormFieldErrorMode, FormFieldOwnProps } from "./src/types.js";
|
|
1
|
+
import { AnyFieldApi, AnyFormApi, FormControlReservedAttribute, FormFieldErrorMode, FormFieldOwnProps } from "./src/types.js";
|
|
2
2
|
import { FormField, FormFieldProps } from "./src/FormField.js";
|
|
3
|
-
import { FormInput, FormInputProps } from "./src/FormInput.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { FormInput, FormInputAttributes, FormInputProps } from "./src/FormInput.js";
|
|
4
|
+
import { FormTextarea, FormTextareaAttributes, FormTextareaProps } from "./src/FormTextarea.js";
|
|
5
|
+
import { FormSelect, FormSelectAttributes, FormSelectProps } from "./src/FormSelect.js";
|
|
6
|
+
import { FormCheckbox, FormCheckboxAttributes, FormCheckboxProps } from "./src/FormCheckbox.js";
|
|
6
7
|
import { FormSubmit, FormSubmitProps } from "./src/FormSubmit.js";
|
|
7
8
|
import { useFocusInvalidOnSubmit } from "./src/useFocusInvalidOnSubmit.js";
|
|
8
9
|
import { getVisibleErrors, normalizeErrors } from "./src/field-errors.js";
|
|
9
10
|
import { useForm, useStore } from "@tanstack/react-form";
|
|
10
11
|
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 };
|
|
12
|
+
export { type AnyFieldApi, type AnyFormApi, type FocusInvalidOptions, FormCheckbox, type FormCheckboxAttributes, type FormCheckboxProps, type FormControlReservedAttribute, FormField, type FormFieldErrorMode, type FormFieldOwnProps, type FormFieldProps, FormInput, type FormInputAttributes, type FormInputProps, FormSelect, type FormSelectAttributes, type FormSelectProps, FormSubmit, type FormSubmitProps, FormTextarea, type FormTextareaAttributes, type FormTextareaProps, getVisibleErrors, normalizeErrors, useFocusInvalidOnSubmit, useForm, useStore };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getVisibleErrors, normalizeErrors } from "./src/field-errors.js";
|
|
2
2
|
import { FormField } from "./src/FormField.js";
|
|
3
3
|
import { FormInput } from "./src/FormInput.js";
|
|
4
|
+
import { FormTextarea } from "./src/FormTextarea.js";
|
|
4
5
|
import { FormSelect } from "./src/FormSelect.js";
|
|
5
6
|
import { FormCheckbox } from "./src/FormCheckbox.js";
|
|
6
7
|
import { FormSubmit } from "./src/FormSubmit.js";
|
|
7
8
|
import { useFocusInvalidOnSubmit } from "./src/useFocusInvalidOnSubmit.js";
|
|
8
9
|
import { useForm, useStore } from "@tanstack/react-form";
|
|
9
|
-
export { FormCheckbox, FormField, FormInput, FormSelect, FormSubmit, getVisibleErrors, normalizeErrors, useFocusInvalidOnSubmit, useForm, useStore };
|
|
10
|
+
export { FormCheckbox, FormField, FormInput, FormSelect, FormSubmit, FormTextarea, getVisibleErrors, normalizeErrors, useFocusInvalidOnSubmit, useForm, useStore };
|
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
import { AnyFormApi, FormFieldOwnProps } from "./types.js";
|
|
2
|
-
import {
|
|
1
|
+
import { AnyFormApi, FormControlReservedAttribute, FormFieldOwnProps } from "./types.js";
|
|
2
|
+
import React, { InputHTMLAttributes, ReactNode } from "react";
|
|
3
3
|
import { FieldSize } from "@pindoba/core-field";
|
|
4
4
|
//#region src/FormCheckbox.d.ts
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Native attributes for the checkbox `<input>` (`value`, `autoFocus`,
|
|
7
|
+
* `data-*`, …). Routed through `passThrough.input.props` so they land on the
|
|
8
|
+
* `<input>`, not the Checkbox's root `<label>`.
|
|
9
|
+
*/
|
|
10
|
+
type FormCheckboxAttributes = Omit<InputHTMLAttributes<HTMLInputElement>, Exclude<FormControlReservedAttribute, "value"> | "type">;
|
|
11
|
+
type FormCheckboxProps = Omit<FormFieldOwnProps, "size"> & FormCheckboxAttributes & {
|
|
6
12
|
/** The TanStack form instance returned by `useForm(...)`. */
|
|
7
13
|
form: AnyFormApi;
|
|
8
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Field name (a boolean key of the form's data). Also the native `name`
|
|
16
|
+
* of the checkbox `<input>`.
|
|
17
|
+
*/
|
|
9
18
|
name: string;
|
|
10
19
|
/** Inline text/content rendered beside the checkbox. */
|
|
11
20
|
children?: ReactNode;
|
|
12
21
|
/** Size variant. Checkbox supports `sm`/`md`/`lg` (no `xs`). */
|
|
13
22
|
size?: Exclude<FieldSize, "xs">;
|
|
23
|
+
/**
|
|
24
|
+
* Ref forwarded to the native checkbox `<input>` (through the underlying
|
|
25
|
+
* `<Checkbox>`) — the focus target, not the root `<label>`.
|
|
26
|
+
* @group Advanced
|
|
27
|
+
*/
|
|
28
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
14
29
|
};
|
|
15
30
|
/** FormCheckbox — a `<Checkbox>` bound to a boolean TanStack form field. */
|
|
16
|
-
declare
|
|
17
|
-
declare namespace FormCheckbox {
|
|
18
|
-
var displayName: string;
|
|
19
|
-
}
|
|
31
|
+
declare const FormCheckbox: React.ForwardRefExoticComponent<Omit<FormCheckboxProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
20
32
|
//#endregion
|
|
21
|
-
export { FormCheckbox, FormCheckboxProps };
|
|
33
|
+
export { FormCheckbox, FormCheckboxAttributes, FormCheckboxProps };
|
|
22
34
|
//# sourceMappingURL=FormCheckbox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormCheckbox.d.ts","names":[],"sources":["../../src/FormCheckbox.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"FormCheckbox.d.ts","names":[],"sources":["../../src/FormCheckbox.tsx"],"mappings":";;;;;;;;;KAuBY,yBAAyB,KACnC,oBAAoB,mBAEpB,QAAQ;KAGE,oBAAoB,KAAK,6BACnC;;EAEE,MAAM;;;;;EAKN;;EAEA,WAAW;;EAEX,OAAO,QAAQ;;;;;;EAMf,MAAM,MAAM,IAAI;;;cAIP,cAAY,MAAA,0BAAA,KAAA,4BAAA,MAAA,cAAA"}
|
package/dist/src/FormCheckbox.js
CHANGED
|
@@ -1,24 +1,41 @@
|
|
|
1
1
|
import { FormField } from "./FormField.js";
|
|
2
|
+
import { routeCheckboxControlProps, splitFormFieldProps } from "@pindoba/core-tanstack-form";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import React from "react";
|
|
3
5
|
import Checkbox from "@pindoba/react-checkbox";
|
|
4
6
|
//#region src/FormCheckbox.tsx
|
|
5
7
|
/** FormCheckbox — a `<Checkbox>` bound to a boolean TanStack form field. */
|
|
6
|
-
function FormCheckbox({ form, name, children,
|
|
8
|
+
const FormCheckbox = React.forwardRef(function FormCheckbox({ form, name, children, ...rest }, ref) {
|
|
9
|
+
const { fieldProps, controlAttrs } = splitFormFieldProps(rest);
|
|
10
|
+
const { onChange, onBlur, ...inputAttrs } = controlAttrs;
|
|
7
11
|
return /* @__PURE__ */ jsx(FormField, {
|
|
8
12
|
form,
|
|
9
13
|
name,
|
|
10
|
-
size,
|
|
11
14
|
...fieldProps,
|
|
12
|
-
control: (props, field) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
control: (props, field) => {
|
|
16
|
+
const { checkboxProps, inputProps } = routeCheckboxControlProps(props, {
|
|
17
|
+
...inputAttrs,
|
|
18
|
+
name
|
|
19
|
+
});
|
|
20
|
+
return /* @__PURE__ */ jsx(Checkbox, {
|
|
21
|
+
...checkboxProps,
|
|
22
|
+
ref,
|
|
23
|
+
size: fieldProps.size,
|
|
24
|
+
passThrough: { input: { props: inputProps } },
|
|
25
|
+
checked: Boolean(field.state.value),
|
|
26
|
+
onChange: (event) => {
|
|
27
|
+
field.handleChange(event.target.checked);
|
|
28
|
+
onChange?.(event);
|
|
29
|
+
},
|
|
30
|
+
onBlur: (event) => {
|
|
31
|
+
field.handleBlur();
|
|
32
|
+
onBlur?.(event);
|
|
33
|
+
},
|
|
34
|
+
children
|
|
35
|
+
});
|
|
36
|
+
}
|
|
20
37
|
});
|
|
21
|
-
}
|
|
38
|
+
});
|
|
22
39
|
FormCheckbox.displayName = "FormCheckbox";
|
|
23
40
|
//#endregion
|
|
24
41
|
export { FormCheckbox };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormCheckbox.js","names":[],"sources":["../../src/FormCheckbox.tsx"],"sourcesContent":["import type { FieldSize } from \"@pindoba/core-field\";\nimport Checkbox from \"@pindoba/react-checkbox\";\nimport
|
|
1
|
+
{"version":3,"file":"FormCheckbox.js","names":[],"sources":["../../src/FormCheckbox.tsx"],"sourcesContent":["import type { FieldSize } from \"@pindoba/core-field\";\nimport {\n routeCheckboxControlProps,\n splitFormFieldProps,\n} from \"@pindoba/core-tanstack-form\";\nimport Checkbox from \"@pindoba/react-checkbox\";\nimport React, {\n type InputHTMLAttributes,\n type JSX,\n type ReactNode,\n} from \"react\";\nimport { FormField } from \"./FormField\";\nimport type {\n AnyFormApi,\n FormControlReservedAttribute,\n FormFieldOwnProps,\n} from \"./types\";\n\n/**\n * Native attributes for the checkbox `<input>` (`value`, `autoFocus`,\n * `data-*`, …). Routed through `passThrough.input.props` so they land on the\n * `<input>`, not the Checkbox's root `<label>`.\n */\nexport type FormCheckboxAttributes = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n // `value` stays: it is the checkbox's native submission value.\n Exclude<FormControlReservedAttribute, \"value\"> | \"type\"\n>;\n\nexport type FormCheckboxProps = Omit<FormFieldOwnProps, \"size\"> &\n FormCheckboxAttributes & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Field name (a boolean key of the form's data). Also the native `name`\n * of the checkbox `<input>`.\n */\n name: string;\n /** Inline text/content rendered beside the checkbox. */\n children?: ReactNode;\n /** Size variant. Checkbox supports `sm`/`md`/`lg` (no `xs`). */\n size?: Exclude<FieldSize, \"xs\">;\n /**\n * Ref forwarded to the native checkbox `<input>` (through the underlying\n * `<Checkbox>`) — the focus target, not the root `<label>`.\n * @group Advanced\n */\n ref?: React.Ref<HTMLInputElement>;\n };\n\n/** FormCheckbox — a `<Checkbox>` bound to a boolean TanStack form field. */\nexport const FormCheckbox = React.forwardRef<\n HTMLInputElement,\n FormCheckboxProps\n>(function FormCheckbox({ form, name, children, ...rest }, ref): JSX.Element {\n const { fieldProps, controlAttrs } = splitFormFieldProps(rest);\n const { onChange, onBlur, ...inputAttrs } = controlAttrs;\n return (\n <FormField\n form={form}\n name={name}\n {...fieldProps}\n control={(props, field) => {\n // The Field's aria wiring must reach the `<input>`: Checkbox spreads\n // unknown props onto its root `<label>`.\n const { checkboxProps, inputProps } = routeCheckboxControlProps(props, {\n ...inputAttrs,\n name,\n });\n return (\n <Checkbox\n {...checkboxProps}\n ref={ref}\n size={fieldProps.size}\n passThrough={{ input: { props: inputProps } }}\n checked={Boolean(field.state.value)}\n onChange={(event) => {\n field.handleChange(event.target.checked);\n onChange?.(event);\n }}\n onBlur={(event) => {\n field.handleBlur();\n onBlur?.(event);\n }}\n >\n {children}\n </Checkbox>\n );\n }}\n />\n );\n});\n\nFormCheckbox.displayName = \"FormCheckbox\";\n"],"mappings":";;;;;;;AAmDA,MAAa,eAAe,MAAM,WAGhC,SAAS,aAAa,EAAE,MAAM,MAAM,UAAU,GAAG,QAAQ,KAAkB;CAC3E,MAAM,EAAE,YAAY,iBAAiB,oBAAoB,IAAI;CAC7D,MAAM,EAAE,UAAU,QAAQ,GAAG,eAAe;CAC5C,OACE,oBAAC,WAAD;EACQ;EACA;EACN,GAAI;EACJ,UAAU,OAAO,UAAU;GAGzB,MAAM,EAAE,eAAe,eAAe,0BAA0B,OAAO;IACrE,GAAG;IACH;GACF,CAAC;GACD,OACE,oBAAC,UAAD;IACE,GAAI;IACC;IACL,MAAM,WAAW;IACjB,aAAa,EAAE,OAAO,EAAE,OAAO,WAAW,EAAE;IAC5C,SAAS,QAAQ,MAAM,MAAM,KAAK;IAClC,WAAW,UAAU;KACnB,MAAM,aAAa,MAAM,OAAO,OAAO;KACvC,WAAW,KAAK;IAClB;IACA,SAAS,UAAU;KACjB,MAAM,WAAW;KACjB,SAAS,KAAK;IAChB;IAEC;GACO,CAAA;EAEd;CACD,CAAA;AAEL,CAAC;AAED,aAAa,cAAc"}
|
package/dist/src/FormInput.d.ts
CHANGED
|
@@ -1,22 +1,40 @@
|
|
|
1
|
-
import { AnyFormApi, FormFieldOwnProps } from "./types.js";
|
|
1
|
+
import { AnyFormApi, FormControlReservedAttribute, FormFieldOwnProps } from "./types.js";
|
|
2
2
|
import { InputProps } from "@pindoba/react-input";
|
|
3
|
-
import
|
|
3
|
+
import React from "react";
|
|
4
4
|
//#region src/FormInput.d.ts
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Native `<input>` attributes a consumer may pass straight through
|
|
7
|
+
* (`autoComplete`, `inputMode`, `autoCapitalize`, `spellCheck`,
|
|
8
|
+
* `enterKeyHint`, `pattern`, `min`/`max`/`step`, `maxLength`, `data-*`, …).
|
|
9
|
+
* The form owns the value and the Field owns the id/aria wiring, so those are
|
|
10
|
+
* reserved.
|
|
11
|
+
*/
|
|
12
|
+
type FormInputAttributes = Omit<InputProps, FormControlReservedAttribute | "type" | "placeholder" | "ref">;
|
|
13
|
+
type FormInputProps = FormFieldOwnProps & FormInputAttributes & {
|
|
6
14
|
/** The TanStack form instance returned by `useForm(...)`. */
|
|
7
15
|
form: AnyFormApi;
|
|
8
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Field name (a key of the form's data). Also rendered as the native
|
|
18
|
+
* `name` attribute, so browsers and password managers can autofill.
|
|
19
|
+
*/
|
|
9
20
|
name: string;
|
|
10
21
|
/** HTML input type forwarded to the underlying `<Input>`. */
|
|
11
22
|
type?: InputProps["type"];
|
|
12
23
|
/** Placeholder forwarded to the underlying `<Input>`. */
|
|
13
24
|
placeholder?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Ref forwarded to the native `<input>` (through the underlying
|
|
27
|
+
* `<Input>`) — the focus target (`ref.current.focus()`).
|
|
28
|
+
* @group Advanced
|
|
29
|
+
*/
|
|
30
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
14
31
|
};
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
/**
|
|
33
|
+
* FormInput — a text `<Input>` bound to a TanStack form field. Every prop
|
|
34
|
+
* that isn't a Field prop (label, description, …) is forwarded to the
|
|
35
|
+
* `<input>`; consumer `onChange`/`onBlur` run after the form's own handlers.
|
|
36
|
+
*/
|
|
37
|
+
declare const FormInput: React.ForwardRefExoticComponent<Omit<FormInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
20
38
|
//#endregion
|
|
21
|
-
export { FormInput, FormInputProps };
|
|
39
|
+
export { FormInput, FormInputAttributes, FormInputProps };
|
|
22
40
|
//# sourceMappingURL=FormInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormInput.d.ts","names":[],"sources":["../../src/FormInput.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"FormInput.d.ts","names":[],"sources":["../../src/FormInput.tsx"],"mappings":";;;;;;;;;;;KAiBY,sBAAsB,KAChC,YACA;KAGU,iBAAiB,oBAC3B;;EAEE,MAAM;;;;;EAKN;;EAEA,OAAO;;EAEP;;;;;;EAMA,MAAM,MAAM,IAAI;;;;;;;cAQP,WAAS,MAAA,0BAAA,KAAA,yBAAA,MAAA,cAAA"}
|
package/dist/src/FormInput.js
CHANGED
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
import { FormField } from "./FormField.js";
|
|
2
|
+
import { splitFormFieldProps } from "@pindoba/core-tanstack-form";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
import Input from "@pindoba/react-input";
|
|
5
|
+
import React from "react";
|
|
4
6
|
//#region src/FormInput.tsx
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* FormInput — a text `<Input>` bound to a TanStack form field. Every prop
|
|
9
|
+
* that isn't a Field prop (label, description, …) is forwarded to the
|
|
10
|
+
* `<input>`; consumer `onChange`/`onBlur` run after the form's own handlers.
|
|
11
|
+
*/
|
|
12
|
+
const FormInput = React.forwardRef(function FormInput({ form, name, type = "text", placeholder, ...rest }, ref) {
|
|
13
|
+
const { fieldProps, controlAttrs } = splitFormFieldProps(rest);
|
|
14
|
+
const { onChange, onBlur, ...inputAttrs } = controlAttrs;
|
|
7
15
|
return /* @__PURE__ */ jsx(FormField, {
|
|
8
16
|
form,
|
|
9
17
|
name,
|
|
10
|
-
size,
|
|
11
18
|
...fieldProps,
|
|
12
19
|
control: (props, field) => /* @__PURE__ */ jsx(Input, {
|
|
20
|
+
...inputAttrs,
|
|
13
21
|
...props,
|
|
14
|
-
|
|
22
|
+
ref,
|
|
23
|
+
name,
|
|
24
|
+
size: fieldProps.size,
|
|
15
25
|
type,
|
|
16
26
|
placeholder,
|
|
17
27
|
value: String(field.state.value ?? ""),
|
|
18
|
-
onChange: (event) =>
|
|
19
|
-
|
|
28
|
+
onChange: (event) => {
|
|
29
|
+
field.handleChange(event.target.value);
|
|
30
|
+
onChange?.(event);
|
|
31
|
+
},
|
|
32
|
+
onBlur: (event) => {
|
|
33
|
+
field.handleBlur();
|
|
34
|
+
onBlur?.(event);
|
|
35
|
+
}
|
|
20
36
|
})
|
|
21
37
|
});
|
|
22
|
-
}
|
|
38
|
+
});
|
|
23
39
|
FormInput.displayName = "FormInput";
|
|
24
40
|
//#endregion
|
|
25
41
|
export { FormInput };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormInput.js","names":[],"sources":["../../src/FormInput.tsx"],"sourcesContent":["import Input, { type InputProps } from \"@pindoba/react-input\";\nimport
|
|
1
|
+
{"version":3,"file":"FormInput.js","names":[],"sources":["../../src/FormInput.tsx"],"sourcesContent":["import { splitFormFieldProps } from \"@pindoba/core-tanstack-form\";\nimport Input, { type InputProps } from \"@pindoba/react-input\";\nimport React, { type JSX } from \"react\";\nimport { FormField } from \"./FormField\";\nimport type {\n AnyFormApi,\n FormControlReservedAttribute,\n FormFieldOwnProps,\n} from \"./types\";\n\n/**\n * Native `<input>` attributes a consumer may pass straight through\n * (`autoComplete`, `inputMode`, `autoCapitalize`, `spellCheck`,\n * `enterKeyHint`, `pattern`, `min`/`max`/`step`, `maxLength`, `data-*`, …).\n * The form owns the value and the Field owns the id/aria wiring, so those are\n * reserved.\n */\nexport type FormInputAttributes = Omit<\n InputProps,\n FormControlReservedAttribute | \"type\" | \"placeholder\" | \"ref\"\n>;\n\nexport type FormInputProps = FormFieldOwnProps &\n FormInputAttributes & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Field name (a key of the form's data). Also rendered as the native\n * `name` attribute, so browsers and password managers can autofill.\n */\n name: string;\n /** HTML input type forwarded to the underlying `<Input>`. */\n type?: InputProps[\"type\"];\n /** Placeholder forwarded to the underlying `<Input>`. */\n placeholder?: string;\n /**\n * Ref forwarded to the native `<input>` (through the underlying\n * `<Input>`) — the focus target (`ref.current.focus()`).\n * @group Advanced\n */\n ref?: React.Ref<HTMLInputElement>;\n };\n\n/**\n * FormInput — a text `<Input>` bound to a TanStack form field. Every prop\n * that isn't a Field prop (label, description, …) is forwarded to the\n * `<input>`; consumer `onChange`/`onBlur` run after the form's own handlers.\n */\nexport const FormInput = React.forwardRef<HTMLInputElement, FormInputProps>(\n function FormInput(\n { form, name, type = \"text\", placeholder, ...rest },\n ref,\n ): JSX.Element {\n const { fieldProps, controlAttrs } = splitFormFieldProps(rest);\n const { onChange, onBlur, ...inputAttrs } = controlAttrs;\n return (\n <FormField\n form={form}\n name={name}\n {...fieldProps}\n control={(props, field) => (\n <Input\n {...inputAttrs}\n {...props}\n ref={ref}\n name={name}\n size={fieldProps.size}\n type={type}\n placeholder={placeholder}\n value={String(field.state.value ?? \"\")}\n onChange={(event) => {\n field.handleChange(event.target.value);\n onChange?.(event);\n }}\n onBlur={(event) => {\n field.handleBlur();\n onBlur?.(event);\n }}\n />\n )}\n />\n );\n },\n);\n\nFormInput.displayName = \"FormInput\";\n"],"mappings":";;;;;;;;;;;AAgDA,MAAa,YAAY,MAAM,WAC7B,SAAS,UACP,EAAE,MAAM,MAAM,OAAO,QAAQ,aAAa,GAAG,QAC7C,KACa;CACb,MAAM,EAAE,YAAY,iBAAiB,oBAAoB,IAAI;CAC7D,MAAM,EAAE,UAAU,QAAQ,GAAG,eAAe;CAC5C,OACE,oBAAC,WAAD;EACQ;EACA;EACN,GAAI;EACJ,UAAU,OAAO,UACf,oBAAC,OAAD;GACE,GAAI;GACJ,GAAI;GACC;GACC;GACN,MAAM,WAAW;GACX;GACO;GACb,OAAO,OAAO,MAAM,MAAM,SAAS,EAAE;GACrC,WAAW,UAAU;IACnB,MAAM,aAAa,MAAM,OAAO,KAAK;IACrC,WAAW,KAAK;GAClB;GACA,SAAS,UAAU;IACjB,MAAM,WAAW;IACjB,SAAS,KAAK;GAChB;EACD,CAAA;CAEJ,CAAA;AAEL,CACF;AAEA,UAAU,cAAc"}
|
package/dist/src/FormSelect.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import { AnyFormApi, FormFieldOwnProps } from "./types.js";
|
|
2
|
-
import
|
|
1
|
+
import { AnyFormApi, FormControlReservedAttribute, FormFieldOwnProps } from "./types.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { SelectProps } from "@pindoba/react-select";
|
|
3
4
|
import { FieldSize } from "@pindoba/core-field";
|
|
4
5
|
import { ListBoxNodeInput } from "@pindoba/core-listbox";
|
|
5
6
|
//#region src/FormSelect.d.ts
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Select props and trigger attributes a consumer may pass through
|
|
9
|
+
* (`clearable`, `leading`, `listbox*`, `data-*`, `aria-*`, …). The form owns
|
|
10
|
+
* the (single) selection, so the value/selection-mode props are reserved.
|
|
11
|
+
*/
|
|
12
|
+
type FormSelectAttributes = Omit<SelectProps, FormControlReservedAttribute | "items" | "placeholder" | "selectionMode" | "onValueChange" | "ref">;
|
|
13
|
+
type FormSelectProps = Omit<FormFieldOwnProps, "size"> & FormSelectAttributes & {
|
|
7
14
|
/** The TanStack form instance returned by `useForm(...)`. */
|
|
8
15
|
form: AnyFormApi;
|
|
9
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Field name (a key of the form's data holding the selected option key).
|
|
18
|
+
* Also the `name` of the hidden native `<select>` mirror.
|
|
19
|
+
*/
|
|
10
20
|
name: string;
|
|
11
21
|
/** Options to choose from. */
|
|
12
22
|
items: ListBoxNodeInput[];
|
|
@@ -14,12 +24,20 @@ type FormSelectProps = Omit<FormFieldOwnProps, "size"> & {
|
|
|
14
24
|
placeholder?: string;
|
|
15
25
|
/** Size variant. Select supports `sm`/`md`/`lg` (no `xs`). */
|
|
16
26
|
size?: Exclude<FieldSize, "xs">;
|
|
27
|
+
/**
|
|
28
|
+
* Autofill hint (e.g. `"country"`) set on the hidden native `<select>`
|
|
29
|
+
* mirror, which the browser autofills and the Select syncs from.
|
|
30
|
+
*/
|
|
31
|
+
autoComplete?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Ref forwarded to the Select's focusable trigger (`role="combobox"`) —
|
|
34
|
+
* the focus target (`ref.current.focus()`).
|
|
35
|
+
* @group Advanced
|
|
36
|
+
*/
|
|
37
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
17
38
|
};
|
|
18
39
|
/** FormSelect — a single-select `<Select>` bound to a TanStack form field. */
|
|
19
|
-
declare
|
|
20
|
-
declare namespace FormSelect {
|
|
21
|
-
var displayName: string;
|
|
22
|
-
}
|
|
40
|
+
declare const FormSelect: React.ForwardRefExoticComponent<Omit<FormSelectProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
23
41
|
//#endregion
|
|
24
|
-
export { FormSelect, FormSelectProps };
|
|
42
|
+
export { FormSelect, FormSelectAttributes, FormSelectProps };
|
|
25
43
|
//# sourceMappingURL=FormSelect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormSelect.d.ts","names":[],"sources":["../../src/FormSelect.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"FormSelect.d.ts","names":[],"sources":["../../src/FormSelect.tsx"],"mappings":";;;;;;;;;;;KAiBY,uBAAuB,KACjC,aACE;KAQQ,kBAAkB,KAAK,6BACjC;;EAEE,MAAM;;;;;EAKN;;EAEA,OAAO;;EAEP;;EAEA,OAAO,QAAQ;;;;;EAKf;;;;;;EAMA,MAAM,MAAM,IAAI;;;cAIP,YAAU,MAAA,0BAAA,KAAA,0BAAA,MAAA,cAAA"}
|
package/dist/src/FormSelect.js
CHANGED
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
import { FormField } from "./FormField.js";
|
|
2
|
+
import { splitFormFieldProps } from "@pindoba/core-tanstack-form";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import React from "react";
|
|
3
5
|
import Select from "@pindoba/react-select";
|
|
4
6
|
//#region src/FormSelect.tsx
|
|
5
7
|
/** FormSelect — a single-select `<Select>` bound to a TanStack form field. */
|
|
6
|
-
function FormSelect({ form, name, items, placeholder,
|
|
8
|
+
const FormSelect = React.forwardRef(function FormSelect({ form, name, items, placeholder, autoComplete, ...rest }, ref) {
|
|
9
|
+
const { fieldProps, controlAttrs } = splitFormFieldProps(rest);
|
|
10
|
+
const { onOpenChange, ...selectAttrs } = controlAttrs;
|
|
7
11
|
return /* @__PURE__ */ jsx(FormField, {
|
|
8
12
|
form,
|
|
9
13
|
name,
|
|
10
|
-
size,
|
|
11
14
|
...fieldProps,
|
|
12
15
|
control: (props, field) => /* @__PURE__ */ jsx(Select, {
|
|
16
|
+
...selectAttrs,
|
|
13
17
|
...props,
|
|
14
|
-
|
|
18
|
+
ref,
|
|
19
|
+
name,
|
|
20
|
+
size: fieldProps.size,
|
|
15
21
|
items,
|
|
16
22
|
placeholder,
|
|
23
|
+
...autoComplete ? { passThrough: { hiddenSelect: { props: { autoComplete } } } } : {},
|
|
17
24
|
value: typeof field.state.value === "string" && field.state.value ? field.state.value : null,
|
|
18
25
|
onValueChange: (next) => field.handleChange(typeof next === "string" ? next : ""),
|
|
19
26
|
onOpenChange: (open) => {
|
|
20
27
|
if (!open) field.handleBlur();
|
|
28
|
+
onOpenChange?.(open);
|
|
21
29
|
}
|
|
22
30
|
})
|
|
23
31
|
});
|
|
24
|
-
}
|
|
32
|
+
});
|
|
25
33
|
FormSelect.displayName = "FormSelect";
|
|
26
34
|
//#endregion
|
|
27
35
|
export { FormSelect };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormSelect.js","names":[],"sources":["../../src/FormSelect.tsx"],"sourcesContent":["import type { FieldSize } from \"@pindoba/core-field\";\nimport type { ListBoxNodeInput } from \"@pindoba/core-listbox\";\nimport Select from \"@pindoba/react-select\";\nimport
|
|
1
|
+
{"version":3,"file":"FormSelect.js","names":[],"sources":["../../src/FormSelect.tsx"],"sourcesContent":["import type { FieldSize } from \"@pindoba/core-field\";\nimport type { ListBoxNodeInput } from \"@pindoba/core-listbox\";\nimport { splitFormFieldProps } from \"@pindoba/core-tanstack-form\";\nimport Select, { type SelectProps } from \"@pindoba/react-select\";\nimport React, { type JSX } from \"react\";\nimport { FormField } from \"./FormField\";\nimport type {\n AnyFormApi,\n FormControlReservedAttribute,\n FormFieldOwnProps,\n} from \"./types\";\n\n/**\n * Select props and trigger attributes a consumer may pass through\n * (`clearable`, `leading`, `listbox*`, `data-*`, `aria-*`, …). The form owns\n * the (single) selection, so the value/selection-mode props are reserved.\n */\nexport type FormSelectAttributes = Omit<\n SelectProps,\n | FormControlReservedAttribute\n | \"items\"\n | \"placeholder\"\n | \"selectionMode\"\n | \"onValueChange\"\n | \"ref\"\n>;\n\nexport type FormSelectProps = Omit<FormFieldOwnProps, \"size\"> &\n FormSelectAttributes & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Field name (a key of the form's data holding the selected option key).\n * Also the `name` of the hidden native `<select>` mirror.\n */\n name: string;\n /** Options to choose from. */\n items: ListBoxNodeInput[];\n /** Placeholder shown when nothing is selected. */\n placeholder?: string;\n /** Size variant. Select supports `sm`/`md`/`lg` (no `xs`). */\n size?: Exclude<FieldSize, \"xs\">;\n /**\n * Autofill hint (e.g. `\"country\"`) set on the hidden native `<select>`\n * mirror, which the browser autofills and the Select syncs from.\n */\n autoComplete?: string;\n /**\n * Ref forwarded to the Select's focusable trigger (`role=\"combobox\"`) —\n * the focus target (`ref.current.focus()`).\n * @group Advanced\n */\n ref?: React.Ref<HTMLDivElement>;\n };\n\n/** FormSelect — a single-select `<Select>` bound to a TanStack form field. */\nexport const FormSelect = React.forwardRef<HTMLDivElement, FormSelectProps>(\n function FormSelect(\n { form, name, items, placeholder, autoComplete, ...rest },\n ref,\n ): JSX.Element {\n const { fieldProps, controlAttrs } = splitFormFieldProps(rest);\n const { onOpenChange, ...selectAttrs } = controlAttrs;\n return (\n <FormField\n form={form}\n name={name}\n {...fieldProps}\n control={(props, field) => (\n <Select\n {...selectAttrs}\n {...props}\n ref={ref}\n name={name}\n size={fieldProps.size}\n items={items}\n placeholder={placeholder}\n {...(autoComplete\n ? { passThrough: { hiddenSelect: { props: { autoComplete } } } }\n : {})}\n value={\n typeof field.state.value === \"string\" && field.state.value\n ? field.state.value\n : null\n }\n onValueChange={(next) =>\n field.handleChange(typeof next === \"string\" ? next : \"\")\n }\n onOpenChange={(open) => {\n // Mark touched when the dropdown closes — so `errorMode=\"touched\"`\n // surfaces a required error after opening and dismissing without\n // picking.\n if (!open) field.handleBlur();\n onOpenChange?.(open);\n }}\n />\n )}\n />\n );\n },\n);\n\nFormSelect.displayName = \"FormSelect\";\n"],"mappings":";;;;;;;AAwDA,MAAa,aAAa,MAAM,WAC9B,SAAS,WACP,EAAE,MAAM,MAAM,OAAO,aAAa,cAAc,GAAG,QACnD,KACa;CACb,MAAM,EAAE,YAAY,iBAAiB,oBAAoB,IAAI;CAC7D,MAAM,EAAE,cAAc,GAAG,gBAAgB;CACzC,OACE,oBAAC,WAAD;EACQ;EACA;EACN,GAAI;EACJ,UAAU,OAAO,UACf,oBAAC,QAAD;GACE,GAAI;GACJ,GAAI;GACC;GACC;GACN,MAAM,WAAW;GACV;GACM;GACb,GAAK,eACD,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAC7D,CAAC;GACL,OACE,OAAO,MAAM,MAAM,UAAU,YAAY,MAAM,MAAM,QACjD,MAAM,MAAM,QACZ;GAEN,gBAAgB,SACd,MAAM,aAAa,OAAO,SAAS,WAAW,OAAO,EAAE;GAEzD,eAAe,SAAS;IAItB,IAAI,CAAC,MAAM,MAAM,WAAW;IAC5B,eAAe,IAAI;GACrB;EACD,CAAA;CAEJ,CAAA;AAEL,CACF;AAEA,WAAW,cAAc"}
|
package/dist/src/FormSubmit.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyFormApi } from "./types.js";
|
|
2
|
+
import React, { ReactNode } from "react";
|
|
2
3
|
import { ButtonProps } from "@pindoba/react-button";
|
|
3
|
-
import { JSX, ReactNode } from "react";
|
|
4
4
|
//#region src/FormSubmit.d.ts
|
|
5
5
|
type FormSubmitProps = {
|
|
6
6
|
/** The TanStack form instance returned by `useForm(...)`. */
|
|
@@ -18,16 +18,19 @@ type FormSubmitProps = {
|
|
|
18
18
|
size?: ButtonProps["size"];
|
|
19
19
|
/** Button label content. Falls back to "Submit". */
|
|
20
20
|
children?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Ref forwarded to the native submit `<button>` (through the underlying
|
|
23
|
+
* `<Button>`).
|
|
24
|
+
* @group Advanced
|
|
25
|
+
*/
|
|
26
|
+
ref?: React.Ref<HTMLButtonElement>;
|
|
21
27
|
};
|
|
22
28
|
/**
|
|
23
29
|
* FormSubmit — a submit `<Button>` wired to the form's submit-readiness. While
|
|
24
30
|
* the `onSubmit` promise is in flight the label is blurred with a corner spinner
|
|
25
31
|
* (`Loading variant="busy"`) and the button is disabled + `aria-busy`.
|
|
26
32
|
*/
|
|
27
|
-
declare
|
|
28
|
-
declare namespace FormSubmit {
|
|
29
|
-
var displayName: string;
|
|
30
|
-
}
|
|
33
|
+
declare const FormSubmit: React.ForwardRefExoticComponent<Omit<FormSubmitProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
31
34
|
//#endregion
|
|
32
35
|
export { FormSubmit, FormSubmitProps };
|
|
33
36
|
//# sourceMappingURL=FormSubmit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormSubmit.d.ts","names":[],"sources":["../../src/FormSubmit.tsx"],"mappings":";;;;KAMY;;EAEV,MAAM;;;;;;;EAON;;EAEA,WAAW;;EAEX,OAAO;;EAEP,WAAW
|
|
1
|
+
{"version":3,"file":"FormSubmit.d.ts","names":[],"sources":["../../src/FormSubmit.tsx"],"mappings":";;;;KAMY;;EAEV,MAAM;;;;;;;EAON;;EAEA,WAAW;;EAEX,OAAO;;EAEP,WAAW;;;;;;EAMX,MAAM,MAAM,IAAI;;;;;;;cAQL,YAAU,MAAA,0BAAA,KAAA,0BAAA,MAAA,cAAA"}
|
package/dist/src/FormSubmit.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useStore } from "@tanstack/react-form";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
3
4
|
import Button from "@pindoba/react-button";
|
|
4
5
|
import Loading from "@pindoba/react-loading";
|
|
5
6
|
//#region src/FormSubmit.tsx
|
|
@@ -8,7 +9,7 @@ import Loading from "@pindoba/react-loading";
|
|
|
8
9
|
* the `onSubmit` promise is in flight the label is blurred with a corner spinner
|
|
9
10
|
* (`Loading variant="busy"`) and the button is disabled + `aria-busy`.
|
|
10
11
|
*/
|
|
11
|
-
function FormSubmit({ form, disableWhenInvalid = false, emphasis = "primary", size, children }) {
|
|
12
|
+
const FormSubmit = React.forwardRef(function FormSubmit({ form, disableWhenInvalid = false, emphasis = "primary", size, children }, ref) {
|
|
12
13
|
const { canSubmit, isSubmitting } = useStore(form.store, (state) => ({
|
|
13
14
|
canSubmit: state.canSubmit,
|
|
14
15
|
isSubmitting: state.isSubmitting
|
|
@@ -18,6 +19,7 @@ function FormSubmit({ form, disableWhenInvalid = false, emphasis = "primary", si
|
|
|
18
19
|
variant: "busy",
|
|
19
20
|
indicator: true,
|
|
20
21
|
children: /* @__PURE__ */ jsx(Button, {
|
|
22
|
+
ref,
|
|
21
23
|
type: "submit",
|
|
22
24
|
emphasis,
|
|
23
25
|
size,
|
|
@@ -26,7 +28,7 @@ function FormSubmit({ form, disableWhenInvalid = false, emphasis = "primary", si
|
|
|
26
28
|
children: children ?? "Submit"
|
|
27
29
|
})
|
|
28
30
|
});
|
|
29
|
-
}
|
|
31
|
+
});
|
|
30
32
|
FormSubmit.displayName = "FormSubmit";
|
|
31
33
|
//#endregion
|
|
32
34
|
export { FormSubmit };
|
|
@@ -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
|
|
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 React, { type JSX, type 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 * Ref forwarded to the native submit `<button>` (through the underlying\n * `<Button>`).\n * @group Advanced\n */\n ref?: React.Ref<HTMLButtonElement>;\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 const FormSubmit = React.forwardRef<HTMLButtonElement, FormSubmitProps>(\n function FormSubmit(\n { form, disableWhenInvalid = false, emphasis = \"primary\", size, children },\n ref,\n ): 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 ref={ref}\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);\n\nFormSubmit.displayName = \"FormSubmit\";\n"],"mappings":";;;;;;;;;;;AAmCA,MAAa,aAAa,MAAM,WAC9B,SAAS,WACP,EAAE,MAAM,qBAAqB,OAAO,WAAW,WAAW,MAAM,YAChE,KACa;CACb,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;GACO;GACL,MAAK;GACK;GACJ;GACN,UAAU,gBAAiB,sBAAsB,CAAC;GAClD,aAAW,eAAe,SAAS,KAAA;GAElC,UAAA,YAAY;EACP,CAAA;CACD,CAAA;AAEb,CACF;AAEA,WAAW,cAAc"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AnyFormApi, FormControlReservedAttribute, FormFieldOwnProps } from "./types.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TextareaProps } from "@pindoba/react-textarea";
|
|
4
|
+
//#region src/FormTextarea.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Native `<textarea>` attributes (`autoComplete`, `maxLength`, `spellCheck`,
|
|
7
|
+
* `wrap`, `data-*`, …) plus the Textarea's own `rows`/`resize`/`autoResize`.
|
|
8
|
+
* The form owns the value and the Field owns the id/aria wiring.
|
|
9
|
+
*/
|
|
10
|
+
type FormTextareaAttributes = Omit<TextareaProps, FormControlReservedAttribute | "ref">;
|
|
11
|
+
type FormTextareaProps = FormFieldOwnProps & FormTextareaAttributes & {
|
|
12
|
+
/** The TanStack form instance returned by `useForm(...)`. */
|
|
13
|
+
form: AnyFormApi;
|
|
14
|
+
/**
|
|
15
|
+
* Field name (a key of the form's data). Also rendered as the native
|
|
16
|
+
* `name` attribute.
|
|
17
|
+
*/
|
|
18
|
+
name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Ref forwarded to the native `<textarea>` (through the underlying
|
|
21
|
+
* `<Textarea>`) — the focus target (`ref.current.focus()`).
|
|
22
|
+
* @group Advanced
|
|
23
|
+
*/
|
|
24
|
+
ref?: React.Ref<HTMLTextAreaElement>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* FormTextarea — a multi-line `<Textarea>` bound to a TanStack form field.
|
|
28
|
+
* Same wiring as `<FormInput>`: Field chrome, `aria-invalid` /
|
|
29
|
+
* `aria-describedby` / `aria-errormessage`, change + blur handlers. Consumer
|
|
30
|
+
* `onChange`/`onBlur` run after the form's own handlers.
|
|
31
|
+
*/
|
|
32
|
+
declare const FormTextarea: React.ForwardRefExoticComponent<Omit<FormTextareaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { FormTextarea, FormTextareaAttributes, FormTextareaProps };
|
|
35
|
+
//# sourceMappingURL=FormTextarea.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormTextarea.d.ts","names":[],"sources":["../../src/FormTextarea.tsx"],"mappings":";;;;;;;;;KAeY,yBAAyB,KACnC,eACA;KAGU,oBAAoB,oBAC9B;;EAEE,MAAM;;;;;EAKN;;;;;;EAMA,MAAM,MAAM,IAAI;;;;;;;;cASP,cAAY,MAAA,0BAAA,KAAA,4BAAA,MAAA,cAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FormField } from "./FormField.js";
|
|
2
|
+
import { splitFormFieldProps } from "@pindoba/core-tanstack-form";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import Textarea from "@pindoba/react-textarea";
|
|
6
|
+
//#region src/FormTextarea.tsx
|
|
7
|
+
/**
|
|
8
|
+
* FormTextarea — a multi-line `<Textarea>` bound to a TanStack form field.
|
|
9
|
+
* Same wiring as `<FormInput>`: Field chrome, `aria-invalid` /
|
|
10
|
+
* `aria-describedby` / `aria-errormessage`, change + blur handlers. Consumer
|
|
11
|
+
* `onChange`/`onBlur` run after the form's own handlers.
|
|
12
|
+
*/
|
|
13
|
+
const FormTextarea = React.forwardRef(function FormTextarea({ form, name, ...rest }, ref) {
|
|
14
|
+
const { fieldProps, controlAttrs } = splitFormFieldProps(rest);
|
|
15
|
+
const { onChange, onBlur, ...textareaAttrs } = controlAttrs;
|
|
16
|
+
return /* @__PURE__ */ jsx(FormField, {
|
|
17
|
+
form,
|
|
18
|
+
name,
|
|
19
|
+
...fieldProps,
|
|
20
|
+
control: (props, field) => /* @__PURE__ */ jsx(Textarea, {
|
|
21
|
+
...textareaAttrs,
|
|
22
|
+
...props,
|
|
23
|
+
ref,
|
|
24
|
+
name,
|
|
25
|
+
size: fieldProps.size,
|
|
26
|
+
value: String(field.state.value ?? ""),
|
|
27
|
+
onChange: (event) => {
|
|
28
|
+
field.handleChange(event.target.value);
|
|
29
|
+
onChange?.(event);
|
|
30
|
+
},
|
|
31
|
+
onBlur: (event) => {
|
|
32
|
+
field.handleBlur();
|
|
33
|
+
onBlur?.(event);
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
FormTextarea.displayName = "FormTextarea";
|
|
39
|
+
//#endregion
|
|
40
|
+
export { FormTextarea };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=FormTextarea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormTextarea.js","names":[],"sources":["../../src/FormTextarea.tsx"],"sourcesContent":["import { splitFormFieldProps } from \"@pindoba/core-tanstack-form\";\nimport Textarea, { type TextareaProps } from \"@pindoba/react-textarea\";\nimport React, { type JSX } from \"react\";\nimport { FormField } from \"./FormField\";\nimport type {\n AnyFormApi,\n FormControlReservedAttribute,\n FormFieldOwnProps,\n} from \"./types\";\n\n/**\n * Native `<textarea>` attributes (`autoComplete`, `maxLength`, `spellCheck`,\n * `wrap`, `data-*`, …) plus the Textarea's own `rows`/`resize`/`autoResize`.\n * The form owns the value and the Field owns the id/aria wiring.\n */\nexport type FormTextareaAttributes = Omit<\n TextareaProps,\n FormControlReservedAttribute | \"ref\"\n>;\n\nexport type FormTextareaProps = FormFieldOwnProps &\n FormTextareaAttributes & {\n /** The TanStack form instance returned by `useForm(...)`. */\n form: AnyFormApi;\n /**\n * Field name (a key of the form's data). Also rendered as the native\n * `name` attribute.\n */\n name: string;\n /**\n * Ref forwarded to the native `<textarea>` (through the underlying\n * `<Textarea>`) — the focus target (`ref.current.focus()`).\n * @group Advanced\n */\n ref?: React.Ref<HTMLTextAreaElement>;\n };\n\n/**\n * FormTextarea — a multi-line `<Textarea>` bound to a TanStack form field.\n * Same wiring as `<FormInput>`: Field chrome, `aria-invalid` /\n * `aria-describedby` / `aria-errormessage`, change + blur handlers. Consumer\n * `onChange`/`onBlur` run after the form's own handlers.\n */\nexport const FormTextarea = React.forwardRef<\n HTMLTextAreaElement,\n FormTextareaProps\n>(function FormTextarea({ form, name, ...rest }, ref): JSX.Element {\n const { fieldProps, controlAttrs } = splitFormFieldProps(rest);\n const { onChange, onBlur, ...textareaAttrs } = controlAttrs;\n return (\n <FormField\n form={form}\n name={name}\n {...fieldProps}\n control={(props, field) => (\n <Textarea\n {...textareaAttrs}\n {...props}\n ref={ref}\n name={name}\n size={fieldProps.size}\n value={String(field.state.value ?? \"\")}\n onChange={(event) => {\n field.handleChange(event.target.value);\n onChange?.(event);\n }}\n onBlur={(event) => {\n field.handleBlur();\n onBlur?.(event);\n }}\n />\n )}\n />\n );\n});\n\nFormTextarea.displayName = \"FormTextarea\";\n"],"mappings":";;;;;;;;;;;;AA2CA,MAAa,eAAe,MAAM,WAGhC,SAAS,aAAa,EAAE,MAAM,MAAM,GAAG,QAAQ,KAAkB;CACjE,MAAM,EAAE,YAAY,iBAAiB,oBAAoB,IAAI;CAC7D,MAAM,EAAE,UAAU,QAAQ,GAAG,kBAAkB;CAC/C,OACE,oBAAC,WAAD;EACQ;EACA;EACN,GAAI;EACJ,UAAU,OAAO,UACf,oBAAC,UAAD;GACE,GAAI;GACJ,GAAI;GACC;GACC;GACN,MAAM,WAAW;GACjB,OAAO,OAAO,MAAM,MAAM,SAAS,EAAE;GACrC,WAAW,UAAU;IACnB,MAAM,aAAa,MAAM,OAAO,KAAK;IACrC,WAAW,KAAK;GAClB;GACA,SAAS,UAAU;IACjB,MAAM,WAAW;IACjB,SAAS,KAAK;GAChB;EACD,CAAA;CAEJ,CAAA;AAEL,CAAC;AAED,aAAa,cAAc"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { FieldPassThrough } from "@pindoba/core-field";
|
|
|
5
5
|
//#region src/types.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Field-level presentation props shared by `<FormField>` and every convenience
|
|
8
|
-
* wrapper (`<FormInput>`, `<FormSelect>`, `<FormCheckbox>`). These mirror the
|
|
8
|
+
* wrapper (`<FormInput>`, `<FormTextarea>`, `<FormSelect>`, `<FormCheckbox>`). These mirror the
|
|
9
9
|
* presentational `<Field>` props; the adapter supplies `error` from TanStack.
|
|
10
10
|
*/
|
|
11
11
|
interface FormFieldOwnProps extends Omit<FormFieldBaseProps, "form" | "name" | "labelTooltip" | "passThrough"> {
|
|
@@ -14,6 +14,12 @@ interface FormFieldOwnProps extends Omit<FormFieldBaseProps, "form" | "name" | "
|
|
|
14
14
|
/** Per-slot escape hatch for styling and attributes. */
|
|
15
15
|
passThrough?: FieldPassThrough;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Keys a convenience wrapper never forwards from its native-attribute bucket:
|
|
19
|
+
* the TanStack binding owns `form`/`name`/value, the Field owns `id` + the
|
|
20
|
+
* shared `size`/`feedback`/`disabled`/`required`/`passThrough` props.
|
|
21
|
+
*/
|
|
22
|
+
type FormControlReservedAttribute = "form" | "name" | "value" | "defaultValue" | "checked" | "defaultChecked" | "id" | "size" | "feedback" | "disabled" | "required" | "passThrough" | "children";
|
|
17
23
|
//#endregion
|
|
18
|
-
export { type AnyFieldApi, type AnyFormApi, type FormFieldErrorMode, FormFieldOwnProps };
|
|
24
|
+
export { type AnyFieldApi, type AnyFormApi, FormControlReservedAttribute, type FormFieldErrorMode, FormFieldOwnProps };
|
|
19
25
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;;;;;UAciB,0BAA0B,KACzC;;EAIA,eAAe;;EAEf,cAAc"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;;;;;UAciB,0BAA0B,KACzC;;EAIA,eAAe;;EAEf,cAAc;;;;;;;KAQJ"}
|
|
@@ -21,7 +21,9 @@ import { FocusInvalidOptions } from "@pindoba/core-tanstack-form";
|
|
|
21
21
|
* markers are in the DOM. TanStack Form does no DOM focus itself, so without
|
|
22
22
|
* this a keyboard user is stranded on the submit button (WCAG 3.3.1).
|
|
23
23
|
*/
|
|
24
|
-
declare function useFocusInvalidOnSubmit(form: AnyFormApi, options?: FocusInvalidOptions):
|
|
24
|
+
declare function useFocusInvalidOnSubmit(form: AnyFormApi, options?: FocusInvalidOptions): {
|
|
25
|
+
current: HTMLFormElement | null;
|
|
26
|
+
};
|
|
25
27
|
//#endregion
|
|
26
28
|
export { useFocusInvalidOnSubmit };
|
|
27
29
|
//# sourceMappingURL=useFocusInvalidOnSubmit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocusInvalidOnSubmit.d.ts","names":[],"sources":["../../src/useFocusInvalidOnSubmit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;iBA6BgB,wBACd,MAAM,YACN,UAAU,
|
|
1
|
+
{"version":3,"file":"useFocusInvalidOnSubmit.d.ts","names":[],"sources":["../../src/useFocusInvalidOnSubmit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;iBA6BgB,wBACd,MAAM,YACN,UAAU;EACP,SAAS"}
|
|
@@ -1 +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<
|
|
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): { current: HTMLFormElement | null } {\n // Returned as a structural `{ current }` box, not `React.RefObject`:\n // RefObject<T> means `current: T | null` on @types/react@18 but `current: T`\n // on 19, so no single RefObject spelling is a valid `<form ref>` on both.\n const formRef = useRef<HTMLFormElement | null>(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,SACqC;CAIrC,MAAM,UAAU,OAA+B,IAAI;CAEnD,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-
|
|
3
|
+
"version": "0.0.0-alpha-20261008173743",
|
|
4
4
|
"homepage": "https://github.com/EduardoLopes/pindoba/tree/main/packages/blocks/react/tanstack-form#README.md",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"files": [
|
|
13
|
-
"dist"
|
|
13
|
+
"dist",
|
|
14
|
+
"!dist/**/__test__"
|
|
14
15
|
],
|
|
15
16
|
"type": "module",
|
|
16
17
|
"main": "./dist/index.js",
|
|
@@ -23,7 +24,8 @@
|
|
|
23
24
|
"./demos": "./src/demos/index.ts",
|
|
24
25
|
"./demos/basic": "./src/demos/basic.tsx",
|
|
25
26
|
"./demos/mixed-controls": "./src/demos/mixed-controls.tsx",
|
|
26
|
-
"./demos/generic-field": "./src/demos/generic-field.tsx"
|
|
27
|
+
"./demos/generic-field": "./src/demos/generic-field.tsx",
|
|
28
|
+
"./demos/textarea": "./src/demos/textarea.tsx"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"@pindoba/typescript-config": "0.0.0-alpha-20260320034942",
|
|
@@ -39,17 +41,18 @@
|
|
|
39
41
|
"react": "^18.3.1 || ^19.0.0"
|
|
40
42
|
},
|
|
41
43
|
"dependencies": {
|
|
42
|
-
"@pindoba/core-field": "0.0.0-alpha-
|
|
43
|
-
"@pindoba/core-listbox": "0.0.0-alpha-
|
|
44
|
-
"@pindoba/core-tanstack-form": "0.0.0-alpha-
|
|
45
|
-
"@pindoba/react-affix": "0.0.0-alpha-
|
|
46
|
-
"@pindoba/react-button": "0.0.0-alpha-
|
|
47
|
-
"@pindoba/react-checkbox": "0.0.0-alpha-
|
|
48
|
-
"@pindoba/react-field": "0.0.0-alpha-
|
|
49
|
-
"@pindoba/react-input": "0.0.0-alpha-
|
|
50
|
-
"@pindoba/react-loading": "0.0.0-alpha-
|
|
51
|
-
"@pindoba/react-select": "0.0.0-alpha-
|
|
52
|
-
"@pindoba/
|
|
44
|
+
"@pindoba/core-field": "0.0.0-alpha-20261008173743",
|
|
45
|
+
"@pindoba/core-listbox": "0.0.0-alpha-20261008173743",
|
|
46
|
+
"@pindoba/core-tanstack-form": "0.0.0-alpha-20261008173743",
|
|
47
|
+
"@pindoba/react-affix": "0.0.0-alpha-20261008173743",
|
|
48
|
+
"@pindoba/react-button": "0.0.0-alpha-20261008173743",
|
|
49
|
+
"@pindoba/react-checkbox": "0.0.0-alpha-20261008173743",
|
|
50
|
+
"@pindoba/react-field": "0.0.0-alpha-20261008173743",
|
|
51
|
+
"@pindoba/react-input": "0.0.0-alpha-20261008173743",
|
|
52
|
+
"@pindoba/react-loading": "0.0.0-alpha-20261008173743",
|
|
53
|
+
"@pindoba/react-select": "0.0.0-alpha-20261008173743",
|
|
54
|
+
"@pindoba/react-textarea": "0.0.0-alpha-20261008173743",
|
|
55
|
+
"@pindoba/styled-system": "0.0.0-alpha-20261008173743",
|
|
53
56
|
"@tanstack/react-form": "^1.33.5"
|
|
54
57
|
},
|
|
55
58
|
"publishConfig": {
|