@godxjp/ui 20.0.0 → 20.1.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/README.md +8 -2
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +12 -1
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +7 -1
- package/dist/components/data-display/popover.d.ts +2 -2
- package/dist/components/data-display/popover.js +61 -11
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +10 -10
- package/dist/components/data-display/table.d.ts +11 -3
- package/dist/components/data-display/table.js +48 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +12 -1
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +4 -2
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/month-picker.d.ts +1 -1
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +1 -1
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +86 -28
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +201 -113
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +475 -115
- package/dist/components/feedback/dialog.js +16 -19
- package/dist/components/general/button.d.ts +1 -1
- package/dist/components/general/button.js +5 -1
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +228 -0
- package/dist/components/layout/app-shell.d.ts +2 -0
- package/dist/components/layout/app-shell.js +20 -7
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +23 -2
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/org-switcher.js +20 -1
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +18 -3
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/dropdown-menu.d.ts +30 -2
- package/dist/components/navigation/dropdown-menu.js +68 -11
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +5 -33
- package/dist/components/navigation/tabs.js +232 -64
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +9 -0
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +13 -0
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/messages/en.json +56 -5
- package/dist/i18n/messages/ja.json +56 -5
- package/dist/i18n/messages/vi.json +56 -5
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +55 -4
- package/dist/props/components/data-entry.prop.d.ts +687 -43
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +17 -1
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +163 -6
- package/dist/props/components/navigation.prop.d.ts +113 -3
- package/dist/props/registry.d.ts +376 -10
- package/dist/props/registry.js +493 -9
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +4 -4
- package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +26 -4
- package/dist/styles/chart-layout.css +15 -0
- package/dist/styles/control.css +515 -14
- package/dist/styles/data-display-layout.css +241 -6
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/layout.css +221 -4
- package/dist/styles/navigation-layout.css +227 -0
- package/dist/styles/shell-layout.css +229 -5
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +5 -0
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +79 -2
- package/dist/tokens/components/data-display.css +9 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +50 -2
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +43 -6
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +29 -16
- package/docs/README.md +1 -1
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/select.tsx +27 -0
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +151 -0
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +11 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/package.json +19 -2
- package/scripts/_agent-setup.mjs +19 -2
- package/scripts/init-guinea-pig.mjs +26 -4
- package/scripts/ui-audit.mjs +243 -30
|
@@ -9,7 +9,12 @@ const Rating = React.forwardRef(
|
|
|
9
9
|
value,
|
|
10
10
|
defaultValue = 0,
|
|
11
11
|
onValueChange,
|
|
12
|
-
max
|
|
12
|
+
max,
|
|
13
|
+
count,
|
|
14
|
+
allowHalf = false,
|
|
15
|
+
allowClear = false,
|
|
16
|
+
character,
|
|
17
|
+
tooltips,
|
|
13
18
|
readOnly,
|
|
14
19
|
disabled,
|
|
15
20
|
name,
|
|
@@ -17,68 +22,103 @@ const Rating = React.forwardRef(
|
|
|
17
22
|
...rest
|
|
18
23
|
}, ref) => {
|
|
19
24
|
const { t } = useTranslation();
|
|
25
|
+
const symbols = count ?? max ?? 5;
|
|
20
26
|
const [internal, setInternal] = React.useState(defaultValue);
|
|
21
27
|
const current = value ?? internal;
|
|
22
28
|
const [hover, setHover] = React.useState(null);
|
|
23
29
|
const display = hover ?? current;
|
|
24
30
|
const interactive = !readOnly && !disabled;
|
|
31
|
+
const stepSize = allowHalf ? 0.5 : 1;
|
|
25
32
|
const select = (next) => {
|
|
26
33
|
if (!interactive) return;
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
const resolved = allowClear && next === current ? 0 : next;
|
|
35
|
+
if (value === void 0) setInternal(resolved);
|
|
36
|
+
onValueChange?.(resolved);
|
|
29
37
|
};
|
|
30
|
-
const focusableStar = current > 0 ? current : 1;
|
|
38
|
+
const focusableStar = current > 0 ? Math.ceil(current) : 1;
|
|
31
39
|
const onKeyDown = (e, star) => {
|
|
32
40
|
if (!interactive) return;
|
|
33
41
|
let next;
|
|
34
42
|
switch (e.key) {
|
|
35
43
|
case "ArrowRight":
|
|
36
44
|
case "ArrowUp":
|
|
37
|
-
next = Math.min(
|
|
45
|
+
next = Math.min(symbols, star + stepSize);
|
|
38
46
|
break;
|
|
39
47
|
case "ArrowLeft":
|
|
40
48
|
case "ArrowDown":
|
|
41
|
-
next = Math.max(
|
|
49
|
+
next = Math.max(stepSize, star - stepSize);
|
|
42
50
|
break;
|
|
43
51
|
case "Home":
|
|
44
|
-
next =
|
|
52
|
+
next = stepSize;
|
|
45
53
|
break;
|
|
46
54
|
case "End":
|
|
47
|
-
next =
|
|
55
|
+
next = symbols;
|
|
48
56
|
break;
|
|
49
57
|
default:
|
|
50
58
|
return;
|
|
51
59
|
}
|
|
52
60
|
e.preventDefault();
|
|
53
|
-
|
|
61
|
+
if (value === void 0) setInternal(next);
|
|
62
|
+
onValueChange?.(next);
|
|
63
|
+
};
|
|
64
|
+
const stepLabel = (star) => {
|
|
65
|
+
const tooltip = tooltips?.[star - 1];
|
|
66
|
+
const base = t("ui.rating.starLabel", { star, max: symbols });
|
|
67
|
+
return tooltip ? `${base}, ${tooltip}` : base;
|
|
54
68
|
};
|
|
69
|
+
const glyph = (star) => typeof character === "function" ? character(star) : character ?? /* @__PURE__ */ jsx(Star, { "aria-hidden": "true" });
|
|
55
70
|
return /* @__PURE__ */ jsxs(
|
|
56
71
|
"div",
|
|
57
72
|
{
|
|
58
73
|
ref,
|
|
59
74
|
role: "radiogroup",
|
|
60
75
|
"data-slot": "rating",
|
|
76
|
+
"data-allow-half": allowHalf ? "true" : void 0,
|
|
61
77
|
className: cn("ui-rating", className),
|
|
62
78
|
"aria-label": rest["aria-label"] ?? t("ui.rating.ariaLabel"),
|
|
63
79
|
children: [
|
|
64
|
-
Array.from({ length:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
Array.from({ length: symbols }, (_, i) => i + 1).map((star) => {
|
|
81
|
+
const symbol = /* @__PURE__ */ jsx(
|
|
82
|
+
"button",
|
|
83
|
+
{
|
|
84
|
+
type: "button",
|
|
85
|
+
role: "radio",
|
|
86
|
+
"aria-checked": current === star,
|
|
87
|
+
"aria-label": stepLabel(star),
|
|
88
|
+
disabled: disabled || readOnly,
|
|
89
|
+
tabIndex: interactive && star === focusableStar ? 0 : -1,
|
|
90
|
+
className: cn(
|
|
91
|
+
"ui-rating-star",
|
|
92
|
+
star <= display && "ui-rating-star-filled",
|
|
93
|
+
allowHalf && star - 0.5 === display && "ui-rating-star-half-filled"
|
|
94
|
+
),
|
|
95
|
+
onMouseEnter: () => interactive && setHover(star),
|
|
96
|
+
onMouseLeave: () => setHover(null),
|
|
97
|
+
onClick: () => select(star),
|
|
98
|
+
onKeyDown: (e) => onKeyDown(e, star),
|
|
99
|
+
children: glyph(star)
|
|
100
|
+
},
|
|
101
|
+
star
|
|
102
|
+
);
|
|
103
|
+
if (!allowHalf) return symbol;
|
|
104
|
+
return /* @__PURE__ */ jsxs("span", { "data-slot": "rating-symbol", className: "ui-rating-symbol", children: [
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
"button",
|
|
107
|
+
{
|
|
108
|
+
type: "button",
|
|
109
|
+
tabIndex: -1,
|
|
110
|
+
"aria-hidden": "true",
|
|
111
|
+
disabled: disabled || readOnly,
|
|
112
|
+
"data-slot": "rating-half",
|
|
113
|
+
className: "ui-rating-star-half",
|
|
114
|
+
onMouseEnter: () => interactive && setHover(star - 0.5),
|
|
115
|
+
onMouseLeave: () => setHover(null),
|
|
116
|
+
onClick: () => select(star - 0.5)
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
symbol
|
|
120
|
+
] }, star);
|
|
121
|
+
}),
|
|
82
122
|
name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: current }) : null
|
|
83
123
|
]
|
|
84
124
|
}
|
|
@@ -18,6 +18,15 @@ export type SegmentedProp = {
|
|
|
18
18
|
/** Uncontrolled initial selection. */
|
|
19
19
|
defaultValue?: string;
|
|
20
20
|
onValueChange?: (value: string) => void;
|
|
21
|
+
/**
|
|
22
|
+
* antd `block` — stretch the bar to its container and share the width EQUALLY between the
|
|
23
|
+
* choices, so the selected pill does not resize as the label changes length.
|
|
24
|
+
*/
|
|
25
|
+
block?: boolean;
|
|
26
|
+
/** antd `vertical` — stack the choices in a column. Arrow keys follow the axis. */
|
|
27
|
+
vertical?: boolean;
|
|
28
|
+
/** Control height tier: `md` (default), `sm` or `lg` — the same tiers as every other control. */
|
|
29
|
+
size?: "sm" | "md" | "lg";
|
|
21
30
|
/** Disable the whole group. */
|
|
22
31
|
disabled?: boolean;
|
|
23
32
|
/** Form field name — submits the selected value with the form. */
|
|
@@ -3,15 +3,30 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
5
5
|
import { cn } from "../../lib/utils.js";
|
|
6
|
-
const Segmented = React.forwardRef(function Segmented2({
|
|
6
|
+
const Segmented = React.forwardRef(function Segmented2({
|
|
7
|
+
options,
|
|
8
|
+
value,
|
|
9
|
+
defaultValue,
|
|
10
|
+
onValueChange,
|
|
11
|
+
disabled,
|
|
12
|
+
block = false,
|
|
13
|
+
vertical = false,
|
|
14
|
+
size,
|
|
15
|
+
name,
|
|
16
|
+
id,
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
}, ref) {
|
|
7
20
|
return /* @__PURE__ */ jsx(
|
|
8
21
|
RadioGroupPrimitive.Root,
|
|
9
22
|
{
|
|
10
23
|
ref,
|
|
11
24
|
id,
|
|
12
25
|
"data-slot": "segmented",
|
|
26
|
+
"data-block": block ? "true" : void 0,
|
|
27
|
+
"data-size": size,
|
|
13
28
|
className: cn("ui-segmented", className),
|
|
14
|
-
orientation: "horizontal",
|
|
29
|
+
orientation: vertical ? "vertical" : "horizontal",
|
|
15
30
|
value,
|
|
16
31
|
defaultValue,
|
|
17
32
|
onValueChange,
|
|
@@ -12,6 +12,10 @@ export type { SeparatorProp, SeparatorProp as SeparatorProps, } from "../../prop
|
|
|
12
12
|
* the ref, and we decide what element carries them.
|
|
13
13
|
*/
|
|
14
14
|
export declare const Separator: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
15
|
+
labelSize?: "2xs" | "xs" | "sm" | "md";
|
|
16
|
+
space?: import("../../props/index.js").GapProp;
|
|
17
|
+
hideBelow?: import("../../props/index.js").BreakpointProp;
|
|
18
|
+
hideFrom?: import("../../props/index.js").BreakpointProp;
|
|
15
19
|
orientation?: import("../../props/index.js").OrientationProp;
|
|
16
20
|
label?: string;
|
|
17
21
|
labelAlign?: import("../../props/index.js").TextAlignProp;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Separator as AriaSeparator } from "react-aria-components";
|
|
4
|
+
import { padStepToken } from "../../lib/variants.js";
|
|
4
5
|
import { cn } from "../../lib/utils.js";
|
|
5
6
|
const Separator = React.forwardRef(
|
|
6
7
|
({
|
|
7
8
|
className,
|
|
9
|
+
labelSize,
|
|
10
|
+
space,
|
|
11
|
+
hideBelow,
|
|
12
|
+
hideFrom,
|
|
13
|
+
style,
|
|
8
14
|
orientation = "horizontal",
|
|
9
15
|
decorative,
|
|
10
16
|
label,
|
|
@@ -28,6 +34,13 @@ const Separator = React.forwardRef(
|
|
|
28
34
|
ref,
|
|
29
35
|
elementType: "div",
|
|
30
36
|
"data-slot": "separator",
|
|
37
|
+
"data-label-size": labelSize,
|
|
38
|
+
"data-hide-below": hideBelow,
|
|
39
|
+
"data-hide-from": hideFrom,
|
|
40
|
+
style: {
|
|
41
|
+
...style,
|
|
42
|
+
...space === void 0 ? void 0 : { marginBlock: padStepToken(space) }
|
|
43
|
+
},
|
|
31
44
|
"data-orientation": orientation,
|
|
32
45
|
"data-tone": tone,
|
|
33
46
|
"data-labelled": labelled ? "" : void 0,
|
|
@@ -1,13 +1,58 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import type { AllowClearProp, ControlStatusProp, ControlVariantProp, MaxTagCountProp, MaxTagPlaceholderProp, SizeProp } from "../../props/vocabulary/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* TagInput is this library's answer to antd's `Select mode="tags"` — a free-text token field — so
|
|
5
|
+
* it takes the same token-level props antd puts on that mode.
|
|
6
|
+
*/
|
|
2
7
|
export type TagInputProps = {
|
|
3
8
|
value?: string[];
|
|
4
9
|
defaultValue?: string[];
|
|
5
10
|
onValueChange?: (tags: string[]) => void;
|
|
6
11
|
placeholder?: string;
|
|
7
12
|
disabled?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Read-only: the tags stay visible, selectable and submitted, but nothing can be added or
|
|
15
|
+
* removed — the draft field is read-only, the chip removers and the clear ✕ are withdrawn, and
|
|
16
|
+
* the container reports `aria-readonly`. Mirrors Select's readOnly contract (still focusable and
|
|
17
|
+
* still in the tab order, unlike `disabled`).
|
|
18
|
+
*/
|
|
19
|
+
readOnly?: boolean;
|
|
8
20
|
name?: string;
|
|
9
21
|
className?: string;
|
|
10
22
|
id?: string;
|
|
11
23
|
"aria-label"?: string;
|
|
24
|
+
/** Control height tier (antd `size`) — the shared `--control-height` ladder. */
|
|
25
|
+
size?: SizeProp;
|
|
26
|
+
/** Validation status (antd `status`). `error` also sets `aria-invalid`; `warning` recolours only. */
|
|
27
|
+
status?: ControlStatusProp;
|
|
28
|
+
/** Control surface (antd `variant`). Default `outlined`. */
|
|
29
|
+
variant?: ControlVariantProp;
|
|
30
|
+
/** Hard ceiling on how many tags may be held (antd `maxCount`). Further input is refused. */
|
|
31
|
+
maxCount?: number;
|
|
32
|
+
/**
|
|
33
|
+
* antd `allowClear` — a single ✕ that drops EVERY tag at once. Off by default (antd's own
|
|
34
|
+
* default for a tags field). The object form replaces the icon and/or the accessible label.
|
|
35
|
+
*/
|
|
36
|
+
allowClear?: AllowClearProp;
|
|
37
|
+
/** Fired after every tag is dropped through the ✕ (antd `onClear`). */
|
|
38
|
+
onClear?: () => void;
|
|
39
|
+
/** How many chips render before the rest collapse into the overflow node (antd `maxTagCount`). */
|
|
40
|
+
maxTagCount?: MaxTagCountProp;
|
|
41
|
+
/** The node standing in for what `maxTagCount` hid (antd `maxTagPlaceholder`). */
|
|
42
|
+
maxTagPlaceholder?: MaxTagPlaceholderProp;
|
|
43
|
+
/** Render one chip yourself (antd `tagRender`) — receives the value and an `onClose` remover. */
|
|
44
|
+
tagRender?: (props: {
|
|
45
|
+
value: string;
|
|
46
|
+
label: React.ReactNode;
|
|
47
|
+
onClose: () => void;
|
|
48
|
+
index: number;
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
}) => React.ReactNode;
|
|
51
|
+
/**
|
|
52
|
+
* Characters that commit the draft into a tag (antd `tokenSeparators`). Default `[","]`; Enter
|
|
53
|
+
* always commits and is not a separator. Pasting a run containing a separator splits it into
|
|
54
|
+
* several tags, which is antd's behaviour and the reason the prop exists.
|
|
55
|
+
*/
|
|
56
|
+
tokenSeparators?: string[];
|
|
12
57
|
};
|
|
13
58
|
export declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import {
|
|
8
|
+
applyMaxTagCount,
|
|
9
|
+
controlSurfaceAttrs,
|
|
10
|
+
resolveAllowClear
|
|
11
|
+
} from "../data-entry/control-surface.js";
|
|
12
|
+
function escapeForCharClass(character) {
|
|
13
|
+
return character.replace(/[\\\]^-]/g, "\\$&");
|
|
14
|
+
}
|
|
7
15
|
const TagInput = React.forwardRef(
|
|
8
16
|
({
|
|
9
17
|
value,
|
|
@@ -11,10 +19,21 @@ const TagInput = React.forwardRef(
|
|
|
11
19
|
onValueChange,
|
|
12
20
|
placeholder,
|
|
13
21
|
disabled,
|
|
22
|
+
readOnly,
|
|
14
23
|
name,
|
|
15
24
|
className,
|
|
16
25
|
id,
|
|
17
|
-
"aria-label": ariaLabel
|
|
26
|
+
"aria-label": ariaLabel,
|
|
27
|
+
size,
|
|
28
|
+
status,
|
|
29
|
+
variant,
|
|
30
|
+
maxCount,
|
|
31
|
+
allowClear,
|
|
32
|
+
onClear,
|
|
33
|
+
maxTagCount,
|
|
34
|
+
maxTagPlaceholder,
|
|
35
|
+
tagRender,
|
|
36
|
+
tokenSeparators = [","]
|
|
18
37
|
}, ref) => {
|
|
19
38
|
const { t } = useTranslation();
|
|
20
39
|
const [internal, setInternal] = React.useState(defaultValue);
|
|
@@ -27,11 +46,25 @@ const TagInput = React.forwardRef(
|
|
|
27
46
|
const add = (raw) => {
|
|
28
47
|
const tag = raw.trim();
|
|
29
48
|
if (!tag || tags.includes(tag)) return;
|
|
49
|
+
if (maxCount !== void 0 && tags.length >= maxCount) return;
|
|
30
50
|
commit([...tags, tag]);
|
|
31
51
|
};
|
|
52
|
+
const addAll = (raw) => {
|
|
53
|
+
let next = [...tags];
|
|
54
|
+
const pieces = tokenSeparators.length ? raw.split(new RegExp(`[${tokenSeparators.map(escapeForCharClass).join("")}]`)) : [raw];
|
|
55
|
+
for (const piece of pieces) {
|
|
56
|
+
const tag = piece.trim();
|
|
57
|
+
if (!tag || next.includes(tag)) continue;
|
|
58
|
+
if (maxCount !== void 0 && next.length >= maxCount) break;
|
|
59
|
+
next = [...next, tag];
|
|
60
|
+
}
|
|
61
|
+
if (next.length !== tags.length) commit(next);
|
|
62
|
+
};
|
|
32
63
|
const removeAt = (i) => commit(tags.filter((_, idx) => idx !== i));
|
|
33
64
|
const onKeyDown = (e) => {
|
|
34
|
-
if (
|
|
65
|
+
if (readOnly) return;
|
|
66
|
+
if (e.nativeEvent.isComposing) return;
|
|
67
|
+
if (e.key === "Enter" || tokenSeparators.includes(e.key)) {
|
|
35
68
|
e.preventDefault();
|
|
36
69
|
add(draft);
|
|
37
70
|
setDraft("");
|
|
@@ -39,35 +72,63 @@ const TagInput = React.forwardRef(
|
|
|
39
72
|
removeAt(tags.length - 1);
|
|
40
73
|
}
|
|
41
74
|
};
|
|
75
|
+
const clearControl = resolveAllowClear(allowClear, false, t("common.clear"));
|
|
76
|
+
const showClear = clearControl.enabled && tags.length > 0 && !disabled && !readOnly;
|
|
77
|
+
const clearAll = () => {
|
|
78
|
+
commit([]);
|
|
79
|
+
onClear?.();
|
|
80
|
+
};
|
|
81
|
+
const chips = tags.map((tag, index) => ({ value: tag, label: tag, index }));
|
|
82
|
+
const {
|
|
83
|
+
visible: visibleChips,
|
|
84
|
+
omitted: omittedChips,
|
|
85
|
+
overflow
|
|
86
|
+
} = applyMaxTagCount(chips, maxTagCount, maxTagPlaceholder);
|
|
42
87
|
return /* @__PURE__ */ jsxs(
|
|
43
88
|
"div",
|
|
44
89
|
{
|
|
45
90
|
"data-slot": "tag-input",
|
|
46
91
|
"aria-disabled": disabled || void 0,
|
|
47
|
-
|
|
92
|
+
"aria-readonly": readOnly || void 0,
|
|
93
|
+
...controlSurfaceAttrs({ variant, status, size }),
|
|
94
|
+
"aria-invalid": status === "error" ? true : void 0,
|
|
95
|
+
className: cn(
|
|
96
|
+
"ui-tag-input ui-control-surface",
|
|
97
|
+
disabled && "ui-tag-input-disabled",
|
|
98
|
+
className
|
|
99
|
+
),
|
|
48
100
|
children: [
|
|
49
|
-
tags.length > 0 ? /* @__PURE__ */
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
101
|
+
tags.length > 0 ? /* @__PURE__ */ jsxs("ul", { role: "list", className: "ui-tag-input-list", "data-slot": "tag-input-list", children: [
|
|
102
|
+
visibleChips.map((chip) => /* @__PURE__ */ jsx(
|
|
103
|
+
"li",
|
|
104
|
+
{
|
|
105
|
+
role: "listitem",
|
|
106
|
+
className: "ui-tag-input-chip",
|
|
107
|
+
"data-slot": "tag-input-chip",
|
|
108
|
+
children: tagRender ? tagRender({
|
|
109
|
+
value: chip.value,
|
|
110
|
+
label: chip.label,
|
|
111
|
+
index: chip.index,
|
|
112
|
+
disabled: Boolean(disabled) || Boolean(readOnly),
|
|
113
|
+
onClose: () => removeAt(chip.index)
|
|
114
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
115
|
+
chip.value,
|
|
116
|
+
!disabled && !readOnly ? /* @__PURE__ */ jsx(
|
|
117
|
+
"button",
|
|
118
|
+
{
|
|
119
|
+
type: "button",
|
|
120
|
+
className: "ui-tag-input-remove",
|
|
121
|
+
"aria-label": t("ui.tagInput.removeTag", { tag: chip.value }),
|
|
122
|
+
onClick: () => removeAt(chip.index),
|
|
123
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
124
|
+
}
|
|
125
|
+
) : null
|
|
126
|
+
] })
|
|
127
|
+
},
|
|
128
|
+
chip.value
|
|
129
|
+
)),
|
|
130
|
+
omittedChips.length > 0 ? /* @__PURE__ */ jsx("li", { role: "listitem", className: "ui-tag-input-chip", "data-slot": "tag-input-overflow", children: overflow ?? t("dataEntry.selection.overflow", { count: omittedChips.length }) }) : null
|
|
131
|
+
] }) : null,
|
|
71
132
|
/* @__PURE__ */ jsx(
|
|
72
133
|
"input",
|
|
73
134
|
{
|
|
@@ -76,12 +137,21 @@ const TagInput = React.forwardRef(
|
|
|
76
137
|
type: "text",
|
|
77
138
|
className: "ui-tag-input-field",
|
|
78
139
|
value: draft,
|
|
79
|
-
placeholder: tags.length === 0 ? placeholder : void 0,
|
|
140
|
+
placeholder: tags.length === 0 && !readOnly ? placeholder : void 0,
|
|
80
141
|
disabled,
|
|
142
|
+
readOnly,
|
|
81
143
|
"aria-label": ariaLabel ?? t("ui.tagInput.inputLabel"),
|
|
82
144
|
onChange: (e) => setDraft(e.target.value),
|
|
83
145
|
onKeyDown,
|
|
146
|
+
onPaste: (e) => {
|
|
147
|
+
const text = e.clipboardData.getData("text");
|
|
148
|
+
if (!tokenSeparators.some((separator) => text.includes(separator))) return;
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
addAll(text);
|
|
151
|
+
setDraft("");
|
|
152
|
+
},
|
|
84
153
|
onBlur: () => {
|
|
154
|
+
if (readOnly) return;
|
|
85
155
|
if (draft.trim()) {
|
|
86
156
|
add(draft);
|
|
87
157
|
setDraft("");
|
|
@@ -89,6 +159,18 @@ const TagInput = React.forwardRef(
|
|
|
89
159
|
}
|
|
90
160
|
}
|
|
91
161
|
),
|
|
162
|
+
showClear ? /* @__PURE__ */ jsx(
|
|
163
|
+
"button",
|
|
164
|
+
{
|
|
165
|
+
type: "button",
|
|
166
|
+
tabIndex: -1,
|
|
167
|
+
"aria-label": clearControl.label,
|
|
168
|
+
"data-slot": "tag-input-clear",
|
|
169
|
+
className: "ui-control-inline-affix-action ui-tag-input-clear",
|
|
170
|
+
onClick: clearAll,
|
|
171
|
+
children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
|
|
172
|
+
}
|
|
173
|
+
) : null,
|
|
92
174
|
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", "data-slot": "tag-input-status", children: t("ui.tagInput.tagCount", { count: tags.length }) }),
|
|
93
175
|
name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: tags.join(",") }) : null
|
|
94
176
|
]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Control, type FieldPath, type FieldValues, type UseFormReturn } from "react-hook-form";
|
|
1
2
|
import type { FormStateAdapter } from "../props/components/form.prop.js";
|
|
2
3
|
/**
|
|
3
4
|
* Context carrying a framework-agnostic {@link FormStateAdapter}. `FormRoot` provides it on the
|
|
@@ -7,11 +8,39 @@ import type { FormStateAdapter } from "../props/components/form.prop.js";
|
|
|
7
8
|
export declare const FormAdapterContext: import("react").Context<FormStateAdapter | null>;
|
|
8
9
|
/** Read the active form-state adapter, or `null` when `FormRoot` runs the react-hook-form path. */
|
|
9
10
|
export declare function useFormAdapter(): FormStateAdapter | null;
|
|
11
|
+
/** Form-wide options shared by BOTH paths — currently the antd-style form-level `disabled`. */
|
|
12
|
+
export interface FormOptionsContextValue {
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
submitting?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Defaults to enabled so a `FormField`/`FormFieldControl` outside a `FormRoot` keeps working. */
|
|
17
|
+
export declare const FormOptionsContext: import("react").Context<FormOptionsContextValue>;
|
|
18
|
+
/**
|
|
19
|
+
* Whether the surrounding `FormRoot` disables its fields (`FormRoot disabled`). Read it for the
|
|
20
|
+
* action buttons, which are NOT fields and so are never disabled automatically.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useFormDisabled(): boolean;
|
|
10
23
|
/**
|
|
11
24
|
* Whether the surrounding `FormRoot` is currently submitting — works for BOTH paths: the adapter's
|
|
12
25
|
* `isSubmitting` (e.g. Inertia's `processing`) or react-hook-form's `formState.isSubmitting`.
|
|
13
26
|
*/
|
|
14
27
|
export declare function useFormSubmitting(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The react-hook-form instance of the surrounding `FormRoot` (antd `Form.useFormInstance`) — for
|
|
30
|
+
* `setValue`/`trigger`/`getValues` deep inside a form without prop-drilling `form`. Throws on the
|
|
31
|
+
* adapter path, which has no RHF instance; use {@link useFormAdapter} there.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useFormInstance<TFieldValues extends FieldValues = FieldValues>(): UseFormReturn<TFieldValues>;
|
|
34
|
+
export declare function getFallbackFormControl(): Control<FieldValues>;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to a field's value (antd `Form.useWatch`) — the "show this section only when `plan`
|
|
37
|
+
* is `enterprise`" case, WITHOUT re-rendering the whole form. Omit `name` for every value.
|
|
38
|
+
* Works on both paths: react-hook-form's `useWatch`, or the adapter's `getValue`/`getValues`.
|
|
39
|
+
*
|
|
40
|
+
* Returns `unknown` — the same contract as `FormFieldControl`'s render-prop `value`. Narrow at the
|
|
41
|
+
* call site (`String(v ?? "")`, a Zod parse, a type guard).
|
|
42
|
+
*/
|
|
43
|
+
export declare function useFormWatch<TFieldValues extends FieldValues = FieldValues>(name?: FieldPath<TFieldValues>): unknown;
|
|
15
44
|
/**
|
|
16
45
|
* Normalise a control's change payload to a bare value. The `FormFieldControl` render-prop spreads
|
|
17
46
|
* `onChange` onto a control that may call it with a DOM `ChangeEvent` (native `<Input>`) OR a raw
|
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createFormControl,
|
|
5
|
+
useFormContext,
|
|
6
|
+
useWatch
|
|
7
|
+
} from "react-hook-form";
|
|
4
8
|
const FormAdapterContext = createContext(null);
|
|
5
9
|
function useFormAdapter() {
|
|
6
10
|
return useContext(FormAdapterContext);
|
|
7
11
|
}
|
|
12
|
+
const FormOptionsContext = createContext({ disabled: false });
|
|
13
|
+
function useFormDisabled() {
|
|
14
|
+
return useContext(FormOptionsContext).disabled;
|
|
15
|
+
}
|
|
8
16
|
function useFormSubmitting() {
|
|
17
|
+
const { submitting } = useContext(FormOptionsContext);
|
|
18
|
+
const adapter = useContext(FormAdapterContext);
|
|
19
|
+
const rhf = useFormContext();
|
|
20
|
+
if (adapter) return Boolean(submitting || adapter.isSubmitting);
|
|
21
|
+
return Boolean(submitting || rhf?.formState?.isSubmitting);
|
|
22
|
+
}
|
|
23
|
+
function useFormInstance() {
|
|
24
|
+
const rhf = useFormContext();
|
|
25
|
+
if (!rhf) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"useFormInstance must be rendered inside <FormRoot form={\u2026}> (react-hook-form path). On the adapter path use useFormAdapter()."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return rhf;
|
|
31
|
+
}
|
|
32
|
+
let fallbackControl;
|
|
33
|
+
function getFallbackFormControl() {
|
|
34
|
+
fallbackControl ??= createFormControl().control;
|
|
35
|
+
return fallbackControl;
|
|
36
|
+
}
|
|
37
|
+
function useFormWatch(name) {
|
|
9
38
|
const adapter = useContext(FormAdapterContext);
|
|
10
39
|
const rhf = useFormContext();
|
|
11
|
-
|
|
12
|
-
|
|
40
|
+
const control = rhf?.control ?? getFallbackFormControl();
|
|
41
|
+
const watched = useWatch({
|
|
42
|
+
control,
|
|
43
|
+
name,
|
|
44
|
+
disabled: !rhf
|
|
45
|
+
});
|
|
46
|
+
if (adapter) return name === void 0 ? adapter.getValues?.() : adapter.getValue(name);
|
|
47
|
+
return watched;
|
|
13
48
|
}
|
|
14
49
|
function extractControlValue(arg) {
|
|
15
50
|
if (arg && typeof arg === "object" && "target" in arg) {
|
|
@@ -23,7 +58,12 @@ function extractControlValue(arg) {
|
|
|
23
58
|
}
|
|
24
59
|
export {
|
|
25
60
|
FormAdapterContext,
|
|
61
|
+
FormOptionsContext,
|
|
26
62
|
extractControlValue,
|
|
63
|
+
getFallbackFormControl,
|
|
27
64
|
useFormAdapter,
|
|
28
|
-
|
|
65
|
+
useFormDisabled,
|
|
66
|
+
useFormInstance,
|
|
67
|
+
useFormSubmitting,
|
|
68
|
+
useFormWatch
|
|
29
69
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type FieldArrayPath, type FieldValues } from "react-hook-form";
|
|
3
|
+
import type { FormFieldArrayProp } from "../props/components/form.prop.js";
|
|
4
|
+
export type { FormFieldArrayProp } from "../props/components/form.prop.js";
|
|
5
|
+
/**
|
|
6
|
+
* FormFieldArray — repeating fields (antd `Form.List`) on react-hook-form's `useFieldArray`, so
|
|
7
|
+
* rows keep their identity across insert/remove/move instead of being re-keyed by index.
|
|
8
|
+
*
|
|
9
|
+
* Each row hands back its dotted path prefix; build the child field name from it, which is what
|
|
10
|
+
* makes nested validation messages land on the right row:
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <FormFieldArray<Values, "contacts"> name="contacts">
|
|
14
|
+
* {({ fields, append, remove }) => (…
|
|
15
|
+
* <FormFieldControl name={`${row.name}.email`} label={t("contact.email")}>…
|
|
16
|
+
* )}
|
|
17
|
+
* </FormFieldArray>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* react-hook-form path only — a server-driven `adapter` owns its own collection state.
|
|
21
|
+
*/
|
|
22
|
+
export declare function FormFieldArray<TFieldValues extends FieldValues, TName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>>({ name, children }: FormFieldArrayProp<TFieldValues, TName>): React.JSX.Element;
|