@lattice-php/lattice 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action/components/action-form.js +3 -3
- package/dist/action/components/action-group.js +1 -1
- package/dist/action/components/action.js +10 -16
- package/dist/action/components/action.js.map +1 -1
- package/dist/action/run-action.d.ts +9 -0
- package/dist/action/run-action.js +22 -0
- package/dist/action/run-action.js.map +1 -0
- package/dist/chat/components/chat-box.js +31 -14
- package/dist/chat/components/chat-box.js.map +1 -1
- package/dist/chat/components/message.js +1 -1
- package/dist/chat/components/prompt-input.js +1 -1
- package/dist/chat/index.js +2 -0
- package/dist/chat/index.js.map +1 -1
- package/dist/core/components/badge.js +1 -1
- package/dist/core/components/button.js +17 -5
- package/dist/core/components/button.js.map +1 -1
- package/dist/core/components/card.js +2 -1
- package/dist/core/components/card.js.map +1 -1
- package/dist/core/components/chart.js +4 -1
- package/dist/core/components/chart.js.map +1 -1
- package/dist/core/components/dialog.js +1 -1
- package/dist/core/components/floating-panel.js +3 -2
- package/dist/core/components/floating-panel.js.map +1 -1
- package/dist/core/components/fragment.js +3 -6
- package/dist/core/components/fragment.js.map +1 -1
- package/dist/core/components/grid.js +2 -1
- package/dist/core/components/grid.js.map +1 -1
- package/dist/core/components/index.js +0 -2
- package/dist/core/components/index.js.map +1 -1
- package/dist/core/components/section.js +5 -9
- package/dist/core/components/section.js.map +1 -1
- package/dist/core/components/stack.js +2 -1
- package/dist/core/components/stack.js.map +1 -1
- package/dist/core/components/tabs.js +1 -1
- package/dist/core/nodes.d.ts +6 -0
- package/dist/core/nodes.js +13 -0
- package/dist/core/nodes.js.map +1 -0
- package/dist/core/renderer.js +1 -1
- package/dist/create-app.d.ts +21 -0
- package/dist/create-app.js +31 -0
- package/dist/create-app.js.map +1 -0
- package/dist/effects/registry.js +2 -1
- package/dist/effects/registry.js.map +1 -1
- package/dist/effects/use-effect-dispatcher.js +1 -1
- package/dist/effects/use-flash-effects.js +1 -1
- package/dist/events/event-names.d.ts +4 -2
- package/dist/events/event-names.js +4 -2
- package/dist/events/event-names.js.map +1 -1
- package/dist/form/components/base/input-otp.d.ts +7 -0
- package/dist/form/components/base/input-otp.js +30 -0
- package/dist/form/components/base/input-otp.js.map +1 -0
- package/dist/form/components/conditions.js +1 -1
- package/dist/form/components/conditions.js.map +1 -1
- package/dist/form/components/fields/file-upload.js +1 -1
- package/dist/form/components/fields/otp-input.d.ts +2 -0
- package/dist/form/components/fields/otp-input.js +25 -0
- package/dist/form/components/fields/otp-input.js.map +1 -0
- package/dist/form/components/fields/row-item.js +1 -1
- package/dist/form/components/fields/table-rows.js +1 -1
- package/dist/form/components/form.js +1 -1
- package/dist/form/components/index.d.ts +1 -0
- package/dist/form/components/index.js +2 -1
- package/dist/form/components/prefill-targets.d.ts +0 -1
- package/dist/form/components/prefill-targets.js +1 -4
- package/dist/form/components/prefill-targets.js.map +1 -1
- package/dist/form/components/use-form-resolver.js +2 -2
- package/dist/form/components/use-form-resolver.js.map +1 -1
- package/dist/form/index.js +1 -0
- package/dist/form/index.js.map +1 -1
- package/dist/i18n/config.d.ts +3 -0
- package/dist/i18n/config.js +20 -4
- package/dist/i18n/config.js.map +1 -1
- package/dist/i18n/date-time.d.ts +7 -0
- package/dist/i18n/date-time.js +33 -0
- package/dist/i18n/date-time.js.map +1 -0
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/index.js +3 -1
- package/dist/i18n/locale-reload.js +1 -1
- package/dist/i18n/page-props.js +1 -1
- package/dist/i18n/page-props.js.map +1 -1
- package/dist/i18n/timezone.d.ts +7 -0
- package/dist/i18n/timezone.js +53 -0
- package/dist/i18n/timezone.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -13
- package/dist/layout/breadcrumbs.js +3 -2
- package/dist/layout/breadcrumbs.js.map +1 -1
- package/dist/layout/callouts.js +1 -1
- package/dist/layout/components.js +1 -1
- package/dist/layout/menu-item.js +2 -2
- package/dist/layout/menu.js +2 -1
- package/dist/layout/menu.js.map +1 -1
- package/dist/layout/popover.js +1 -1
- package/dist/layout/sidebar.js +69 -29
- package/dist/layout/sidebar.js.map +1 -1
- package/dist/layout/topbar.js +2 -1
- package/dist/layout/topbar.js.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/remote/components/data-list.js +1 -1
- package/dist/remote/index.js +1 -5
- package/dist/remote/index.js.map +1 -1
- package/dist/table/components/bulk-bar.js +10 -15
- package/dist/table/components/bulk-bar.js.map +1 -1
- package/dist/table/components/cells/text-cell.js +46 -4
- package/dist/table/components/cells/text-cell.js.map +1 -1
- package/dist/table/components/table.js +1 -1
- package/dist/table/filter-values.d.ts +5 -0
- package/dist/table/filter-values.js +10 -3
- package/dist/table/filter-values.js.map +1 -1
- package/dist/table/format.d.ts +11 -1
- package/dist/table/format.js +23 -21
- package/dist/table/format.js.map +1 -1
- package/dist/table/query.js +5 -4
- package/dist/table/query.js.map +1 -1
- package/dist/toast/toaster.js +2 -2
- package/dist/types/generated.d.ts +51 -24
- package/dist/vite.js +32 -1
- package/dist/vite.js.map +1 -1
- package/package.json +14 -3
- package/dist/remote/components/chat-box.d.ts +0 -3
- package/dist/remote/components/chat-box.js +0 -65
- package/dist/remote/components/chat-box.js.map +0 -1
package/dist/layout/sidebar.js
CHANGED
|
@@ -1,45 +1,85 @@
|
|
|
1
|
+
import { LATTICE_EVENT } from "../events/event-names.js";
|
|
1
2
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import { Icon } from "../icons/sprite.js";
|
|
3
3
|
import { CollapsedContext } from "../core/collapsed-context.js";
|
|
4
|
-
import {
|
|
4
|
+
import { nodeIdentity } from "../core/test-id.js";
|
|
5
|
+
import { router } from "@inertiajs/react";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
8
|
//#region resources/js/layout/sidebar.tsx
|
|
9
|
+
var DESKTOP_QUERY = "(min-width: 768px)";
|
|
7
10
|
function readStored(key, remember) {
|
|
8
11
|
if (!remember || typeof window === "undefined") return false;
|
|
9
12
|
return window.localStorage.getItem(key) === "true";
|
|
10
13
|
}
|
|
14
|
+
function matchesTarget(event, identity) {
|
|
15
|
+
const target = event.detail?.target;
|
|
16
|
+
return target == null || target === identity;
|
|
17
|
+
}
|
|
18
|
+
function useIsDesktop() {
|
|
19
|
+
const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
20
|
+
const [isDesktop, setIsDesktop] = useState(() => supported() ? window.matchMedia(DESKTOP_QUERY).matches : true);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!supported()) return;
|
|
23
|
+
const query = window.matchMedia(DESKTOP_QUERY);
|
|
24
|
+
const update = () => setIsDesktop(query.matches);
|
|
25
|
+
update();
|
|
26
|
+
query.addEventListener("change", update);
|
|
27
|
+
return () => query.removeEventListener("change", update);
|
|
28
|
+
}, []);
|
|
29
|
+
return isDesktop;
|
|
30
|
+
}
|
|
11
31
|
var SidebarComponent = ({ children, node }) => {
|
|
12
32
|
const collapsible = node.props.collapsible;
|
|
13
33
|
const rememberState = node.props.rememberState;
|
|
14
|
-
const
|
|
34
|
+
const identity = nodeIdentity(node);
|
|
35
|
+
const storageKey = `lattice:sidebar:${identity ?? "default"}`;
|
|
36
|
+
const isDesktop = useIsDesktop();
|
|
15
37
|
const [collapsed, setCollapsed] = useState(() => readStored(storageKey, collapsible && rememberState));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
const [mobileOpen, setMobileOpen] = useState(false);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
function toggle(event) {
|
|
41
|
+
if (!matchesTarget(event, identity)) return;
|
|
42
|
+
if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {
|
|
43
|
+
if (!collapsible) return;
|
|
44
|
+
setCollapsed((value) => {
|
|
45
|
+
const next = !value;
|
|
46
|
+
if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
|
|
47
|
+
return next;
|
|
48
|
+
});
|
|
49
|
+
} else setMobileOpen((open) => !open);
|
|
50
|
+
}
|
|
51
|
+
window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);
|
|
52
|
+
return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);
|
|
53
|
+
}, [
|
|
54
|
+
identity,
|
|
55
|
+
collapsible,
|
|
56
|
+
rememberState,
|
|
57
|
+
storageKey
|
|
58
|
+
]);
|
|
59
|
+
useEffect(() => router.on("navigate", () => setMobileOpen(false)), []);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!mobileOpen) return;
|
|
62
|
+
function close(event) {
|
|
63
|
+
if (event.key === "Escape") setMobileOpen(false);
|
|
64
|
+
}
|
|
65
|
+
window.addEventListener("keydown", close);
|
|
66
|
+
return () => window.removeEventListener("keydown", close);
|
|
67
|
+
}, [mobileOpen]);
|
|
68
|
+
const isCollapsed = collapsible && collapsed && isDesktop;
|
|
69
|
+
return /* @__PURE__ */ jsxs(CollapsedContext.Provider, {
|
|
25
70
|
value: isCollapsed,
|
|
26
|
-
children: /* @__PURE__ */
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"aria-hidden": "true",
|
|
39
|
-
className: "size-lt-icon-md shrink-0"
|
|
40
|
-
})
|
|
41
|
-
}) : null, children]
|
|
42
|
-
})
|
|
71
|
+
children: [mobileOpen ? /* @__PURE__ */ jsx("div", {
|
|
72
|
+
"aria-hidden": "true",
|
|
73
|
+
className: "fixed inset-0 z-30 bg-black/50 md:hidden",
|
|
74
|
+
"data-test": "sidebar-backdrop",
|
|
75
|
+
onClick: () => setMobileOpen(false)
|
|
76
|
+
}) : null, /* @__PURE__ */ jsx("aside", {
|
|
77
|
+
className: cn("fixed inset-y-0 left-0 z-40 flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform", "md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]", mobileOpen ? "translate-x-0" : "-translate-x-full", isCollapsed ? "md:w-16 md:overflow-visible" : "md:w-64 md:overflow-x-hidden md:overflow-y-auto"),
|
|
78
|
+
"data-collapsed": isCollapsed ? "true" : "false",
|
|
79
|
+
"data-lattice-component": identity,
|
|
80
|
+
"data-test": "sidebar",
|
|
81
|
+
children
|
|
82
|
+
})]
|
|
43
83
|
});
|
|
44
84
|
};
|
|
45
85
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":[],"sources":["../../resources/js/layout/sidebar.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../resources/js/layout/sidebar.tsx"],"sourcesContent":["import { router } from \"@inertiajs/react\";\nimport { useEffect, useState } from \"react\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { CollapsedContext } from \"../core/collapsed-context\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst DESKTOP_QUERY = \"(min-width: 768px)\";\n\nfunction readStored(key: string, remember: boolean): boolean {\n if (!remember || typeof window === \"undefined\") {\n return false;\n }\n\n return window.localStorage.getItem(key) === \"true\";\n}\n\nfunction matchesTarget(event: Event, identity: string | undefined): boolean {\n const target = (event as CustomEvent<{ target?: string }>).detail?.target;\n\n return target == null || target === identity;\n}\n\nfunction useIsDesktop(): boolean {\n const supported = () => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\";\n const [isDesktop, setIsDesktop] = useState(() =>\n supported() ? window.matchMedia(DESKTOP_QUERY).matches : true,\n );\n\n useEffect(() => {\n if (!supported()) {\n return;\n }\n\n const query = window.matchMedia(DESKTOP_QUERY);\n const update = (): void => setIsDesktop(query.matches);\n\n update();\n query.addEventListener(\"change\", update);\n\n return () => query.removeEventListener(\"change\", update);\n }, []);\n\n return isDesktop;\n}\n\nconst SidebarComponent: RendererComponent<\"sidebar\"> = ({ children, node }) => {\n const collapsible = node.props.collapsible;\n const rememberState = node.props.rememberState;\n const identity = nodeIdentity(node);\n const storageKey = `lattice:sidebar:${identity ?? \"default\"}`;\n const isDesktop = useIsDesktop();\n\n const [collapsed, setCollapsed] = useState(() =>\n readStored(storageKey, collapsible && rememberState),\n );\n const [mobileOpen, setMobileOpen] = useState(false);\n\n useEffect(() => {\n function toggle(event: Event): void {\n if (!matchesTarget(event, identity)) {\n return;\n }\n\n if (window.matchMedia?.(DESKTOP_QUERY).matches ?? true) {\n if (!collapsible) {\n return;\n }\n\n setCollapsed((value) => {\n const next = !value;\n\n if (rememberState && typeof window !== \"undefined\") {\n window.localStorage.setItem(storageKey, String(next));\n }\n\n return next;\n });\n } else {\n setMobileOpen((open) => !open);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n\n return () => window.removeEventListener(LATTICE_EVENT.toggleSidebar, toggle);\n }, [identity, collapsible, rememberState, storageKey]);\n\n useEffect(() => router.on(\"navigate\", () => setMobileOpen(false)), []);\n\n useEffect(() => {\n if (!mobileOpen) {\n return;\n }\n\n function close(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n setMobileOpen(false);\n }\n }\n\n window.addEventListener(\"keydown\", close);\n\n return () => window.removeEventListener(\"keydown\", close);\n }, [mobileOpen]);\n\n const isCollapsed = collapsible && collapsed && isDesktop;\n\n return (\n <CollapsedContext.Provider value={isCollapsed}>\n {mobileOpen ? (\n <div\n aria-hidden=\"true\"\n className=\"fixed inset-0 z-30 bg-black/50 md:hidden\"\n data-test=\"sidebar-backdrop\"\n onClick={() => setMobileOpen(false)}\n />\n ) : null}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-40 flex h-svh w-72 max-w-[80vw] shrink-0 flex-col gap-4 border-r border-lt-border bg-lt-bg p-4 transition-transform\",\n \"md:sticky md:top-0 md:z-auto md:max-w-none md:translate-x-0 md:transition-[width]\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n isCollapsed\n ? \"md:w-16 md:overflow-visible\"\n : \"md:w-64 md:overflow-x-hidden md:overflow-y-auto\",\n )}\n data-collapsed={isCollapsed ? \"true\" : \"false\"}\n data-lattice-component={identity}\n data-test=\"sidebar\"\n >\n {children}\n </aside>\n </CollapsedContext.Provider>\n );\n};\n\nexport default SidebarComponent;\n"],"mappings":";;;;;;;;AAQA,IAAM,gBAAgB;AAEtB,SAAS,WAAW,KAAa,UAA4B;CAC3D,IAAI,CAAC,YAAY,OAAO,WAAW,aACjC,OAAO;CAGT,OAAO,OAAO,aAAa,QAAQ,GAAG,MAAM;AAC9C;AAEA,SAAS,cAAc,OAAc,UAAuC;CAC1E,MAAM,SAAU,MAA2C,QAAQ;CAEnE,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,SAAS,eAAwB;CAC/B,MAAM,kBAAkB,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe;CACtF,MAAM,CAAC,WAAW,gBAAgB,eAChC,UAAU,IAAI,OAAO,WAAW,aAAa,EAAE,UAAU,IAC3D;CAEA,gBAAgB;EACd,IAAI,CAAC,UAAU,GACb;EAGF,MAAM,QAAQ,OAAO,WAAW,aAAa;EAC7C,MAAM,eAAqB,aAAa,MAAM,OAAO;EAErD,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EAEvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,CAAC;CAEL,OAAO;AACT;AAEA,IAAM,oBAAkD,EAAE,UAAU,WAAW;CAC7E,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,gBAAgB,KAAK,MAAM;CACjC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,mBAAmB,YAAY;CAClD,MAAM,YAAY,aAAa;CAE/B,MAAM,CAAC,WAAW,gBAAgB,eAChC,WAAW,YAAY,eAAe,aAAa,CACrD;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,gBAAgB;EACd,SAAS,OAAO,OAAoB;GAClC,IAAI,CAAC,cAAc,OAAO,QAAQ,GAChC;GAGF,IAAI,OAAO,aAAa,aAAa,EAAE,WAAW,MAAM;IACtD,IAAI,CAAC,aACH;IAGF,cAAc,UAAU;KACtB,MAAM,OAAO,CAAC;KAEd,IAAI,iBAAiB,OAAO,WAAW,aACrC,OAAO,aAAa,QAAQ,YAAY,OAAO,IAAI,CAAC;KAGtD,OAAO;IACT,CAAC;GACH,OACE,eAAe,SAAS,CAAC,IAAI;EAEjC;EAEA,OAAO,iBAAiB,cAAc,eAAe,MAAM;EAE3D,aAAa,OAAO,oBAAoB,cAAc,eAAe,MAAM;CAC7E,GAAG;EAAC;EAAU;EAAa;EAAe;CAAU,CAAC;CAErD,gBAAgB,OAAO,GAAG,kBAAkB,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC;CAErE,gBAAgB;EACd,IAAI,CAAC,YACH;EAGF,SAAS,MAAM,OAA4B;GACzC,IAAI,MAAM,QAAQ,UAChB,cAAc,KAAK;EAEvB;EAEA,OAAO,iBAAiB,WAAW,KAAK;EAExC,aAAa,OAAO,oBAAoB,WAAW,KAAK;CAC1D,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,cAAc,eAAe,aAAa;CAEhD,OACE,qBAAC,iBAAiB,UAAlB;EAA2B,OAAO;YAAlC,CACG,aACC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,aAAU;GACV,eAAe,cAAc,KAAK;EACnC,CAAA,IACC,MACJ,oBAAC,SAAD;GACE,WAAW,GACT,gJACA,qFACA,aAAa,kBAAkB,qBAC/B,cACI,gCACA,iDACN;GACA,kBAAgB,cAAc,SAAS;GACvC,0BAAwB;GACxB,aAAU;GAET;EACI,CAAA,CACkB;;AAE/B"}
|
package/dist/layout/topbar.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { nodeIdentity } from "../core/test-id.js";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
//#region resources/js/layout/topbar.tsx
|
|
4
5
|
var TopbarComponent = ({ children, node }) => {
|
|
5
6
|
const sticky = node.props.sticky;
|
|
6
7
|
return /* @__PURE__ */ jsx("header", {
|
|
7
|
-
"data-lattice-component": node
|
|
8
|
+
"data-lattice-component": nodeIdentity(node),
|
|
8
9
|
className: cn("flex h-14 w-full items-center gap-2 border-b border-lt-border bg-lt-bg px-4 text-lt-fg", sticky && "sticky top-0 z-30"),
|
|
9
10
|
children
|
|
10
11
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topbar.js","names":[],"sources":["../../resources/js/layout/topbar.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst TopbarComponent: RendererComponent<\"topbar\"> = ({ children, node }) => {\n const sticky = node.props.sticky;\n\n return (\n <header\n data-lattice-component={node
|
|
1
|
+
{"version":3,"file":"topbar.js","names":[],"sources":["../../resources/js/layout/topbar.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nconst TopbarComponent: RendererComponent<\"topbar\"> = ({ children, node }) => {\n const sticky = node.props.sticky;\n\n return (\n <header\n data-lattice-component={nodeIdentity(node)}\n className={cn(\n \"flex h-14 w-full items-center gap-2 border-b border-lt-border bg-lt-bg px-4 text-lt-fg\",\n sticky && \"sticky top-0 z-30\",\n )}\n >\n {children}\n </header>\n );\n};\n\nexport default TopbarComponent;\n"],"mappings":";;;;AAIA,IAAM,mBAAgD,EAAE,UAAU,WAAW;CAC3E,MAAM,SAAS,KAAK,MAAM;CAE1B,OACE,oBAAC,UAAD;EACE,0BAAwB,aAAa,IAAI;EACzC,WAAW,GACT,0FACA,UAAU,mBACZ;EAEC;CACK,CAAA;AAEZ"}
|
package/dist/registry.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRegistry } from "./core/registry.js";
|
|
2
|
+
import { layoutComponents } from "./layout/components.js";
|
|
2
3
|
import { actionComponents } from "./action/index.js";
|
|
3
4
|
import { chatPlugin } from "./chat/index.js";
|
|
4
5
|
import { coreComponents } from "./core/components/index.js";
|
|
5
6
|
import { formComponents } from "./form/index.js";
|
|
6
7
|
import { remoteComponents } from "./remote/index.js";
|
|
7
|
-
import { layoutComponents } from "./layout/components.js";
|
|
8
8
|
import { tableComponents } from "./table/index.js";
|
|
9
9
|
//#region resources/js/registry.ts
|
|
10
10
|
var registry = createRegistry(coreComponents, actionComponents, formComponents, layoutComponents, tableComponents, chatPlugin, remoteComponents);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Renderer } from "../../core/renderer.js";
|
|
1
2
|
import { useT } from "../../i18n/instance.js";
|
|
2
3
|
import { remoteJson } from "../../core/api.js";
|
|
3
|
-
import { Renderer } from "../../core/renderer.js";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region resources/js/remote/components/data-list.tsx
|
package/dist/remote/index.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { createPlugin, eagerComponent } from "../core/registry.js";
|
|
2
2
|
import { DataList } from "./components/data-list.js";
|
|
3
|
-
import { RemoteChatBox } from "./components/chat-box.js";
|
|
4
3
|
//#region resources/js/remote/index.ts
|
|
5
4
|
var remoteComponents = createPlugin({
|
|
6
|
-
components: {
|
|
7
|
-
"remote.data-list": eagerComponent(DataList),
|
|
8
|
-
"remote.chat-box": eagerComponent(RemoteChatBox)
|
|
9
|
-
},
|
|
5
|
+
components: { "remote.data-list": eagerComponent(DataList) },
|
|
10
6
|
name: "lattice/remote"
|
|
11
7
|
});
|
|
12
8
|
//#endregion
|
package/dist/remote/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/remote/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport DataListComponent from \"./components/data-list\";\
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/remote/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport DataListComponent from \"./components/data-list\";\n\nexport const remoteComponents = createPlugin({\n components: {\n \"remote.data-list\": eagerComponent(DataListComponent),\n },\n name: \"lattice/remote\",\n});\n"],"mappings":";;;AAGA,IAAa,mBAAmB,aAAa;CAC3C,YAAY,EACV,oBAAoB,eAAe,QAAiB,EACtD;CACA,MAAM;AACR,CAAC"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { withHeaders } from "../../core/headers.js";
|
|
2
|
+
import { useT } from "../../i18n/instance.js";
|
|
2
3
|
import { prefixedTestId } from "../../core/test-id.js";
|
|
4
|
+
import { getActionEffects } from "../../effects/dispatch.js";
|
|
5
|
+
import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
|
|
3
6
|
import { Button } from "../../core/components/button.js";
|
|
4
|
-
import { useT } from "../../i18n/instance.js";
|
|
5
7
|
import { Spinner } from "../../core/components/spinner.js";
|
|
6
8
|
import { ConfirmDialog } from "../../core/components/confirm-dialog.js";
|
|
7
|
-
import {
|
|
8
|
-
import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
|
|
9
|
+
import { runAction } from "../../action/run-action.js";
|
|
9
10
|
import { ActionForm } from "../../action/components/action-form.js";
|
|
10
|
-
import { useState } from "react";
|
|
11
11
|
import { useHttp } from "@inertiajs/react";
|
|
12
|
+
import { useState } from "react";
|
|
12
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
14
|
//#region resources/js/table/components/bulk-bar.tsx
|
|
14
15
|
function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAllMatching, onSelectAllMatching, onCompleted }) {
|
|
@@ -22,19 +23,13 @@ function BulkBar({ actions, selectedKeys, allMatching, total, query, canSelectAl
|
|
|
22
23
|
...query
|
|
23
24
|
} : { selected: selectedKeys };
|
|
24
25
|
async function submit(action) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
...query
|
|
31
|
-
} : { selected: selectedKeys }
|
|
32
|
-
}));
|
|
33
|
-
dispatch(getActionEffects((await http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? "") })).effects));
|
|
26
|
+
http.transform((data) => ({
|
|
27
|
+
...data,
|
|
28
|
+
...selectionPayload()
|
|
29
|
+
}));
|
|
30
|
+
if (await runAction(() => http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? "") }), dispatch)) {
|
|
34
31
|
setConfirming(null);
|
|
35
32
|
onCompleted();
|
|
36
|
-
} catch (error) {
|
|
37
|
-
dispatchActionError(error);
|
|
38
33
|
}
|
|
39
34
|
}
|
|
40
35
|
function run(action) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useHttp } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport { ActionForm } from \"@lattice-php/lattice/action/components/action-form\";\nimport {
|
|
1
|
+
{"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useHttp } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport { ActionForm } from \"@lattice-php/lattice/action/components/action-form\";\nimport { runAction } from \"@lattice-php/lattice/action/run-action\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/core/components/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/core/components/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { BulkAction } from \"../bulk\";\n\ntype BulkData = {\n allMatching?: boolean;\n selected?: string[];\n};\n\nexport function BulkBar({\n actions,\n selectedKeys,\n allMatching,\n total,\n query,\n canSelectAllMatching,\n onSelectAllMatching,\n onCompleted,\n}: {\n actions: BulkAction[];\n selectedKeys: string[];\n allMatching: boolean;\n total?: number;\n query: Record<string, unknown>;\n canSelectAllMatching: boolean;\n onSelectAllMatching: () => void;\n onCompleted: () => void;\n}) {\n const { t } = useT(\"lattice\");\n const http = useHttp<BulkData, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [confirming, setConfirming] = useState<BulkAction | null>(null);\n const [filling, setFilling] = useState<BulkAction | null>(null);\n\n const selectionPayload = (): Record<string, unknown> =>\n allMatching ? { allMatching: true, ...query } : { selected: selectedKeys };\n\n async function submit(action: BulkAction): Promise<void> {\n http.transform((data) => ({ ...data, ...selectionPayload() }));\n\n const ok = await runAction(\n () => http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? \"\") }),\n dispatch,\n );\n\n if (ok) {\n setConfirming(null);\n onCompleted();\n }\n }\n\n function run(action: BulkAction): void {\n if (action.form) {\n setFilling(action);\n\n return;\n }\n\n if (action.confirmation) {\n setConfirming(action);\n\n return;\n }\n\n void submit(action);\n }\n\n const count = allMatching ? (total ?? selectedKeys.length) : selectedKeys.length;\n\n return (\n <div className=\"flex flex-wrap items-center gap-3 border-b border-lt-border bg-lt-muted/50 p-4 text-sm\">\n <span className=\"font-medium\">\n {allMatching\n ? t(\"bulk.allSelected\", \"All {{count}} selected\", { count })\n : t(\"bulk.selected\", \"{{count}} selected\", { count })}\n </span>\n {canSelectAllMatching && (\n <button\n type=\"button\"\n data-test=\"bulk-select-all-matching\"\n className=\"font-medium text-lt-primary underline underline-offset-2\"\n onClick={onSelectAllMatching}\n >\n {t(\"bulk.selectAllMatching\", \"Select all {{total}} matching\", { total })}\n </button>\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n {actions.map((action) => (\n <Button\n key={action.id}\n type=\"button\"\n data-test={prefixedTestId(\"bulk-action\", action.id)}\n variant={action.variant}\n disabled={http.processing}\n onClick={() => run(action)}\n >\n {http.processing && <Spinner />}\n {action.label}\n </Button>\n ))}\n </div>\n\n {confirming?.confirmation && (\n <ConfirmDialog\n title={confirming.confirmation.title ?? confirming.label}\n description={confirming.confirmation.description ?? undefined}\n confirmLabel={confirming.confirmation.confirmLabel ?? confirming.label}\n cancelLabel={confirming.confirmation.cancelLabel ?? \"Cancel\"}\n confirmVariant={confirming.variant}\n processing={http.processing}\n onConfirm={() => void submit(confirming)}\n onCancel={() => setConfirming(null)}\n />\n )}\n\n {filling?.form && (\n <ActionForm\n cancelLabel={filling.confirmation?.cancelLabel ?? \"Cancel\"}\n componentRef={filling.ref}\n description={filling.confirmation?.description ?? undefined}\n endpoint={filling.endpoint}\n extraData={selectionPayload()}\n formNode={filling.form}\n method={filling.method}\n onClose={() => setFilling(null)}\n onSuccess={(response) => {\n dispatch(getActionEffects(response.effects));\n setFilling(null);\n onCompleted();\n }}\n submitLabel={filling.confirmation?.confirmLabel ?? filling.label}\n title={filling.confirmation?.title ?? filling.label}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAoBA,SAAgB,QAAQ,EACtB,SACA,cACA,aACA,OACA,OACA,sBACA,qBACA,eAUC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,OAAO,QAAkC,CAAC,CAAC;CACjD,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAA4B,IAAI;CAE9D,MAAM,yBACJ,cAAc;EAAE,aAAa;EAAM,GAAG;CAAM,IAAI,EAAE,UAAU,aAAa;CAE3E,eAAe,OAAO,QAAmC;EACvD,KAAK,WAAW,UAAU;GAAE,GAAG;GAAM,GAAG,iBAAiB;EAAE,EAAE;EAO7D,IAAI,MALa,gBACT,KAAK,OAAO,QAAQ,OAAO,UAAU,EAAE,SAAS,YAAY,OAAO,OAAO,EAAE,EAAE,CAAC,GACrF,QACF,GAEQ;GACN,cAAc,IAAI;GAClB,YAAY;EACd;CACF;CAEA,SAAS,IAAI,QAA0B;EACrC,IAAI,OAAO,MAAM;GACf,WAAW,MAAM;GAEjB;EACF;EAEA,IAAI,OAAO,cAAc;GACvB,cAAc,MAAM;GAEpB;EACF;EAEA,OAAY,MAAM;CACpB;CAEA,MAAM,QAAQ,cAAe,SAAS,aAAa,SAAU,aAAa;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,QAAD;IAAM,WAAU;cACb,cACG,EAAE,oBAAoB,0BAA0B,EAAE,MAAM,CAAC,IACzD,EAAE,iBAAiB,sBAAsB,EAAE,MAAM,CAAC;GAClD,CAAA;GACL,wBACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,0BAA0B,iCAAiC,EAAE,MAAM,CAAC;GACjE,CAAA;GAEV,oBAAC,OAAD;IAAK,WAAU;cACZ,QAAQ,KAAK,WACZ,qBAAC,QAAD;KAEE,MAAK;KACL,aAAW,eAAe,eAAe,OAAO,EAAE;KAClD,SAAS,OAAO;KAChB,UAAU,KAAK;KACf,eAAe,IAAI,MAAM;eAN3B,CAQG,KAAK,cAAc,oBAAC,SAAD,CAAU,CAAA,GAC7B,OAAO,KACF;OATD,OAAO,EASN,CACT;GACE,CAAA;GAEJ,YAAY,gBACX,oBAAC,eAAD;IACE,OAAO,WAAW,aAAa,SAAS,WAAW;IACnD,aAAa,WAAW,aAAa,eAAe,KAAA;IACpD,cAAc,WAAW,aAAa,gBAAgB,WAAW;IACjE,aAAa,WAAW,aAAa,eAAe;IACpD,gBAAgB,WAAW;IAC3B,YAAY,KAAK;IACjB,iBAAiB,KAAK,OAAO,UAAU;IACvC,gBAAgB,cAAc,IAAI;GACnC,CAAA;GAGF,SAAS,QACR,oBAAC,YAAD;IACE,aAAa,QAAQ,cAAc,eAAe;IAClD,cAAc,QAAQ;IACtB,aAAa,QAAQ,cAAc,eAAe,KAAA;IAClD,UAAU,QAAQ;IAClB,WAAW,iBAAiB;IAC5B,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,eAAe,WAAW,IAAI;IAC9B,YAAY,aAAa;KACvB,SAAS,iBAAiB,SAAS,OAAO,CAAC;KAC3C,WAAW,IAAI;KACf,YAAY;IACd;IACA,aAAa,QAAQ,cAAc,gBAAgB,QAAQ;IAC3D,OAAO,QAAQ,cAAc,SAAS,QAAQ;GAC/C,CAAA;EAEA;;AAET"}
|
|
@@ -1,13 +1,50 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
1
2
|
import { Icon } from "../../../icons/sprite.js";
|
|
2
|
-
import { copyToClipboard } from "../../../clipboard/index.js";
|
|
3
3
|
import { formatCell, resolveLink } from "../../format.js";
|
|
4
|
+
import { DateTime } from "../../../i18n/date-time.js";
|
|
5
|
+
import { copyToClipboard } from "../../../clipboard/index.js";
|
|
4
6
|
import { useEffect, useState } from "react";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
8
|
//#region resources/js/table/components/cells/text-cell.tsx
|
|
7
|
-
var TextCell = (
|
|
9
|
+
var TextCell = (args) => {
|
|
10
|
+
if (args.props.multiple) return /* @__PURE__ */ jsx(MultipleCell, { ...args });
|
|
11
|
+
if (args.props.badge) return /* @__PURE__ */ jsx(SingleBadgeCell, { ...args });
|
|
12
|
+
return /* @__PURE__ */ jsx(PlainTextCell, { ...args });
|
|
13
|
+
};
|
|
14
|
+
function Badge({ label, color }) {
|
|
15
|
+
if (label === "") return null;
|
|
16
|
+
return /* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: cn("lt-cell-badge", `lt-cell-tone-${color || "gray"}`),
|
|
18
|
+
children: label
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function MultipleCell({ column, props, value }) {
|
|
22
|
+
const items = Array.isArray(value) ? value : [];
|
|
23
|
+
if (items.length === 0) return null;
|
|
24
|
+
if (!props.badge) return /* @__PURE__ */ jsx("span", { children: items.map((item) => formatCell(item, column)).join(", ") });
|
|
25
|
+
return /* @__PURE__ */ jsx("div", {
|
|
26
|
+
className: "flex flex-wrap gap-1",
|
|
27
|
+
children: items.map((item, index) => {
|
|
28
|
+
const chip = item;
|
|
29
|
+
return /* @__PURE__ */ jsx(Badge, {
|
|
30
|
+
label: formatCell(chip.value, column),
|
|
31
|
+
color: chip.color
|
|
32
|
+
}, index);
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function SingleBadgeCell({ column, props, row, value }) {
|
|
37
|
+
const colorKey = props.badge.colorKey;
|
|
38
|
+
return /* @__PURE__ */ jsx(Badge, {
|
|
39
|
+
label: formatCell(value, column),
|
|
40
|
+
color: String(row[colorKey] ?? "")
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function PlainTextCell({ column, props, row, value }) {
|
|
44
|
+
const dateProps = column.props?.date;
|
|
45
|
+
const href = resolveLink(column, row, value);
|
|
8
46
|
const text = formatCell(value, column);
|
|
9
47
|
const [copied, setCopied] = useState(false);
|
|
10
|
-
const href = resolveLink(column, row, value);
|
|
11
48
|
const content = href ? /* @__PURE__ */ jsx("a", {
|
|
12
49
|
className: "underline underline-offset-2",
|
|
13
50
|
href,
|
|
@@ -24,6 +61,11 @@ var TextCell = ({ column, props, row, value }) => {
|
|
|
24
61
|
copyToClipboard(text);
|
|
25
62
|
setCopied(true);
|
|
26
63
|
}
|
|
64
|
+
if (dateProps && !href && !props.copyable && value !== null && value !== void 0) return /* @__PURE__ */ jsx(DateTime, {
|
|
65
|
+
value,
|
|
66
|
+
dateStyle: dateProps.dateStyle,
|
|
67
|
+
timeStyle: dateProps.timeStyle
|
|
68
|
+
});
|
|
27
69
|
if (!props.copyable) return content;
|
|
28
70
|
return /* @__PURE__ */ jsxs("span", {
|
|
29
71
|
className: "inline-flex items-center gap-2",
|
|
@@ -42,7 +84,7 @@ var TextCell = ({ column, props, row, value }) => {
|
|
|
42
84
|
}), copied ? "Copied" : "Copy"]
|
|
43
85
|
})]
|
|
44
86
|
});
|
|
45
|
-
}
|
|
87
|
+
}
|
|
46
88
|
//#endregion
|
|
47
89
|
export { TextCell };
|
|
48
90
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import { copyToClipboard } from \"@lattice-php/lattice/clipboard\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useEffect, useState } from \"react\";\nimport { formatCell, resolveLink } from \"../../format\";\nimport type { ColumnCellComponent } from \"../../registry\";\n\nexport const TextCell: ColumnCellComponent<\"column.text\"> = ({ column, props,
|
|
1
|
+
{"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import { copyToClipboard } from \"@lattice-php/lattice/clipboard\";\nimport { DateTime } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { type ReactNode, useEffect, useState } from \"react\";\nimport { formatCell, resolveLink } from \"../../format\";\nimport type { ColumnCellArgs, ColumnCellComponent } from \"../../registry\";\nimport type { ColumnPropsOf } from \"../../types\";\n\ntype TextProps = ColumnCellArgs<\"column.text\">[\"props\"];\n\nexport const TextCell: ColumnCellComponent<\"column.text\"> = (args) => {\n if (args.props.multiple) {\n return <MultipleCell {...args} />;\n }\n\n if (args.props.badge) {\n return <SingleBadgeCell {...args} />;\n }\n\n return <PlainTextCell {...args} />;\n};\n\nfunction Badge({ label, color }: { label: string; color?: string | null }): ReactNode {\n if (label === \"\") {\n return null;\n }\n\n return <span className={cn(\"lt-cell-badge\", `lt-cell-tone-${color || \"gray\"}`)}>{label}</span>;\n}\n\nfunction MultipleCell({ column, props, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const items = Array.isArray(value) ? value : [];\n\n if (items.length === 0) {\n return null;\n }\n\n if (!props.badge) {\n return <span>{items.map((item) => formatCell(item, column)).join(\", \")}</span>;\n }\n\n return (\n <div className=\"flex flex-wrap gap-1\">\n {items.map((item, index) => {\n const chip = item as { value: unknown; color?: string };\n\n return <Badge key={index} label={formatCell(chip.value, column)} color={chip.color} />;\n })}\n </div>\n );\n}\n\nfunction SingleBadgeCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const colorKey = (props.badge as NonNullable<TextProps[\"badge\"]>).colorKey;\n\n return <Badge label={formatCell(value, column)} color={String(row[colorKey] ?? \"\")} />;\n}\n\nfunction PlainTextCell({ column, props, row, value }: ColumnCellArgs<\"column.text\">): ReactNode {\n const dateProps = (column.props as ColumnPropsOf<\"column.text\"> | null)?.date;\n const href = resolveLink(column, row, value);\n const text = formatCell(value, column);\n const [copied, setCopied] = useState(false);\n\n const content = href ? (\n <a\n className=\"underline underline-offset-2\"\n href={href}\n rel={props.link?.external ? \"noreferrer\" : undefined}\n target={props.link?.external ? \"_blank\" : undefined}\n >\n {text}\n </a>\n ) : (\n text\n );\n\n useEffect(() => {\n if (!copied) {\n return;\n }\n\n const timeout = window.setTimeout(() => setCopied(false), 1500);\n\n return () => window.clearTimeout(timeout);\n }, [copied]);\n\n function handleCopy(): void {\n void copyToClipboard(text);\n setCopied(true);\n }\n\n if (dateProps && !href && !props.copyable && value !== null && value !== undefined) {\n return (\n <DateTime value={value} dateStyle={dateProps.dateStyle} timeStyle={dateProps.timeStyle} />\n );\n }\n\n if (!props.copyable) {\n return content;\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\">\n <span>{content}</span>\n <button\n type=\"button\"\n data-test={`copy-${column.key}`}\n className=\"inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs\"\n aria-label={`${copied ? \"Copied\" : \"Copy\"} ${column.label}`}\n onClick={handleCopy}\n >\n {copied ? (\n <Icon name=\"check\" className=\"size-lt-icon-xs\" />\n ) : (\n <Icon name=\"copy\" className=\"size-lt-icon-xs\" />\n )}\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </span>\n );\n}\n"],"mappings":";;;;;;;;AAWA,IAAa,YAAgD,SAAS;CACpE,IAAI,KAAK,MAAM,UACb,OAAO,oBAAC,cAAD,EAAc,GAAI,KAAO,CAAA;CAGlC,IAAI,KAAK,MAAM,OACb,OAAO,oBAAC,iBAAD,EAAiB,GAAI,KAAO,CAAA;CAGrC,OAAO,oBAAC,eAAD,EAAe,GAAI,KAAO,CAAA;AACnC;AAEA,SAAS,MAAM,EAAE,OAAO,SAA8D;CACpF,IAAI,UAAU,IACZ,OAAO;CAGT,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,iBAAiB,gBAAgB,SAAS,QAAQ;YAAI;CAAY,CAAA;AAC/F;AAEA,SAAS,aAAa,EAAE,QAAQ,OAAO,SAAmD;CACxF,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;CAE9C,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,IAAI,CAAC,MAAM,OACT,OAAO,oBAAC,QAAD,EAAA,UAAO,MAAM,KAAK,SAAS,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI,EAAQ,CAAA;CAG/E,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,MAAM,UAAU;GAC1B,MAAM,OAAO;GAEb,OAAO,oBAAC,OAAD;IAAmB,OAAO,WAAW,KAAK,OAAO,MAAM;IAAG,OAAO,KAAK;GAAQ,GAAlE,KAAkE;EACvF,CAAC;CACE,CAAA;AAET;AAEA,SAAS,gBAAgB,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAChG,MAAM,WAAY,MAAM,MAA0C;CAElE,OAAO,oBAAC,OAAD;EAAO,OAAO,WAAW,OAAO,MAAM;EAAG,OAAO,OAAO,IAAI,aAAa,EAAE;CAAI,CAAA;AACvF;AAEA,SAAS,cAAc,EAAE,QAAQ,OAAO,KAAK,SAAmD;CAC9F,MAAM,YAAa,OAAO,OAA+C;CACzE,MAAM,OAAO,YAAY,QAAQ,KAAK,KAAK;CAC3C,MAAM,OAAO,WAAW,OAAO,MAAM;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,MAAM,UAAU,OACd,oBAAC,KAAD;EACE,WAAU;EACJ;EACN,KAAK,MAAM,MAAM,WAAW,eAAe,KAAA;EAC3C,QAAQ,MAAM,MAAM,WAAW,WAAW,KAAA;YAEzC;CACA,CAAA,IAEH;CAGF,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,UAAU,OAAO,iBAAiB,UAAU,KAAK,GAAG,IAAI;EAE9D,aAAa,OAAO,aAAa,OAAO;CAC1C,GAAG,CAAC,MAAM,CAAC;CAEX,SAAS,aAAmB;EAC1B,gBAAqB,IAAI;EACzB,UAAU,IAAI;CAChB;CAEA,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,YAAY,UAAU,QAAQ,UAAU,KAAA,GACvE,OACE,oBAAC,UAAD;EAAiB;EAAO,WAAW,UAAU;EAAW,WAAW,UAAU;CAAY,CAAA;CAI7F,IAAI,CAAC,MAAM,UACT,OAAO;CAGT,OACE,qBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,oBAAC,QAAD,EAAA,UAAO,QAAc,CAAA,GACrB,qBAAC,UAAD;GACE,MAAK;GACL,aAAW,QAAQ,OAAO;GAC1B,WAAU;GACV,cAAY,GAAG,SAAS,WAAW,OAAO,GAAG,OAAO;GACpD,SAAS;aALX,CAOG,SACC,oBAAC,MAAD;IAAM,MAAK;IAAQ,WAAU;GAAmB,CAAA,IAEhD,oBAAC,MAAD;IAAM,MAAK;IAAO,WAAU;GAAmB,CAAA,GAEhD,SAAS,WAAW,MACf;IACJ;;AAEV"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
-
import { nodeIdentity } from "../../core/test-id.js";
|
|
3
2
|
import { Icon } from "../../icons/sprite.js";
|
|
4
3
|
import { useT } from "../../i18n/instance.js";
|
|
4
|
+
import { nodeIdentity } from "../../core/test-id.js";
|
|
5
5
|
import { useColumnResizing } from "../../core/use-column-resizing.js";
|
|
6
6
|
import { alignJustifyItems, alignText } from "../align.js";
|
|
7
7
|
import { getBulkActions } from "../bulk.js";
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { FilterData, Option } from '../types/generated';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a single scalar filter member is absent — the atomic rule the
|
|
4
|
+
* filter-emptiness and query-serialization logic both build on.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isEmptyMember(value: unknown): value is null | undefined | "";
|
|
2
7
|
/**
|
|
3
8
|
* Whether a table-filter value should clear the filter rather than apply it —
|
|
4
9
|
* an empty string, empty list, or an object whose every member is empty.
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
//#region resources/js/table/filter-values.ts
|
|
2
2
|
/**
|
|
3
|
+
* Whether a single scalar filter member is absent — the atomic rule the
|
|
4
|
+
* filter-emptiness and query-serialization logic both build on.
|
|
5
|
+
*/
|
|
6
|
+
function isEmptyMember(value) {
|
|
7
|
+
return value == null || value === "";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
3
10
|
* Whether a table-filter value should clear the filter rather than apply it —
|
|
4
11
|
* an empty string, empty list, or an object whose every member is empty.
|
|
5
12
|
*/
|
|
6
13
|
function isEmptyFilterValue(value) {
|
|
7
|
-
if (value
|
|
14
|
+
if (isEmptyMember(value)) return true;
|
|
8
15
|
if (Array.isArray(value)) return value.length === 0;
|
|
9
|
-
if (typeof value === "object") return Object.values(value).every(
|
|
16
|
+
if (typeof value === "object") return Object.values(value).every(isEmptyMember);
|
|
10
17
|
return false;
|
|
11
18
|
}
|
|
12
19
|
function isActiveFilterValue(value) {
|
|
@@ -25,6 +32,6 @@ function filterOptions(filter) {
|
|
|
25
32
|
return Array.isArray(value) ? value : [];
|
|
26
33
|
}
|
|
27
34
|
//#endregion
|
|
28
|
-
export { filterOptions, isActiveFilterValue, isEmptyFilterValue, stringProp };
|
|
35
|
+
export { filterOptions, isActiveFilterValue, isEmptyFilterValue, isEmptyMember, stringProp };
|
|
29
36
|
|
|
30
37
|
//# sourceMappingURL=filter-values.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-values.js","names":[],"sources":["../../resources/js/table/filter-values.ts"],"sourcesContent":["import type { FilterData, Option } from \"@lattice-php/lattice/types/generated\";\n\n/**\n * Whether a table-filter value should clear the filter rather than apply it —\n * an empty string, empty list, or an object whose every member is empty.\n */\nexport function isEmptyFilterValue(value: unknown): boolean {\n if (value
|
|
1
|
+
{"version":3,"file":"filter-values.js","names":[],"sources":["../../resources/js/table/filter-values.ts"],"sourcesContent":["import type { FilterData, Option } from \"@lattice-php/lattice/types/generated\";\n\n/**\n * Whether a single scalar filter member is absent — the atomic rule the\n * filter-emptiness and query-serialization logic both build on.\n */\nexport function isEmptyMember(value: unknown): value is null | undefined | \"\" {\n return value == null || value === \"\";\n}\n\n/**\n * Whether a table-filter value should clear the filter rather than apply it —\n * an empty string, empty list, or an object whose every member is empty.\n */\nexport function isEmptyFilterValue(value: unknown): boolean {\n if (isEmptyMember(value)) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n\n if (typeof value === \"object\") {\n return Object.values(value).every(isEmptyMember);\n }\n\n return false;\n}\n\nexport function isActiveFilterValue(value: unknown): boolean {\n return !isEmptyFilterValue(value);\n}\n\n/**\n * Read a string entry from a filter's loose `props` bag, falling back when the\n * key is absent or not a string.\n */\nexport function stringProp(filter: FilterData, key: string, fallback: string): string {\n const value = filter.props[key];\n\n return typeof value === \"string\" ? value : fallback;\n}\n\nexport function filterOptions(filter: FilterData): Option[] {\n const value = filter.props.options;\n\n return Array.isArray(value) ? (value as Option[]) : [];\n}\n"],"mappings":";;;;;AAMA,SAAgB,cAAc,OAAgD;CAC5E,OAAO,SAAS,QAAQ,UAAU;AACpC;;;;;AAMA,SAAgB,mBAAmB,OAAyB;CAC1D,IAAI,cAAc,KAAK,GACrB,OAAO;CAGT,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,WAAW;CAG1B,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,OAAO,KAAK,EAAE,MAAM,aAAa;CAGjD,OAAO;AACT;AAEA,SAAgB,oBAAoB,OAAyB;CAC3D,OAAO,CAAC,mBAAmB,KAAK;AAClC;;;;;AAMA,SAAgB,WAAW,QAAoB,KAAa,UAA0B;CACpF,MAAM,QAAQ,OAAO,MAAM;CAE3B,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAgB,cAAc,QAA8B;CAC1D,MAAM,QAAQ,OAAO,MAAM;CAE3B,OAAO,MAAM,QAAQ,KAAK,IAAK,QAAqB,CAAC;AACvD"}
|
package/dist/table/format.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
import { TableColumn, TableRow } from './types';
|
|
2
|
-
export
|
|
2
|
+
export type FormatOptions = {
|
|
3
|
+
locale?: string;
|
|
4
|
+
timeZone?: string;
|
|
5
|
+
};
|
|
6
|
+
export type DateConfig = {
|
|
7
|
+
dateStyle: string | null;
|
|
8
|
+
timeStyle: string | null;
|
|
9
|
+
};
|
|
10
|
+
export declare function formatCell(value: unknown, column?: TableColumn, options?: FormatOptions): string;
|
|
11
|
+
export declare function formatDateValue(value: unknown, date: DateConfig, options?: FormatOptions): string;
|
|
12
|
+
export declare function preciseDateTime(value: unknown, options?: FormatOptions): string;
|
|
3
13
|
export declare function resolveLink(column: TableColumn, row: TableRow, value: unknown): string | null;
|
package/dist/table/format.js
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
//#region resources/js/table/format.ts
|
|
2
|
-
function formatCell(value, column) {
|
|
2
|
+
function formatCell(value, column, options) {
|
|
3
3
|
if (value === null || value === void 0) return "";
|
|
4
4
|
const date = (column?.props)?.date;
|
|
5
|
-
if (date) return
|
|
5
|
+
if (date) return formatDateValue(value, date, options);
|
|
6
6
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
7
7
|
return JSON.stringify(value);
|
|
8
8
|
}
|
|
9
|
-
function
|
|
9
|
+
function formatDateValue(value, date, options) {
|
|
10
|
+
const parsed = new Date(String(value));
|
|
11
|
+
if (Number.isNaN(parsed.getTime())) return String(value ?? "");
|
|
12
|
+
const intl = { timeZone: options?.timeZone };
|
|
13
|
+
if (date.dateStyle) intl.dateStyle = date.dateStyle;
|
|
14
|
+
if (date.timeStyle) intl.timeStyle = date.timeStyle;
|
|
15
|
+
return new Intl.DateTimeFormat(options?.locale, intl).format(parsed);
|
|
16
|
+
}
|
|
17
|
+
function preciseDateTime(value, options) {
|
|
10
18
|
const date = new Date(String(value));
|
|
11
|
-
if (Number.isNaN(date.getTime())) return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
20
|
+
const formatted = new Intl.DateTimeFormat(options?.locale, {
|
|
21
|
+
year: "numeric",
|
|
22
|
+
month: "short",
|
|
23
|
+
day: "numeric",
|
|
24
|
+
hour: "2-digit",
|
|
25
|
+
minute: "2-digit",
|
|
26
|
+
second: "2-digit",
|
|
27
|
+
timeZone: options?.timeZone,
|
|
28
|
+
timeZoneName: "short"
|
|
15
29
|
}).format(date);
|
|
16
|
-
|
|
17
|
-
Y: String(date.getFullYear()),
|
|
18
|
-
y: String(date.getFullYear()).slice(-2),
|
|
19
|
-
m: String(date.getMonth() + 1).padStart(2, "0"),
|
|
20
|
-
n: String(date.getMonth() + 1),
|
|
21
|
-
d: String(date.getDate()).padStart(2, "0"),
|
|
22
|
-
j: String(date.getDate()),
|
|
23
|
-
H: String(date.getHours()).padStart(2, "0"),
|
|
24
|
-
G: String(date.getHours()),
|
|
25
|
-
i: String(date.getMinutes()).padStart(2, "0"),
|
|
26
|
-
s: String(date.getSeconds()).padStart(2, "0")
|
|
27
|
-
};
|
|
28
|
-
return format.replace(/[YymndjHGis]/g, (token) => replacements[token] ?? token);
|
|
30
|
+
return options?.timeZone ? `${formatted} (${options.timeZone})` : formatted;
|
|
29
31
|
}
|
|
30
32
|
function resolveLink(column, row, value) {
|
|
31
33
|
const link = column.props?.link;
|
|
@@ -38,6 +40,6 @@ function resolveLink(column, row, value) {
|
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
//#endregion
|
|
41
|
-
export { formatCell, resolveLink };
|
|
43
|
+
export { formatCell, formatDateValue, preciseDateTime, resolveLink };
|
|
42
44
|
|
|
43
45
|
//# sourceMappingURL=format.js.map
|
package/dist/table/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","names":[],"sources":["../../resources/js/table/format.ts"],"sourcesContent":["import type { ColumnPropsOf, TableColumn, TableRow } from \"./types\";\n\nexport function formatCell(value: unknown, column?: TableColumn): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n const date = (column?.props as ColumnPropsOf<\"column.text\"> | null)?.date;\n\n if (date) {\n return
|
|
1
|
+
{"version":3,"file":"format.js","names":[],"sources":["../../resources/js/table/format.ts"],"sourcesContent":["import type { ColumnPropsOf, TableColumn, TableRow } from \"./types\";\n\nexport type FormatOptions = {\n locale?: string;\n timeZone?: string;\n};\n\nexport type DateConfig = { dateStyle: string | null; timeStyle: string | null };\n\nexport function formatCell(value: unknown, column?: TableColumn, options?: FormatOptions): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n const date = (column?.props as ColumnPropsOf<\"column.text\"> | null)?.date;\n\n if (date) {\n return formatDateValue(value, date, options);\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n return JSON.stringify(value);\n}\n\nexport function formatDateValue(value: unknown, date: DateConfig, options?: FormatOptions): string {\n const parsed = new Date(String(value));\n\n if (Number.isNaN(parsed.getTime())) {\n return String(value ?? \"\");\n }\n\n const intl: Intl.DateTimeFormatOptions = { timeZone: options?.timeZone };\n\n if (date.dateStyle) {\n intl.dateStyle = date.dateStyle as Intl.DateTimeFormatOptions[\"dateStyle\"];\n }\n\n if (date.timeStyle) {\n intl.timeStyle = date.timeStyle as Intl.DateTimeFormatOptions[\"timeStyle\"];\n }\n\n return new Intl.DateTimeFormat(options?.locale, intl).format(parsed);\n}\n\nexport function preciseDateTime(value: unknown, options?: FormatOptions): string {\n const date = new Date(String(value));\n\n if (Number.isNaN(date.getTime())) {\n return \"\";\n }\n\n const formatted = new Intl.DateTimeFormat(options?.locale, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n timeZone: options?.timeZone,\n timeZoneName: \"short\",\n }).format(date);\n\n return options?.timeZone ? `${formatted} (${options.timeZone})` : formatted;\n}\n\nexport function resolveLink(column: TableColumn, row: TableRow, value: unknown): string | null {\n const link = (column.props as ColumnPropsOf<\"column.text\"> | null)?.link;\n\n if (!link) {\n return null;\n }\n\n const href = link.href ?? String(value ?? \"\");\n\n if (href === \"\") {\n return null;\n }\n\n return href.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n if (key === \"value\") {\n return encodeURIComponent(String(value ?? \"\"));\n }\n\n return encodeURIComponent(String(row[key] ?? \"\"));\n });\n}\n"],"mappings":";AASA,SAAgB,WAAW,OAAgB,QAAsB,SAAiC;CAChG,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,QAAQ,QAAQ,QAA+C;CAErE,IAAI,MACF,OAAO,gBAAgB,OAAO,MAAM,OAAO;CAG7C,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAC7E,OAAO,OAAO,KAAK;CAGrB,OAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAgB,gBAAgB,OAAgB,MAAkB,SAAiC;CACjG,MAAM,SAAS,IAAI,KAAK,OAAO,KAAK,CAAC;CAErC,IAAI,OAAO,MAAM,OAAO,QAAQ,CAAC,GAC/B,OAAO,OAAO,SAAS,EAAE;CAG3B,MAAM,OAAmC,EAAE,UAAU,SAAS,SAAS;CAEvE,IAAI,KAAK,WACP,KAAK,YAAY,KAAK;CAGxB,IAAI,KAAK,WACP,KAAK,YAAY,KAAK;CAGxB,OAAO,IAAI,KAAK,eAAe,SAAS,QAAQ,IAAI,EAAE,OAAO,MAAM;AACrE;AAEA,SAAgB,gBAAgB,OAAgB,SAAiC;CAC/E,MAAM,OAAO,IAAI,KAAK,OAAO,KAAK,CAAC;CAEnC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC7B,OAAO;CAGT,MAAM,YAAY,IAAI,KAAK,eAAe,SAAS,QAAQ;EACzD,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,UAAU,SAAS;EACnB,cAAc;CAChB,CAAC,EAAE,OAAO,IAAI;CAEd,OAAO,SAAS,WAAW,GAAG,UAAU,IAAI,QAAQ,SAAS,KAAK;AACpE;AAEA,SAAgB,YAAY,QAAqB,KAAe,OAA+B;CAC7F,MAAM,OAAQ,OAAO,OAA+C;CAEpE,IAAI,CAAC,MACH,OAAO;CAGT,MAAM,OAAO,KAAK,QAAQ,OAAO,SAAS,EAAE;CAE5C,IAAI,SAAS,IACX,OAAO;CAGT,OAAO,KAAK,QAAQ,iBAAiB,GAAG,QAAgB;EACtD,IAAI,QAAQ,SACV,OAAO,mBAAmB,OAAO,SAAS,EAAE,CAAC;EAG/C,OAAO,mBAAmB,OAAO,IAAI,QAAQ,EAAE,CAAC;CAClD,CAAC;AACH"}
|
package/dist/table/query.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { translate } from "../i18n/instance.js";
|
|
2
2
|
import "../core/column-sizing.js";
|
|
3
|
+
import { isEmptyMember } from "./filter-values.js";
|
|
3
4
|
//#region resources/js/table/query.ts
|
|
4
5
|
function getColumnSort(state, column) {
|
|
5
6
|
return state.sorts.find((currentSort) => currentSort.key === column.key);
|
|
@@ -30,7 +31,7 @@ function appendTableFilters(url, tableFilters) {
|
|
|
30
31
|
continue;
|
|
31
32
|
}
|
|
32
33
|
if (Array.isArray(value)) {
|
|
33
|
-
for (const item of value) if (item
|
|
34
|
+
for (const item of value) if (!isEmptyMember(item)) url.searchParams.append(`tf[${key}][]`, String(item));
|
|
34
35
|
continue;
|
|
35
36
|
}
|
|
36
37
|
if (typeof value === "object" && value !== null) for (const [subKey, subValue] of Object.entries(value)) url.searchParams.set(`tf[${key}][${subKey}]`, String(subValue));
|
|
@@ -45,14 +46,14 @@ function getTableFilterParams(tableFilters) {
|
|
|
45
46
|
return params;
|
|
46
47
|
}
|
|
47
48
|
function normalizeTableFilterValue(value) {
|
|
48
|
-
if (value
|
|
49
|
+
if (isEmptyMember(value)) return;
|
|
49
50
|
if (typeof value === "string") return value;
|
|
50
51
|
if (Array.isArray(value)) {
|
|
51
|
-
const items = value.filter((item) => item
|
|
52
|
+
const items = value.filter((item) => !isEmptyMember(item)).map(String);
|
|
52
53
|
return items.length > 0 ? items : void 0;
|
|
53
54
|
}
|
|
54
55
|
if (typeof value === "object") {
|
|
55
|
-
const entries = Object.entries(value).filter(([, subValue]) => subValue
|
|
56
|
+
const entries = Object.entries(value).filter(([, subValue]) => !isEmptyMember(subValue)).map(([subKey, subValue]) => [subKey, String(subValue)]);
|
|
56
57
|
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
57
58
|
}
|
|
58
59
|
return String(value);
|