asma-ui-core 3.90.1 → 3.92.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.
@@ -1,36 +1,40 @@
1
- import { cn as T } from "../../../../helpers/cn.js";
2
- import { DotsVerticalIcon as O } from "../../../icons/dots-vertical-icon/DotsVerticalIcon.js";
1
+ import { cn as w } from "../../../../helpers/cn.js";
2
+ import { DotsVerticalIcon as S } from "../../../icons/dots-vertical-icon/DotsVerticalIcon.js";
3
3
  import { LoadingIcon as $ } from "../../../icons/loading-icon/LoadingIcon.js";
4
4
  import { StyledTooltip as z } from "../../../data-display/tooltip/StyledTooltip.js";
5
- import { StyledButton as w } from "../../../inputs/button/StyledButton.js";
6
- import { StyledMenu as j } from "../../../navigation/menu/StyledMenu.js";
7
- import { StyledMenuItem as K } from "../../../navigation/menu/StyledMenuItem.js";
8
- import { useElementWidthPx as F } from "../../../../hooks/useElementWidthPx.js";
5
+ import { StyledButton as _ } from "../../../inputs/button/StyledButton.js";
6
+ import { StyledMenu as F } from "../../../navigation/menu/StyledMenu.js";
7
+ import { StyledMenuItem as j } from "../../../navigation/menu/StyledMenuItem.js";
8
+ import { useElementWidthPx as K } from "../../../../hooks/useElementWidthPx.js";
9
9
  import { useWidthRegistry as H } from "../../../../hooks/useWidthRegistry.js";
10
- import { planToolbarActions as D } from "../../../custom/module/header-layout/planToolbarActions.js";
11
- import { ToolbarActionButton as G } from "../../../custom/module/header-layout/ToolbarActionGroup.js";
12
- import { useToolbarTranslations as U } from "../../../custom/module/header-layout/useTranslations.js";
13
- import { useMemo as C, useState as X } from "react";
14
- import { Fragment as _, jsx as r, jsxs as i } from "react/jsx-runtime";
15
- var Y = 470, V = 8, k = "dialog-footer-right", N = "dialog-footer-more", I = (t, n) => `dialog-footer-action:${t}:${n ? "label" : "icon"}`;
16
- function ce({ leftActions: t = [], leadingSlot: n, secondaryAction: a, primaryAction: s, fixed: P = !1, rounded: B = !0, locale: E = "en", className: M, dataTest: d = "styled-dialog-footer" }) {
17
- const W = U(E), { ref: R, widthPx: c } = F(), { register: m, widths: o } = H(), [p, h] = X(null), g = c > 0 && c < Y, S = g ? 8 : 16, u = C(() => t.filter((e) => !e.hidden).map((e) => e.icon == null && e.canHideLabel == null ? {
10
+ import { planToolbarActions as U } from "../../../custom/module/header-layout/planToolbarActions.js";
11
+ import { ToolbarActionButton as D } from "../../../custom/module/header-layout/ToolbarActionGroup.js";
12
+ import { useToolbarTranslations as G } from "../../../custom/module/header-layout/useTranslations.js";
13
+ import { useMemo as y, useState as V } from "react";
14
+ import { Fragment as C, jsx as r, jsxs as l } from "react/jsx-runtime";
15
+ var X = 2, Y = 470, q = 8, N = "dialog-footer-right", M = "dialog-footer-more", O = (n, a) => `dialog-footer-action:${n}:${a ? "label" : "icon"}`;
16
+ function me({ leftActions: n = [], leadingSlot: a, secondaryAction: s, primaryAction: d, fixed: k = !1, rounded: I = !0, locale: A = "en", className: E, dataTest: c = "styled-dialog-footer" }) {
17
+ const P = G(A), { ref: R, widthPx: m } = K(), { register: h, widths: t } = H(), [p, f] = V(null), u = m > 0 && m < Y, W = u ? 8 : 16, o = y(() => n.filter((e) => !e.hidden).map((e) => e.icon == null && e.canHideLabel == null ? {
18
18
  ...e,
19
19
  canHideLabel: !1
20
- } : e), [t]), A = o[k] ?? 0, x = a != null || s != null, v = Math.max(0, c - S * 2 - A - (x ? V : 0)), f = C(() => D({
21
- actions: u,
20
+ } : e), [n]), B = t[N] ?? 0, x = s != null || d != null, v = Math.max(0, m - W * 2 - B - (x ? q : 0)), g = y(() => o.length >= X ? {
21
+ inlineActions: [],
22
+ overflowActions: o,
23
+ showMoreMenu: !0
24
+ } : U({
25
+ actions: o,
22
26
  availableWidth: v,
23
27
  collapseLabels: !0,
24
- resolveActionWidth: (e, l) => o[I(e.id, l)],
25
- moreButtonWidthPx: o[N]
28
+ resolveActionWidth: (e, i) => t[O(e.id, i)],
29
+ moreButtonWidthPx: t[M]
26
30
  }), [
27
- u,
31
+ o,
28
32
  v,
29
- o
30
- ]), b = (e, l, L) => {
31
- const y = /* @__PURE__ */ r(w, {
32
- dataTest: e.dataTest ?? `${d}-${L}`,
33
- variant: e.variant ?? l,
33
+ t
34
+ ]), b = (e, i, L) => {
35
+ const T = /* @__PURE__ */ r(_, {
36
+ dataTest: e.dataTest ?? `${c}-${L}`,
37
+ variant: e.variant ?? i,
34
38
  error: e.tone === "danger",
35
39
  size: "medium",
36
40
  type: e.type ?? "button",
@@ -50,44 +54,44 @@ function ce({ leftActions: t = [], leadingSlot: n, secondaryAction: a, primaryAc
50
54
  title: e.tooltip,
51
55
  children: /* @__PURE__ */ r("span", {
52
56
  className: "inline-flex",
53
- children: y
57
+ children: T
54
58
  })
55
- }) : y;
59
+ }) : T;
56
60
  };
57
- return /* @__PURE__ */ i("div", {
61
+ return /* @__PURE__ */ l("div", {
58
62
  ref: R,
59
- "data-testid": d,
60
- className: T("flex items-center justify-end self-stretch border-0 border-t border-solid border-delta-200 bg-white", g ? "gap-2 p-2" : "gap-4 p-4", B && "rounded-b-lg", P && "sticky bottom-0 z-[1] shadow-[0_0_16px_0_rgba(34,33,51,0.2)]", M),
63
+ "data-testid": c,
64
+ className: w("flex items-center justify-end self-stretch border-0 border-t border-solid border-delta-200 bg-white", u ? "gap-2 p-2" : "gap-4 p-4", I && "rounded-b-lg", k && "sticky bottom-0 z-[1] shadow-[0_0_16px_0_rgba(34,33,51,0.2)]", E),
61
65
  children: [/* @__PURE__ */ r("div", {
62
66
  className: "flex shrink-0 flex-nowrap items-center gap-2",
63
- children: n ?? /* @__PURE__ */ i(_, { children: [f.inlineActions.map(({ action: e, showLabel: l }) => /* @__PURE__ */ r("span", {
64
- ref: m(I(e.id, l)),
67
+ children: a ?? /* @__PURE__ */ l(C, { children: [g.inlineActions.map(({ action: e, showLabel: i }) => /* @__PURE__ */ r("span", {
68
+ ref: h(O(e.id, i)),
65
69
  className: "inline-flex shrink-0",
66
- children: /* @__PURE__ */ r(G, {
70
+ children: /* @__PURE__ */ r(D, {
67
71
  action: e,
68
- showLabel: l
72
+ showLabel: i
69
73
  })
70
- }, e.id)), f.showMoreMenu && /* @__PURE__ */ i(_, { children: [/* @__PURE__ */ r("span", {
71
- ref: m(N),
74
+ }, e.id)), g.showMoreMenu && /* @__PURE__ */ l(C, { children: [/* @__PURE__ */ r("span", {
75
+ ref: h(M),
72
76
  className: "inline-flex shrink-0",
73
- children: /* @__PURE__ */ r(w, {
74
- dataTest: `${d}-more`,
77
+ children: /* @__PURE__ */ r(_, {
78
+ dataTest: `${c}-more`,
75
79
  variant: "outlined",
76
80
  size: "medium",
77
81
  type: "button",
78
- onClick: (e) => h(e.currentTarget),
79
- "aria-label": W.more,
82
+ onClick: (e) => f(e.currentTarget),
83
+ "aria-label": P.more,
80
84
  "aria-haspopup": "menu",
81
85
  "aria-expanded": p != null,
82
- startIcon: /* @__PURE__ */ r(O, {
86
+ startIcon: /* @__PURE__ */ r(S, {
83
87
  width: 24,
84
88
  height: 24
85
89
  })
86
90
  })
87
- }), /* @__PURE__ */ r(j, {
91
+ }), /* @__PURE__ */ r(F, {
88
92
  anchorEl: p,
89
93
  open: p != null,
90
- onClose: () => h(null),
94
+ onClose: () => f(null),
91
95
  anchorOrigin: {
92
96
  vertical: "top",
93
97
  horizontal: "left"
@@ -96,27 +100,27 @@ function ce({ leftActions: t = [], leadingSlot: n, secondaryAction: a, primaryAc
96
100
  vertical: "bottom",
97
101
  horizontal: "left"
98
102
  },
99
- children: f.overflowActions.map((e) => /* @__PURE__ */ r(K, {
103
+ children: g.overflowActions.map((e) => /* @__PURE__ */ r(j, {
100
104
  disabled: e.disabled,
101
105
  onClick: () => {
102
- h(null), e.onClick();
106
+ f(null), e.onClick();
103
107
  },
104
- children: /* @__PURE__ */ i("div", {
105
- className: T("flex items-center gap-2", e.tone === "danger" ? "text-beta-500" : "text-delta-700"),
108
+ children: /* @__PURE__ */ l("div", {
109
+ className: w("flex items-center gap-2", e.tone === "danger" ? "text-beta-500" : "text-delta-700"),
106
110
  children: [e.icon, /* @__PURE__ */ r("span", { children: e.label })]
107
111
  })
108
112
  }, e.id))
109
113
  })] })] })
110
114
  }), x && /* @__PURE__ */ r("span", {
111
115
  className: "flex min-w-px flex-1 flex-nowrap items-center justify-end",
112
- children: /* @__PURE__ */ i("span", {
113
- ref: m(k),
116
+ children: /* @__PURE__ */ l("span", {
117
+ ref: h(N),
114
118
  className: "flex shrink-0 flex-nowrap items-center gap-2",
115
- children: [a && b(a, "outlined", "secondary"), s && b(s, "contained", "primary")]
119
+ children: [s && b(s, "outlined", "secondary"), d && b(d, "contained", "primary")]
116
120
  })
117
121
  })]
118
122
  });
119
123
  }
120
124
  export {
121
- ce as StyledDialogFooter
125
+ me as StyledDialogFooter
122
126
  };
@@ -0,0 +1,70 @@
1
+ import { useCallback as y, useEffect as u, useRef as F } from "react";
2
+ import { useController as S, useFormContext as x } from "react-hook-form";
3
+ var B = 150, P = 20, U = "onAutoFillStart";
4
+ function h(r) {
5
+ return r == null ? !0 : typeof r == "string" ? r.trim().length === 0 : typeof r == "number" ? Number.isNaN(r) : !1;
6
+ }
7
+ function V(r) {
8
+ return !(!r || r.required === !1 || r.required == null);
9
+ }
10
+ function X({ getLanguageCode: r, browserAutofill: l = !1 }) {
11
+ return function({ name: n, control: p, rules: f, helperText: I, requestFocus: s, render: L }) {
12
+ const d = x(), { field: t, fieldState: i } = S({
13
+ name: n,
14
+ control: p ?? d.control,
15
+ rules: f
16
+ }), { trigger: a, setValue: A } = d, { ref: o } = t, C = V(f), N = r(), v = F(null), g = (e) => {
17
+ e != null && e !== t.value && t.onChange(e), a(n);
18
+ };
19
+ u(() => {
20
+ s && o({ focus: s });
21
+ }, [o, s]), u(() => {
22
+ i.invalid && a(n);
23
+ }, [N]), u(() => {
24
+ l && (h(t.value) || a(n));
25
+ }, []), u(() => {
26
+ if (!l) return;
27
+ let e = 0;
28
+ const c = setInterval(() => {
29
+ e += 1;
30
+ const T = v.current;
31
+ T?.matches(":-webkit-autofill") ? (g(T.value), clearInterval(c)) : e >= P && clearInterval(c);
32
+ }, B);
33
+ return () => clearInterval(c);
34
+ }, []);
35
+ const _ = () => {
36
+ if (!C && h(t.value)) {
37
+ A(n, t.value, {
38
+ shouldTouch: !0,
39
+ shouldValidate: !1
40
+ });
41
+ return;
42
+ }
43
+ t.onBlur(), a(n);
44
+ };
45
+ u(() => {
46
+ i.error && a(n);
47
+ }, [t.value]);
48
+ const R = (...e) => {
49
+ t.onChange(...e);
50
+ }, E = (e) => {
51
+ l && e.animationName === U && g(e.target?.value);
52
+ }, M = y((e) => {
53
+ v.current = e, typeof o == "function" && o(e);
54
+ }, [o]), O = i.error?.message, m = !!i.error && (!l || i.isTouched);
55
+ return L({
56
+ value: t.value,
57
+ onChange: R,
58
+ onBlur: _,
59
+ onAnimationStart: E,
60
+ name: t.name,
61
+ ref: l ? M : o,
62
+ error: m,
63
+ helperText: m ? O : I,
64
+ reserveHelperText: f != null
65
+ });
66
+ };
67
+ }
68
+ export {
69
+ X as createAsmaFieldController
70
+ };
@@ -0,0 +1,12 @@
1
+ import { createAsmaFieldController as m } from "./createAsmaFieldController.js";
2
+ import { submitChanged as n } from "./submitChanged.js";
3
+ function u(t) {
4
+ const e = t.browserAutofill === !0, r = (o, i, l) => n(o, i, l, { touchInvalidFields: e });
5
+ return {
6
+ AsmaFieldController: m(t),
7
+ submitChanged: r
8
+ };
9
+ }
10
+ export {
11
+ u as createAsmaForms
12
+ };
@@ -0,0 +1,14 @@
1
+ var n = 'input, textarea, select, button, [contenteditable="true"], [contenteditable=""], [tabindex]';
2
+ function o(t) {
3
+ return t.matches(n);
4
+ }
5
+ function c(t) {
6
+ const e = document.getElementById(t) ?? Array.from(document.querySelectorAll("[data-testid]")).find((r) => r.dataset.testid === t);
7
+ return e ? ((o(e) ? e : e.querySelector(n) ?? e).focus({ preventScroll: !0 }), e.scrollIntoView({
8
+ behavior: "instant",
9
+ block: "center"
10
+ }), !0) : !1;
11
+ }
12
+ export {
13
+ c as focusFormField
14
+ };
@@ -0,0 +1,24 @@
1
+ function u(e, f) {
2
+ if (e === !0) return { ...f };
3
+ if (!e || typeof e != "object") return {};
4
+ const c = {};
5
+ for (const n of Object.keys(e)) {
6
+ const o = e[n], t = f[n];
7
+ if (o === !0) {
8
+ c[n] = t;
9
+ continue;
10
+ }
11
+ if (Array.isArray(t)) {
12
+ o && (c[n] = t);
13
+ continue;
14
+ }
15
+ if (o && typeof o == "object" && t != null && typeof t == "object") {
16
+ const r = u(o, t);
17
+ Object.keys(r).length > 0 && (c[n] = r);
18
+ }
19
+ }
20
+ return c;
21
+ }
22
+ export {
23
+ u as getDirtyValues
24
+ };
@@ -0,0 +1,2 @@
1
+ export * from '../src/forms/index'
2
+ export {}
@@ -0,0 +1,12 @@
1
+ import { getDirtyValues as r } from "./getDirtyValues.js";
2
+ import { touchInvalidFields as t } from "./touchInvalidFields.js";
3
+ import { createAsmaForms as e } from "./createAsmaForms.js";
4
+ import { focusFormField as f } from "./focusFormField.js";
5
+ import { useAsmaForm as a } from "./useAsmaForm.js";
6
+ export {
7
+ e as createAsmaForms,
8
+ f as focusFormField,
9
+ r as getDirtyValues,
10
+ t as touchInvalidFields,
11
+ a as useAsmaForm
12
+ };
@@ -0,0 +1,11 @@
1
+ import { getDirtyValues as o } from "./getDirtyValues.js";
2
+ import { touchInvalidFields as n } from "./touchInvalidFields.js";
3
+ async function f(t, a, i, e = {}) {
4
+ if (!(i ? await t.trigger() : await t.trigger(void 0, { shouldFocus: !0 })))
5
+ return e.touchInvalidFields && n(t), i?.(), !1;
6
+ const r = t.getValues(), { dirtyFields: u } = t.control._formState, l = await a(o(u, r), r);
7
+ return t.reset(l ?? r), !0;
8
+ }
9
+ export {
10
+ f as submitChanged
11
+ };
@@ -0,0 +1,12 @@
1
+ function l(e) {
2
+ for (const t of Object.keys(e.control._formState.errors)) {
3
+ const o = t;
4
+ e.setValue(o, e.getValues(o), {
5
+ shouldTouch: !0,
6
+ shouldValidate: !1
7
+ });
8
+ }
9
+ }
10
+ export {
11
+ l as touchInvalidFields
12
+ };
@@ -0,0 +1,16 @@
1
+ import { useForm as o } from "react-hook-form";
2
+ var e = {
3
+ mode: "onBlur",
4
+ reValidateMode: "onSubmit",
5
+ criteriaMode: "all",
6
+ shouldFocusError: !0
7
+ };
8
+ function t(r) {
9
+ return o({
10
+ ...r,
11
+ ...e
12
+ });
13
+ }
14
+ export {
15
+ t as useAsmaForm
16
+ };
@@ -34,10 +34,11 @@ export interface StyledDialogFooterButton {
34
34
  }
35
35
  export interface StyledDialogFooterProps {
36
36
  /**
37
- * Left cluster (Figma "Left"): destructive and utility actions. They keep their
38
- * labels while they fit, collapse to icon-only next, and move into an icon-only
39
- * "More" menu once even that overflows — so 1, 2, 3 and 3+ actions all resolve to
40
- * the approved layout without the caller branching on width.
37
+ * Left cluster (Figma "Left"): destructive and utility actions.
38
+ *
39
+ * One action renders inline, keeping its label while it fits and collapsing to icon-only
40
+ * when it does not. Two or more always collapse into the icon-only "More" menu, matching
41
+ * the Figma `More` state — so the caller never branches on count or width itself.
41
42
  */
42
43
  leftActions?: DynamicToolbarAction[];
43
44
  /** Replaces the planned left cluster with arbitrary content — Figma's "Checkbox+Label" left variant, or footer info text. */
@@ -59,15 +60,15 @@ export interface StyledDialogFooterProps {
59
60
  *
60
61
  * @figmaNode wXrXt5uKNNzV2DnQCgyYZH#26769-135283
61
62
  * @remarks Figma "Dialog footer" component set. The Figma `State` property
62
- * (Create/Edit/More/Reset filter) is **not** a prop — it is the emergent result of which
63
- * actions the caller passes and how much room the container leaves, which is the whole
64
- * point of ASMA-7099. `Mobile` is likewise derived from the **container** width, not the
65
- * viewport, so a footer inside a narrow popover compacts even on a desktop screen.
63
+ * (Create/Edit/More/Reset filter) is **not** a prop — it follows from the actions the caller
64
+ * passes: one left action is `Edit`, two or more is `More`. `Mobile` is derived from the
65
+ * **container** width, not the viewport, so a footer inside a narrow popover compacts even on
66
+ * a desktop screen.
66
67
  *
67
68
  * Layout: `Left` cluster (planned, adaptive) · `Right` cluster (Cancel + primary, always
68
69
  * visible and never overflowed — the primary action must stay reachable).
69
70
  *
70
- * @param leftActions - adaptive left cluster; label → icon-only → More menu
71
+ * @param leftActions - left cluster; one action inline, two or more behind the More menu
71
72
  * @param leadingSlot - arbitrary left content, replaces `leftActions`
72
73
  * @param secondaryAction - outlined Cancel
73
74
  * @param primaryAction - contained primary
@@ -0,0 +1,28 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ import { Control, ControllerRenderProps, FieldPath, FieldPathValue, FieldValues, RegisterOptions } from 'react-hook-form';
3
+ import { AsmaFormsOptions } from './types';
4
+ export interface AutofillAnimationEvent {
5
+ animationName: string;
6
+ target: EventTarget | null;
7
+ }
8
+ export interface AsmaFieldRenderProps<TValue = unknown> {
9
+ value: TValue;
10
+ onChange: (...event: unknown[]) => void;
11
+ onBlur: () => void;
12
+ onAnimationStart: (event: AutofillAnimationEvent) => void;
13
+ name: string;
14
+ ref: ControllerRenderProps['ref'];
15
+ error: boolean;
16
+ helperText: ReactNode;
17
+ reserveHelperText: boolean;
18
+ }
19
+ export interface AsmaFieldControllerProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> {
20
+ name: TName;
21
+ control?: Control<TFieldValues>;
22
+ rules?: Omit<RegisterOptions<TFieldValues, TName>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
23
+ helperText?: ReactNode;
24
+ /** For controls that own their input ref (comboboxes, rich editors): RHF focuses the field through this instead of a DOM node. */
25
+ requestFocus?: () => void;
26
+ render: (props: AsmaFieldRenderProps<FieldPathValue<TFieldValues, TName>>) => ReactElement;
27
+ }
28
+ export declare function createAsmaFieldController({ getLanguageCode, browserAutofill, }: AsmaFormsOptions): <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ name, control, rules, helperText, requestFocus, render, }: AsmaFieldControllerProps<TFieldValues, TName>) => ReactElement;
@@ -0,0 +1,9 @@
1
+ import { FieldValues, UseFormReturn } from 'react-hook-form';
2
+ import { createAsmaFieldController } from './createAsmaFieldController';
3
+ import { SubmitChangedPatch } from './submitChanged';
4
+ import { AsmaFormsOptions } from './types';
5
+ export interface AsmaFormsApi {
6
+ AsmaFieldController: ReturnType<typeof createAsmaFieldController>;
7
+ submitChanged: <TFieldValues extends FieldValues>(methods: UseFormReturn<TFieldValues>, onPatch: SubmitChangedPatch<TFieldValues>, onInvalid?: () => void) => Promise<boolean>;
8
+ }
9
+ export declare function createAsmaForms(options: AsmaFormsOptions): AsmaFormsApi;
@@ -0,0 +1 @@
1
+ export declare function focusFormField(fieldDomId: string): boolean;
@@ -0,0 +1 @@
1
+ export declare function getDirtyValues<T extends Record<string, unknown>>(dirtyFields: Partial<Record<keyof T, unknown>> | boolean | undefined, values: T): Partial<T>;
@@ -0,0 +1,8 @@
1
+ export { createAsmaForms } from './createAsmaForms';
2
+ export { focusFormField } from './focusFormField';
3
+ export { getDirtyValues } from './getDirtyValues';
4
+ export { touchInvalidFields } from './touchInvalidFields';
5
+ export { useAsmaForm } from './useAsmaForm';
6
+ export type { AsmaFieldControllerProps, AsmaFieldRenderProps, AutofillAnimationEvent } from './createAsmaFieldController';
7
+ export type { SubmitChangedPatch } from './submitChanged';
8
+ export type { AsmaFormsOptions } from './types';
@@ -0,0 +1,6 @@
1
+ import { FieldValues, UseFormReturn } from 'react-hook-form';
2
+ export type SubmitChangedPatch<TFieldValues extends FieldValues> = (dirty: Partial<TFieldValues>, all: TFieldValues) => Promise<TFieldValues | void>;
3
+ export interface SubmitChangedOptions {
4
+ touchInvalidFields?: boolean;
5
+ }
6
+ export declare function submitChanged<TFieldValues extends FieldValues>(methods: UseFormReturn<TFieldValues>, onPatch: SubmitChangedPatch<TFieldValues>, onInvalid?: () => void, options?: SubmitChangedOptions): Promise<boolean>;
@@ -0,0 +1,2 @@
1
+ import { FieldValues, UseFormReturn } from 'react-hook-form';
2
+ export declare function touchInvalidFields<TFieldValues extends FieldValues>(methods: UseFormReturn<TFieldValues>): void;
@@ -0,0 +1,6 @@
1
+ export interface AsmaFormsOptions {
2
+ /** Read during every render; a change re-validates already-invalid fields so their message re-renders in the new language. */
3
+ getLanguageCode: () => string;
4
+ /** Login/auth forms: mount validation, autofill sync, merged ref, touched-gated errors, touch-on-submit. */
5
+ browserAutofill?: boolean;
6
+ }
@@ -0,0 +1,2 @@
1
+ import { FieldValues, UseFormProps, UseFormReturn } from 'react-hook-form';
2
+ export declare function useAsmaForm<TFieldValues extends FieldValues = FieldValues, TContext = unknown>(props?: UseFormProps<TFieldValues, TContext>): UseFormReturn<TFieldValues, TContext>;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.90.1",
6
+ "version": "3.92.0",
7
7
  "type": "module",
8
8
  "sideEffects": [
9
9
  "**/*.css",
@@ -26,6 +26,9 @@
26
26
  ],
27
27
  "icons/*": [
28
28
  "dist/src/components/icons/*/index.d.ts"
29
+ ],
30
+ "forms": [
31
+ "dist/src/forms/index.d.ts"
29
32
  ]
30
33
  }
31
34
  },
@@ -45,6 +48,11 @@
45
48
  "types": "./dist/src/components/icons/*/index.d.ts",
46
49
  "default": "./dist/components/icons/*/index.js"
47
50
  },
51
+ "./forms": {
52
+ "types": "./dist/src/forms/index.d.ts",
53
+ "import": "./dist/forms/index.js",
54
+ "default": "./dist/forms/index.js"
55
+ },
48
56
  "./dist/style.css": "./dist/style.css",
49
57
  "./tw-configs/twConfigs.json": "./tw-configs/twConfigs.json",
50
58
  "./src/styles/breakpoints": "./src/styles/_breakpoints.scss"
@@ -102,6 +110,8 @@
102
110
  "@storybook/addon-themes": "^10.3.3",
103
111
  "@storybook/addon-vitest": "10.3.3",
104
112
  "@storybook/react-vite": "10.3.3",
113
+ "@testing-library/dom": "^10.4.1",
114
+ "@testing-library/react": "^16.3.2",
105
115
  "@tippyjs/react": "^4.2.6",
106
116
  "@types/node": "^24.12.4",
107
117
  "@types/react": "^18.3.23",
@@ -120,10 +130,12 @@
120
130
  "eslint-plugin-react-you-might-not-need-an-effect": "^0.7.0",
121
131
  "eslint-plugin-regexp": "^2.10.0",
122
132
  "eslint-plugin-storybook": "10.3.3",
133
+ "jsdom": "^30.0.1",
123
134
  "playwright": "^1.57.0",
124
135
  "react": "^18.3.1",
125
136
  "react-copy-to-clipboard": "^5.1.0",
126
137
  "react-dom": "^18.3.1",
138
+ "react-hook-form": "^7.89.0",
127
139
  "react-hot-toast": "^2.4.1",
128
140
  "sass": "^1.98.0",
129
141
  "storybook": "10.3.3",
@@ -142,7 +154,13 @@
142
154
  },
143
155
  "peerDependencies": {
144
156
  "react": "^18.0.0 || ^19.0.0",
145
- "react-dom": "^18.0.0 || ^19.0.0"
157
+ "react-dom": "^18.0.0 || ^19.0.0",
158
+ "react-hook-form": "^7.85.0"
159
+ },
160
+ "peerDependenciesMeta": {
161
+ "react-hook-form": {
162
+ "optional": true
163
+ }
146
164
  },
147
165
  "repository": {
148
166
  "type": "git",