@lssm/lib.design-system 1.7.2 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/atoms/ActionButtons.d.ts +10 -10
- package/dist/components/atoms/Button.d.ts +2 -2
- package/dist/components/atoms/Button.mobile.d.ts +2 -2
- package/dist/components/atoms/Button.mobile.d.ts.map +1 -1
- package/dist/components/atoms/ButtonLink.d.ts +2 -2
- package/dist/components/atoms/ButtonLink.mobile.d.ts +2 -2
- package/dist/components/atoms/ButtonLink.mobile.d.ts.map +1 -1
- package/dist/components/atoms/DataChips.d.ts +7 -7
- package/dist/components/atoms/DataChips.d.ts.map +1 -1
- package/dist/components/atoms/EmptyState.d.ts +2 -2
- package/dist/components/atoms/EmptyState.d.ts.map +1 -1
- package/dist/components/atoms/ErrorState.d.ts +2 -2
- package/dist/components/atoms/ErrorState.mobile.d.ts +2 -2
- package/dist/components/atoms/ErrorState.mobile.d.ts.map +1 -1
- package/dist/components/atoms/Input.d.ts +2 -2
- package/dist/components/atoms/Input.d.ts.map +1 -1
- package/dist/components/atoms/Input.mobile.d.ts +2 -2
- package/dist/components/atoms/Input.mobile.d.ts.map +1 -1
- package/dist/components/atoms/Link.d.ts +2 -2
- package/dist/components/atoms/Link.d.ts.map +1 -1
- package/dist/components/atoms/Link.web.d.ts +2 -2
- package/dist/components/atoms/LoaderCircular.d.ts +4 -4
- package/dist/components/atoms/LoaderCircular.d.ts.map +1 -1
- package/dist/components/atoms/LoaderCircular.mobile.d.ts +2 -2
- package/dist/components/atoms/NavBrand.d.ts +2 -2
- package/dist/components/atoms/Stepper.d.ts +2 -2
- package/dist/components/atoms/Textarea.d.ts +2 -2
- package/dist/components/atoms/Textarea.mobile.d.ts +2 -2
- package/dist/components/data-view/DataViewDetail.d.ts +2 -3
- package/dist/components/data-view/DataViewDetail.d.ts.map +1 -1
- package/dist/components/data-view/DataViewList.d.ts +2 -3
- package/dist/components/data-view/DataViewList.d.ts.map +1 -1
- package/dist/components/data-view/DataViewRenderer.d.ts +2 -3
- package/dist/components/data-view/DataViewRenderer.d.ts.map +1 -1
- package/dist/components/data-view/DataViewTable.d.ts +2 -3
- package/dist/components/data-view/DataViewTable.d.ts.map +1 -1
- package/dist/components/forms/FormCardLayout.d.ts +2 -2
- package/dist/components/forms/FormCardLayout.d.ts.map +1 -1
- package/dist/components/forms/FormDialog.d.ts +2 -2
- package/dist/components/forms/FormDialog.d.ts.map +1 -1
- package/dist/components/forms/FormLayout.d.ts +4 -4
- package/dist/components/forms/FormLayout.d.ts.map +1 -1
- package/dist/components/forms/FormOneByOneLayout.d.ts +2 -2
- package/dist/components/forms/FormOneByOneLayout.d.ts.map +1 -1
- package/dist/components/forms/FormStepsLayout.d.ts +2 -2
- package/dist/components/forms/ZodForm.d.ts +2 -2
- package/dist/components/forms/ZodForm.d.ts.map +1 -1
- package/dist/components/legal/atoms/DefinitionList.d.ts +2 -2
- package/dist/components/legal/atoms/KeyValueList.d.ts +2 -2
- package/dist/components/legal/atoms/LegalCallout.d.ts +4 -4
- package/dist/components/legal/atoms/LegalCallout.d.ts.map +1 -1
- package/dist/components/legal/atoms/LegalHeading.d.ts +5 -5
- package/dist/components/legal/atoms/LegalHeading.d.ts.map +1 -1
- package/dist/components/legal/atoms/LegalList.d.ts +4 -4
- package/dist/components/legal/atoms/LegalList.d.ts.map +1 -1
- package/dist/components/legal/atoms/LegalSection.d.ts +4 -4
- package/dist/components/legal/atoms/LegalSection.d.ts.map +1 -1
- package/dist/components/legal/atoms/LegalText.d.ts +6 -6
- package/dist/components/legal/molecules/Consent.d.ts +3 -3
- package/dist/components/legal/molecules/ContactFields.d.ts +2 -2
- package/dist/components/legal/molecules/LegalMeta.d.ts +2 -2
- package/dist/components/legal/molecules/LegalTOC.d.ts +4 -4
- package/dist/components/legal/molecules/LegalTOC.d.ts.map +1 -1
- package/dist/components/legal/organisms/ContactForm.d.ts +2 -2
- package/dist/components/legal/organisms/GDPRDataRequest.d.ts +2 -2
- package/dist/components/legal/organisms/GDPRDataRequest.d.ts.map +1 -1
- package/dist/components/legal/organisms/GDPRRights.d.ts +2 -2
- package/dist/components/legal/organisms/LegalPageLayout.d.ts +2 -2
- package/dist/components/legal/templates/ContactTemplate.d.ts +2 -2
- package/dist/components/legal/templates/ContactTemplate.d.ts.map +1 -1
- package/dist/components/legal/templates/CookiesTemplate.d.ts +2 -2
- package/dist/components/legal/templates/PrivacyTemplate.d.ts +2 -2
- package/dist/components/legal/templates/SalesTermsTemplate.d.ts +2 -2
- package/dist/components/legal/templates/TermsTemplate.d.ts +2 -2
- package/dist/components/molecules/AiLinkButton.d.ts +2 -2
- package/dist/components/molecules/Breadcrumbs.d.ts +2 -2
- package/dist/components/molecules/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/molecules/CommandPalette.d.ts +2 -2
- package/dist/components/molecules/CommandSearchTrigger.d.ts +2 -2
- package/dist/components/molecules/EntityCard.d.ts +4 -4
- package/dist/components/molecules/EntityCard.d.ts.map +1 -1
- package/dist/components/molecules/FiltersToolbar.d.ts +2 -2
- package/dist/components/molecules/FiltersToolbar.mobile.d.ts +2 -2
- package/dist/components/molecules/HoverPreview.d.ts +2 -2
- package/dist/components/molecules/LangSwitch.d.ts +2 -2
- package/dist/components/molecules/LangSwitchDropdown.d.ts +2 -2
- package/dist/components/molecules/LoaderBlock.d.ts +2 -2
- package/dist/components/molecules/LoaderBlock.mobile.d.ts +2 -2
- package/dist/components/molecules/MobileNavMenu.d.ts +2 -2
- package/dist/components/molecules/NavItemCard.d.ts +2 -2
- package/dist/components/molecules/NavMain.d.ts +2 -2
- package/dist/components/molecules/NavUser.d.ts +2 -2
- package/dist/components/molecules/OverviewCard.d.ts +2 -2
- package/dist/components/molecules/SkeletonBlock/index.mobile.d.ts +2 -2
- package/dist/components/molecules/SkeletonBlock/index.web.d.ts +2 -2
- package/dist/components/molecules/SkeletonCircle/index.mobile.d.ts +2 -2
- package/dist/components/molecules/SkeletonCircle/index.mobile.d.ts.map +1 -1
- package/dist/components/molecules/SkeletonCircle/index.web.d.ts +2 -2
- package/dist/components/molecules/SkeletonCircle/index.web.d.ts.map +1 -1
- package/dist/components/molecules/SkeletonList/index.mobile.d.ts +2 -2
- package/dist/components/molecules/SkeletonList/index.web.d.ts +2 -2
- package/dist/components/molecules/StatCard.d.ts +5 -5
- package/dist/components/molecules/StatCard.d.ts.map +1 -1
- package/dist/components/molecules/StatusChip.d.ts +5 -5
- package/dist/components/molecules/StatusChip.d.ts.map +1 -1
- package/dist/components/molecules/hover-previews/Doc.d.ts +2 -2
- package/dist/components/molecules/hover-previews/Media.d.ts +2 -2
- package/dist/components/molecules/hover-previews/Simple.d.ts +2 -2
- package/dist/components/molecules/hover-previews/Simple.d.ts.map +1 -1
- package/dist/components/molecules/hover-previews/Stats.d.ts +2 -2
- package/dist/components/molecules/hover-previews/User.d.ts +2 -2
- package/dist/components/molecules/hover-previews/User.d.ts.map +1 -1
- package/dist/components/native/BottomTabs.mobile.d.ts +2 -2
- package/dist/components/native/BottomTabs.mobile.d.ts.map +1 -1
- package/dist/components/native/FlatListScreen.mobile.d.ts +5 -5
- package/dist/components/native/FlatListScreen.mobile.d.ts.map +1 -1
- package/dist/components/native/SheetMenu.mobile.d.ts +2 -2
- package/dist/components/native/SheetMenu.mobile.d.ts.map +1 -1
- package/dist/components/organisms/AcademyLayout.d.ts +2 -2
- package/dist/components/organisms/AcademyLayout.d.ts.map +1 -1
- package/dist/components/organisms/AppHeader.d.ts +2 -2
- package/dist/components/organisms/AppHeader.d.ts.map +1 -1
- package/dist/components/organisms/AppHeader.mobile.d.ts +2 -2
- package/dist/components/organisms/AppHeader.mobile.d.ts.map +1 -1
- package/dist/components/organisms/AppLayout.d.ts +2 -2
- package/dist/components/organisms/AppLayout.d.ts.map +1 -1
- package/dist/components/organisms/AppSidebar.d.ts +2 -2
- package/dist/components/organisms/AppSidebar.d.ts.map +1 -1
- package/dist/components/organisms/EmptyDataList.d.ts +2 -2
- package/dist/components/organisms/EmptyDataList.d.ts.map +1 -1
- package/dist/components/organisms/EmptyDataList.mobile.d.ts +2 -2
- package/dist/components/organisms/EmptyDataList.mobile.d.ts.map +1 -1
- package/dist/components/organisms/EmptySearchResult.d.ts +2 -2
- package/dist/components/organisms/EmptySearchResult.d.ts.map +1 -1
- package/dist/components/organisms/FAQSection.d.ts +2 -2
- package/dist/components/organisms/FeatureCarousel.d.ts +2 -2
- package/dist/components/organisms/FeatureCarousel.d.ts.map +1 -1
- package/dist/components/organisms/FeaturesSection.d.ts +2 -2
- package/dist/components/organisms/FeaturesSection.d.ts.map +1 -1
- package/dist/components/organisms/Footer.d.ts +2 -2
- package/dist/components/organisms/Footer.d.ts.map +1 -1
- package/dist/components/organisms/GridLayout.d.ts +4 -4
- package/dist/components/organisms/GridLayout.d.ts.map +1 -1
- package/dist/components/organisms/Header.d.ts +4 -4
- package/dist/components/organisms/Header.d.ts.map +1 -1
- package/dist/components/organisms/Header.mobile.d.ts +2 -2
- package/dist/components/organisms/HeroResponsive.d.ts +2 -2
- package/dist/components/organisms/HeroResponsive.d.ts.map +1 -1
- package/dist/components/organisms/HeroSection.d.ts +2 -2
- package/dist/components/organisms/HeroSection.d.ts.map +1 -1
- package/dist/components/organisms/ListCardPage.d.ts +5 -5
- package/dist/components/organisms/ListCardPage.d.ts.map +1 -1
- package/dist/components/organisms/ListGridPage.d.ts +5 -5
- package/dist/components/organisms/ListGridPage.d.ts.map +1 -1
- package/dist/components/organisms/ListPageResponsive.d.ts +2 -2
- package/dist/components/organisms/ListPageResponsive.d.ts.map +1 -1
- package/dist/components/organisms/ListTablePage.d.ts +4 -4
- package/dist/components/organisms/ListTablePage.d.ts.map +1 -1
- package/dist/components/organisms/MarketingHeader.d.ts +2 -2
- package/dist/components/organisms/MarketingHeaderDesktop.d.ts +2 -2
- package/dist/components/organisms/MarketingHeaderDesktop.d.ts.map +1 -1
- package/dist/components/organisms/MarketingHeaderMobile.d.ts +2 -2
- package/dist/components/organisms/MarketingHeaderMobile.d.ts.map +1 -1
- package/dist/components/organisms/MarketingLayout.d.ts +2 -2
- package/dist/components/organisms/PageHeaderResponsive.d.ts +2 -2
- package/dist/components/organisms/PageHeaderResponsive.mobile.d.ts +2 -2
- package/dist/components/organisms/PricingCarousel.d.ts +2 -2
- package/dist/components/organisms/PricingSection.d.ts +2 -2
- package/dist/components/organisms/TestimonialCarousel.d.ts +2 -2
- package/dist/components/templates/lists/ListPageTemplate/index.mobile.d.ts +2 -2
- package/dist/components/templates/lists/ListPageTemplate/index.mobile.d.ts.map +1 -1
- package/dist/components/templates/lists/ListPageTemplate/index.mobile.js +1 -1
- package/dist/components/templates/lists/ListPageTemplate/index.web.d.ts +2 -2
- package/dist/components/templates/lists/ListPageTemplate/index.web.d.ts.map +1 -1
- package/dist/contracts/src/client/react/drivers/shadcn.js +12 -0
- package/dist/contracts/src/client/react/drivers/shadcn.js.map +1 -0
- package/dist/contracts/src/client/react/form-render.js +299 -0
- package/dist/contracts/src/client/react/form-render.js.map +1 -0
- package/dist/contracts/src/forms.js +89 -0
- package/dist/contracts/src/forms.js.map +1 -0
- package/dist/lib/keyboard.d.ts.map +1 -1
- package/dist/renderers/form-contract.d.ts +2 -5
- package/dist/renderers/form-contract.d.ts.map +1 -1
- package/dist/renderers/form-contract.js +6 -6
- package/dist/renderers/form-contract.js.map +1 -1
- package/dist/theme/tokenBridge.d.ts.map +1 -1
- package/dist/theme/variants.d.ts +3 -3
- package/dist/types/navigation.d.ts.map +1 -1
- package/dist/ui-kit-web/dist/ui/sidebar.js +84 -182
- package/dist/ui-kit-web/dist/ui/sidebar.js.map +1 -1
- package/package.json +301 -150
- package/dist/contracts/dist/client/react/drivers/shadcn.js +0 -8
- package/dist/contracts/dist/client/react/drivers/shadcn.js.map +0 -1
- package/dist/contracts/dist/client/react/form-render.js +0 -262
- package/dist/contracts/dist/client/react/form-render.js.map +0 -1
- package/dist/contracts/dist/forms.js +0 -79
- package/dist/contracts/dist/forms.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React$1 from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime62 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/organisms/TestimonialCarousel.d.ts
|
|
5
5
|
interface Testimonial {
|
|
@@ -14,7 +14,7 @@ declare function TestimonialCarousel({
|
|
|
14
14
|
}: {
|
|
15
15
|
testimonials: Testimonial[];
|
|
16
16
|
className?: string;
|
|
17
|
-
}):
|
|
17
|
+
}): react_jsx_runtime62.JSX.Element;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { Testimonial, TestimonialCarousel };
|
|
20
20
|
//# sourceMappingURL=TestimonialCarousel.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ListPageTemplateProps } from "./types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime92 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/templates/lists/ListPageTemplate/index.mobile.d.ts
|
|
5
5
|
declare function ListPageTemplate<T = any>({
|
|
@@ -16,7 +16,7 @@ declare function ListPageTemplate<T = any>({
|
|
|
16
16
|
data,
|
|
17
17
|
renderItem,
|
|
18
18
|
emptyProps
|
|
19
|
-
}: ListPageTemplateProps<T>):
|
|
19
|
+
}: ListPageTemplateProps<T>): react_jsx_runtime92.JSX.Element;
|
|
20
20
|
//#endregion
|
|
21
21
|
export { ListPageTemplate, ListPageTemplateProps };
|
|
22
22
|
//# sourceMappingURL=index.mobile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mobile.d.ts","names":[],"sources":["../../../../../src/components/templates/lists/ListPageTemplate/index.mobile.tsx"],"sourcesContent":[],"mappings":";;;;iBAUgB;;;;;;;;;;;;;;GAcb,sBAAsB,KAAE,
|
|
1
|
+
{"version":3,"file":"index.mobile.d.ts","names":[],"sources":["../../../../../src/components/templates/lists/ListPageTemplate/index.mobile.tsx"],"sourcesContent":[],"mappings":";;;;iBAUgB;;;;;;;;;;;;;;GAcb,sBAAsB,KAAE,mBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FiltersToolbar } from "../../../molecules/FiltersToolbar.mobile.js";
|
|
2
1
|
import { FlatListScreen } from "../../../native/FlatListScreen.mobile.js";
|
|
2
|
+
import { FiltersToolbar } from "../../../molecules/FiltersToolbar.mobile.js";
|
|
3
3
|
import { EmptyDataList } from "../../../organisms/EmptyDataList.mobile.js";
|
|
4
4
|
import { PageHeaderResponsive } from "../../../organisms/PageHeaderResponsive.mobile.js";
|
|
5
5
|
import "react";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ListPageTemplateProps } from "./types.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime93 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/templates/lists/ListPageTemplate/index.web.d.ts
|
|
5
5
|
declare function ListPageTemplate<T = any>({
|
|
@@ -17,7 +17,7 @@ declare function ListPageTemplate<T = any>({
|
|
|
17
17
|
data,
|
|
18
18
|
renderItem,
|
|
19
19
|
emptyProps
|
|
20
|
-
}: ListPageTemplateProps<T>):
|
|
20
|
+
}: ListPageTemplateProps<T>): react_jsx_runtime93.JSX.Element;
|
|
21
21
|
//#endregion
|
|
22
22
|
export { ListPageTemplate, ListPageTemplateProps };
|
|
23
23
|
//# sourceMappingURL=index.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.web.d.ts","names":[],"sources":["../../../../../src/components/templates/lists/ListPageTemplate/index.web.tsx"],"sourcesContent":[],"mappings":";;;;iBAegB;;;;;;;;;;;;;;;GAeb,sBAAsB,KAAE,
|
|
1
|
+
{"version":3,"file":"index.web.d.ts","names":[],"sources":["../../../../../src/components/templates/lists/ListPageTemplate/index.web.tsx"],"sourcesContent":[],"mappings":";;;;iBAegB;;;;;;;;;;;;;;;GAeb,sBAAsB,KAAE,mBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region ../contracts/src/client/react/drivers/shadcn.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a shadcn/ui driver by mapping required slots to components.
|
|
4
|
+
* Host apps should import their shadcn primitives and pass them here.
|
|
5
|
+
*/
|
|
6
|
+
function shadcnDriver(slots) {
|
|
7
|
+
return slots;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { shadcnDriver };
|
|
12
|
+
//# sourceMappingURL=shadcn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadcn.js","names":[],"sources":["../../../../../../../contracts/src/client/react/drivers/shadcn.ts"],"sourcesContent":["import type { DriverSlots } from '../form-render';\n\n/**\n * Create a shadcn/ui driver by mapping required slots to components.\n * Host apps should import their shadcn primitives and pass them here.\n */\nexport function shadcnDriver(slots: DriverSlots): DriverSlots {\n return slots;\n}\n\nexport type ShadcnDriver = ReturnType<typeof shadcnDriver>;\n"],"mappings":";;;;;AAMA,SAAgB,aAAa,OAAiC;AAC5D,QAAO"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { buildZodWithRelations, evalPredicate } from "../../forms.js";
|
|
2
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
|
4
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region ../contracts/src/client/react/form-render.tsx
|
|
8
|
+
function toOptionsArray(src) {
|
|
9
|
+
if (!src) return void 0;
|
|
10
|
+
if (Array.isArray(src)) return {
|
|
11
|
+
kind: "static",
|
|
12
|
+
options: src
|
|
13
|
+
};
|
|
14
|
+
return src;
|
|
15
|
+
}
|
|
16
|
+
function getAtPath(values, path) {
|
|
17
|
+
if (!path) return void 0;
|
|
18
|
+
const segs = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
19
|
+
let cur = values;
|
|
20
|
+
for (const s of segs) {
|
|
21
|
+
if (cur == null) return void 0;
|
|
22
|
+
cur = cur[s];
|
|
23
|
+
}
|
|
24
|
+
return cur;
|
|
25
|
+
}
|
|
26
|
+
function makeDepsKey(values, deps) {
|
|
27
|
+
if (!deps || deps.length === 0) return "[]";
|
|
28
|
+
try {
|
|
29
|
+
return JSON.stringify(deps.map((d) => getAtPath(values, d)));
|
|
30
|
+
} catch {
|
|
31
|
+
return "[]";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function useResolvedOptions(values, source, resolvers) {
|
|
35
|
+
const [opts, setOpts] = useState([]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
let mounted = true;
|
|
38
|
+
const run = async () => {
|
|
39
|
+
if (!source) return setOpts([]);
|
|
40
|
+
if (source.kind === "static") return setOpts([...source.options ?? []]);
|
|
41
|
+
const fn = resolvers?.[source.resolverKey];
|
|
42
|
+
if (!fn) return setOpts([]);
|
|
43
|
+
const res = await fn(values, source.args);
|
|
44
|
+
if (mounted) setOpts([...res ?? []]);
|
|
45
|
+
};
|
|
46
|
+
run();
|
|
47
|
+
return () => {
|
|
48
|
+
mounted = false;
|
|
49
|
+
};
|
|
50
|
+
}, [useMemo(() => {
|
|
51
|
+
if (!source) return "nil";
|
|
52
|
+
if (source.kind === "static") return JSON.stringify(source.options ?? []);
|
|
53
|
+
return makeDepsKey(values, source.deps);
|
|
54
|
+
}, [source, values]), source && source.resolverKey]);
|
|
55
|
+
return opts;
|
|
56
|
+
}
|
|
57
|
+
function fieldPath(parent, name, arrayIndex) {
|
|
58
|
+
if (!name) return parent ?? "";
|
|
59
|
+
const child = typeof arrayIndex === "number" ? `${name.replace(/^\$index$/, String(arrayIndex))}` : name;
|
|
60
|
+
return parent ? `${parent}${typeof arrayIndex === "number" ? `.${arrayIndex}` : ""}.${child}`.replace(/\.+/g, ".") : child;
|
|
61
|
+
}
|
|
62
|
+
function createFormRenderer(base) {
|
|
63
|
+
const conf = base;
|
|
64
|
+
const { driver } = conf;
|
|
65
|
+
function InternalForm(props) {
|
|
66
|
+
const { spec, options, merged } = props;
|
|
67
|
+
const baseZod = useMemo(() => buildZodWithRelations(spec), [spec]);
|
|
68
|
+
const form = useForm({
|
|
69
|
+
...merged.formOptions,
|
|
70
|
+
resolver: zodResolver(baseZod),
|
|
71
|
+
defaultValues: options?.defaultValues
|
|
72
|
+
});
|
|
73
|
+
const values = form.watch();
|
|
74
|
+
const renderOne = (f, parent, arrayIndex) => {
|
|
75
|
+
const DriverField = driver.Field;
|
|
76
|
+
const DriverLabel = driver.FieldLabel;
|
|
77
|
+
const DriverDesc = driver.FieldDescription;
|
|
78
|
+
const DriverError = driver.FieldError;
|
|
79
|
+
const name = fieldPath(parent, f.name, arrayIndex);
|
|
80
|
+
const visible = evalPredicate(values, f.visibleWhen);
|
|
81
|
+
const enabled = evalPredicate(values, f.enabledWhen);
|
|
82
|
+
const invalid = Boolean(form.getFieldState(name)?.invalid);
|
|
83
|
+
if (!visible) return null;
|
|
84
|
+
const id = name?.replace(/\./g, "-");
|
|
85
|
+
const commonWrapProps = {
|
|
86
|
+
"data-invalid": invalid,
|
|
87
|
+
hidden: !visible,
|
|
88
|
+
disabled: !enabled
|
|
89
|
+
};
|
|
90
|
+
const labelNode = f.labelI18n ? /* @__PURE__ */ jsx(DriverLabel, {
|
|
91
|
+
htmlFor: id,
|
|
92
|
+
children: f.labelI18n
|
|
93
|
+
}) : null;
|
|
94
|
+
const descNode = f.descriptionI18n ? /* @__PURE__ */ jsx(DriverDesc, { children: f.descriptionI18n }) : null;
|
|
95
|
+
if (f.kind === "group") {
|
|
96
|
+
const children = f.fields.map((c, i) => /* @__PURE__ */ jsx(React.Fragment, { children: renderOne(c, name, arrayIndex) }, `${name}-${i}`));
|
|
97
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
98
|
+
...commonWrapProps,
|
|
99
|
+
children: [
|
|
100
|
+
labelNode,
|
|
101
|
+
children,
|
|
102
|
+
descNode
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (f.kind === "array") return renderArray(f, parent);
|
|
107
|
+
return /* @__PURE__ */ jsx(Controller, {
|
|
108
|
+
name,
|
|
109
|
+
control: form.control,
|
|
110
|
+
render: ({ field, fieldState }) => {
|
|
111
|
+
const err = fieldState.error ? [fieldState.error] : [];
|
|
112
|
+
const ariaInvalid = fieldState.invalid || void 0;
|
|
113
|
+
if (f.kind === "text") {
|
|
114
|
+
const Input = driver.Input;
|
|
115
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
116
|
+
...commonWrapProps,
|
|
117
|
+
children: [
|
|
118
|
+
labelNode,
|
|
119
|
+
/* @__PURE__ */ jsx(Input, {
|
|
120
|
+
id,
|
|
121
|
+
"aria-invalid": ariaInvalid,
|
|
122
|
+
placeholder: f.placeholderI18n,
|
|
123
|
+
autoComplete: f.autoComplete,
|
|
124
|
+
inputMode: f.inputMode,
|
|
125
|
+
maxLength: f.maxLength,
|
|
126
|
+
minLength: f.minLength,
|
|
127
|
+
disabled: !enabled,
|
|
128
|
+
...field,
|
|
129
|
+
...f.uiProps,
|
|
130
|
+
keyboard: f.keyboard,
|
|
131
|
+
autoComplete: f.keyboard?.autoComplete ?? f.autoComplete
|
|
132
|
+
}),
|
|
133
|
+
descNode,
|
|
134
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (f.kind === "textarea") {
|
|
139
|
+
const Textarea = driver.Textarea;
|
|
140
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
141
|
+
...commonWrapProps,
|
|
142
|
+
children: [
|
|
143
|
+
labelNode,
|
|
144
|
+
/* @__PURE__ */ jsx(Textarea, {
|
|
145
|
+
id,
|
|
146
|
+
"aria-invalid": ariaInvalid,
|
|
147
|
+
placeholder: f.placeholderI18n,
|
|
148
|
+
rows: f.rows,
|
|
149
|
+
maxLength: f.maxLength,
|
|
150
|
+
disabled: !enabled,
|
|
151
|
+
...field,
|
|
152
|
+
...f.uiProps,
|
|
153
|
+
keyboard: f.keyboard,
|
|
154
|
+
autoComplete: f.keyboard?.autoComplete ?? f.autoComplete
|
|
155
|
+
}),
|
|
156
|
+
descNode,
|
|
157
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (f.kind === "select") {
|
|
162
|
+
const Select = driver.Select;
|
|
163
|
+
const opts = useResolvedOptions(values, toOptionsArray(f.options), merged.resolvers);
|
|
164
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
165
|
+
...commonWrapProps,
|
|
166
|
+
children: [
|
|
167
|
+
labelNode,
|
|
168
|
+
/* @__PURE__ */ jsx(Select, {
|
|
169
|
+
id,
|
|
170
|
+
name,
|
|
171
|
+
"aria-invalid": ariaInvalid,
|
|
172
|
+
disabled: !enabled,
|
|
173
|
+
value: field.value,
|
|
174
|
+
onChange: (v) => field.onChange(v),
|
|
175
|
+
options: opts,
|
|
176
|
+
...f.uiProps
|
|
177
|
+
}),
|
|
178
|
+
descNode,
|
|
179
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (f.kind === "checkbox") {
|
|
184
|
+
const Checkbox = driver.Checkbox;
|
|
185
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
186
|
+
...commonWrapProps,
|
|
187
|
+
children: [
|
|
188
|
+
labelNode,
|
|
189
|
+
/* @__PURE__ */ jsx(Checkbox, {
|
|
190
|
+
id,
|
|
191
|
+
name,
|
|
192
|
+
disabled: !enabled,
|
|
193
|
+
checked: !!field.value,
|
|
194
|
+
onCheckedChange: (v) => field.onChange(v),
|
|
195
|
+
...f.uiProps
|
|
196
|
+
}),
|
|
197
|
+
descNode,
|
|
198
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
199
|
+
]
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (f.kind === "radio") {
|
|
203
|
+
const RadioGroup = driver.RadioGroup;
|
|
204
|
+
const opts = useResolvedOptions(values, toOptionsArray(f.options), merged.resolvers);
|
|
205
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
206
|
+
...commonWrapProps,
|
|
207
|
+
children: [
|
|
208
|
+
labelNode,
|
|
209
|
+
/* @__PURE__ */ jsx(RadioGroup, {
|
|
210
|
+
id,
|
|
211
|
+
name,
|
|
212
|
+
disabled: !enabled,
|
|
213
|
+
value: field.value,
|
|
214
|
+
onValueChange: (v) => field.onChange(v),
|
|
215
|
+
options: opts,
|
|
216
|
+
...f.uiProps
|
|
217
|
+
}),
|
|
218
|
+
descNode,
|
|
219
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (f.kind === "switch") {
|
|
224
|
+
const Switch = driver.Switch;
|
|
225
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
226
|
+
...commonWrapProps,
|
|
227
|
+
children: [
|
|
228
|
+
labelNode,
|
|
229
|
+
/* @__PURE__ */ jsx(Switch, {
|
|
230
|
+
id,
|
|
231
|
+
name,
|
|
232
|
+
disabled: !enabled,
|
|
233
|
+
checked: !!field.value,
|
|
234
|
+
onCheckedChange: (v) => field.onChange(v),
|
|
235
|
+
...f.uiProps
|
|
236
|
+
}),
|
|
237
|
+
descNode,
|
|
238
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
239
|
+
]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
243
|
+
}
|
|
244
|
+
}, name);
|
|
245
|
+
};
|
|
246
|
+
const renderArray = (f, parent) => {
|
|
247
|
+
const name = fieldPath(parent, f.name);
|
|
248
|
+
const { fields, append, remove } = useFieldArray({
|
|
249
|
+
control: form.control,
|
|
250
|
+
name
|
|
251
|
+
});
|
|
252
|
+
const canAdd = f.max == null || fields.length < f.max;
|
|
253
|
+
const canRemove = (idx) => (f.min == null ? fields.length > 0 : fields.length > f.min) && idx >= 0;
|
|
254
|
+
const Button$1 = driver.Button;
|
|
255
|
+
const Label = driver.FieldLabel;
|
|
256
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
257
|
+
f.labelI18n ? /* @__PURE__ */ jsx(Label, { children: f.labelI18n }) : null,
|
|
258
|
+
fields.map((row, idx) => /* @__PURE__ */ jsxs("div", { children: [renderOne(f.of, name, idx), canRemove(idx) ? /* @__PURE__ */ jsx(Button$1, {
|
|
259
|
+
type: "button",
|
|
260
|
+
variant: "ghost",
|
|
261
|
+
size: "sm",
|
|
262
|
+
onClick: () => remove(idx),
|
|
263
|
+
children: "Remove"
|
|
264
|
+
}) : null] }, row.id ?? idx)),
|
|
265
|
+
canAdd ? /* @__PURE__ */ jsx(Button$1, {
|
|
266
|
+
type: "button",
|
|
267
|
+
variant: "outline",
|
|
268
|
+
size: "sm",
|
|
269
|
+
onClick: () => append({}),
|
|
270
|
+
children: "Add"
|
|
271
|
+
}) : null
|
|
272
|
+
] }, name);
|
|
273
|
+
};
|
|
274
|
+
const onSubmit = async (data) => {
|
|
275
|
+
const actionKey = spec.actions?.[0]?.key ?? "submit";
|
|
276
|
+
if (merged.onSubmitOverride) return merged.onSubmitOverride(data, actionKey);
|
|
277
|
+
};
|
|
278
|
+
const Button = driver.Button;
|
|
279
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
280
|
+
onSubmit: form.handleSubmit(onSubmit),
|
|
281
|
+
children: [(spec.fields || []).map((f, i) => /* @__PURE__ */ jsx(React.Fragment, { children: renderOne(f) }, i)), spec.actions && spec.actions.length ? /* @__PURE__ */ jsx("div", { children: spec.actions.map((a) => /* @__PURE__ */ jsx(Button, {
|
|
282
|
+
type: "submit",
|
|
283
|
+
children: a.labelI18n
|
|
284
|
+
}, a.key)) }) : null]
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return { render: (spec, options) => /* @__PURE__ */ jsx(InternalForm, {
|
|
288
|
+
spec,
|
|
289
|
+
options,
|
|
290
|
+
merged: {
|
|
291
|
+
...conf,
|
|
292
|
+
...options?.overrides ?? {}
|
|
293
|
+
}
|
|
294
|
+
}) };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
//#endregion
|
|
298
|
+
export { createFormRenderer };
|
|
299
|
+
//# sourceMappingURL=form-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-render.js","names":["cur: any","Button"],"sources":["../../../../../../contracts/src/client/react/form-render.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react';\nimport { Controller, useFieldArray, useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport type {\n ArrayFieldSpec,\n FieldSpec,\n FormOption,\n FormSpec,\n OptionsSource,\n FormValuesFor,\n} from '../../forms';\nimport { buildZodWithRelations, evalPredicate } from '../../forms';\nimport type { AnySchemaModel } from '@lssm/lib.schema';\n\n// Minimal, library-agnostic driver slots. Hosts can provide any UI lib via this interface.\nexport interface DriverSlots {\n Field: React.ComponentType<\n React.PropsWithChildren<{\n 'data-invalid'?: boolean;\n hidden?: boolean;\n disabled?: boolean;\n }>\n >;\n FieldLabel: React.ComponentType<\n React.PropsWithChildren<{ htmlFor?: string }>\n >;\n FieldDescription: React.ComponentType<React.PropsWithChildren<{}>>;\n FieldError: React.ComponentType<{ errors: { message?: string }[] }>;\n FieldGroup?: React.ComponentType<\n React.PropsWithChildren<{ className?: string }>\n >;\n FieldSet?: React.ComponentType<\n React.PropsWithChildren<{ className?: string }>\n >;\n FieldLegend?: React.ComponentType<\n React.PropsWithChildren<{ variant?: 'label' | 'default' }>\n >;\n\n Input: React.ComponentType<React.InputHTMLAttributes<HTMLInputElement>>;\n Textarea: React.ComponentType<\n React.TextareaHTMLAttributes<HTMLTextAreaElement>\n >;\n // Select receives resolved options for simplicity\n Select: React.ComponentType<\n {\n id?: string;\n name?: string;\n value?: unknown;\n onChange?: (v: any) => void;\n disabled?: boolean;\n 'aria-invalid'?: boolean;\n options: FormOption[];\n } & Record<string, unknown>\n >;\n Checkbox: React.ComponentType<\n {\n id?: string;\n name?: string;\n checked?: boolean;\n onCheckedChange?: (v: boolean) => void;\n disabled?: boolean;\n } & Record<string, unknown>\n >;\n RadioGroup: React.ComponentType<\n {\n id?: string;\n name?: string;\n value?: unknown;\n onValueChange?: (v: any) => void;\n disabled?: boolean;\n options: FormOption[];\n } & Record<string, unknown>\n >;\n Switch: React.ComponentType<\n {\n id?: string;\n name?: string;\n checked?: boolean;\n onCheckedChange?: (v: boolean) => void;\n disabled?: boolean;\n } & Record<string, unknown>\n >;\n Button: React.ComponentType<\n React.PropsWithChildren<{\n type?: 'button' | 'submit' | 'reset';\n variant?: string;\n size?: string;\n onClick?: () => void;\n disabled?: boolean;\n }>\n >;\n}\n\nexport type ResolverMap<TValues> = Record<\n string,\n (values: TValues, args?: any) => Promise<FormOption[]> | FormOption[]\n>;\nexport type ComputationMap<TValues> = Record<string, (values: TValues) => any>;\n\nexport interface CreateRendererOptions<TValues = any> {\n driver: DriverSlots;\n formOptions?: Record<string, unknown>;\n onSubmitOverride?: (\n values: TValues,\n actionKey: string\n ) => Promise<void> | void;\n activeFlags?: string[];\n resolvers?: ResolverMap<TValues>;\n computations?: ComputationMap<TValues>;\n unmountStrategy?: 'keep' | 'clear';\n}\n\nexport interface RenderOptions<TValues = any> {\n defaultValues?: Partial<TValues>;\n overrides?: Partial<CreateRendererOptions<TValues>>;\n}\n\nfunction toOptionsArray(\n src: OptionsSource | FormOption[] | undefined\n): OptionsSource | undefined {\n if (!src) return undefined;\n if (Array.isArray(src)) return { kind: 'static', options: src };\n return src;\n}\n\nfunction getAtPath(values: unknown, path: string): unknown {\n if (!path) return undefined;\n const segs = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n let cur: any = values;\n for (const s of segs) {\n if (cur == null) return undefined;\n cur = cur[s as keyof typeof cur];\n }\n return cur;\n}\n\nfunction makeDepsKey(values: unknown, deps: string[] | undefined) {\n if (!deps || deps.length === 0) return '[]';\n try {\n return JSON.stringify(deps.map((d) => getAtPath(values, d)));\n } catch {\n return '[]';\n }\n}\n\nfunction useResolvedOptions<TValues>(\n values: TValues,\n source: OptionsSource | undefined,\n resolvers?: ResolverMap<TValues>\n): FormOption[] {\n const [opts, setOpts] = useState<FormOption[]>([]);\n const depKey = useMemo(() => {\n if (!source) return 'nil';\n if (source.kind === 'static') return JSON.stringify(source.options ?? []);\n return makeDepsKey(values, source.deps);\n }, [source, values]);\n\n useEffect(() => {\n let mounted = true;\n const run = async () => {\n if (!source) return setOpts([]);\n if (source.kind === 'static') return setOpts([...(source.options ?? [])]);\n const fn = resolvers?.[source.resolverKey];\n if (!fn) return setOpts([]);\n const res = await fn(values as any, source.args);\n if (mounted) setOpts([...(res ?? [])]);\n };\n run();\n return () => {\n mounted = false;\n };\n }, [depKey, source && (source as any).resolverKey]);\n return opts;\n}\n\nfunction fieldPath(\n parent: string | undefined,\n name?: string,\n arrayIndex?: number\n) {\n if (!name) return parent ?? '';\n const child =\n typeof arrayIndex === 'number'\n ? `${name.replace(/^\\$index$/, String(arrayIndex))}`\n : name;\n return parent\n ? `${parent}${typeof arrayIndex === 'number' ? `.${arrayIndex}` : ''}.${child}`.replace(\n /\\.+/g,\n '.'\n )\n : child;\n}\n\nexport function createFormRenderer<M extends AnySchemaModel = AnySchemaModel>(\n base: CreateRendererOptions<FormValuesFor<M>>\n) {\n const conf = base;\n const { driver } = conf;\n\n function InternalForm(props: {\n spec: FormSpec<M>;\n options?: RenderOptions<FormValuesFor<M>>;\n merged: CreateRendererOptions<FormValuesFor<M>>;\n }): React.ReactElement {\n const { spec, options, merged } = props;\n const baseZod = useMemo(() => buildZodWithRelations(spec), [spec]);\n const form = useForm<FormValuesFor<M>>({\n ...merged.formOptions,\n resolver: zodResolver(baseZod as any),\n defaultValues: options?.defaultValues as any,\n });\n\n const values = form.watch();\n\n const renderOne = (\n f: FieldSpec,\n parent?: string,\n arrayIndex?: number\n ): React.ReactElement | null => {\n const DriverField = driver.Field;\n const DriverLabel = driver.FieldLabel;\n const DriverDesc = driver.FieldDescription;\n const DriverError = driver.FieldError;\n const name = fieldPath(parent, f.name, arrayIndex);\n const visible = evalPredicate(values, f.visibleWhen);\n const enabled = evalPredicate(values, f.enabledWhen);\n const invalid = Boolean(form.getFieldState(name as any)?.invalid);\n\n if (!visible) return null;\n\n const id = name?.replace(/\\./g, '-');\n\n const commonWrapProps = {\n 'data-invalid': invalid,\n hidden: !visible,\n disabled: !enabled,\n } as any;\n const labelNode = f.labelI18n ? (\n <DriverLabel htmlFor={id}>{f.labelI18n}</DriverLabel>\n ) : null;\n const descNode = f.descriptionI18n ? (\n <DriverDesc>{f.descriptionI18n}</DriverDesc>\n ) : null;\n\n if (f.kind === 'group') {\n const children = f.fields.map((c: FieldSpec, i: number) => (\n <React.Fragment key={`${name}-${i}`}>\n {renderOne(c, name, arrayIndex)}\n </React.Fragment>\n ));\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n {children}\n {descNode}\n </DriverField>\n );\n }\n\n if (f.kind === 'array') {\n return renderArray(f as ArrayFieldSpec, parent);\n }\n\n // Leaf controls\n return (\n <Controller\n key={name}\n name={name as any}\n control={form.control}\n render={({ field, fieldState }) => {\n const err = fieldState.error ? [fieldState.error] : [];\n const ariaInvalid = fieldState.invalid || undefined;\n\n if (f.kind === 'text') {\n const Input = driver.Input;\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <Input\n id={id}\n aria-invalid={ariaInvalid}\n placeholder={f.placeholderI18n}\n autoComplete={(f as any).autoComplete as any}\n inputMode={(f as any).inputMode as any}\n maxLength={(f as any).maxLength as any}\n minLength={(f as any).minLength as any}\n disabled={!enabled}\n {...field}\n {...(f.uiProps as any)}\n // Pass keyboard/autocomplete hints down for adapters that support them\n {...({\n keyboard: (f as any).keyboard,\n autoComplete:\n (f as any).keyboard?.autoComplete ??\n (f as any).autoComplete,\n } as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n if (f.kind === 'textarea') {\n const Textarea = driver.Textarea;\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <Textarea\n id={id}\n aria-invalid={ariaInvalid}\n placeholder={f.placeholderI18n}\n rows={(f as any).rows as any}\n maxLength={(f as any).maxLength as any}\n disabled={!enabled}\n {...field}\n {...(f.uiProps as any)}\n {...({\n keyboard: (f as any).keyboard,\n autoComplete:\n (f as any).keyboard?.autoComplete ??\n (f as any).autoComplete,\n } as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n if (f.kind === 'select') {\n const Select = driver.Select;\n const src = toOptionsArray((f as any).options);\n const opts = useResolvedOptions(values, src, merged.resolvers);\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <Select\n id={id}\n name={name}\n aria-invalid={ariaInvalid}\n disabled={!enabled}\n value={field.value}\n onChange={(v: any) => field.onChange(v)}\n options={opts}\n {...(f.uiProps as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n if (f.kind === 'checkbox') {\n const Checkbox = driver.Checkbox;\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <Checkbox\n id={id}\n name={name}\n disabled={!enabled}\n checked={!!field.value}\n onCheckedChange={(v: boolean) => field.onChange(v)}\n {...(f.uiProps as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n if (f.kind === 'radio') {\n const RadioGroup = driver.RadioGroup;\n const src = toOptionsArray((f as any).options);\n const opts = useResolvedOptions(values, src, merged.resolvers);\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <RadioGroup\n id={id}\n name={name}\n disabled={!enabled}\n value={field.value}\n onValueChange={(v: any) => field.onChange(v)}\n options={opts}\n {...(f.uiProps as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n if (f.kind === 'switch') {\n const Switch = driver.Switch;\n return (\n <DriverField {...commonWrapProps}>\n {labelNode}\n <Switch\n id={id}\n name={name}\n disabled={!enabled}\n checked={!!field.value}\n onCheckedChange={(v: boolean) => field.onChange(v)}\n {...(f.uiProps as any)}\n />\n {descNode}\n {fieldState.invalid ? (\n <DriverError errors={err as any} />\n ) : null}\n </DriverField>\n );\n }\n return <></>;\n }}\n />\n );\n };\n\n const renderArray = (f: ArrayFieldSpec, parent?: string) => {\n const name = fieldPath(parent, f.name);\n const { fields, append, remove } = useFieldArray({\n control: form.control as any,\n name: name as any,\n });\n const canAdd = f.max == null || fields.length < f.max;\n const canRemove = (idx: number) =>\n (f.min == null ? fields.length > 0 : fields.length > f.min) && idx >= 0;\n const Button = driver.Button;\n const Label = driver.FieldLabel;\n return (\n <div key={name}>\n {f.labelI18n ? <Label>{f.labelI18n}</Label> : null}\n {fields.map((row, idx) => (\n <div key={row.id ?? idx}>\n {renderOne(f.of as FieldSpec, name, idx)}\n {canRemove(idx) ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => remove(idx)}\n >\n Remove\n </Button>\n ) : null}\n </div>\n ))}\n {canAdd ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => append({})}\n >\n Add\n </Button>\n ) : null}\n </div>\n );\n };\n\n const onSubmit = async (data: FormValuesFor<M>) => {\n const actionKey = spec.actions?.[0]?.key ?? 'submit';\n if (merged.onSubmitOverride) {\n return merged.onSubmitOverride(data, actionKey);\n }\n // default: noop\n };\n\n const Button = driver.Button;\n return (\n <form onSubmit={form.handleSubmit(onSubmit)}>\n {(spec.fields || []).map((f: FieldSpec, i: number) => (\n <React.Fragment key={i}>{renderOne(f)}</React.Fragment>\n ))}\n {spec.actions && spec.actions.length ? (\n <div>\n {spec.actions.map((a: { key: string; labelI18n: string }) => (\n <Button key={a.key} type=\"submit\">\n {a.labelI18n}\n </Button>\n ))}\n </div>\n ) : null}\n </form>\n );\n }\n\n return {\n render: (spec: FormSpec<M>, options?: RenderOptions<FormValuesFor<M>>) => (\n <InternalForm\n spec={spec}\n options={options}\n merged={{\n ...conf,\n ...(options?.overrides ?? {}),\n }}\n />\n ),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//#region ../contracts/src/forms.ts
|
|
2
|
+
function getAtPath(values, path) {
|
|
3
|
+
if (!path) return void 0;
|
|
4
|
+
const segs = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
5
|
+
let cur = values;
|
|
6
|
+
for (const s of segs) {
|
|
7
|
+
if (cur == null) return void 0;
|
|
8
|
+
cur = cur[s];
|
|
9
|
+
}
|
|
10
|
+
return cur;
|
|
11
|
+
}
|
|
12
|
+
function evalPredicate(values, pred) {
|
|
13
|
+
if (!pred) return true;
|
|
14
|
+
if (pred.not) return !evalPredicate(values, pred.not);
|
|
15
|
+
if (pred.all && pred.all.length) return pred.all.every((p) => evalPredicate(values, p));
|
|
16
|
+
if (pred.any && pred.any.length) return pred.any.some((p) => evalPredicate(values, p));
|
|
17
|
+
if (pred.when) {
|
|
18
|
+
const { path, op = "truthy", value } = pred.when;
|
|
19
|
+
const v = getAtPath(values, path);
|
|
20
|
+
switch (op) {
|
|
21
|
+
case "equals": return v === value;
|
|
22
|
+
case "notEquals": return v !== value;
|
|
23
|
+
case "in": return Array.isArray(value) && value.includes(v);
|
|
24
|
+
case "notIn": return Array.isArray(value) && !value.includes(v);
|
|
25
|
+
case "gt": return Number(v) > Number(value);
|
|
26
|
+
case "gte": return Number(v) >= Number(value);
|
|
27
|
+
case "lt": return Number(v) < Number(value);
|
|
28
|
+
case "lte": return Number(v) <= Number(value);
|
|
29
|
+
case "empty": return v == null || (Array.isArray(v) ? v.length === 0 : String(v).length === 0);
|
|
30
|
+
case "lengthGt": return (Array.isArray(v) || typeof v === "string") && v.length > Number(value ?? 0);
|
|
31
|
+
case "lengthGte": return (Array.isArray(v) || typeof v === "string") && v.length >= Number(value ?? 0);
|
|
32
|
+
case "lengthLt": return (Array.isArray(v) || typeof v === "string") && v.length < Number(value ?? 0);
|
|
33
|
+
case "lengthLte": return (Array.isArray(v) || typeof v === "string") && v.length <= Number(value ?? 0);
|
|
34
|
+
case "truthy":
|
|
35
|
+
default: return Boolean(v);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Wrap the base zod schema with relation-driven refinements (requiredWhen, array min/max)
|
|
42
|
+
* and optional custom constraints. Call this when wiring RHF resolver.
|
|
43
|
+
*/
|
|
44
|
+
function buildZodWithRelations(spec, handlers) {
|
|
45
|
+
return spec.model.getZod().superRefine((values, ctx) => {
|
|
46
|
+
const visit = (field, parentPath) => {
|
|
47
|
+
const path = field.name ? parentPath ? `${parentPath}.${field.name}` : field.name : parentPath ?? "";
|
|
48
|
+
if (field.requiredWhen) {
|
|
49
|
+
if (evalPredicate(values, field.requiredWhen)) {
|
|
50
|
+
const v = getAtPath(values, path);
|
|
51
|
+
if (v == null || typeof v === "string" && v.trim().length === 0 || Array.isArray(v) && v.length === 0) ctx.addIssue({
|
|
52
|
+
code: "custom",
|
|
53
|
+
path: path.split("."),
|
|
54
|
+
message: "required"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (field.kind === "array") {
|
|
59
|
+
const arr = getAtPath(values, path);
|
|
60
|
+
if (field.min != null && Array.isArray(arr) && arr.length < field.min) ctx.addIssue({
|
|
61
|
+
code: "custom",
|
|
62
|
+
path: path.split("."),
|
|
63
|
+
message: `min:${field.min}`
|
|
64
|
+
});
|
|
65
|
+
if (field.max != null && Array.isArray(arr) && arr.length > field.max) ctx.addIssue({
|
|
66
|
+
code: "custom",
|
|
67
|
+
path: path.split("."),
|
|
68
|
+
message: `max:${field.max}`
|
|
69
|
+
});
|
|
70
|
+
visit(field.of, path);
|
|
71
|
+
} else if (field.kind === "group") for (const child of field.fields) visit(child, path);
|
|
72
|
+
};
|
|
73
|
+
for (const f of spec.fields) visit(f);
|
|
74
|
+
if (spec.constraints && handlers) for (const c of spec.constraints) {
|
|
75
|
+
const fn = handlers[c.key];
|
|
76
|
+
if (!fn) continue;
|
|
77
|
+
const res = fn(values, c.paths, c.args);
|
|
78
|
+
if (!res.ok) ctx.addIssue({
|
|
79
|
+
code: "custom",
|
|
80
|
+
path: (res.path ?? c.paths[0] ?? "").split(".").filter(Boolean),
|
|
81
|
+
message: res.message ?? c.messageI18n
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
export { buildZodWithRelations, evalPredicate };
|
|
89
|
+
//# sourceMappingURL=forms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.js","names":["cur: any"],"sources":["../../../../contracts/src/forms.ts"],"sourcesContent":["import type { AnySchemaModel, ZodSchemaModel } from '@lssm/lib.schema';\nimport type { OwnerShipMeta } from './ownership';\n\n// ---- Core types\n\nexport type PredicateOp =\n | 'equals'\n | 'notEquals'\n | 'in'\n | 'notIn'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'truthy'\n | 'empty'\n | 'lengthGt'\n | 'lengthGte'\n | 'lengthLt'\n | 'lengthLte';\n\n// Author-time generic path helpers (computed from provided fields shape)\nexport interface WhenClause {\n /** Dot path in form values; arrays may use `$index` within array context. */\n path: string;\n op?: PredicateOp;\n value?: unknown;\n}\n\nexport interface Predicate {\n when?: WhenClause;\n all?: Predicate[];\n any?: Predicate[];\n not?: Predicate;\n}\n\nexport interface FormOption {\n labelI18n: string;\n value: string | number | boolean;\n descriptionI18n?: string;\n disabled?: boolean;\n}\n\nexport type OptionsSource =\n | { kind: 'static'; options: readonly FormOption[] }\n | {\n kind: 'resolver';\n resolverKey: string;\n /** Dot paths in form values to watch */\n deps: string[];\n args?: Record<string, unknown>;\n };\n\nexport interface BaseFieldSpec {\n /** Field kind discriminator. */\n kind:\n | 'text'\n | 'textarea'\n | 'select'\n | 'checkbox'\n | 'radio'\n | 'switch'\n | 'group'\n | 'array';\n /** Field name (dot path relative to the form root or parent context). */\n name?: string;\n labelI18n?: string;\n descriptionI18n?: string;\n placeholderI18n?: string;\n required?: boolean;\n /** Conditional UI behavior */\n visibleWhen?: Predicate;\n enabledWhen?: Predicate;\n requiredWhen?: Predicate;\n /** UI hints */\n uiKey?: string;\n uiProps?: Record<string, unknown>;\n wrapper?: { orientation?: 'horizontal' | 'vertical' };\n /** HTML/Native autofill token (supports custom tokens) */\n autoComplete?: string;\n /** Keyboard/adaptation hints (web/native). Shape mirrors design-system KeyboardOptions but stays decoupled. */\n keyboard?: {\n kind?: string;\n autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters';\n autoComplete?: string;\n autoCorrect?: boolean;\n enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'search' | 'send';\n };\n /** Optional computed value hook, provided by host computations map */\n computeFrom?: {\n computeKey: string;\n deps: string[];\n mode?: 'change' | 'blur-xs' | 'submit';\n readOnly?: boolean;\n };\n}\n\nexport interface TextFieldSpec extends BaseFieldSpec {\n kind: 'text';\n name: string;\n inputMode?:\n | 'text'\n | 'email'\n | 'tel'\n | 'url'\n | 'numeric'\n | 'decimal'\n | 'search';\n autoComplete?: string;\n maxLength?: number;\n minLength?: number;\n}\n\nexport interface TextareaFieldSpec extends BaseFieldSpec {\n kind: 'textarea';\n name: string;\n rows?: number;\n maxLength?: number;\n minLength?: number;\n}\n\nexport interface SelectFieldSpec extends BaseFieldSpec {\n kind: 'select';\n name: string;\n options: OptionsSource | readonly FormOption[]; // allow shorthand array\n}\n\nexport interface CheckboxFieldSpec extends BaseFieldSpec {\n kind: 'checkbox';\n name: string;\n}\n\nexport interface RadioFieldSpec extends BaseFieldSpec {\n kind: 'radio';\n name: string;\n options: OptionsSource | readonly FormOption[];\n}\n\nexport interface SwitchFieldSpec extends BaseFieldSpec {\n kind: 'switch';\n name: string;\n}\n\nexport interface GroupFieldSpec extends BaseFieldSpec {\n kind: 'group';\n /** Optional legend/label at group level */\n labelI18n?: string;\n fields: FieldSpec[];\n}\n\nexport interface ArrayFieldSpec extends BaseFieldSpec {\n kind: 'array';\n /** Root-level field that is an array in the model (e.g., \"emails\") */\n name: string;\n /** Child field spec for each item (e.g., address inside emails[i].address). */\n of: Exclude<FieldSpec, ArrayFieldSpec | GroupFieldSpec>;\n min?: number;\n max?: number;\n}\n\nexport type FieldSpec =\n | TextFieldSpec\n | TextareaFieldSpec\n | SelectFieldSpec\n | CheckboxFieldSpec\n | RadioFieldSpec\n | SwitchFieldSpec\n | GroupFieldSpec\n | ArrayFieldSpec;\n\nexport interface FormAction {\n key: string;\n labelI18n: string;\n op?: { name: string; version: number };\n success?: { navigateTo?: string; toastI18n?: string };\n}\n\nexport interface ConstraintDecl {\n key: string; // host maps this to a function\n messageI18n: string;\n paths: string[]; // inputs for the constraint function\n args?: Record<string, unknown>;\n}\n\nexport type FormValuesFor<M extends AnySchemaModel> = ZodSchemaModel<M>;\n\nexport interface FormSpec<M extends AnySchemaModel = AnySchemaModel> {\n meta: OwnerShipMeta & { key: string; version: number };\n /** Canonical form data shape */\n model: M;\n /** Flat list or tree using groups/arrays */\n fields: FieldSpec[];\n policy?: { flags?: string[]; pii?: string[] };\n actions?: FormAction[];\n renderHints?: { ui: 'shadcn' | 'custom'; form: 'react-hook-form' };\n constraints?: ConstraintDecl[];\n}\n\n// ---- Registry\n\nfunction formKey(meta: FormSpec['meta']) {\n return `${meta.key}.v${meta.version}`;\n}\n\nexport class FormRegistry {\n private items = new Map<string, FormSpec>();\n\n register(spec: FormSpec): this {\n const key = formKey(spec.meta);\n if (this.items.has(key)) throw new Error(`Duplicate form ${key}`);\n this.items.set(key, spec);\n return this;\n }\n\n list(): FormSpec[] {\n return [...this.items.values()];\n }\n\n get(key: string, version?: number) {\n if (version != null) return this.items.get(`${key}.v${version}`);\n let candidate: FormSpec | undefined;\n let max = -Infinity;\n for (const [k, v] of this.items.entries()) {\n if (!k.startsWith(`${key}.v`)) continue;\n if (v.meta.version > max) {\n max = v.meta.version;\n candidate = v;\n }\n }\n return candidate;\n }\n}\n\n// ---- Relations helpers (runtime)\n\nfunction getAtPath(values: unknown, path: string): unknown {\n if (!path) return undefined;\n const segs = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n let cur: any = values as any;\n for (const s of segs) {\n if (cur == null) return undefined;\n cur = cur[s as keyof typeof cur];\n }\n return cur;\n}\n\nexport function evalPredicate(values: unknown, pred?: Predicate): boolean {\n if (!pred) return true;\n if (pred.not) return !evalPredicate(values, pred.not);\n if (pred.all && pred.all.length)\n return pred.all.every((p) => evalPredicate(values, p));\n if (pred.any && pred.any.length)\n return pred.any.some((p) => evalPredicate(values, p));\n if (pred.when) {\n const { path, op = 'truthy', value } = pred.when;\n const v = getAtPath(values, path);\n switch (op) {\n case 'equals':\n return v === value;\n case 'notEquals':\n return v !== value;\n case 'in':\n return Array.isArray(value) && value.includes(v as never);\n case 'notIn':\n return Array.isArray(value) && !value.includes(v as never);\n case 'gt':\n return Number(v) > Number(value);\n case 'gte':\n return Number(v) >= Number(value);\n case 'lt':\n return Number(v) < Number(value);\n case 'lte':\n return Number(v) <= Number(value);\n case 'empty':\n return (\n v == null ||\n (Array.isArray(v) ? v.length === 0 : String(v).length === 0)\n );\n case 'lengthGt':\n return (\n (Array.isArray(v) || typeof v === 'string') &&\n (v as any).length > Number(value ?? 0)\n );\n case 'lengthGte':\n return (\n (Array.isArray(v) || typeof v === 'string') &&\n (v as any).length >= Number(value ?? 0)\n );\n case 'lengthLt':\n return (\n (Array.isArray(v) || typeof v === 'string') &&\n (v as any).length < Number(value ?? 0)\n );\n case 'lengthLte':\n return (\n (Array.isArray(v) || typeof v === 'string') &&\n (v as any).length <= Number(value ?? 0)\n );\n case 'truthy':\n default:\n return Boolean(v);\n }\n }\n return true;\n}\n\nexport type ConstraintHandler = (\n values: Record<string, unknown>,\n paths: string[],\n args?: Record<string, unknown>\n) => { ok: true } | { ok: false; message?: string; path?: string };\n\n/**\n * Wrap the base zod schema with relation-driven refinements (requiredWhen, array min/max)\n * and optional custom constraints. Call this when wiring RHF resolver.\n */\nexport function buildZodWithRelations(\n spec: FormSpec,\n handlers?: Record<string, ConstraintHandler>\n) {\n const base = spec.model.getZod();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (base as any).superRefine(\n (values: Record<string, unknown>, ctx: any) => {\n const visit = (field: FieldSpec, parentPath?: string) => {\n const path = field.name\n ? parentPath\n ? `${parentPath}.${field.name}`\n : field.name\n : (parentPath ?? '');\n\n // requiredWhen enforcement (UI also shows required)\n if (field.requiredWhen) {\n const should = evalPredicate(values, field.requiredWhen);\n if (should) {\n const v = getAtPath(values, path);\n const empty =\n v == null ||\n (typeof v === 'string' && v.trim().length === 0) ||\n (Array.isArray(v) && v.length === 0);\n if (empty)\n ctx.addIssue({\n code: 'custom',\n path: path.split('.'),\n message: 'required',\n });\n }\n }\n\n // arrays min/max\n if (field.kind === 'array') {\n const arr = getAtPath(values, path) as unknown[] | undefined;\n if (\n field.min != null &&\n Array.isArray(arr) &&\n arr.length < field.min\n ) {\n ctx.addIssue({\n code: 'custom',\n path: path.split('.'),\n message: `min:${field.min}`,\n });\n }\n if (\n field.max != null &&\n Array.isArray(arr) &&\n arr.length > field.max\n ) {\n ctx.addIssue({\n code: 'custom',\n path: path.split('.'),\n message: `max:${field.max}`,\n });\n }\n // child\n visit(field.of, path);\n } else if (field.kind === 'group') {\n for (const child of field.fields) visit(child, path);\n }\n };\n\n for (const f of spec.fields) visit(f);\n\n // custom constraints\n if (spec.constraints && handlers) {\n for (const c of spec.constraints) {\n const fn = handlers[c.key];\n if (!fn) continue;\n const res = fn(values, c.paths, c.args);\n if (!res.ok) {\n ctx.addIssue({\n code: 'custom',\n path: (res.path ?? c.paths[0] ?? '').split('.').filter(Boolean),\n message: res.message ?? c.messageI18n,\n });\n }\n }\n }\n }\n );\n}\n\n// ---- Authoring-time helper: enforce typed paths from fields (best-effort bounded)\n\ninterface AnyFieldLike {\n kind: string;\n name?: string;\n fields?: readonly AnyFieldLike[];\n of?: AnyFieldLike;\n}\n\ntype TopLevelNames<F extends readonly AnyFieldLike[]> = F[number] extends {\n name: infer N extends string;\n}\n ? N\n : never;\n\ntype ArrayChildren<F extends readonly AnyFieldLike[]> = F[number] extends {\n kind: 'array';\n name: infer N extends string;\n of: infer C;\n}\n ? C extends { name: infer CN extends string }\n ? `${N}.$index.${CN}`\n : never\n : never;\n\ntype GroupTopLevelNames<F extends readonly AnyFieldLike[]> = F[number] extends {\n kind: 'group';\n fields: infer G extends readonly AnyFieldLike[];\n}\n ? TopLevelNames<G>\n : never;\n\ntype GroupArrayChildren<F extends readonly AnyFieldLike[]> = F[number] extends {\n kind: 'group';\n fields: infer G extends readonly AnyFieldLike[];\n}\n ? ArrayChildren<G>\n : never;\n\ntype PathOfFields<F extends readonly AnyFieldLike[]> =\n | TopLevelNames<F>\n | ArrayChildren<F>\n | GroupTopLevelNames<F>\n | GroupArrayChildren<F>;\n\nexport interface TypedWhenClause<P extends string> {\n path: P;\n op?: PredicateOp;\n value?: unknown;\n}\nexport interface TypedPredicate<P extends string> {\n when?: TypedWhenClause<P>;\n all?: TypedPredicate<P>[];\n any?: TypedPredicate<P>[];\n not?: TypedPredicate<P>;\n}\nexport type TypedOptionsSource<P extends string> =\n | { kind: 'static'; options: readonly FormOption[] }\n | {\n kind: 'resolver';\n resolverKey: string;\n deps: P[];\n args?: Record<string, unknown>;\n };\n\nexport type EnhanceFields<\n F extends readonly AnyFieldLike[],\n P extends string,\n> = {\n [K in keyof F]: F[K] & {\n visibleWhen?: TypedPredicate<P>;\n enabledWhen?: TypedPredicate<P>;\n requiredWhen?: TypedPredicate<P>;\n } & (F[K] extends { kind: 'select' }\n ? { options: TypedOptionsSource<P> | readonly FormOption[] }\n : {}) &\n (F[K] extends { kind: 'radio' }\n ? { options: TypedOptionsSource<P> | readonly FormOption[] }\n : {}) & {\n computeFrom?: {\n computeKey: string;\n deps: P[];\n mode?: 'change' | 'blur-xs' | 'submit';\n readOnly?: boolean;\n };\n };\n};\n\nexport function defineFormSpec<\n M extends AnySchemaModel,\n F extends readonly AnyFieldLike[],\n>(spec: {\n meta: FormSpec<M>['meta'];\n model: M;\n fields: EnhanceFields<F, PathOfFields<F>>;\n policy?: FormSpec<M>['policy'];\n actions?: FormSpec<M>['actions'];\n renderHints?: FormSpec<M>['renderHints'];\n constraints?: {\n key: string;\n messageI18n: string;\n paths: PathOfFields<F>[];\n args?: Record<string, unknown>;\n }[];\n}): FormSpec<M> {\n return spec as unknown as FormSpec<M>;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.d.ts","names":[],"sources":["../../src/lib/keyboard.ts"],"sourcesContent":[],"mappings":";KAAY,YAAA;AAAA,KA6BA,iBAAA,GA7BY,IAAA,GAAA,KAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,YAAA,GAAA,iBAAA,GAAA,aAAA,GAAA,kBAAA,GAAA,UAAA,GAAA,UAAA,GAAA,cAAA,GAAA,kBAAA,GAAA,eAAA,GAAA,oBAAA,GAAA,cAAA,GAAA,gBAAA,GAAA,eAAA,GAAA,eAAA,GAAA,eAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,SAAA,GAAA,cAAA,GAAA,aAAA,GAAA,SAAA,GAAA,eAAA,GAAA,oBAAA,GAAA,gBAAA,GAAA,WAAA,GAAA,QAAA,GAAA,cAAA,GAAA,aAAA,GAAA,QAAA,GAAA,SAAA,GAAA,oBAAA,GAAA,UAAA,GAAA,MAAA,GAAA,UAAA,GAAA,YAAA,GAAA,WAAA,GAAA,KAAA,GAAA,OAAA,GAAA,OAAA,GAAA,MAAA,GAAA,KAAA,GAAA,kBAAA,GAAA,cAAA,GAAA,eAAA,GAAA,WAAA,GAAA,kBAAA,GAAA,kBAAA,GAAA,eAAA,GAAA,KAAA,GAAA,UAAA,GAAA,WAAA,MAAA,EAAA,GAAA,CAAA,MAAA,GAAA,CAAA,CAAA,CAAA;AA6BZ,UAoEK,eAAA,CApEY;EAoEZ,IAAA,CAAA,EACR,YADuB;EAwJhB,cAAA,CAAA,EAAA,MAAgB,GAAA,WAAQ,GAAA,
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","names":[],"sources":["../../src/lib/keyboard.ts"],"sourcesContent":[],"mappings":";KAAY,YAAA;AAAA,KA6BA,iBAAA,GA7BY,IAAA,GAAA,KAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,YAAA,GAAA,iBAAA,GAAA,aAAA,GAAA,kBAAA,GAAA,UAAA,GAAA,UAAA,GAAA,cAAA,GAAA,kBAAA,GAAA,eAAA,GAAA,oBAAA,GAAA,cAAA,GAAA,gBAAA,GAAA,eAAA,GAAA,eAAA,GAAA,eAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,gBAAA,GAAA,SAAA,GAAA,cAAA,GAAA,aAAA,GAAA,SAAA,GAAA,eAAA,GAAA,oBAAA,GAAA,gBAAA,GAAA,WAAA,GAAA,QAAA,GAAA,cAAA,GAAA,aAAA,GAAA,QAAA,GAAA,SAAA,GAAA,oBAAA,GAAA,UAAA,GAAA,MAAA,GAAA,UAAA,GAAA,YAAA,GAAA,WAAA,GAAA,KAAA,GAAA,OAAA,GAAA,OAAA,GAAA,MAAA,GAAA,KAAA,GAAA,kBAAA,GAAA,cAAA,GAAA,eAAA,GAAA,WAAA,GAAA,kBAAA,GAAA,kBAAA,GAAA,eAAA,GAAA,KAAA,GAAA,UAAA,GAAA,WAAA,MAAA,EAAA,GAAA,CAAA,MAAA,GAAA,CAAA,CAAA,CAAA;AA6BZ,UAoEK,eAAA,CApEY;EAoEZ,IAAA,CAAA,EACR,YADuB;EAwJhB,cAAA,CAAA,EAAA,MAAgB,GAAA,WAAQ,GAAA,OAAe,GAAA,YAAA;EA0IvC,YAAA,CAAA,EA/RC,iBA+RkB;;;;iBA1InB,gBAAA,QAAwB,kBAAe;iBA0IvC,mBAAA,QAA2B,kBAAe"}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import * as _lssm_lib_schema0 from "@lssm/lib.schema";
|
|
3
|
-
import * as _lssm_lib_contracts_forms0 from "@lssm/lib.contracts/forms";
|
|
4
|
-
import * as _lssm_lib_contracts_client_react_form_render0 from "@lssm/lib.contracts/client/react/form-render";
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
2
|
|
|
6
3
|
//#region src/renderers/form-contract.d.ts
|
|
7
4
|
declare const formRenderer: {
|
|
8
|
-
render: (spec:
|
|
5
|
+
render: (spec: void 0<void 0>, options?: void 0<Record<string, any>> | undefined) => react_jsx_runtime0.JSX.Element;
|
|
9
6
|
};
|
|
10
7
|
//#endregion
|
|
11
8
|
export { formRenderer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-contract.d.ts","names":[],"sources":["../../src/renderers/form-contract.tsx"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"form-contract.d.ts","names":[],"sources":["../../src/renderers/form-contract.tsx"],"sourcesContent":[],"mappings":";;;cAoFa;wBAiBX,KAAA,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { createFormRenderer } from "../contracts/src/client/react/form-render.js";
|
|
5
|
+
import { shadcnDriver } from "../contracts/src/client/react/drivers/shadcn.js";
|
|
6
6
|
import { Label } from "../ui-kit-web/dist/ui/label.js";
|
|
7
7
|
import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel } from "../ui-kit-web/dist/ui/field.js";
|
|
8
8
|
import { Button } from "../components/atoms/Button.js";
|
|
@@ -20,7 +20,7 @@ const Select$1 = (props) => {
|
|
|
20
20
|
const { options, value, onChange,...rest } = props;
|
|
21
21
|
return /* @__PURE__ */ jsxs(Select, {
|
|
22
22
|
value: value ?? "",
|
|
23
|
-
onValueChange: (v
|
|
23
|
+
onValueChange: (v) => onChange?.(v),
|
|
24
24
|
...rest,
|
|
25
25
|
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
26
26
|
className: "w-[180px]",
|
|
@@ -34,7 +34,7 @@ const Select$1 = (props) => {
|
|
|
34
34
|
};
|
|
35
35
|
const Checkbox$1 = (props) => /* @__PURE__ */ jsx(Checkbox, {
|
|
36
36
|
checked: !!props.checked,
|
|
37
|
-
onCheckedChange: (v
|
|
37
|
+
onCheckedChange: (v) => props.onCheckedChange?.(v),
|
|
38
38
|
...props
|
|
39
39
|
});
|
|
40
40
|
const RadioGroup$1 = (props) => /* @__PURE__ */ jsx(RadioGroup, {
|
|
@@ -52,10 +52,10 @@ const RadioGroup$1 = (props) => /* @__PURE__ */ jsx(RadioGroup, {
|
|
|
52
52
|
});
|
|
53
53
|
const Switch$1 = (props) => /* @__PURE__ */ jsx(Switch, {
|
|
54
54
|
checked: !!props.checked,
|
|
55
|
-
onCheckedChange: (v
|
|
55
|
+
onCheckedChange: (v) => props.onCheckedChange?.(v),
|
|
56
56
|
...props
|
|
57
57
|
});
|
|
58
|
-
const formRenderer =
|
|
58
|
+
const formRenderer = createFormRenderer({ driver: shadcnDriver({
|
|
59
59
|
Field,
|
|
60
60
|
FieldLabel,
|
|
61
61
|
FieldDescription,
|