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.
- package/dist/components/feedback/dialog/dialog-footer/StyledDialogFooter.js +54 -50
- package/dist/forms/createAsmaFieldController.js +70 -0
- package/dist/forms/createAsmaForms.js +12 -0
- package/dist/forms/focusFormField.js +14 -0
- package/dist/forms/getDirtyValues.js +24 -0
- package/dist/forms/index.d.ts +2 -0
- package/dist/forms/index.js +12 -0
- package/dist/forms/submitChanged.js +11 -0
- package/dist/forms/touchInvalidFields.js +12 -0
- package/dist/forms/useAsmaForm.js +16 -0
- package/dist/src/components/feedback/dialog/dialog-footer/StyledDialogFooter.d.ts +10 -9
- package/dist/src/forms/createAsmaFieldController.d.ts +28 -0
- package/dist/src/forms/createAsmaForms.d.ts +9 -0
- package/dist/src/forms/focusFormField.d.ts +1 -0
- package/dist/src/forms/getDirtyValues.d.ts +1 -0
- package/dist/src/forms/index.d.ts +8 -0
- package/dist/src/forms/submitChanged.d.ts +6 -0
- package/dist/src/forms/touchInvalidFields.d.ts +2 -0
- package/dist/src/forms/types.d.ts +6 -0
- package/dist/src/forms/useAsmaForm.d.ts +2 -0
- package/package.json +20 -2
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
import { cn as
|
|
2
|
-
import { DotsVerticalIcon as
|
|
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
|
|
6
|
-
import { StyledMenu as
|
|
7
|
-
import { StyledMenuItem as
|
|
8
|
-
import { useElementWidthPx as
|
|
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
|
|
11
|
-
import { ToolbarActionButton as
|
|
12
|
-
import { useToolbarTranslations as
|
|
13
|
-
import { useMemo as
|
|
14
|
-
import { Fragment as
|
|
15
|
-
var Y = 470,
|
|
16
|
-
function
|
|
17
|
-
const
|
|
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), [
|
|
21
|
-
|
|
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,
|
|
25
|
-
moreButtonWidthPx:
|
|
28
|
+
resolveActionWidth: (e, i) => t[O(e.id, i)],
|
|
29
|
+
moreButtonWidthPx: t[M]
|
|
26
30
|
}), [
|
|
27
|
-
|
|
31
|
+
o,
|
|
28
32
|
v,
|
|
29
|
-
|
|
30
|
-
]), b = (e,
|
|
31
|
-
const
|
|
32
|
-
dataTest: e.dataTest ?? `${
|
|
33
|
-
variant: e.variant ??
|
|
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:
|
|
57
|
+
children: T
|
|
54
58
|
})
|
|
55
|
-
}) :
|
|
59
|
+
}) : T;
|
|
56
60
|
};
|
|
57
|
-
return /* @__PURE__ */
|
|
61
|
+
return /* @__PURE__ */ l("div", {
|
|
58
62
|
ref: R,
|
|
59
|
-
"data-testid":
|
|
60
|
-
className:
|
|
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:
|
|
64
|
-
ref:
|
|
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(
|
|
70
|
+
children: /* @__PURE__ */ r(D, {
|
|
67
71
|
action: e,
|
|
68
|
-
showLabel:
|
|
72
|
+
showLabel: i
|
|
69
73
|
})
|
|
70
|
-
}, e.id)),
|
|
71
|
-
ref:
|
|
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(
|
|
74
|
-
dataTest: `${
|
|
77
|
+
children: /* @__PURE__ */ r(_, {
|
|
78
|
+
dataTest: `${c}-more`,
|
|
75
79
|
variant: "outlined",
|
|
76
80
|
size: "medium",
|
|
77
81
|
type: "button",
|
|
78
|
-
onClick: (e) =>
|
|
79
|
-
"aria-label":
|
|
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(
|
|
86
|
+
startIcon: /* @__PURE__ */ r(S, {
|
|
83
87
|
width: 24,
|
|
84
88
|
height: 24
|
|
85
89
|
})
|
|
86
90
|
})
|
|
87
|
-
}), /* @__PURE__ */ r(
|
|
91
|
+
}), /* @__PURE__ */ r(F, {
|
|
88
92
|
anchorEl: p,
|
|
89
93
|
open: p != null,
|
|
90
|
-
onClose: () =>
|
|
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:
|
|
103
|
+
children: g.overflowActions.map((e) => /* @__PURE__ */ r(j, {
|
|
100
104
|
disabled: e.disabled,
|
|
101
105
|
onClick: () => {
|
|
102
|
-
|
|
106
|
+
f(null), e.onClick();
|
|
103
107
|
},
|
|
104
|
-
children: /* @__PURE__ */
|
|
105
|
-
className:
|
|
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__ */
|
|
113
|
-
ref:
|
|
116
|
+
children: /* @__PURE__ */ l("span", {
|
|
117
|
+
ref: h(N),
|
|
114
118
|
className: "flex shrink-0 flex-nowrap items-center gap-2",
|
|
115
|
-
children: [
|
|
119
|
+
children: [s && b(s, "outlined", "secondary"), d && b(d, "contained", "primary")]
|
|
116
120
|
})
|
|
117
121
|
})]
|
|
118
122
|
});
|
|
119
123
|
}
|
|
120
124
|
export {
|
|
121
|
-
|
|
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,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,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.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
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
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
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 -
|
|
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,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
|
+
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.
|
|
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",
|