@object-ui/plugin-form 2.0.0 → 3.0.1
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/.turbo/turbo-build.log +14 -5
- package/CHANGELOG.md +32 -0
- package/dist/index.js +40 -40
- package/dist/index.umd.cjs +2 -2
- package/dist/packages/plugin-form/src/ObjectForm.stories.d.ts +23 -0
- package/dist/packages/plugin-form/src/__tests__/form-validation-submit.test.d.ts +8 -0
- package/package.json +9 -9
- package/src/ObjectForm.stories.tsx +85 -0
- package/src/ObjectForm.tsx +2 -2
- package/src/WizardForm.tsx +5 -5
- package/src/__tests__/form-validation-submit.test.tsx +286 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @object-ui/plugin-form@
|
|
2
|
+
> @object-ui/plugin-form@3.0.1 build /home/runner/work/objectui/objectui/packages/plugin-form
|
|
3
3
|
> vite build
|
|
4
4
|
|
|
5
5
|
[36mvite v7.3.1 [32mbuilding client environment for production...[36m[39m
|
|
@@ -9,13 +9,22 @@ rendering chunks...
|
|
|
9
9
|
[32m
|
|
10
10
|
[36m[vite:dts][32m Start generate declaration files...[39m
|
|
11
11
|
computing gzip size...
|
|
12
|
-
[
|
|
13
|
-
|
|
12
|
+
[96m../../examples/crm/src/objects/contact.object.ts[0m:[93m3[0m:[93m14[0m - [91merror[0m[90m TS2742: [0mThe inferred type of 'ContactObject' cannot be named without a reference to 'examples/crm/node_modules/@objectstack/spec/dist/state-machine.zod-DoC0JvQb'. This is likely not portable. A type annotation is necessary.
|
|
13
|
+
|
|
14
|
+
[7m3[0m export const ContactObject = ObjectSchema.create({
|
|
15
|
+
[7m [0m [91m ~~~~~~~~~~~~~[0m
|
|
16
|
+
[96msrc/ObjectForm.stories.tsx[0m:[93m4[0m:[93m43[0m - [91merror[0m[90m TS2307: [0mCannot find module '@storybook-config/datasource' or its corresponding type declarations.
|
|
17
|
+
|
|
18
|
+
[7m4[0m import { createStorybookDataSource } from '@storybook-config/datasource';
|
|
19
|
+
[7m [0m [91m ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[0m
|
|
20
|
+
|
|
21
|
+
[2mdist/[22m[36mindex.js [39m[1m[2m53.50 kB[22m[1m[22m[2m │ gzip: 10.77 kB[22m
|
|
22
|
+
[32m[36m[vite:dts][32m Declaration files built in 22556ms.
|
|
14
23
|
[39m
|
|
15
24
|
[33mNo name was provided for external module "@object-ui/core" in "output.globals" – guessing "core".[39m
|
|
16
25
|
[33mNo name was provided for external module "@object-ui/react" in "output.globals" – guessing "react".[39m
|
|
17
26
|
[33mNo name was provided for external module "@object-ui/fields" in "output.globals" – guessing "fields".[39m
|
|
18
27
|
[33mNo name was provided for external module "@object-ui/components" in "output.globals" – guessing "components".[39m
|
|
19
28
|
[33mNo name was provided for external module "lucide-react" in "output.globals" – guessing "lucideReact".[39m
|
|
20
|
-
[2mdist/[22m[36mindex.umd.cjs [39m[1m[2m36.
|
|
21
|
-
[32m✓ built in
|
|
29
|
+
[2mdist/[22m[36mindex.umd.cjs [39m[1m[2m36.18 kB[22m[1m[22m[2m │ gzip: 9.06 kB[22m
|
|
30
|
+
[32m✓ built in 23.98s[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @object-ui/plugin-form
|
|
2
2
|
|
|
3
|
+
## 3.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [adf2cc0]
|
|
8
|
+
- @object-ui/react@3.0.1
|
|
9
|
+
- @object-ui/components@3.0.1
|
|
10
|
+
- @object-ui/fields@3.0.1
|
|
11
|
+
- @object-ui/types@3.0.1
|
|
12
|
+
- @object-ui/core@3.0.1
|
|
13
|
+
|
|
14
|
+
## 3.0.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
|
|
19
|
+
- Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
|
|
20
|
+
- Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
|
|
21
|
+
- Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
|
|
22
|
+
- Added gzip + brotli pre-compression via vite-plugin-compression2
|
|
23
|
+
- Lazy MSW loading for build:server (~150 KB gzip saved)
|
|
24
|
+
- Added bundle analysis with rollup-plugin-visualizer
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [87979c3]
|
|
29
|
+
- @object-ui/types@3.0.0
|
|
30
|
+
- @object-ui/core@3.0.0
|
|
31
|
+
- @object-ui/react@3.0.0
|
|
32
|
+
- @object-ui/components@3.0.0
|
|
33
|
+
- @object-ui/fields@3.0.0
|
|
34
|
+
|
|
3
35
|
## 2.0.0
|
|
4
36
|
|
|
5
37
|
### Major Changes
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { cn as V, Tabs as je, TabsList as ge, TabsTrigger as we, TabsContent as
|
|
|
6
6
|
import { ChevronRight as pe, ChevronDown as ze, Check as Pe, ChevronLeft as Le } from "lucide-react";
|
|
7
7
|
var ee = { exports: {} }, B = {};
|
|
8
8
|
var ae;
|
|
9
|
-
function
|
|
9
|
+
function he() {
|
|
10
10
|
if (ae) return B;
|
|
11
11
|
ae = 1;
|
|
12
12
|
var e = /* @__PURE__ */ Symbol.for("react.transitional.element"), l = /* @__PURE__ */ Symbol.for("react.fragment");
|
|
@@ -29,7 +29,7 @@ function Ae() {
|
|
|
29
29
|
}
|
|
30
30
|
var X = {};
|
|
31
31
|
var de;
|
|
32
|
-
function
|
|
32
|
+
function Ae() {
|
|
33
33
|
return de || (de = 1, process.env.NODE_ENV !== "production" && (function() {
|
|
34
34
|
function e(r) {
|
|
35
35
|
if (r == null) return null;
|
|
@@ -54,7 +54,7 @@ function he() {
|
|
|
54
54
|
switch (typeof r.tag == "number" && console.error(
|
|
55
55
|
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
|
|
56
56
|
), r.$$typeof) {
|
|
57
|
-
case
|
|
57
|
+
case A:
|
|
58
58
|
return "Portal";
|
|
59
59
|
case s:
|
|
60
60
|
return r.displayName || "Context";
|
|
@@ -121,7 +121,7 @@ function he() {
|
|
|
121
121
|
}
|
|
122
122
|
function E(r, m) {
|
|
123
123
|
function O() {
|
|
124
|
-
|
|
124
|
+
h || (h = !0, console.error(
|
|
125
125
|
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
|
|
126
126
|
m
|
|
127
127
|
));
|
|
@@ -224,7 +224,7 @@ React keys must be passed directly to JSX without using spread:
|
|
|
224
224
|
function N(r) {
|
|
225
225
|
return typeof r == "object" && r !== null && r.$$typeof === P;
|
|
226
226
|
}
|
|
227
|
-
var D = J, P = /* @__PURE__ */ Symbol.for("react.transitional.element"),
|
|
227
|
+
var D = J, P = /* @__PURE__ */ Symbol.for("react.transitional.element"), A = /* @__PURE__ */ Symbol.for("react.portal"), F = /* @__PURE__ */ Symbol.for("react.fragment"), _ = /* @__PURE__ */ Symbol.for("react.strict_mode"), q = /* @__PURE__ */ Symbol.for("react.profiler"), u = /* @__PURE__ */ Symbol.for("react.consumer"), s = /* @__PURE__ */ Symbol.for("react.context"), n = /* @__PURE__ */ Symbol.for("react.forward_ref"), o = /* @__PURE__ */ Symbol.for("react.suspense"), a = /* @__PURE__ */ Symbol.for("react.suspense_list"), c = /* @__PURE__ */ Symbol.for("react.memo"), i = /* @__PURE__ */ Symbol.for("react.lazy"), v = /* @__PURE__ */ Symbol.for("react.activity"), $ = /* @__PURE__ */ Symbol.for("react.client.reference"), p = D.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, x = Object.prototype.hasOwnProperty, R = Array.isArray, L = console.createTask ? console.createTask : function() {
|
|
228
228
|
return null;
|
|
229
229
|
};
|
|
230
230
|
D = {
|
|
@@ -232,7 +232,7 @@ React keys must be passed directly to JSX without using spread:
|
|
|
232
232
|
return r();
|
|
233
233
|
}
|
|
234
234
|
};
|
|
235
|
-
var
|
|
235
|
+
var h, le = {}, ne = D.react_stack_bottom_frame.bind(
|
|
236
236
|
D,
|
|
237
237
|
b
|
|
238
238
|
)(), ie = L(d(b)), oe = {};
|
|
@@ -261,7 +261,7 @@ React keys must be passed directly to JSX without using spread:
|
|
|
261
261
|
}
|
|
262
262
|
var ce;
|
|
263
263
|
function Ve() {
|
|
264
|
-
return ce || (ce = 1, process.env.NODE_ENV === "production" ? ee.exports =
|
|
264
|
+
return ce || (ce = 1, process.env.NODE_ENV === "production" ? ee.exports = he() : ee.exports = Ae()), ee.exports;
|
|
265
265
|
}
|
|
266
266
|
var t = Ve();
|
|
267
267
|
const G = ({
|
|
@@ -378,7 +378,7 @@ const G = ({
|
|
|
378
378
|
} catch (n) {
|
|
379
379
|
throw e.onError && e.onError(n), n;
|
|
380
380
|
}
|
|
381
|
-
}, [e, l]),
|
|
381
|
+
}, [e, l]), A = k(() => {
|
|
382
382
|
e.onCancel && e.onCancel();
|
|
383
383
|
}, [e]), F = (s, n) => s.name || s.label || `tab-${n}`;
|
|
384
384
|
if (C)
|
|
@@ -401,7 +401,7 @@ const G = ({
|
|
|
401
401
|
showSubmit: e.showSubmit !== !1 && e.mode !== "view",
|
|
402
402
|
showCancel: e.showCancel !== !1,
|
|
403
403
|
onSubmit: P,
|
|
404
|
-
onCancel:
|
|
404
|
+
onCancel: A
|
|
405
405
|
}, u = e.tabPosition === "left" || e.tabPosition === "right";
|
|
406
406
|
return /* @__PURE__ */ t.jsx("div", { className: V("w-full", f, e.className), children: /* @__PURE__ */ t.jsxs(
|
|
407
407
|
je,
|
|
@@ -459,7 +459,7 @@ const G = ({
|
|
|
459
459
|
dataSource: l,
|
|
460
460
|
className: f
|
|
461
461
|
}) => {
|
|
462
|
-
const [d, w] = g(null), [b, T] = g({}), [E, S] = g(!0), [C, j] = g(null), [y, N] = g(0), [D, P] = g(/* @__PURE__ */ new Set()), [
|
|
462
|
+
const [d, w] = g(null), [b, T] = g({}), [E, S] = g(!0), [C, j] = g(null), [y, N] = g(0), [D, P] = g(/* @__PURE__ */ new Set()), [A, F] = g(!1), _ = e.sections.length, q = y === 0, u = y === _ - 1;
|
|
463
463
|
J.useEffect(() => {
|
|
464
464
|
(async () => {
|
|
465
465
|
if (!l) {
|
|
@@ -496,19 +496,19 @@ const G = ({
|
|
|
496
496
|
if (typeof R == "object")
|
|
497
497
|
x.push(R);
|
|
498
498
|
else if (d?.fields?.[L]) {
|
|
499
|
-
const
|
|
499
|
+
const h = d.fields[L];
|
|
500
500
|
x.push({
|
|
501
501
|
name: L,
|
|
502
|
-
label:
|
|
503
|
-
type: U(
|
|
504
|
-
required:
|
|
505
|
-
disabled: e.readOnly || e.mode === "view" ||
|
|
506
|
-
placeholder:
|
|
507
|
-
description:
|
|
508
|
-
validation: Y(
|
|
509
|
-
field:
|
|
510
|
-
options:
|
|
511
|
-
multiple:
|
|
502
|
+
label: h.label || L,
|
|
503
|
+
type: U(h.type),
|
|
504
|
+
required: h.required || !1,
|
|
505
|
+
disabled: e.readOnly || e.mode === "view" || h.readonly,
|
|
506
|
+
placeholder: h.placeholder,
|
|
507
|
+
description: h.help || h.description,
|
|
508
|
+
validation: Y(h),
|
|
509
|
+
field: h,
|
|
510
|
+
options: h.options,
|
|
511
|
+
multiple: h.multiple
|
|
512
512
|
});
|
|
513
513
|
} else
|
|
514
514
|
x.push({
|
|
@@ -556,7 +556,7 @@ const G = ({
|
|
|
556
556
|
const $ = e.sections[y];
|
|
557
557
|
return /* @__PURE__ */ t.jsxs("div", { className: V("w-full", f, e.className), children: [
|
|
558
558
|
e.showStepIndicator !== !1 && /* @__PURE__ */ t.jsx("nav", { "aria-label": "Progress", className: "mb-8", children: /* @__PURE__ */ t.jsx("ol", { className: "flex items-center", children: e.sections.map((p, x) => {
|
|
559
|
-
const R = x === y, L = D.has(x),
|
|
559
|
+
const R = x === y, L = D.has(x), h = e.allowSkip || L || x <= y;
|
|
560
560
|
return /* @__PURE__ */ t.jsxs(
|
|
561
561
|
"li",
|
|
562
562
|
{
|
|
@@ -568,7 +568,7 @@ const G = ({
|
|
|
568
568
|
x !== _ - 1 && /* @__PURE__ */ t.jsx(
|
|
569
569
|
"div",
|
|
570
570
|
{
|
|
571
|
-
className: "absolute top-4 left-
|
|
571
|
+
className: "absolute top-3 sm:top-4 left-6 -right-4 sm:left-10 sm:-right-2 h-0.5",
|
|
572
572
|
"aria-hidden": "true",
|
|
573
573
|
children: /* @__PURE__ */ t.jsx(
|
|
574
574
|
"div",
|
|
@@ -587,24 +587,24 @@ const G = ({
|
|
|
587
587
|
type: "button",
|
|
588
588
|
className: V(
|
|
589
589
|
"group relative flex items-center",
|
|
590
|
-
|
|
590
|
+
h ? "cursor-pointer" : "cursor-not-allowed"
|
|
591
591
|
),
|
|
592
592
|
onClick: () => v(x),
|
|
593
|
-
disabled: !
|
|
593
|
+
disabled: !h,
|
|
594
594
|
children: [
|
|
595
595
|
/* @__PURE__ */ t.jsx(
|
|
596
596
|
"span",
|
|
597
597
|
{
|
|
598
598
|
className: V(
|
|
599
|
-
"flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors",
|
|
599
|
+
"flex h-6 w-6 sm:h-8 sm:w-8 items-center justify-center rounded-full text-xs sm:text-sm font-medium transition-colors",
|
|
600
600
|
L && "bg-primary text-primary-foreground",
|
|
601
601
|
R && !L && "border-2 border-primary bg-background text-primary",
|
|
602
602
|
!R && !L && "border-2 border-muted bg-background text-muted-foreground"
|
|
603
603
|
),
|
|
604
|
-
children: L ? /* @__PURE__ */ t.jsx(Pe, { className: "h-4 w-4" }) : x + 1
|
|
604
|
+
children: L ? /* @__PURE__ */ t.jsx(Pe, { className: "h-3 w-3 sm:h-4 sm:w-4" }) : x + 1
|
|
605
605
|
}
|
|
606
606
|
),
|
|
607
|
-
/* @__PURE__ */ t.jsx("span", { className: "ml-3 text-sm font-medium hidden sm:block", children: /* @__PURE__ */ t.jsx(
|
|
607
|
+
/* @__PURE__ */ t.jsx("span", { className: "ml-2 sm:ml-3 text-xs sm:text-sm font-medium hidden sm:block", children: /* @__PURE__ */ t.jsx(
|
|
608
608
|
"span",
|
|
609
609
|
{
|
|
610
610
|
className: V(
|
|
@@ -674,8 +674,8 @@ const G = ({
|
|
|
674
674
|
K,
|
|
675
675
|
{
|
|
676
676
|
onClick: () => o(b),
|
|
677
|
-
disabled:
|
|
678
|
-
children:
|
|
677
|
+
disabled: A || e.mode === "view",
|
|
678
|
+
children: A ? "Submitting..." : e.submitText || (e.mode === "create" ? "Create" : "Update")
|
|
679
679
|
}
|
|
680
680
|
) : /* @__PURE__ */ t.jsxs(
|
|
681
681
|
K,
|
|
@@ -769,7 +769,7 @@ const G = ({
|
|
|
769
769
|
}
|
|
770
770
|
}, [e, l]), D = k(() => {
|
|
771
771
|
e.onCancel && e.onCancel();
|
|
772
|
-
}, [e]), P = Q(() => e.sections.slice(0, 1), [e.sections]),
|
|
772
|
+
}, [e]), P = Q(() => e.sections.slice(0, 1), [e.sections]), A = Q(() => e.sections.slice(1), [e.sections]);
|
|
773
773
|
Q(
|
|
774
774
|
() => e.sections.flatMap((s) => y(s)),
|
|
775
775
|
[e.sections, y]
|
|
@@ -814,10 +814,10 @@ const G = ({
|
|
|
814
814
|
o.name || o.label || a
|
|
815
815
|
)) });
|
|
816
816
|
return /* @__PURE__ */ t.jsx("div", { className: V("w-full", f, e.className), children: /* @__PURE__ */ t.jsxs(Ne, { orientation: F, className: "min-h-[300px] rounded-lg border", children: [
|
|
817
|
-
/* @__PURE__ */ t.jsx(se, { defaultSize: _, minSize: 20, children: u(P,
|
|
818
|
-
|
|
817
|
+
/* @__PURE__ */ t.jsx(se, { defaultSize: _, minSize: 20, children: u(P, A.length === 0) }),
|
|
818
|
+
A.length > 0 && /* @__PURE__ */ t.jsxs(t.Fragment, { children: [
|
|
819
819
|
/* @__PURE__ */ t.jsx(Se, { withHandle: e.splitResizable !== !1 }),
|
|
820
|
-
/* @__PURE__ */ t.jsx(se, { defaultSize: 100 - _, minSize: 20, children: u(
|
|
820
|
+
/* @__PURE__ */ t.jsx(se, { defaultSize: 100 - _, minSize: 20, children: u(A, !0) })
|
|
821
821
|
] })
|
|
822
822
|
] }) });
|
|
823
823
|
}, Me = ({
|
|
@@ -859,7 +859,7 @@ const G = ({
|
|
|
859
859
|
}
|
|
860
860
|
})();
|
|
861
861
|
}, [d, e.mode, e.recordId, e.initialData, e.initialValues, l, e.objectName]);
|
|
862
|
-
const
|
|
862
|
+
const A = k((o) => {
|
|
863
863
|
const a = [];
|
|
864
864
|
for (const c of o.fields) {
|
|
865
865
|
const i = typeof c == "string" ? c : c.name;
|
|
@@ -959,7 +959,7 @@ const G = ({
|
|
|
959
959
|
{
|
|
960
960
|
schema: {
|
|
961
961
|
...s,
|
|
962
|
-
fields:
|
|
962
|
+
fields: A(o),
|
|
963
963
|
showSubmit: a === e.sections.length - 1 && s.showSubmit,
|
|
964
964
|
showCancel: a === e.sections.length - 1 && s.showCancel
|
|
965
965
|
}
|
|
@@ -1037,7 +1037,7 @@ const G = ({
|
|
|
1037
1037
|
}
|
|
1038
1038
|
})();
|
|
1039
1039
|
}, [d, e.mode, e.recordId, e.initialData, e.initialValues, l, e.objectName]);
|
|
1040
|
-
const
|
|
1040
|
+
const A = k((n) => {
|
|
1041
1041
|
const o = [];
|
|
1042
1042
|
for (const a of n.fields) {
|
|
1043
1043
|
const c = typeof a == "string" ? a : a.name;
|
|
@@ -1137,7 +1137,7 @@ const G = ({
|
|
|
1137
1137
|
{
|
|
1138
1138
|
schema: {
|
|
1139
1139
|
...u,
|
|
1140
|
-
fields:
|
|
1140
|
+
fields: A(n),
|
|
1141
1141
|
showSubmit: o === e.sections.length - 1 && u.showSubmit,
|
|
1142
1142
|
showCancel: o === e.sections.length - 1 && u.showCancel
|
|
1143
1143
|
}
|
|
@@ -1401,12 +1401,12 @@ const G = ({
|
|
|
1401
1401
|
...T
|
|
1402
1402
|
};
|
|
1403
1403
|
if (j)
|
|
1404
|
-
return /* @__PURE__ */ t.jsxs("div", { className: "p-4 border border-red-300 bg-red-50 rounded-md", children: [
|
|
1404
|
+
return /* @__PURE__ */ t.jsxs("div", { className: "p-3 sm:p-4 border border-red-300 bg-red-50 rounded-md", children: [
|
|
1405
1405
|
/* @__PURE__ */ t.jsx("h3", { className: "text-red-800 font-semibold", children: "Error loading form" }),
|
|
1406
1406
|
/* @__PURE__ */ t.jsx("p", { className: "text-red-600 text-sm mt-1", children: j.message })
|
|
1407
1407
|
] });
|
|
1408
1408
|
if (S)
|
|
1409
|
-
return /* @__PURE__ */ t.jsxs("div", { className: "p-8 text-center", children: [
|
|
1409
|
+
return /* @__PURE__ */ t.jsxs("div", { className: "p-4 sm:p-8 text-center", children: [
|
|
1410
1410
|
/* @__PURE__ */ t.jsx("div", { className: "inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900" }),
|
|
1411
1411
|
/* @__PURE__ */ t.jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Loading form..." })
|
|
1412
1412
|
] });
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(z,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/fields"),require("@object-ui/components"),require("lucide-react")):typeof define=="function"&&define.amd?define(["exports","react","@object-ui/core","@object-ui/react","@object-ui/fields","@object-ui/components","lucide-react"],o):(z=typeof globalThis<"u"?globalThis:z||self,o(z.ObjectUIPluginForm={},z.React,z.core,z.react,z.fields,z.components,z.lucideReact))})(this,(function(z,o,K,R,L,j,H){"use strict";var G={exports:{}},B={};var ee;function me(){if(ee)return B;ee=1;var e=Symbol.for("react.transitional.element"),l=Symbol.for("react.fragment");function c(u,v,m){var C=null;if(m!==void 0&&(C=""+m),v.key!==void 0&&(C=""+v.key),"key"in v){m={};for(var O in v)O!=="key"&&(m[O]=v[O])}else m=v;return v=m.ref,{$$typeof:e,type:u,key:C,ref:v!==void 0?v:null,props:m}}return B.Fragment=l,B.jsx=c,B.jsxs=c,B}var J={};var te;function ye(){return te||(te=1,process.env.NODE_ENV!=="production"&&(function(){function e(r){if(r==null)return null;if(typeof r=="function")return r.$$typeof===W?null:r.displayName||r.name||null;if(typeof r=="string")return r;switch(r){case I:return"Fragment";case M:return"Profiler";case k:return"StrictMode";case s:return"Suspense";case d:return"SuspenseList";case S:return"Activity"}if(typeof r=="object")switch(typeof r.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),r.$$typeof){case $:return"Portal";case a:return r.displayName||"Context";case p:return(r._context.displayName||"Context")+".Consumer";case i:var y=r.render;return r=r.displayName,r||(r=y.displayName||y.name||"",r=r!==""?"ForwardRef("+r+")":"ForwardRef"),r;case f:return y=r.displayName||null,y!==null?y:e(r.type)||"Memo";case n:y=r._payload,r=r._init;try{return e(r(y))}catch{}}return null}function l(r){return""+r}function c(r){try{l(r);var y=!1}catch{y=!0}if(y){y=console;var F=y.error,h=typeof Symbol=="function"&&Symbol.toStringTag&&r[Symbol.toStringTag]||r.constructor.name||"Object";return F.call(y,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",h),l(r)}}function u(r){if(r===I)return"<>";if(typeof r=="object"&&r!==null&&r.$$typeof===n)return"<...>";try{var y=e(r);return y?"<"+y+">":"<...>"}catch{return"<...>"}}function v(){var r=b.A;return r===null?null:r.getOwner()}function m(){return Error("react-stack-top-frame")}function C(r){if(
|
|
1
|
+
(function(z,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/fields"),require("@object-ui/components"),require("lucide-react")):typeof define=="function"&&define.amd?define(["exports","react","@object-ui/core","@object-ui/react","@object-ui/fields","@object-ui/components","lucide-react"],o):(z=typeof globalThis<"u"?globalThis:z||self,o(z.ObjectUIPluginForm={},z.React,z.core,z.react,z.fields,z.components,z.lucideReact))})(this,(function(z,o,K,R,L,j,H){"use strict";var G={exports:{}},B={};var ee;function me(){if(ee)return B;ee=1;var e=Symbol.for("react.transitional.element"),l=Symbol.for("react.fragment");function c(u,v,m){var C=null;if(m!==void 0&&(C=""+m),v.key!==void 0&&(C=""+v.key),"key"in v){m={};for(var O in v)O!=="key"&&(m[O]=v[O])}else m=v;return v=m.ref,{$$typeof:e,type:u,key:C,ref:v!==void 0?v:null,props:m}}return B.Fragment=l,B.jsx=c,B.jsxs=c,B}var J={};var te;function ye(){return te||(te=1,process.env.NODE_ENV!=="production"&&(function(){function e(r){if(r==null)return null;if(typeof r=="function")return r.$$typeof===W?null:r.displayName||r.name||null;if(typeof r=="string")return r;switch(r){case I:return"Fragment";case M:return"Profiler";case k:return"StrictMode";case s:return"Suspense";case d:return"SuspenseList";case S:return"Activity"}if(typeof r=="object")switch(typeof r.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),r.$$typeof){case $:return"Portal";case a:return r.displayName||"Context";case p:return(r._context.displayName||"Context")+".Consumer";case i:var y=r.render;return r=r.displayName,r||(r=y.displayName||y.name||"",r=r!==""?"ForwardRef("+r+")":"ForwardRef"),r;case f:return y=r.displayName||null,y!==null?y:e(r.type)||"Memo";case n:y=r._payload,r=r._init;try{return e(r(y))}catch{}}return null}function l(r){return""+r}function c(r){try{l(r);var y=!1}catch{y=!0}if(y){y=console;var F=y.error,h=typeof Symbol=="function"&&Symbol.toStringTag&&r[Symbol.toStringTag]||r.constructor.name||"Object";return F.call(y,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",h),l(r)}}function u(r){if(r===I)return"<>";if(typeof r=="object"&&r!==null&&r.$$typeof===n)return"<...>";try{var y=e(r);return y?"<"+y+">":"<...>"}catch{return"<...>"}}function v(){var r=b.A;return r===null?null:r.getOwner()}function m(){return Error("react-stack-top-frame")}function C(r){if(w.call(r,"key")){var y=Object.getOwnPropertyDescriptor(r,"key").get;if(y&&y.isReactWarning)return!1}return r.key!==void 0}function O(r,y){function F(){q||(q=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",y))}F.isReactWarning=!0,Object.defineProperty(r,"key",{get:F,configurable:!0})}function T(){var r=e(this.type);return fe[r]||(fe[r]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),r=this.props.ref,r!==void 0?r:null}function E(r,y,F,h,X,Q){var P=F.ref;return r={$$typeof:V,type:r,key:y,props:F,_owner:h},(P!==void 0?P:null)!==null?Object.defineProperty(r,"ref",{enumerable:!1,get:T}):Object.defineProperty(r,"ref",{enumerable:!1,value:null}),r._store={},Object.defineProperty(r._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(r,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(r,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:X}),Object.defineProperty(r,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Q}),Object.freeze&&(Object.freeze(r.props),Object.freeze(r)),r}function g(r,y,F,h,X,Q){var P=y.children;if(P!==void 0)if(h)if(_(P)){for(h=0;h<P.length;h++)x(P[h]);Object.freeze&&Object.freeze(P)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else x(P);if(w.call(y,"key")){P=e(r);var U=Object.keys(y).filter(function(we){return we!=="key"});h=0<U.length?"{key: someKey, "+U.join(": ..., ")+": ...}":"{key: someKey}",be[P+h]||(U=0<U.length?"{"+U.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
2
|
let props = %s;
|
|
3
3
|
<%s {...props} />
|
|
4
4
|
React keys must be passed directly to JSX without using spread:
|
|
5
5
|
let props = %s;
|
|
6
|
-
<%s key={someKey} {...props} />`,h,P,U,P),be[P+h]=!0)}if(P=null,F!==void 0&&(c(F),P=""+F),C(y)&&(c(y.key),P=""+y.key),"key"in y){F={};for(var Z in y)Z!=="key"&&(F[Z]=y[Z])}else F=y;return P&&O(F,typeof r=="function"?r.displayName||r.name||"Unknown":r),E(r,P,F,v(),X,Q)}function x(r){N(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===n&&(r._payload.status==="fulfilled"?N(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function N(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var D=o,V=Symbol.for("react.transitional.element"),$=Symbol.for("react.portal"),I=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),M=Symbol.for("react.profiler"),p=Symbol.for("react.consumer"),a=Symbol.for("react.context"),i=Symbol.for("react.forward_ref"),s=Symbol.for("react.suspense"),d=Symbol.for("react.suspense_list"),f=Symbol.for("react.memo"),n=Symbol.for("react.lazy"),S=Symbol.for("react.activity"),W=Symbol.for("react.client.reference"),b=D.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,g=Object.prototype.hasOwnProperty,_=Array.isArray,A=console.createTask?console.createTask:function(){return null};D={react_stack_bottom_frame:function(r){return r()}};var q,fe={},ce=D.react_stack_bottom_frame.bind(D,m)(),pe=A(u(m)),be={};J.Fragment=I,J.jsx=function(r,y,F){var h=1e4>b.recentlyCreatedOwnerStacks++;return w(r,y,F,!1,h?Error("react-stack-top-frame"):ce,h?A(u(r)):pe)},J.jsxs=function(r,y,F){var h=1e4>b.recentlyCreatedOwnerStacks++;return w(r,y,F,!0,h?Error("react-stack-top-frame"):ce,h?A(u(r)):pe)}})()),J}var re;function je(){return re||(re=1,process.env.NODE_ENV==="production"?G.exports=me():G.exports=ye()),G.exports}var t=je();const Y=({label:e,description:l,collapsible:c=!1,collapsed:u=!1,columns:v=1,children:m,className:C})=>{const[O,T]=o.useState(u),E={1:"grid-cols-1",2:"grid-cols-1 md:grid-cols-2",3:"grid-cols-1 md:grid-cols-2 lg:grid-cols-3",4:"grid-cols-1 md:grid-cols-2 lg:grid-cols-4"},w=()=>{c&&T(!O)};return t.jsxs("div",{className:j.cn("form-section",C),children:[(e||l)&&t.jsxs("div",{className:j.cn("flex items-start gap-2 mb-4",c&&"cursor-pointer select-none"),onClick:w,role:c?"button":void 0,"aria-expanded":c?!O:void 0,children:[c&&t.jsx("span",{className:"mt-0.5 text-muted-foreground",children:O?t.jsx(H.ChevronRight,{className:"h-4 w-4"}):t.jsx(H.ChevronDown,{className:"h-4 w-4"})}),t.jsxs("div",{className:"flex-1",children:[e&&t.jsx("h3",{className:"text-base font-semibold text-foreground",children:e}),l&&t.jsx("p",{className:"text-sm text-muted-foreground mt-0.5",children:l})]})]}),!O&&t.jsx("div",{className:j.cn("grid gap-4",E[v]),children:m})]})},le=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,w]=o.useState(null),[x,N]=o.useState(e.defaultTab||e.sections[0]?.name||e.sections[0]?.label||"tab-0");o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const i=await l.getObjectSchema(e.objectName);v(i)}catch(i){w(i)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId||!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const i=await l.findOne(e.objectName,e.recordId);C(i||{})}catch(i){w(i)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const D=o.useCallback(a=>{const i=[];for(const s of a.fields){const d=typeof s=="string"?s:s.name;if(typeof s=="object")i.push(s);else if(u?.fields?.[d]){const f=u.fields[d];i.push({name:d,label:f.label||d,type:L.mapFieldTypeToFormType(f.type),required:f.required||!1,disabled:e.readOnly||e.mode==="view"||f.readonly,placeholder:f.placeholder,description:f.help||f.description,validation:L.buildValidationRules(f),field:f,options:f.options,multiple:f.multiple})}else i.push({name:d,label:d,type:"input"})}return i},[u,e.readOnly,e.mode]),V=o.useCallback(async a=>{if(!l)return e.onSuccess&&await e.onSuccess(a),a;try{let i;return e.mode==="create"?i=await l.create(e.objectName,a):e.mode==="edit"&&e.recordId&&(i=await l.update(e.objectName,e.recordId,a)),e.onSuccess&&await e.onSuccess(i),i}catch(i){throw e.onError&&e.onError(i),i}},[e,l]),$=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),I=(a,i)=>a.name||a.label||`tab-${i}`;if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const M={type:"form",fields:e.sections.flatMap(a=>D(a)),layout:"vertical",defaultValues:m,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:V,onCancel:$},p=e.tabPosition==="left"||e.tabPosition==="right";return t.jsx("div",{className:j.cn("w-full",c,e.className),children:t.jsxs(j.Tabs,{value:x,onValueChange:N,orientation:p?"vertical":"horizontal",className:j.cn(p&&"flex gap-4"),children:[t.jsx(j.TabsList,{className:j.cn(p?"flex-col h-auto":"",e.tabPosition==="bottom"&&"order-last",e.tabPosition==="right"&&"order-last"),children:e.sections.map((a,i)=>t.jsx(j.TabsTrigger,{value:I(a,i),className:p?"w-full justify-start":"",children:a.label||`Tab ${i+1}`},I(a,i)))}),t.jsx("div",{className:"flex-1",children:e.sections.map((a,i)=>t.jsx(j.TabsContent,{value:I(a,i),className:"mt-0",children:t.jsx(Y,{description:a.description,columns:a.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...M,fields:D(a),showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1}})})},I(a,i)))})]})})},ie=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,w]=o.useState(null),[x,N]=o.useState(0),[D,V]=o.useState(new Set),[$,I]=o.useState(!1),k=e.sections.length,M=x===0,p=x===k-1;o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const g=await l.getObjectSchema(e.objectName);v(g)}catch(g){w(g)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId||!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const g=await l.findOne(e.objectName,e.recordId);C(g||{})}catch(g){w(g)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const a=o.useCallback(b=>{const g=[];for(const _ of b.fields){const A=typeof _=="string"?_:_.name;if(typeof _=="object")g.push(_);else if(u?.fields?.[A]){const q=u.fields[A];g.push({name:A,label:q.label||A,type:L.mapFieldTypeToFormType(q.type),required:q.required||!1,disabled:e.readOnly||e.mode==="view"||q.readonly,placeholder:q.placeholder,description:q.help||q.description,validation:L.buildValidationRules(q),field:q,options:q.options,multiple:q.multiple})}else g.push({name:A,label:A,type:"input"})}return g},[u,e.readOnly,e.mode]),i=o.useMemo(()=>x>=0&&x<k?a(e.sections[x]):[],[x,k,e.sections,a]),s=o.useCallback(async b=>{const g={...m,...b};if(C(g),V(_=>new Set(_).add(x)),p){I(!0);try{if(!l)return e.onSuccess&&await e.onSuccess(g),g;let _;return e.mode==="create"?_=await l.create(e.objectName,g):e.mode==="edit"&&e.recordId&&(_=await l.update(e.objectName,e.recordId,g)),e.onSuccess&&await e.onSuccess(_),_}catch(_){throw e.onError&&e.onError(_),_}finally{I(!1)}}else d(x+1)},[m,x,p,e,l]),d=o.useCallback(b=>{b>=0&&b<k&&(N(b),e.onStepChange&&e.onStepChange(b))},[k,e]),f=o.useCallback(()=>{d(x-1)},[x,d]),n=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),S=o.useCallback(b=>{(e.allowSkip||D.has(b)||b<=x)&&d(b)},[e.allowSkip,D,x,d]);if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const W=e.sections[x];return t.jsxs("div",{className:j.cn("w-full",c,e.className),children:[e.showStepIndicator!==!1&&t.jsx("nav",{"aria-label":"Progress",className:"mb-8",children:t.jsx("ol",{className:"flex items-center",children:e.sections.map((b,g)=>{const _=g===x,A=D.has(g),q=e.allowSkip||A||g<=x;return t.jsxs("li",{className:j.cn("relative flex-1",g!==k-1&&"pr-8 sm:pr-12"),children:[g!==k-1&&t.jsx("div",{className:"absolute top-4 left-8 -right-4 sm:left-10 sm:-right-2 h-0.5","aria-hidden":"true",children:t.jsx("div",{className:j.cn("h-full",A?"bg-primary":"bg-muted")})}),t.jsxs("button",{type:"button",className:j.cn("group relative flex items-center",q?"cursor-pointer":"cursor-not-allowed"),onClick:()=>S(g),disabled:!q,children:[t.jsx("span",{className:j.cn("flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors",A&&"bg-primary text-primary-foreground",_&&!A&&"border-2 border-primary bg-background text-primary",!_&&!A&&"border-2 border-muted bg-background text-muted-foreground"),children:A?t.jsx(H.Check,{className:"h-4 w-4"}):g+1}),t.jsx("span",{className:"ml-3 text-sm font-medium hidden sm:block",children:t.jsx("span",{className:j.cn(_?"text-foreground":"text-muted-foreground"),children:b.label||`Step ${g+1}`})})]})]},g)})})}),t.jsx("div",{className:"min-h-[200px]",children:W&&t.jsx(Y,{label:W.label,description:W.description,columns:W.columns||1,children:i.length>0?t.jsx(R.SchemaRenderer,{schema:{type:"form",fields:i,layout:"vertical",defaultValues:m,showSubmit:!1,showCancel:!1,onSubmit:s}}):t.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"No fields configured for this step"})})}),t.jsxs("div",{className:"flex items-center justify-between mt-6 pt-4 border-t",children:[t.jsx("div",{children:e.showCancel!==!1&&t.jsx(j.Button,{variant:"ghost",onClick:n,children:e.cancelText||"Cancel"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxs("span",{className:"text-sm text-muted-foreground mr-2",children:["Step ",x+1," of ",k]}),!M&&t.jsxs(j.Button,{variant:"outline",onClick:f,children:[t.jsx(H.ChevronLeft,{className:"h-4 w-4 mr-1"}),e.prevText||"Back"]}),p?t.jsx(j.Button,{onClick:()=>s(m),disabled:$||e.mode==="view",children:$?"Submitting...":e.submitText||(e.mode==="create"?"Create":"Update")}):t.jsxs(j.Button,{onClick:()=>s(m),children:[e.nextText||"Next",t.jsx(H.ChevronRight,{className:"h-4 w-4 ml-1"})]})]})]})]})},ne=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,w]=o.useState(null);o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const i=await l.getObjectSchema(e.objectName);v(i)}catch(i){w(i),T(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){C(e.initialData||e.initialValues||{}),T(!1);return}if(!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const i=await l.findOne(e.objectName,e.recordId);C(i||{})}catch(i){w(i)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const x=o.useCallback(a=>{const i=[];for(const s of a.fields){const d=typeof s=="string"?s:s.name;if(typeof s=="object")i.push(s);else if(u?.fields?.[d]){const f=u.fields[d];i.push({name:d,label:f.label||d,type:L.mapFieldTypeToFormType(f.type),required:f.required||!1,disabled:e.readOnly||e.mode==="view"||f.readonly,placeholder:f.placeholder,description:f.help||f.description,validation:L.buildValidationRules(f),field:f,options:f.options,multiple:f.multiple})}else i.push({name:d,label:d,type:"input"})}return i},[u,e.readOnly,e.mode]),N=o.useCallback(async a=>{if(!l)return e.onSuccess&&await e.onSuccess(a),a;try{let i;return e.mode==="create"?i=await l.create(e.objectName,a):e.mode==="edit"&&e.recordId&&(i=await l.update(e.objectName,e.recordId,a)),e.onSuccess&&await e.onSuccess(i),i}catch(i){throw e.onError&&e.onError(i),i}},[e,l]),D=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),V=o.useMemo(()=>e.sections.slice(0,1),[e.sections]),$=o.useMemo(()=>e.sections.slice(1),[e.sections]);o.useMemo(()=>e.sections.flatMap(a=>x(a)),[e.sections,x]);const I=e.splitDirection||"horizontal",k=e.splitSize||50;if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const M={type:"form",layout:"vertical",defaultValues:m,onSubmit:N,onCancel:D},p=(a,i)=>t.jsx("div",{className:"space-y-4 p-4",children:a.map((s,d)=>t.jsx(Y,{label:s.label,description:s.description,columns:s.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...M,fields:x(s),showSubmit:i&&e.showSubmit!==!1&&e.mode!=="view",showCancel:i&&e.showCancel!==!1,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText}})},s.name||s.label||d))});return t.jsx("div",{className:j.cn("w-full",c,e.className),children:t.jsxs(j.ResizablePanelGroup,{orientation:I,className:"min-h-[300px] rounded-lg border",children:[t.jsx(j.ResizablePanel,{defaultSize:k,minSize:20,children:p(V,$.length===0)}),$.length>0&&t.jsxs(t.Fragment,{children:[t.jsx(j.ResizableHandle,{withHandle:e.splitResizable!==!1}),t.jsx(j.ResizablePanel,{defaultSize:100-k,minSize:20,children:p($,!0)})]})]})})},oe=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState([]),[O,T]=o.useState({}),[E,w]=o.useState(!0),[x,N]=o.useState(null),D=e.open!==!1,V=e.drawerSide||"right";o.useEffect(()=>{(async()=>{if(!l){w(!1);return}try{const d=await l.getObjectSchema(e.objectName);v(d)}catch(d){N(d),w(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){T(e.initialData||e.initialValues||{}),w(!1);return}if(!l){T(e.initialData||e.initialValues||{}),w(!1);return}try{const d=await l.findOne(e.objectName,e.recordId);T(d||{})}catch(d){N(d)}finally{w(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const $=o.useCallback(s=>{const d=[];for(const f of s.fields){const n=typeof f=="string"?f:f.name;if(typeof f=="object")d.push(f);else if(u?.fields?.[n]){const S=u.fields[n];d.push({name:n,label:S.label||n,type:L.mapFieldTypeToFormType(S.type),required:S.required||!1,disabled:e.readOnly||e.mode==="view"||S.readonly,placeholder:S.placeholder,description:S.help||S.description,validation:L.buildValidationRules(S),field:S,options:S.options,multiple:S.multiple})}else d.push({name:n,label:n,type:"input"})}return d},[u,e.readOnly,e.mode]);o.useEffect(()=>{if(!u&&l)return;if(e.customFields?.length){C(e.customFields),w(!1);return}if(e.sections?.length){w(!1);return}if(!u)return;const s=e.fields||Object.keys(u.fields||{}),d=[];for(const f of s){const n=typeof f=="string"?f:f.name;if(!n)continue;const S=u.fields?.[n];S&&d.push({name:n,label:S.label||n,type:L.mapFieldTypeToFormType(S.type),required:S.required||!1,disabled:e.readOnly||e.mode==="view"||S.readonly,placeholder:S.placeholder,description:S.help||S.description,validation:L.buildValidationRules(S),field:S,options:S.options,multiple:S.multiple})}C(d),w(!1)},[u,e.fields,e.customFields,e.sections,e.readOnly,e.mode,l]);const I=o.useCallback(async s=>{if(!l)return e.onSuccess&&await e.onSuccess(s),e.onOpenChange?.(!1),s;try{let d;return e.mode==="create"?d=await l.create(e.objectName,s):e.mode==="edit"&&e.recordId&&(d=await l.update(e.objectName,e.recordId,s)),e.onSuccess&&await e.onSuccess(d),e.onOpenChange?.(!1),d}catch(d){throw e.onError&&e.onError(d),d}},[e,l]),k=o.useCallback(()=>{e.onCancel&&e.onCancel(),e.onOpenChange?.(!1)},[e]),M=o.useMemo(()=>e.drawerWidth?V==="left"||V==="right"?{width:e.drawerWidth,maxWidth:e.drawerWidth}:{height:e.drawerWidth,maxHeight:e.drawerWidth}:void 0,[e.drawerWidth,V]),a={type:"form",layout:e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical",defaultValues:O,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:I,onCancel:k},i=()=>x?t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:x.message})]}):E?t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]}):e.sections?.length?t.jsx("div",{className:"space-y-6",children:e.sections.map((s,d)=>t.jsx(Y,{label:s.label,description:s.description,columns:s.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...a,fields:$(s),showSubmit:d===e.sections.length-1&&a.showSubmit,showCancel:d===e.sections.length-1&&a.showCancel}})},s.name||s.label||d))}):t.jsx(R.SchemaRenderer,{schema:{...a,fields:m,columns:e.columns}});return t.jsx(j.Sheet,{open:D,onOpenChange:e.onOpenChange,children:t.jsxs(j.SheetContent,{side:V,className:j.cn("overflow-y-auto",c,e.className),style:M,children:[(e.title||e.description)&&t.jsxs(j.SheetHeader,{children:[e.title&&t.jsx(j.SheetTitle,{children:e.title}),e.description&&t.jsx(j.SheetDescription,{children:e.description})]}),t.jsx("div",{className:"py-4",children:i()})]})})},se={sm:"max-w-sm",default:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl",full:"max-w-[95vw] w-full"},ae=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState([]),[O,T]=o.useState({}),[E,w]=o.useState(!0),[x,N]=o.useState(null),D=e.open!==!1,V=se[e.modalSize||"default"]||se.default;o.useEffect(()=>{(async()=>{if(!l){w(!1);return}try{const s=await l.getObjectSchema(e.objectName);v(s)}catch(s){N(s),w(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){T(e.initialData||e.initialValues||{}),w(!1);return}if(!l){T(e.initialData||e.initialValues||{}),w(!1);return}try{const s=await l.findOne(e.objectName,e.recordId);T(s||{})}catch(s){N(s)}finally{w(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const $=o.useCallback(i=>{const s=[];for(const d of i.fields){const f=typeof d=="string"?d:d.name;if(typeof d=="object")s.push(d);else if(u?.fields?.[f]){const n=u.fields[f];s.push({name:f,label:n.label||f,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n,options:n.options,multiple:n.multiple})}else s.push({name:f,label:f,type:"input"})}return s},[u,e.readOnly,e.mode]);o.useEffect(()=>{if(!u&&l)return;if(e.customFields?.length){C(e.customFields),w(!1);return}if(e.sections?.length){w(!1);return}if(!u)return;const i=e.fields||Object.keys(u.fields||{}),s=[];for(const d of i){const f=typeof d=="string"?d:d.name;if(!f)continue;const n=u.fields?.[f];n&&s.push({name:f,label:n.label||f,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n,options:n.options,multiple:n.multiple})}C(s),w(!1)},[u,e.fields,e.customFields,e.sections,e.readOnly,e.mode,l]);const I=o.useCallback(async i=>{if(!l)return e.onSuccess&&await e.onSuccess(i),e.onOpenChange?.(!1),i;try{let s;return e.mode==="create"?s=await l.create(e.objectName,i):e.mode==="edit"&&e.recordId&&(s=await l.update(e.objectName,e.recordId,i)),e.onSuccess&&await e.onSuccess(s),e.onOpenChange?.(!1),s}catch(s){throw e.onError&&e.onError(s),s}},[e,l]),k=o.useCallback(()=>{e.onCancel&&e.onCancel(),e.onOpenChange?.(!1)},[e]),p={type:"form",layout:e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical",defaultValues:O,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:I,onCancel:k},a=()=>x?t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:x.message})]}):E?t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]}):e.sections?.length?t.jsx("div",{className:"space-y-6",children:e.sections.map((i,s)=>t.jsx(Y,{label:i.label,description:i.description,columns:i.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...p,fields:$(i),showSubmit:s===e.sections.length-1&&p.showSubmit,showCancel:s===e.sections.length-1&&p.showCancel}})},i.name||i.label||s))}):t.jsx(R.SchemaRenderer,{schema:{...p,fields:m,columns:e.columns}});return t.jsx(j.Dialog,{open:D,onOpenChange:e.onOpenChange,children:t.jsxs(j.DialogContent,{className:j.cn(V,"max-h-[90vh] overflow-y-auto",c,e.className),children:[(e.title||e.description)&&t.jsxs(j.DialogHeader,{children:[e.title&&t.jsx(j.DialogTitle,{children:e.title}),e.description&&t.jsx(j.DialogDescription,{children:e.description})]}),t.jsx("div",{className:"py-2",children:a()})]})})},de=({schema:e,dataSource:l})=>{if(e.formType==="tabbed"&&e.sections?.length)return t.jsx(le,{schema:{...e,formType:"tabbed",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),defaultTab:e.defaultTab,tabPosition:e.tabPosition},dataSource:l,className:e.className});if(e.formType==="wizard"&&e.sections?.length)return t.jsx(ie,{schema:{...e,formType:"wizard",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),allowSkip:e.allowSkip,showStepIndicator:e.showStepIndicator,nextText:e.nextText,prevText:e.prevText,onStepChange:e.onStepChange},dataSource:l,className:e.className});if(e.formType==="split"&&e.sections?.length)return t.jsx(ne,{schema:{...e,formType:"split",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),splitDirection:e.splitDirection,splitSize:e.splitSize,splitResizable:e.splitResizable},dataSource:l,className:e.className});if(e.formType==="drawer"){const{layout:c,...u}=e,v=e.layout==="vertical"||e.layout==="horizontal"?e.layout:void 0;return t.jsx(oe,{schema:{...u,layout:v,formType:"drawer",sections:e.sections?.map(m=>({name:m.name,label:m.label,description:m.description,columns:m.columns,fields:m.fields})),open:e.open,onOpenChange:e.onOpenChange,drawerSide:e.drawerSide,drawerWidth:e.drawerWidth},dataSource:l,className:e.className})}if(e.formType==="modal"){const{layout:c,...u}=e,v=e.layout==="vertical"||e.layout==="horizontal"?e.layout:void 0;return t.jsx(ae,{schema:{...u,layout:v,formType:"modal",sections:e.sections?.map(m=>({name:m.name,label:m.label,description:m.description,columns:m.columns,fields:m.fields})),open:e.open,onOpenChange:e.onOpenChange,modalSize:e.modalSize,modalCloseButton:e.modalCloseButton},dataSource:l,className:e.className})}return t.jsx(xe,{schema:e,dataSource:l})},xe=({schema:e,dataSource:l})=>{const[c,u]=o.useState(null),[v,m]=o.useState([]),[C,O]=o.useState(null),[T,E]=o.useState(!0),[w,x]=o.useState(null),N=e.customFields&&e.customFields.length>0;o.useEffect(()=>{N&&(O(e.initialData||e.initialValues||{}),E(!1))},[N,e.initialData,e.initialValues]),o.useEffect(()=>{const p=async()=>{try{if(!l)throw new Error("DataSource is required when using ObjectQL schema fetching (inline fields not provided)");const a=await l.getObjectSchema(e.objectName);if(!a)throw new Error(`No schema found for object "${e.objectName}"`);u(a)}catch(a){x(a),E(!1)}};N?u({name:e.objectName,fields:{}}):e.objectName&&l?p():N||E(!1)},[e.objectName,l,N]),o.useEffect(()=>{c&&!N&&(async()=>{if(!e.recordId||e.mode==="create"){O(e.initialData||e.initialValues||{}),E(!1);return}if(!N){if(!l){x(new Error("DataSource is required for fetching record data (inline data not provided)")),E(!1);return}E(!0);try{const a=await l.findOne(e.objectName,e.recordId);O(a)}catch(a){console.error("Failed to fetch record:",a),x(a)}finally{E(!1)}}})()},[e.objectName,e.recordId,e.mode,e.initialValues,e.initialData,l,c,N]),o.useEffect(()=>{if(N&&e.customFields){m(e.customFields),E(!1);return}if(!c)return;const p=[],a=e.fields||Object.keys(c.fields||{});(Array.isArray(a)?a:Object.keys(a)).forEach(d=>{const f=typeof d=="string"?d:d.name;if(!f)return;const n=c.fields?.[f];if(!n&&!N)return;const S=!n?.permissions||n?.permissions.write!==!1;if(e.mode!=="view"&&!S)return;const W=e.customFields?.find(b=>b.name===f);if(W)p.push(W);else if(n){const b={name:f,label:n.label||d,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n};if((n.type==="select"||n.type==="lookup"||n.type==="master_detail")&&(b.options=n.options||[],b.multiple=n.multiple),(n.type==="number"||n.type==="currency"||n.type==="percent")&&(b.inputType="number",b.min=n.min,b.max=n.max,b.step=n.precision?Math.pow(10,-n.precision):void 0),n.type==="date"&&(b.inputType="date"),n.type==="datetime"&&(b.inputType="datetime-local"),(n.type==="text"||n.type==="textarea"||n.type==="markdown"||n.type==="html")&&(b.maxLength=n.max_length,b.minLength=n.min_length),(n.type==="file"||n.type==="image")&&(b.inputType="file",b.multiple=n.multiple,b.accept=n.accept?n.accept.join(","):void 0,n.max_size)){const g=`Max size: ${L.formatFileSize(n.max_size)}`;b.description=b.description?`${b.description} (${g})`:g}n.type==="email"&&(b.inputType="email"),n.type==="phone"&&(b.inputType="tel"),n.type==="url"&&(b.inputType="url"),n.type==="password"&&(b.inputType="password"),n.type==="time"&&(b.inputType="time"),(n.type==="formula"||n.type==="summary"||n.type==="auto_number")&&(b.disabled=!0),n.visible_on&&(b.visible=g=>L.evaluateCondition(n.visible_on,g)),p.push(b)}}),m(p),!N&&e.recordId&&e.mode!=="create"&&l||E(!1)},[c,e.fields,e.customFields,e.readOnly,e.mode,N,e.recordId,l]);const D=o.useCallback(async(p,a)=>{if(p&&(p.nativeEvent||p._reactName==="onSubmit")&&(console.warn("ObjectForm: Received Event instead of data in handleSubmit! This suggests a Form renderer issue."),a===void 0&&(a=p,p={})),N&&!l)return e.onSuccess&&await e.onSuccess(p),p;if(!l)throw new Error("DataSource is required for form submission (inline mode not configured)");try{let i;if(e.mode==="create")i=await l.create(e.objectName,p);else if(e.mode==="edit"&&e.recordId)i=await l.update(e.objectName,e.recordId,p);else throw new Error("Invalid form mode or missing record ID");return e.onSuccess&&await e.onSuccess(i),i}catch(i){throw console.error("Failed to submit form:",i),e.onError&&e.onError(i),i}},[e,l,N]),V=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),I={...o.useMemo(()=>{if(!c?.fields)return{};const p={};return Object.keys(c.fields).forEach(a=>{const i=c.fields[a];i.defaultValue!==void 0&&(p[a]=i.defaultValue)}),p},[c]),...C};if(w)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:w.message})]});if(T)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const k=e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical";if(e.sections?.length&&(!e.formType||e.formType==="simple"))return t.jsx("div",{className:"w-full space-y-6",children:e.sections.map((p,a)=>{const i=p.fields.map(d=>typeof d=="string"?d:d.name),s=v.filter(d=>i.includes(d.name));return t.jsx(Y,{label:p.label,description:p.description,collapsible:p.collapsible,collapsed:p.collapsed,columns:p.columns,children:t.jsx(R.SchemaRenderer,{schema:{type:"form",fields:s,layout:k,defaultValues:I,showSubmit:a===e.sections.length-1&&e.showSubmit!==!1&&e.mode!=="view",showCancel:a===e.sections.length-1&&e.showCancel!==!1,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,onSubmit:D,onCancel:V}})},p.name||p.label||a)})});const M={type:"form",fields:v,layout:k,columns:e.columns,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,resetOnSubmit:e.showReset,defaultValues:I,onSubmit:D,onCancel:V,className:e.className};return t.jsx("div",{className:"w-full",children:t.jsx(R.SchemaRenderer,{schema:M})})},ue=({schema:e})=>t.jsx(de,{schema:e});K.ComponentRegistry.register("object-form",ue,{namespace:"plugin-form",label:"Object Form",category:"plugin",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"fields",type:"array",label:"Fields"},{name:"mode",type:"enum",label:"Mode",enum:["create","edit","view"]},{name:"formType",type:"enum",label:"Form Type",enum:["simple","tabbed","wizard","split","drawer","modal"]},{name:"sections",type:"array",label:"Sections"},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Layout",enum:["vertical","horizontal","inline","grid"]},{name:"columns",type:"number",label:"Columns"},{name:"defaultTab",type:"string",label:"Default Tab"},{name:"tabPosition",type:"enum",label:"Tab Position",enum:["top","bottom","left","right"]},{name:"allowSkip",type:"boolean",label:"Allow Skip Steps"},{name:"showStepIndicator",type:"boolean",label:"Show Step Indicator"},{name:"splitDirection",type:"enum",label:"Split Direction",enum:["horizontal","vertical"]},{name:"splitSize",type:"number",label:"Split Panel Size (%)"},{name:"splitResizable",type:"boolean",label:"Split Resizable"},{name:"drawerSide",type:"enum",label:"Drawer Side",enum:["top","bottom","left","right"]},{name:"drawerWidth",type:"string",label:"Drawer Width"},{name:"modalSize",type:"enum",label:"Modal Size",enum:["sm","default","lg","xl","full"]}]}),K.ComponentRegistry.register("form",ue,{namespace:"view",skipFallback:!0,label:"Data Form View",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"fields",type:"array",label:"Fields"},{name:"mode",type:"enum",label:"Mode",enum:["create","edit","view"]}]}),z.DrawerForm=oe,z.FormSection=Y,z.ModalForm=ae,z.ObjectForm=de,z.SplitForm=ne,z.TabbedForm=le,z.WizardForm=ie,Object.defineProperty(z,Symbol.toStringTag,{value:"Module"})}));
|
|
6
|
+
<%s key={someKey} {...props} />`,h,P,U,P),be[P+h]=!0)}if(P=null,F!==void 0&&(c(F),P=""+F),C(y)&&(c(y.key),P=""+y.key),"key"in y){F={};for(var Z in y)Z!=="key"&&(F[Z]=y[Z])}else F=y;return P&&O(F,typeof r=="function"?r.displayName||r.name||"Unknown":r),E(r,P,F,v(),X,Q)}function x(r){N(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===n&&(r._payload.status==="fulfilled"?N(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function N(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var D=o,V=Symbol.for("react.transitional.element"),$=Symbol.for("react.portal"),I=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),M=Symbol.for("react.profiler"),p=Symbol.for("react.consumer"),a=Symbol.for("react.context"),i=Symbol.for("react.forward_ref"),s=Symbol.for("react.suspense"),d=Symbol.for("react.suspense_list"),f=Symbol.for("react.memo"),n=Symbol.for("react.lazy"),S=Symbol.for("react.activity"),W=Symbol.for("react.client.reference"),b=D.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,w=Object.prototype.hasOwnProperty,_=Array.isArray,A=console.createTask?console.createTask:function(){return null};D={react_stack_bottom_frame:function(r){return r()}};var q,fe={},ce=D.react_stack_bottom_frame.bind(D,m)(),pe=A(u(m)),be={};J.Fragment=I,J.jsx=function(r,y,F){var h=1e4>b.recentlyCreatedOwnerStacks++;return g(r,y,F,!1,h?Error("react-stack-top-frame"):ce,h?A(u(r)):pe)},J.jsxs=function(r,y,F){var h=1e4>b.recentlyCreatedOwnerStacks++;return g(r,y,F,!0,h?Error("react-stack-top-frame"):ce,h?A(u(r)):pe)}})()),J}var re;function je(){return re||(re=1,process.env.NODE_ENV==="production"?G.exports=me():G.exports=ye()),G.exports}var t=je();const Y=({label:e,description:l,collapsible:c=!1,collapsed:u=!1,columns:v=1,children:m,className:C})=>{const[O,T]=o.useState(u),E={1:"grid-cols-1",2:"grid-cols-1 md:grid-cols-2",3:"grid-cols-1 md:grid-cols-2 lg:grid-cols-3",4:"grid-cols-1 md:grid-cols-2 lg:grid-cols-4"},g=()=>{c&&T(!O)};return t.jsxs("div",{className:j.cn("form-section",C),children:[(e||l)&&t.jsxs("div",{className:j.cn("flex items-start gap-2 mb-4",c&&"cursor-pointer select-none"),onClick:g,role:c?"button":void 0,"aria-expanded":c?!O:void 0,children:[c&&t.jsx("span",{className:"mt-0.5 text-muted-foreground",children:O?t.jsx(H.ChevronRight,{className:"h-4 w-4"}):t.jsx(H.ChevronDown,{className:"h-4 w-4"})}),t.jsxs("div",{className:"flex-1",children:[e&&t.jsx("h3",{className:"text-base font-semibold text-foreground",children:e}),l&&t.jsx("p",{className:"text-sm text-muted-foreground mt-0.5",children:l})]})]}),!O&&t.jsx("div",{className:j.cn("grid gap-4",E[v]),children:m})]})},le=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,g]=o.useState(null),[x,N]=o.useState(e.defaultTab||e.sections[0]?.name||e.sections[0]?.label||"tab-0");o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const i=await l.getObjectSchema(e.objectName);v(i)}catch(i){g(i)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId||!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const i=await l.findOne(e.objectName,e.recordId);C(i||{})}catch(i){g(i)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const D=o.useCallback(a=>{const i=[];for(const s of a.fields){const d=typeof s=="string"?s:s.name;if(typeof s=="object")i.push(s);else if(u?.fields?.[d]){const f=u.fields[d];i.push({name:d,label:f.label||d,type:L.mapFieldTypeToFormType(f.type),required:f.required||!1,disabled:e.readOnly||e.mode==="view"||f.readonly,placeholder:f.placeholder,description:f.help||f.description,validation:L.buildValidationRules(f),field:f,options:f.options,multiple:f.multiple})}else i.push({name:d,label:d,type:"input"})}return i},[u,e.readOnly,e.mode]),V=o.useCallback(async a=>{if(!l)return e.onSuccess&&await e.onSuccess(a),a;try{let i;return e.mode==="create"?i=await l.create(e.objectName,a):e.mode==="edit"&&e.recordId&&(i=await l.update(e.objectName,e.recordId,a)),e.onSuccess&&await e.onSuccess(i),i}catch(i){throw e.onError&&e.onError(i),i}},[e,l]),$=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),I=(a,i)=>a.name||a.label||`tab-${i}`;if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const M={type:"form",fields:e.sections.flatMap(a=>D(a)),layout:"vertical",defaultValues:m,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:V,onCancel:$},p=e.tabPosition==="left"||e.tabPosition==="right";return t.jsx("div",{className:j.cn("w-full",c,e.className),children:t.jsxs(j.Tabs,{value:x,onValueChange:N,orientation:p?"vertical":"horizontal",className:j.cn(p&&"flex gap-4"),children:[t.jsx(j.TabsList,{className:j.cn(p?"flex-col h-auto":"",e.tabPosition==="bottom"&&"order-last",e.tabPosition==="right"&&"order-last"),children:e.sections.map((a,i)=>t.jsx(j.TabsTrigger,{value:I(a,i),className:p?"w-full justify-start":"",children:a.label||`Tab ${i+1}`},I(a,i)))}),t.jsx("div",{className:"flex-1",children:e.sections.map((a,i)=>t.jsx(j.TabsContent,{value:I(a,i),className:"mt-0",children:t.jsx(Y,{description:a.description,columns:a.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...M,fields:D(a),showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1}})})},I(a,i)))})]})})},ie=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,g]=o.useState(null),[x,N]=o.useState(0),[D,V]=o.useState(new Set),[$,I]=o.useState(!1),k=e.sections.length,M=x===0,p=x===k-1;o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const w=await l.getObjectSchema(e.objectName);v(w)}catch(w){g(w)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId||!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const w=await l.findOne(e.objectName,e.recordId);C(w||{})}catch(w){g(w)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const a=o.useCallback(b=>{const w=[];for(const _ of b.fields){const A=typeof _=="string"?_:_.name;if(typeof _=="object")w.push(_);else if(u?.fields?.[A]){const q=u.fields[A];w.push({name:A,label:q.label||A,type:L.mapFieldTypeToFormType(q.type),required:q.required||!1,disabled:e.readOnly||e.mode==="view"||q.readonly,placeholder:q.placeholder,description:q.help||q.description,validation:L.buildValidationRules(q),field:q,options:q.options,multiple:q.multiple})}else w.push({name:A,label:A,type:"input"})}return w},[u,e.readOnly,e.mode]),i=o.useMemo(()=>x>=0&&x<k?a(e.sections[x]):[],[x,k,e.sections,a]),s=o.useCallback(async b=>{const w={...m,...b};if(C(w),V(_=>new Set(_).add(x)),p){I(!0);try{if(!l)return e.onSuccess&&await e.onSuccess(w),w;let _;return e.mode==="create"?_=await l.create(e.objectName,w):e.mode==="edit"&&e.recordId&&(_=await l.update(e.objectName,e.recordId,w)),e.onSuccess&&await e.onSuccess(_),_}catch(_){throw e.onError&&e.onError(_),_}finally{I(!1)}}else d(x+1)},[m,x,p,e,l]),d=o.useCallback(b=>{b>=0&&b<k&&(N(b),e.onStepChange&&e.onStepChange(b))},[k,e]),f=o.useCallback(()=>{d(x-1)},[x,d]),n=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),S=o.useCallback(b=>{(e.allowSkip||D.has(b)||b<=x)&&d(b)},[e.allowSkip,D,x,d]);if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const W=e.sections[x];return t.jsxs("div",{className:j.cn("w-full",c,e.className),children:[e.showStepIndicator!==!1&&t.jsx("nav",{"aria-label":"Progress",className:"mb-8",children:t.jsx("ol",{className:"flex items-center",children:e.sections.map((b,w)=>{const _=w===x,A=D.has(w),q=e.allowSkip||A||w<=x;return t.jsxs("li",{className:j.cn("relative flex-1",w!==k-1&&"pr-8 sm:pr-12"),children:[w!==k-1&&t.jsx("div",{className:"absolute top-3 sm:top-4 left-6 -right-4 sm:left-10 sm:-right-2 h-0.5","aria-hidden":"true",children:t.jsx("div",{className:j.cn("h-full",A?"bg-primary":"bg-muted")})}),t.jsxs("button",{type:"button",className:j.cn("group relative flex items-center",q?"cursor-pointer":"cursor-not-allowed"),onClick:()=>S(w),disabled:!q,children:[t.jsx("span",{className:j.cn("flex h-6 w-6 sm:h-8 sm:w-8 items-center justify-center rounded-full text-xs sm:text-sm font-medium transition-colors",A&&"bg-primary text-primary-foreground",_&&!A&&"border-2 border-primary bg-background text-primary",!_&&!A&&"border-2 border-muted bg-background text-muted-foreground"),children:A?t.jsx(H.Check,{className:"h-3 w-3 sm:h-4 sm:w-4"}):w+1}),t.jsx("span",{className:"ml-2 sm:ml-3 text-xs sm:text-sm font-medium hidden sm:block",children:t.jsx("span",{className:j.cn(_?"text-foreground":"text-muted-foreground"),children:b.label||`Step ${w+1}`})})]})]},w)})})}),t.jsx("div",{className:"min-h-[200px]",children:W&&t.jsx(Y,{label:W.label,description:W.description,columns:W.columns||1,children:i.length>0?t.jsx(R.SchemaRenderer,{schema:{type:"form",fields:i,layout:"vertical",defaultValues:m,showSubmit:!1,showCancel:!1,onSubmit:s}}):t.jsx("div",{className:"text-center py-8 text-muted-foreground",children:"No fields configured for this step"})})}),t.jsxs("div",{className:"flex items-center justify-between mt-6 pt-4 border-t",children:[t.jsx("div",{children:e.showCancel!==!1&&t.jsx(j.Button,{variant:"ghost",onClick:n,children:e.cancelText||"Cancel"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxs("span",{className:"text-sm text-muted-foreground mr-2",children:["Step ",x+1," of ",k]}),!M&&t.jsxs(j.Button,{variant:"outline",onClick:f,children:[t.jsx(H.ChevronLeft,{className:"h-4 w-4 mr-1"}),e.prevText||"Back"]}),p?t.jsx(j.Button,{onClick:()=>s(m),disabled:$||e.mode==="view",children:$?"Submitting...":e.submitText||(e.mode==="create"?"Create":"Update")}):t.jsxs(j.Button,{onClick:()=>s(m),children:[e.nextText||"Next",t.jsx(H.ChevronRight,{className:"h-4 w-4 ml-1"})]})]})]})]})},ne=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState({}),[O,T]=o.useState(!0),[E,g]=o.useState(null);o.useEffect(()=>{(async()=>{if(!l){T(!1);return}try{const i=await l.getObjectSchema(e.objectName);v(i)}catch(i){g(i),T(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){C(e.initialData||e.initialValues||{}),T(!1);return}if(!l){C(e.initialData||e.initialValues||{}),T(!1);return}try{const i=await l.findOne(e.objectName,e.recordId);C(i||{})}catch(i){g(i)}finally{T(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const x=o.useCallback(a=>{const i=[];for(const s of a.fields){const d=typeof s=="string"?s:s.name;if(typeof s=="object")i.push(s);else if(u?.fields?.[d]){const f=u.fields[d];i.push({name:d,label:f.label||d,type:L.mapFieldTypeToFormType(f.type),required:f.required||!1,disabled:e.readOnly||e.mode==="view"||f.readonly,placeholder:f.placeholder,description:f.help||f.description,validation:L.buildValidationRules(f),field:f,options:f.options,multiple:f.multiple})}else i.push({name:d,label:d,type:"input"})}return i},[u,e.readOnly,e.mode]),N=o.useCallback(async a=>{if(!l)return e.onSuccess&&await e.onSuccess(a),a;try{let i;return e.mode==="create"?i=await l.create(e.objectName,a):e.mode==="edit"&&e.recordId&&(i=await l.update(e.objectName,e.recordId,a)),e.onSuccess&&await e.onSuccess(i),i}catch(i){throw e.onError&&e.onError(i),i}},[e,l]),D=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),V=o.useMemo(()=>e.sections.slice(0,1),[e.sections]),$=o.useMemo(()=>e.sections.slice(1),[e.sections]);o.useMemo(()=>e.sections.flatMap(a=>x(a)),[e.sections,x]);const I=e.splitDirection||"horizontal",k=e.splitSize||50;if(E)return t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:E.message})]});if(O)return t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const M={type:"form",layout:"vertical",defaultValues:m,onSubmit:N,onCancel:D},p=(a,i)=>t.jsx("div",{className:"space-y-4 p-4",children:a.map((s,d)=>t.jsx(Y,{label:s.label,description:s.description,columns:s.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...M,fields:x(s),showSubmit:i&&e.showSubmit!==!1&&e.mode!=="view",showCancel:i&&e.showCancel!==!1,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText}})},s.name||s.label||d))});return t.jsx("div",{className:j.cn("w-full",c,e.className),children:t.jsxs(j.ResizablePanelGroup,{orientation:I,className:"min-h-[300px] rounded-lg border",children:[t.jsx(j.ResizablePanel,{defaultSize:k,minSize:20,children:p(V,$.length===0)}),$.length>0&&t.jsxs(t.Fragment,{children:[t.jsx(j.ResizableHandle,{withHandle:e.splitResizable!==!1}),t.jsx(j.ResizablePanel,{defaultSize:100-k,minSize:20,children:p($,!0)})]})]})})},oe=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState([]),[O,T]=o.useState({}),[E,g]=o.useState(!0),[x,N]=o.useState(null),D=e.open!==!1,V=e.drawerSide||"right";o.useEffect(()=>{(async()=>{if(!l){g(!1);return}try{const d=await l.getObjectSchema(e.objectName);v(d)}catch(d){N(d),g(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){T(e.initialData||e.initialValues||{}),g(!1);return}if(!l){T(e.initialData||e.initialValues||{}),g(!1);return}try{const d=await l.findOne(e.objectName,e.recordId);T(d||{})}catch(d){N(d)}finally{g(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const $=o.useCallback(s=>{const d=[];for(const f of s.fields){const n=typeof f=="string"?f:f.name;if(typeof f=="object")d.push(f);else if(u?.fields?.[n]){const S=u.fields[n];d.push({name:n,label:S.label||n,type:L.mapFieldTypeToFormType(S.type),required:S.required||!1,disabled:e.readOnly||e.mode==="view"||S.readonly,placeholder:S.placeholder,description:S.help||S.description,validation:L.buildValidationRules(S),field:S,options:S.options,multiple:S.multiple})}else d.push({name:n,label:n,type:"input"})}return d},[u,e.readOnly,e.mode]);o.useEffect(()=>{if(!u&&l)return;if(e.customFields?.length){C(e.customFields),g(!1);return}if(e.sections?.length){g(!1);return}if(!u)return;const s=e.fields||Object.keys(u.fields||{}),d=[];for(const f of s){const n=typeof f=="string"?f:f.name;if(!n)continue;const S=u.fields?.[n];S&&d.push({name:n,label:S.label||n,type:L.mapFieldTypeToFormType(S.type),required:S.required||!1,disabled:e.readOnly||e.mode==="view"||S.readonly,placeholder:S.placeholder,description:S.help||S.description,validation:L.buildValidationRules(S),field:S,options:S.options,multiple:S.multiple})}C(d),g(!1)},[u,e.fields,e.customFields,e.sections,e.readOnly,e.mode,l]);const I=o.useCallback(async s=>{if(!l)return e.onSuccess&&await e.onSuccess(s),e.onOpenChange?.(!1),s;try{let d;return e.mode==="create"?d=await l.create(e.objectName,s):e.mode==="edit"&&e.recordId&&(d=await l.update(e.objectName,e.recordId,s)),e.onSuccess&&await e.onSuccess(d),e.onOpenChange?.(!1),d}catch(d){throw e.onError&&e.onError(d),d}},[e,l]),k=o.useCallback(()=>{e.onCancel&&e.onCancel(),e.onOpenChange?.(!1)},[e]),M=o.useMemo(()=>e.drawerWidth?V==="left"||V==="right"?{width:e.drawerWidth,maxWidth:e.drawerWidth}:{height:e.drawerWidth,maxHeight:e.drawerWidth}:void 0,[e.drawerWidth,V]),a={type:"form",layout:e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical",defaultValues:O,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:I,onCancel:k},i=()=>x?t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:x.message})]}):E?t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]}):e.sections?.length?t.jsx("div",{className:"space-y-6",children:e.sections.map((s,d)=>t.jsx(Y,{label:s.label,description:s.description,columns:s.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...a,fields:$(s),showSubmit:d===e.sections.length-1&&a.showSubmit,showCancel:d===e.sections.length-1&&a.showCancel}})},s.name||s.label||d))}):t.jsx(R.SchemaRenderer,{schema:{...a,fields:m,columns:e.columns}});return t.jsx(j.Sheet,{open:D,onOpenChange:e.onOpenChange,children:t.jsxs(j.SheetContent,{side:V,className:j.cn("overflow-y-auto",c,e.className),style:M,children:[(e.title||e.description)&&t.jsxs(j.SheetHeader,{children:[e.title&&t.jsx(j.SheetTitle,{children:e.title}),e.description&&t.jsx(j.SheetDescription,{children:e.description})]}),t.jsx("div",{className:"py-4",children:i()})]})})},se={sm:"max-w-sm",default:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl",full:"max-w-[95vw] w-full"},ae=({schema:e,dataSource:l,className:c})=>{const[u,v]=o.useState(null),[m,C]=o.useState([]),[O,T]=o.useState({}),[E,g]=o.useState(!0),[x,N]=o.useState(null),D=e.open!==!1,V=se[e.modalSize||"default"]||se.default;o.useEffect(()=>{(async()=>{if(!l){g(!1);return}try{const s=await l.getObjectSchema(e.objectName);v(s)}catch(s){N(s),g(!1)}})()},[e.objectName,l]),o.useEffect(()=>{(u||!l)&&(async()=>{if(e.mode==="create"||!e.recordId){T(e.initialData||e.initialValues||{}),g(!1);return}if(!l){T(e.initialData||e.initialValues||{}),g(!1);return}try{const s=await l.findOne(e.objectName,e.recordId);T(s||{})}catch(s){N(s)}finally{g(!1)}})()},[u,e.mode,e.recordId,e.initialData,e.initialValues,l,e.objectName]);const $=o.useCallback(i=>{const s=[];for(const d of i.fields){const f=typeof d=="string"?d:d.name;if(typeof d=="object")s.push(d);else if(u?.fields?.[f]){const n=u.fields[f];s.push({name:f,label:n.label||f,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n,options:n.options,multiple:n.multiple})}else s.push({name:f,label:f,type:"input"})}return s},[u,e.readOnly,e.mode]);o.useEffect(()=>{if(!u&&l)return;if(e.customFields?.length){C(e.customFields),g(!1);return}if(e.sections?.length){g(!1);return}if(!u)return;const i=e.fields||Object.keys(u.fields||{}),s=[];for(const d of i){const f=typeof d=="string"?d:d.name;if(!f)continue;const n=u.fields?.[f];n&&s.push({name:f,label:n.label||f,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n,options:n.options,multiple:n.multiple})}C(s),g(!1)},[u,e.fields,e.customFields,e.sections,e.readOnly,e.mode,l]);const I=o.useCallback(async i=>{if(!l)return e.onSuccess&&await e.onSuccess(i),e.onOpenChange?.(!1),i;try{let s;return e.mode==="create"?s=await l.create(e.objectName,i):e.mode==="edit"&&e.recordId&&(s=await l.update(e.objectName,e.recordId,i)),e.onSuccess&&await e.onSuccess(s),e.onOpenChange?.(!1),s}catch(s){throw e.onError&&e.onError(s),s}},[e,l]),k=o.useCallback(()=>{e.onCancel&&e.onCancel(),e.onOpenChange?.(!1)},[e]),p={type:"form",layout:e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical",defaultValues:O,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,onSubmit:I,onCancel:k},a=()=>x?t.jsxs("div",{className:"p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:x.message})]}):E?t.jsxs("div",{className:"p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]}):e.sections?.length?t.jsx("div",{className:"space-y-6",children:e.sections.map((i,s)=>t.jsx(Y,{label:i.label,description:i.description,columns:i.columns||1,children:t.jsx(R.SchemaRenderer,{schema:{...p,fields:$(i),showSubmit:s===e.sections.length-1&&p.showSubmit,showCancel:s===e.sections.length-1&&p.showCancel}})},i.name||i.label||s))}):t.jsx(R.SchemaRenderer,{schema:{...p,fields:m,columns:e.columns}});return t.jsx(j.Dialog,{open:D,onOpenChange:e.onOpenChange,children:t.jsxs(j.DialogContent,{className:j.cn(V,"max-h-[90vh] overflow-y-auto",c,e.className),children:[(e.title||e.description)&&t.jsxs(j.DialogHeader,{children:[e.title&&t.jsx(j.DialogTitle,{children:e.title}),e.description&&t.jsx(j.DialogDescription,{children:e.description})]}),t.jsx("div",{className:"py-2",children:a()})]})})},de=({schema:e,dataSource:l})=>{if(e.formType==="tabbed"&&e.sections?.length)return t.jsx(le,{schema:{...e,formType:"tabbed",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),defaultTab:e.defaultTab,tabPosition:e.tabPosition},dataSource:l,className:e.className});if(e.formType==="wizard"&&e.sections?.length)return t.jsx(ie,{schema:{...e,formType:"wizard",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),allowSkip:e.allowSkip,showStepIndicator:e.showStepIndicator,nextText:e.nextText,prevText:e.prevText,onStepChange:e.onStepChange},dataSource:l,className:e.className});if(e.formType==="split"&&e.sections?.length)return t.jsx(ne,{schema:{...e,formType:"split",sections:e.sections.map(c=>({name:c.name,label:c.label,description:c.description,columns:c.columns,fields:c.fields})),splitDirection:e.splitDirection,splitSize:e.splitSize,splitResizable:e.splitResizable},dataSource:l,className:e.className});if(e.formType==="drawer"){const{layout:c,...u}=e,v=e.layout==="vertical"||e.layout==="horizontal"?e.layout:void 0;return t.jsx(oe,{schema:{...u,layout:v,formType:"drawer",sections:e.sections?.map(m=>({name:m.name,label:m.label,description:m.description,columns:m.columns,fields:m.fields})),open:e.open,onOpenChange:e.onOpenChange,drawerSide:e.drawerSide,drawerWidth:e.drawerWidth},dataSource:l,className:e.className})}if(e.formType==="modal"){const{layout:c,...u}=e,v=e.layout==="vertical"||e.layout==="horizontal"?e.layout:void 0;return t.jsx(ae,{schema:{...u,layout:v,formType:"modal",sections:e.sections?.map(m=>({name:m.name,label:m.label,description:m.description,columns:m.columns,fields:m.fields})),open:e.open,onOpenChange:e.onOpenChange,modalSize:e.modalSize,modalCloseButton:e.modalCloseButton},dataSource:l,className:e.className})}return t.jsx(xe,{schema:e,dataSource:l})},xe=({schema:e,dataSource:l})=>{const[c,u]=o.useState(null),[v,m]=o.useState([]),[C,O]=o.useState(null),[T,E]=o.useState(!0),[g,x]=o.useState(null),N=e.customFields&&e.customFields.length>0;o.useEffect(()=>{N&&(O(e.initialData||e.initialValues||{}),E(!1))},[N,e.initialData,e.initialValues]),o.useEffect(()=>{const p=async()=>{try{if(!l)throw new Error("DataSource is required when using ObjectQL schema fetching (inline fields not provided)");const a=await l.getObjectSchema(e.objectName);if(!a)throw new Error(`No schema found for object "${e.objectName}"`);u(a)}catch(a){x(a),E(!1)}};N?u({name:e.objectName,fields:{}}):e.objectName&&l?p():N||E(!1)},[e.objectName,l,N]),o.useEffect(()=>{c&&!N&&(async()=>{if(!e.recordId||e.mode==="create"){O(e.initialData||e.initialValues||{}),E(!1);return}if(!N){if(!l){x(new Error("DataSource is required for fetching record data (inline data not provided)")),E(!1);return}E(!0);try{const a=await l.findOne(e.objectName,e.recordId);O(a)}catch(a){console.error("Failed to fetch record:",a),x(a)}finally{E(!1)}}})()},[e.objectName,e.recordId,e.mode,e.initialValues,e.initialData,l,c,N]),o.useEffect(()=>{if(N&&e.customFields){m(e.customFields),E(!1);return}if(!c)return;const p=[],a=e.fields||Object.keys(c.fields||{});(Array.isArray(a)?a:Object.keys(a)).forEach(d=>{const f=typeof d=="string"?d:d.name;if(!f)return;const n=c.fields?.[f];if(!n&&!N)return;const S=!n?.permissions||n?.permissions.write!==!1;if(e.mode!=="view"&&!S)return;const W=e.customFields?.find(b=>b.name===f);if(W)p.push(W);else if(n){const b={name:f,label:n.label||d,type:L.mapFieldTypeToFormType(n.type),required:n.required||!1,disabled:e.readOnly||e.mode==="view"||n.readonly,placeholder:n.placeholder,description:n.help||n.description,validation:L.buildValidationRules(n),field:n};if((n.type==="select"||n.type==="lookup"||n.type==="master_detail")&&(b.options=n.options||[],b.multiple=n.multiple),(n.type==="number"||n.type==="currency"||n.type==="percent")&&(b.inputType="number",b.min=n.min,b.max=n.max,b.step=n.precision?Math.pow(10,-n.precision):void 0),n.type==="date"&&(b.inputType="date"),n.type==="datetime"&&(b.inputType="datetime-local"),(n.type==="text"||n.type==="textarea"||n.type==="markdown"||n.type==="html")&&(b.maxLength=n.max_length,b.minLength=n.min_length),(n.type==="file"||n.type==="image")&&(b.inputType="file",b.multiple=n.multiple,b.accept=n.accept?n.accept.join(","):void 0,n.max_size)){const w=`Max size: ${L.formatFileSize(n.max_size)}`;b.description=b.description?`${b.description} (${w})`:w}n.type==="email"&&(b.inputType="email"),n.type==="phone"&&(b.inputType="tel"),n.type==="url"&&(b.inputType="url"),n.type==="password"&&(b.inputType="password"),n.type==="time"&&(b.inputType="time"),(n.type==="formula"||n.type==="summary"||n.type==="auto_number")&&(b.disabled=!0),n.visible_on&&(b.visible=w=>L.evaluateCondition(n.visible_on,w)),p.push(b)}}),m(p),!N&&e.recordId&&e.mode!=="create"&&l||E(!1)},[c,e.fields,e.customFields,e.readOnly,e.mode,N,e.recordId,l]);const D=o.useCallback(async(p,a)=>{if(p&&(p.nativeEvent||p._reactName==="onSubmit")&&(console.warn("ObjectForm: Received Event instead of data in handleSubmit! This suggests a Form renderer issue."),a===void 0&&(a=p,p={})),N&&!l)return e.onSuccess&&await e.onSuccess(p),p;if(!l)throw new Error("DataSource is required for form submission (inline mode not configured)");try{let i;if(e.mode==="create")i=await l.create(e.objectName,p);else if(e.mode==="edit"&&e.recordId)i=await l.update(e.objectName,e.recordId,p);else throw new Error("Invalid form mode or missing record ID");return e.onSuccess&&await e.onSuccess(i),i}catch(i){throw console.error("Failed to submit form:",i),e.onError&&e.onError(i),i}},[e,l,N]),V=o.useCallback(()=>{e.onCancel&&e.onCancel()},[e]),I={...o.useMemo(()=>{if(!c?.fields)return{};const p={};return Object.keys(c.fields).forEach(a=>{const i=c.fields[a];i.defaultValue!==void 0&&(p[a]=i.defaultValue)}),p},[c]),...C};if(g)return t.jsxs("div",{className:"p-3 sm:p-4 border border-red-300 bg-red-50 rounded-md",children:[t.jsx("h3",{className:"text-red-800 font-semibold",children:"Error loading form"}),t.jsx("p",{className:"text-red-600 text-sm mt-1",children:g.message})]});if(T)return t.jsxs("div",{className:"p-4 sm:p-8 text-center",children:[t.jsx("div",{className:"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"}),t.jsx("p",{className:"mt-2 text-sm text-gray-600",children:"Loading form..."})]});const k=e.layout==="vertical"||e.layout==="horizontal"?e.layout:"vertical";if(e.sections?.length&&(!e.formType||e.formType==="simple"))return t.jsx("div",{className:"w-full space-y-6",children:e.sections.map((p,a)=>{const i=p.fields.map(d=>typeof d=="string"?d:d.name),s=v.filter(d=>i.includes(d.name));return t.jsx(Y,{label:p.label,description:p.description,collapsible:p.collapsible,collapsed:p.collapsed,columns:p.columns,children:t.jsx(R.SchemaRenderer,{schema:{type:"form",fields:s,layout:k,defaultValues:I,showSubmit:a===e.sections.length-1&&e.showSubmit!==!1&&e.mode!=="view",showCancel:a===e.sections.length-1&&e.showCancel!==!1,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,onSubmit:D,onCancel:V}})},p.name||p.label||a)})});const M={type:"form",fields:v,layout:k,columns:e.columns,submitLabel:e.submitText||(e.mode==="create"?"Create":"Update"),cancelLabel:e.cancelText,showSubmit:e.showSubmit!==!1&&e.mode!=="view",showCancel:e.showCancel!==!1,resetOnSubmit:e.showReset,defaultValues:I,onSubmit:D,onCancel:V,className:e.className};return t.jsx("div",{className:"w-full",children:t.jsx(R.SchemaRenderer,{schema:M})})},ue=({schema:e})=>t.jsx(de,{schema:e});K.ComponentRegistry.register("object-form",ue,{namespace:"plugin-form",label:"Object Form",category:"plugin",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"fields",type:"array",label:"Fields"},{name:"mode",type:"enum",label:"Mode",enum:["create","edit","view"]},{name:"formType",type:"enum",label:"Form Type",enum:["simple","tabbed","wizard","split","drawer","modal"]},{name:"sections",type:"array",label:"Sections"},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Layout",enum:["vertical","horizontal","inline","grid"]},{name:"columns",type:"number",label:"Columns"},{name:"defaultTab",type:"string",label:"Default Tab"},{name:"tabPosition",type:"enum",label:"Tab Position",enum:["top","bottom","left","right"]},{name:"allowSkip",type:"boolean",label:"Allow Skip Steps"},{name:"showStepIndicator",type:"boolean",label:"Show Step Indicator"},{name:"splitDirection",type:"enum",label:"Split Direction",enum:["horizontal","vertical"]},{name:"splitSize",type:"number",label:"Split Panel Size (%)"},{name:"splitResizable",type:"boolean",label:"Split Resizable"},{name:"drawerSide",type:"enum",label:"Drawer Side",enum:["top","bottom","left","right"]},{name:"drawerWidth",type:"string",label:"Drawer Width"},{name:"modalSize",type:"enum",label:"Modal Size",enum:["sm","default","lg","xl","full"]}]}),K.ComponentRegistry.register("form",ue,{namespace:"view",skipFallback:!0,label:"Data Form View",category:"view",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"fields",type:"array",label:"Fields"},{name:"mode",type:"enum",label:"Mode",enum:["create","edit","view"]}]}),z.DrawerForm=oe,z.FormSection=Y,z.ModalForm=ae,z.ObjectForm=de,z.SplitForm=ne,z.TabbedForm=le,z.WizardForm=ie,Object.defineProperty(z,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: import('react').ForwardRefExoticComponent<Omit<{
|
|
5
|
+
schema: import('../../core/src').SchemaNode;
|
|
6
|
+
} & Record<string, any>, "ref"> & import('react').RefAttributes<any>>;
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: string;
|
|
9
|
+
};
|
|
10
|
+
tags: string[];
|
|
11
|
+
argTypes: {
|
|
12
|
+
schema: {
|
|
13
|
+
table: {
|
|
14
|
+
disable: true;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
export declare const Default: Story;
|
|
22
|
+
export declare const WithSections: Story;
|
|
23
|
+
export declare const ComplexFields: Story;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-form",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Form plugin for Object UI",
|
|
@@ -16,23 +16,23 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"lucide-react": "^0.563.0",
|
|
19
|
-
"@object-ui/
|
|
20
|
-
"@object-ui/
|
|
21
|
-
"@object-ui/fields": "
|
|
22
|
-
"@object-ui/react": "
|
|
23
|
-
"@object-ui/types": "
|
|
19
|
+
"@object-ui/components": "3.0.1",
|
|
20
|
+
"@object-ui/core": "3.0.1",
|
|
21
|
+
"@object-ui/fields": "3.0.1",
|
|
22
|
+
"@object-ui/react": "3.0.1",
|
|
23
|
+
"@object-ui/types": "3.0.1"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"react": "^18.0.0 || ^19.0.0",
|
|
27
27
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@vitejs/plugin-react": "^5.1.
|
|
31
|
-
"msw": "^2.12.
|
|
30
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
31
|
+
"msw": "^2.12.10",
|
|
32
32
|
"typescript": "^5.9.3",
|
|
33
33
|
"vite": "^7.3.1",
|
|
34
34
|
"vite-plugin-dts": "^4.5.4",
|
|
35
|
-
"@object-ui/data-objectstack": "
|
|
35
|
+
"@object-ui/data-objectstack": "3.0.1"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "vite build",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react';
|
|
3
|
+
import type { BaseSchema } from '@object-ui/types';
|
|
4
|
+
import { createStorybookDataSource } from '@storybook-config/datasource';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Plugins/ObjectForm',
|
|
8
|
+
component: SchemaRenderer,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {
|
|
14
|
+
schema: { table: { disable: true } },
|
|
15
|
+
},
|
|
16
|
+
} satisfies Meta<any>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
const dataSource = createStorybookDataSource();
|
|
22
|
+
|
|
23
|
+
const renderStory = (args: any) => (
|
|
24
|
+
<SchemaRendererProvider dataSource={dataSource}>
|
|
25
|
+
<SchemaRenderer schema={args as unknown as BaseSchema} />
|
|
26
|
+
</SchemaRendererProvider>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: renderStory,
|
|
31
|
+
args: {
|
|
32
|
+
type: 'object-form',
|
|
33
|
+
objectName: 'Contact',
|
|
34
|
+
customFields: [
|
|
35
|
+
{ name: 'firstName', label: 'First Name', type: 'text', required: true },
|
|
36
|
+
{ name: 'lastName', label: 'Last Name', type: 'text', required: true },
|
|
37
|
+
{ name: 'email', label: 'Email', type: 'email', required: true },
|
|
38
|
+
{ name: 'phone', label: 'Phone', type: 'tel' },
|
|
39
|
+
],
|
|
40
|
+
className: 'w-full max-w-2xl',
|
|
41
|
+
} as any,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const WithSections: Story = {
|
|
45
|
+
render: renderStory,
|
|
46
|
+
args: {
|
|
47
|
+
type: 'object-form',
|
|
48
|
+
objectName: 'Employee',
|
|
49
|
+
sections: [
|
|
50
|
+
{
|
|
51
|
+
title: 'Personal Information',
|
|
52
|
+
fields: [
|
|
53
|
+
{ name: 'firstName', label: 'First Name', type: 'text', required: true },
|
|
54
|
+
{ name: 'lastName', label: 'Last Name', type: 'text', required: true },
|
|
55
|
+
{ name: 'dateOfBirth', label: 'Date of Birth', type: 'date' },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Work Details',
|
|
60
|
+
fields: [
|
|
61
|
+
{ name: 'department', label: 'Department', type: 'select', options: ['Engineering', 'Marketing', 'Sales', 'HR'] },
|
|
62
|
+
{ name: 'role', label: 'Role', type: 'text' },
|
|
63
|
+
{ name: 'startDate', label: 'Start Date', type: 'date' },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
className: 'w-full max-w-2xl',
|
|
68
|
+
} as any,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const ComplexFields: Story = {
|
|
72
|
+
render: renderStory,
|
|
73
|
+
args: {
|
|
74
|
+
type: 'object-form',
|
|
75
|
+
objectName: 'Product',
|
|
76
|
+
customFields: [
|
|
77
|
+
{ name: 'name', label: 'Product Name', type: 'text', required: true },
|
|
78
|
+
{ name: 'category', label: 'Category', type: 'select', options: ['Electronics', 'Clothing', 'Food', 'Books'], required: true },
|
|
79
|
+
{ name: 'price', label: 'Price', type: 'number', required: true },
|
|
80
|
+
{ name: 'inStock', label: 'In Stock', type: 'checkbox' },
|
|
81
|
+
{ name: 'description', label: 'Description', type: 'textarea', rows: 4 },
|
|
82
|
+
],
|
|
83
|
+
className: 'w-full max-w-2xl',
|
|
84
|
+
} as any,
|
|
85
|
+
};
|
package/src/ObjectForm.tsx
CHANGED
|
@@ -511,7 +511,7 @@ const SimpleObjectForm: React.FC<ObjectFormProps> = ({
|
|
|
511
511
|
// Render error state
|
|
512
512
|
if (error) {
|
|
513
513
|
return (
|
|
514
|
-
<div className="p-4 border border-red-300 bg-red-50 rounded-md">
|
|
514
|
+
<div className="p-3 sm:p-4 border border-red-300 bg-red-50 rounded-md">
|
|
515
515
|
<h3 className="text-red-800 font-semibold">Error loading form</h3>
|
|
516
516
|
<p className="text-red-600 text-sm mt-1">{error.message}</p>
|
|
517
517
|
</div>
|
|
@@ -521,7 +521,7 @@ const SimpleObjectForm: React.FC<ObjectFormProps> = ({
|
|
|
521
521
|
// Render loading state
|
|
522
522
|
if (loading) {
|
|
523
523
|
return (
|
|
524
|
-
<div className="p-8 text-center">
|
|
524
|
+
<div className="p-4 sm:p-8 text-center">
|
|
525
525
|
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
|
|
526
526
|
<p className="mt-2 text-sm text-gray-600">Loading form...</p>
|
|
527
527
|
</div>
|
package/src/WizardForm.tsx
CHANGED
|
@@ -364,7 +364,7 @@ export const WizardForm: React.FC<WizardFormProps> = ({
|
|
|
364
364
|
{/* Connector line */}
|
|
365
365
|
{index !== totalSteps - 1 && (
|
|
366
366
|
<div
|
|
367
|
-
className="absolute top-4 left-
|
|
367
|
+
className="absolute top-3 sm:top-4 left-6 -right-4 sm:left-10 sm:-right-2 h-0.5"
|
|
368
368
|
aria-hidden="true"
|
|
369
369
|
>
|
|
370
370
|
<div
|
|
@@ -385,24 +385,24 @@ export const WizardForm: React.FC<WizardFormProps> = ({
|
|
|
385
385
|
onClick={() => handleStepClick(index)}
|
|
386
386
|
disabled={!isClickable}
|
|
387
387
|
>
|
|
388
|
-
{/* Step circle */}
|
|
388
|
+
{/* Step circle - smaller on mobile */}
|
|
389
389
|
<span
|
|
390
390
|
className={cn(
|
|
391
|
-
'flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors',
|
|
391
|
+
'flex h-6 w-6 sm:h-8 sm:w-8 items-center justify-center rounded-full text-xs sm:text-sm font-medium transition-colors',
|
|
392
392
|
isCompleted && 'bg-primary text-primary-foreground',
|
|
393
393
|
isActive && !isCompleted && 'border-2 border-primary bg-background text-primary',
|
|
394
394
|
!isActive && !isCompleted && 'border-2 border-muted bg-background text-muted-foreground'
|
|
395
395
|
)}
|
|
396
396
|
>
|
|
397
397
|
{isCompleted ? (
|
|
398
|
-
<Check className="h-4 w-4" />
|
|
398
|
+
<Check className="h-3 w-3 sm:h-4 sm:w-4" />
|
|
399
399
|
) : (
|
|
400
400
|
index + 1
|
|
401
401
|
)}
|
|
402
402
|
</span>
|
|
403
403
|
|
|
404
404
|
{/* Step label */}
|
|
405
|
-
<span className="ml-3 text-sm font-medium hidden sm:block">
|
|
405
|
+
<span className="ml-2 sm:ml-3 text-xs sm:text-sm font-medium hidden sm:block">
|
|
406
406
|
<span
|
|
407
407
|
className={cn(
|
|
408
408
|
isActive ? 'text-foreground' : 'text-muted-foreground'
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* P3.4 Integration Test — Form Validation + Submit Workflow
|
|
11
|
+
*
|
|
12
|
+
* Tests the full lifecycle: required-field validation → inline errors →
|
|
13
|
+
* successful submit → form reset.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
17
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
18
|
+
import userEvent from '@testing-library/user-event';
|
|
19
|
+
import React from 'react';
|
|
20
|
+
import { ObjectForm } from '../ObjectForm';
|
|
21
|
+
|
|
22
|
+
// ─── Shared Fixtures ────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
const mockObjectSchema = {
|
|
25
|
+
name: 'contacts',
|
|
26
|
+
fields: {
|
|
27
|
+
firstName: { label: 'First Name', type: 'text', required: true },
|
|
28
|
+
lastName: { label: 'Last Name', type: 'text', required: false },
|
|
29
|
+
email: { label: 'Email', type: 'email', required: true },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const createMockDataSource = () => ({
|
|
34
|
+
getObjectSchema: vi.fn().mockResolvedValue(mockObjectSchema),
|
|
35
|
+
findOne: vi.fn().mockResolvedValue({}),
|
|
36
|
+
find: vi.fn().mockResolvedValue([]),
|
|
37
|
+
create: vi.fn().mockResolvedValue({ id: '1' }),
|
|
38
|
+
update: vi.fn().mockResolvedValue({ id: '1' }),
|
|
39
|
+
delete: vi.fn().mockResolvedValue(true),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// ─── Tests ──────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
describe('P3.4 Form Validation + Submit Workflow', () => {
|
|
45
|
+
let mockDataSource: ReturnType<typeof createMockDataSource>;
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
mockDataSource = createMockDataSource();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// --- Required field validation before submit ---
|
|
52
|
+
|
|
53
|
+
it('validates required fields and prevents submission when empty', async () => {
|
|
54
|
+
const user = userEvent.setup();
|
|
55
|
+
const onSuccess = vi.fn();
|
|
56
|
+
|
|
57
|
+
render(
|
|
58
|
+
<ObjectForm
|
|
59
|
+
schema={{
|
|
60
|
+
type: 'object-form',
|
|
61
|
+
objectName: 'contacts',
|
|
62
|
+
mode: 'create',
|
|
63
|
+
fields: ['firstName', 'email'],
|
|
64
|
+
onSuccess,
|
|
65
|
+
}}
|
|
66
|
+
dataSource={mockDataSource as any}
|
|
67
|
+
/>,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Wait for the form to load
|
|
71
|
+
await waitFor(() => {
|
|
72
|
+
expect(screen.getByText('First Name')).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Click submit without filling in required fields
|
|
76
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
77
|
+
await user.click(submitButton);
|
|
78
|
+
|
|
79
|
+
// The data source should NOT have been called
|
|
80
|
+
await waitFor(() => {
|
|
81
|
+
expect(mockDataSource.create).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// --- Inline validation errors ---
|
|
87
|
+
|
|
88
|
+
it('shows inline validation error messages for required fields', async () => {
|
|
89
|
+
const user = userEvent.setup();
|
|
90
|
+
|
|
91
|
+
render(
|
|
92
|
+
<ObjectForm
|
|
93
|
+
schema={{
|
|
94
|
+
type: 'object-form',
|
|
95
|
+
objectName: 'contacts',
|
|
96
|
+
mode: 'create',
|
|
97
|
+
fields: ['firstName', 'email'],
|
|
98
|
+
}}
|
|
99
|
+
dataSource={mockDataSource as any}
|
|
100
|
+
/>,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect(screen.getByText('First Name')).toBeInTheDocument();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Submit with empty required fields
|
|
108
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
109
|
+
await user.click(submitButton);
|
|
110
|
+
|
|
111
|
+
// Validation messages should appear
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(screen.getByText(/first name is required/i)).toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// --- Successful submit calls handler ---
|
|
118
|
+
|
|
119
|
+
it('calls onSuccess handler after successful submission', async () => {
|
|
120
|
+
const user = userEvent.setup();
|
|
121
|
+
const onSuccess = vi.fn();
|
|
122
|
+
|
|
123
|
+
render(
|
|
124
|
+
<ObjectForm
|
|
125
|
+
schema={{
|
|
126
|
+
type: 'object-form',
|
|
127
|
+
objectName: 'contacts',
|
|
128
|
+
mode: 'create',
|
|
129
|
+
fields: ['firstName', 'email'],
|
|
130
|
+
onSuccess,
|
|
131
|
+
}}
|
|
132
|
+
dataSource={mockDataSource as any}
|
|
133
|
+
/>,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// Wait for the form to load
|
|
137
|
+
await waitFor(() => {
|
|
138
|
+
expect(screen.getByText('First Name')).toBeInTheDocument();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Fill in the required fields
|
|
142
|
+
const inputs = screen.getAllByRole('textbox');
|
|
143
|
+
// First Name input
|
|
144
|
+
await user.type(inputs[0], 'John');
|
|
145
|
+
// Email input
|
|
146
|
+
await user.type(inputs[1], 'john@example.com');
|
|
147
|
+
|
|
148
|
+
// Submit
|
|
149
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
150
|
+
await user.click(submitButton);
|
|
151
|
+
|
|
152
|
+
// dataSource.create should have been called
|
|
153
|
+
await waitFor(() => {
|
|
154
|
+
expect(mockDataSource.create).toHaveBeenCalledWith(
|
|
155
|
+
'contacts',
|
|
156
|
+
expect.objectContaining({
|
|
157
|
+
firstName: 'John',
|
|
158
|
+
email: 'john@example.com',
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// onSuccess should have been called with result
|
|
164
|
+
await waitFor(() => {
|
|
165
|
+
expect(onSuccess).toHaveBeenCalledWith({ id: '1' });
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// --- Form reset after submit ---
|
|
170
|
+
|
|
171
|
+
it('resets form fields after successful submission when showReset is true', async () => {
|
|
172
|
+
const user = userEvent.setup();
|
|
173
|
+
|
|
174
|
+
render(
|
|
175
|
+
<ObjectForm
|
|
176
|
+
schema={{
|
|
177
|
+
type: 'object-form',
|
|
178
|
+
objectName: 'contacts',
|
|
179
|
+
mode: 'create',
|
|
180
|
+
fields: ['firstName', 'email'],
|
|
181
|
+
showReset: true,
|
|
182
|
+
onSuccess: vi.fn(),
|
|
183
|
+
}}
|
|
184
|
+
dataSource={mockDataSource as any}
|
|
185
|
+
/>,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
await waitFor(() => {
|
|
189
|
+
expect(screen.getByText('First Name')).toBeInTheDocument();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const inputs = screen.getAllByRole('textbox');
|
|
193
|
+
await user.type(inputs[0], 'Jane');
|
|
194
|
+
await user.type(inputs[1], 'jane@example.com');
|
|
195
|
+
|
|
196
|
+
// Submit
|
|
197
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
198
|
+
await user.click(submitButton);
|
|
199
|
+
|
|
200
|
+
// After successful submit the inputs should be cleared
|
|
201
|
+
await waitFor(() => {
|
|
202
|
+
expect(mockDataSource.create).toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await waitFor(() => {
|
|
206
|
+
expect(inputs[0]).toHaveValue('');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// --- Inline-field form (no dataSource) ---
|
|
211
|
+
|
|
212
|
+
it('supports inline customFields without a dataSource', async () => {
|
|
213
|
+
const user = userEvent.setup();
|
|
214
|
+
const onSuccess = vi.fn();
|
|
215
|
+
|
|
216
|
+
render(
|
|
217
|
+
<ObjectForm
|
|
218
|
+
schema={{
|
|
219
|
+
type: 'object-form',
|
|
220
|
+
objectName: 'inline_form',
|
|
221
|
+
mode: 'create',
|
|
222
|
+
customFields: [
|
|
223
|
+
{ name: 'username', label: 'Username', type: 'input', required: true },
|
|
224
|
+
],
|
|
225
|
+
onSuccess,
|
|
226
|
+
}}
|
|
227
|
+
/>,
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
await waitFor(() => {
|
|
231
|
+
expect(screen.getByText('Username')).toBeInTheDocument();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Submit empty — should not succeed
|
|
235
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
236
|
+
await user.click(submitButton);
|
|
237
|
+
expect(onSuccess).not.toHaveBeenCalled();
|
|
238
|
+
|
|
239
|
+
// Fill in and resubmit
|
|
240
|
+
const input = screen.getByRole('textbox');
|
|
241
|
+
await user.type(input, 'admin');
|
|
242
|
+
await user.click(submitButton);
|
|
243
|
+
|
|
244
|
+
await waitFor(() => {
|
|
245
|
+
expect(onSuccess).toHaveBeenCalledWith(
|
|
246
|
+
expect.objectContaining({ username: 'admin' }),
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// --- Error callback on failed submission ---
|
|
252
|
+
|
|
253
|
+
it('calls onError when dataSource.create rejects', async () => {
|
|
254
|
+
const user = userEvent.setup();
|
|
255
|
+
const onError = vi.fn();
|
|
256
|
+
mockDataSource.create.mockRejectedValueOnce(new Error('Network failure'));
|
|
257
|
+
|
|
258
|
+
render(
|
|
259
|
+
<ObjectForm
|
|
260
|
+
schema={{
|
|
261
|
+
type: 'object-form',
|
|
262
|
+
objectName: 'contacts',
|
|
263
|
+
mode: 'create',
|
|
264
|
+
fields: ['firstName', 'email'],
|
|
265
|
+
onError,
|
|
266
|
+
}}
|
|
267
|
+
dataSource={mockDataSource as any}
|
|
268
|
+
/>,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
await waitFor(() => {
|
|
272
|
+
expect(screen.getByText('First Name')).toBeInTheDocument();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const inputs = screen.getAllByRole('textbox');
|
|
276
|
+
await user.type(inputs[0], 'John');
|
|
277
|
+
await user.type(inputs[1], 'john@example.com');
|
|
278
|
+
|
|
279
|
+
const submitButton = screen.getByRole('button', { name: /create/i });
|
|
280
|
+
await user.click(submitButton);
|
|
281
|
+
|
|
282
|
+
await waitFor(() => {
|
|
283
|
+
expect(onError).toHaveBeenCalledWith(expect.any(Error));
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|