@lattice-php/lattice 0.11.0 → 0.13.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/clipboard/copyable-text.d.ts +9 -0
- package/dist/clipboard/copyable-text.js +38 -0
- package/dist/clipboard/copyable-text.js.map +1 -0
- package/dist/clipboard/index.d.ts +1 -0
- package/dist/clipboard/index.js +2 -1
- package/dist/clipboard/index.js.map +1 -1
- package/dist/core/components/collapsible.d.ts +3 -0
- package/dist/core/components/collapsible.js +61 -0
- package/dist/core/components/collapsible.js.map +1 -0
- package/dist/core/components/index.js +2 -0
- package/dist/core/components/index.js.map +1 -1
- package/dist/core/components/modal.js +3 -0
- package/dist/core/components/modal.js.map +1 -1
- package/dist/core/components/text.js +8 -1
- package/dist/core/components/text.js.map +1 -1
- package/dist/core/use-column-resizing.js +1 -5
- package/dist/core/use-column-resizing.js.map +1 -1
- package/dist/core/use-column-visibility.d.ts +18 -0
- package/dist/core/use-column-visibility.js +91 -0
- package/dist/core/use-column-visibility.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/table/components/cells/text-cell.js +7 -30
- package/dist/table/components/cells/text-cell.js.map +1 -1
- package/dist/table/components/column-visibility-menu.d.ts +10 -0
- package/dist/table/components/column-visibility-menu.js +53 -0
- package/dist/table/components/column-visibility-menu.js.map +1 -0
- package/dist/table/components/table.js +35 -16
- package/dist/table/components/table.js.map +1 -1
- package/dist/types/generated.d.ts +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface CopyableTextProps {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
testId?: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function CopyableText({ value, label, testId, children }: CopyableTextProps): ReactNode;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Icon } from "../icons/sprite.js";
|
|
2
|
+
import { useT } from "../i18n/instance.js";
|
|
3
|
+
import { copyToClipboard } from "./index.js";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region resources/js/clipboard/copyable-text.tsx
|
|
7
|
+
function CopyableText({ value, label, testId, children }) {
|
|
8
|
+
const { t } = useT("lattice");
|
|
9
|
+
const [copied, setCopied] = useState(false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!copied) return;
|
|
12
|
+
const timeout = window.setTimeout(() => setCopied(false), 1500);
|
|
13
|
+
return () => window.clearTimeout(timeout);
|
|
14
|
+
}, [copied]);
|
|
15
|
+
function handleCopy() {
|
|
16
|
+
copyToClipboard(value);
|
|
17
|
+
setCopied(true);
|
|
18
|
+
}
|
|
19
|
+
const ariaLabel = copied ? t("common.copiedValue", "Copied {{label}}", { label }) : t("common.copyValue", "Copy {{label}}", { label });
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
21
|
+
className: "inline-flex items-center gap-2",
|
|
22
|
+
children: [children ?? value, /* @__PURE__ */ jsxs("button", {
|
|
23
|
+
type: "button",
|
|
24
|
+
"data-test": testId,
|
|
25
|
+
className: "inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs",
|
|
26
|
+
"aria-label": ariaLabel,
|
|
27
|
+
onClick: handleCopy,
|
|
28
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
29
|
+
name: copied ? "check" : "copy",
|
|
30
|
+
className: "size-lt-icon-xs"
|
|
31
|
+
}), copied ? t("common.copied", "Copied") : t("common.copy", "Copy")]
|
|
32
|
+
})]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { CopyableText };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=copyable-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyable-text.js","names":[],"sources":["../../resources/js/clipboard/copyable-text.tsx"],"sourcesContent":["import { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { type ReactNode, useEffect, useState } from \"react\";\nimport { copyToClipboard } from \"./index\";\n\ninterface CopyableTextProps {\n value: string;\n label: string;\n testId?: string;\n children?: ReactNode;\n}\n\nexport function CopyableText({ value, label, testId, children }: CopyableTextProps): ReactNode {\n const { t } = useT(\"lattice\");\n const [copied, setCopied] = useState(false);\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(value);\n setCopied(true);\n }\n\n const ariaLabel = copied\n ? t(\"common.copiedValue\", \"Copied {{label}}\", { label })\n : t(\"common.copyValue\", \"Copy {{label}}\", { label });\n\n return (\n <div className=\"inline-flex items-center gap-2\">\n {children ?? value}\n <button\n type=\"button\"\n data-test={testId}\n className=\"inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs\"\n aria-label={ariaLabel}\n onClick={handleCopy}\n >\n <Icon name={copied ? \"check\" : \"copy\"} className=\"size-lt-icon-xs\" />\n {copied ? t(\"common.copied\", \"Copied\") : t(\"common.copy\", \"Copy\")}\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;AAYA,SAAgB,aAAa,EAAE,OAAO,OAAO,QAAQ,YAA0C;CAC7F,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,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,KAAK;EAC1B,UAAU,IAAI;CAChB;CAEA,MAAM,YAAY,SACd,EAAE,sBAAsB,oBAAoB,EAAE,MAAM,CAAC,IACrD,EAAE,oBAAoB,kBAAkB,EAAE,MAAM,CAAC;CAErD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,YAAY,OACb,qBAAC,UAAD;GACE,MAAK;GACL,aAAW;GACX,WAAU;GACV,cAAY;GACZ,SAAS;aALX,CAOE,oBAAC,MAAD;IAAM,MAAM,SAAS,UAAU;IAAQ,WAAU;GAAmB,CAAA,GACnE,SAAS,EAAE,iBAAiB,QAAQ,IAAI,EAAE,eAAe,MAAM,CAC1D;IACL;;AAET"}
|
package/dist/clipboard/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CopyableText } from "./copyable-text.js";
|
|
1
2
|
import { useState } from "react";
|
|
2
3
|
//#region resources/js/clipboard/index.ts
|
|
3
4
|
async function copyToClipboard(text) {
|
|
@@ -19,6 +20,6 @@ function useClipboard() {
|
|
|
19
20
|
return [copiedText, copy];
|
|
20
21
|
}
|
|
21
22
|
//#endregion
|
|
22
|
-
export { copyToClipboard, useClipboard };
|
|
23
|
+
export { CopyableText, copyToClipboard, useClipboard };
|
|
23
24
|
|
|
24
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/clipboard/index.ts"],"sourcesContent":["import { useState } from \"react\";\n\nexport type CopiedValue = string | null;\nexport type CopyFn = (text: string) => Promise<boolean>;\nexport type UseClipboardReturn = [CopiedValue, CopyFn];\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function useClipboard(): UseClipboardReturn {\n const [copiedText, setCopiedText] = useState<CopiedValue>(null);\n\n const copy: CopyFn = async (text) => {\n const copied = await copyToClipboard(text);\n\n setCopiedText(copied ? text : null);\n\n return copied;\n };\n\n return [copiedText, copy];\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/clipboard/index.ts"],"sourcesContent":["import { useState } from \"react\";\n\nexport { CopyableText } from \"./copyable-text\";\n\nexport type CopiedValue = string | null;\nexport type CopyFn = (text: string) => Promise<boolean>;\nexport type UseClipboardReturn = [CopiedValue, CopyFn];\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function useClipboard(): UseClipboardReturn {\n const [copiedText, setCopiedText] = useState<CopiedValue>(null);\n\n const copy: CopyFn = async (text) => {\n const copied = await copyToClipboard(text);\n\n setCopiedText(copied ? text : null);\n\n return copied;\n };\n\n return [copiedText, copy];\n}\n"],"mappings":";;;AAQA,eAAsB,gBAAgB,MAAgC;CACpE,IAAI,CAAC,WAAW,WACd,OAAO;CAGT,IAAI;EACF,MAAM,UAAU,UAAU,UAAU,IAAI;EAExC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,eAAmC;CACjD,MAAM,CAAC,YAAY,iBAAiB,SAAsB,IAAI;CAE9D,MAAM,OAAe,OAAO,SAAS;EACnC,MAAM,SAAS,MAAM,gBAAgB,IAAI;EAEzC,cAAc,SAAS,OAAO,IAAI;EAElC,OAAO;CACT;CAEA,OAAO,CAAC,YAAY,IAAI;AAC1B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { Icon } from "../../icons/sprite.js";
|
|
3
|
+
import { Renderer } from "../renderer.js";
|
|
4
|
+
import { nodeIdentity, prefixedTestId } from "../test-id.js";
|
|
5
|
+
import { toNodes } from "../nodes.js";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region resources/js/core/components/collapsible.tsx
|
|
9
|
+
function readStored(key, remember, fallback) {
|
|
10
|
+
if (!remember || typeof window === "undefined") return fallback;
|
|
11
|
+
const stored = window.localStorage.getItem(key);
|
|
12
|
+
return stored === null ? fallback : stored === "true";
|
|
13
|
+
}
|
|
14
|
+
var CollapsibleComponent = ({ children, node }) => {
|
|
15
|
+
const rememberState = node.props.rememberState === true;
|
|
16
|
+
const trigger = toNodes(node.props.trigger);
|
|
17
|
+
const identity = nodeIdentity(node);
|
|
18
|
+
const storageKey = `lattice:collapsible:${identity ?? "default"}`;
|
|
19
|
+
const contentId = `${identity ?? "collapsible"}-content`;
|
|
20
|
+
const [open, setOpen] = useState(() => readStored(storageKey, rememberState, node.props.collapsed === false));
|
|
21
|
+
function toggle() {
|
|
22
|
+
setOpen((value) => {
|
|
23
|
+
const next = !value;
|
|
24
|
+
if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
|
|
25
|
+
return next;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
29
|
+
"data-lattice-component": identity,
|
|
30
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
31
|
+
"aria-controls": contentId,
|
|
32
|
+
"aria-expanded": open,
|
|
33
|
+
"data-test": prefixedTestId("collapsible-toggle", identity) ?? "collapsible-toggle-default",
|
|
34
|
+
className: "flex w-full cursor-pointer items-center justify-between gap-4 rounded-lt-sm py-2 text-left text-lt-fg transition-colors hover:bg-lt-muted",
|
|
35
|
+
onClick: toggle,
|
|
36
|
+
onKeyDown: (event) => {
|
|
37
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
toggle();
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
role: "button",
|
|
43
|
+
tabIndex: 0,
|
|
44
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
45
|
+
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
46
|
+
children: /* @__PURE__ */ jsx(Renderer, { nodes: trigger })
|
|
47
|
+
}), /* @__PURE__ */ jsx(Icon, {
|
|
48
|
+
name: "chevron-down",
|
|
49
|
+
className: cn("size-lt-icon-md shrink-0 text-lt-muted-fg transition-transform", !open && "-rotate-90")
|
|
50
|
+
})]
|
|
51
|
+
}), open && children && /* @__PURE__ */ jsx("div", {
|
|
52
|
+
id: contentId,
|
|
53
|
+
className: "flex flex-col gap-4 pt-2",
|
|
54
|
+
children
|
|
55
|
+
})]
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
export { CollapsibleComponent as default };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=collapsible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collapsible.js","names":[],"sources":["../../../resources/js/core/components/collapsible.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport { nodeIdentity, prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { toNodes } from \"@lattice-php/lattice/core/nodes\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nfunction readStored(key: string, remember: boolean, fallback: boolean): boolean {\n if (!remember || typeof window === \"undefined\") {\n return fallback;\n }\n\n const stored = window.localStorage.getItem(key);\n\n return stored === null ? fallback : stored === \"true\";\n}\n\nconst CollapsibleComponent: RendererComponent<\"collapsible\"> = ({ children, node }) => {\n const rememberState = node.props.rememberState === true;\n const trigger = toNodes(node.props.trigger);\n const identity = nodeIdentity(node);\n const storageKey = `lattice:collapsible:${identity ?? \"default\"}`;\n const contentId = `${identity ?? \"collapsible\"}-content`;\n\n const [open, setOpen] = useState(() =>\n readStored(storageKey, rememberState, node.props.collapsed === false),\n );\n\n function toggle(): void {\n setOpen((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 }\n\n return (\n <div data-lattice-component={identity}>\n <div\n aria-controls={contentId}\n aria-expanded={open}\n data-test={prefixedTestId(\"collapsible-toggle\", identity) ?? \"collapsible-toggle-default\"}\n className=\"flex w-full cursor-pointer items-center justify-between gap-4 rounded-lt-sm py-2 text-left text-lt-fg transition-colors hover:bg-lt-muted\"\n onClick={toggle}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n toggle();\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Renderer nodes={trigger} />\n </div>\n <Icon\n name=\"chevron-down\"\n className={cn(\n \"size-lt-icon-md shrink-0 text-lt-muted-fg transition-transform\",\n !open && \"-rotate-90\",\n )}\n />\n </div>\n\n {open && children && (\n <div id={contentId} className=\"flex flex-col gap-4 pt-2\">\n {children}\n </div>\n )}\n </div>\n );\n};\n\nexport default CollapsibleComponent;\n"],"mappings":";;;;;;;;AAQA,SAAS,WAAW,KAAa,UAAmB,UAA4B;CAC9E,IAAI,CAAC,YAAY,OAAO,WAAW,aACjC,OAAO;CAGT,MAAM,SAAS,OAAO,aAAa,QAAQ,GAAG;CAE9C,OAAO,WAAW,OAAO,WAAW,WAAW;AACjD;AAEA,IAAM,wBAA0D,EAAE,UAAU,WAAW;CACrF,MAAM,gBAAgB,KAAK,MAAM,kBAAkB;CACnD,MAAM,UAAU,QAAQ,KAAK,MAAM,OAAO;CAC1C,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,uBAAuB,YAAY;CACtD,MAAM,YAAY,GAAG,YAAY,cAAc;CAE/C,MAAM,CAAC,MAAM,WAAW,eACtB,WAAW,YAAY,eAAe,KAAK,MAAM,cAAc,KAAK,CACtE;CAEA,SAAS,SAAe;EACtB,SAAS,UAAU;GACjB,MAAM,OAAO,CAAC;GAEd,IAAI,iBAAiB,OAAO,WAAW,aACrC,OAAO,aAAa,QAAQ,YAAY,OAAO,IAAI,CAAC;GAGtD,OAAO;EACT,CAAC;CACH;CAEA,OACE,qBAAC,OAAD;EAAK,0BAAwB;YAA7B,CACE,qBAAC,OAAD;GACE,iBAAe;GACf,iBAAe;GACf,aAAW,eAAe,sBAAsB,QAAQ,KAAK;GAC7D,WAAU;GACV,SAAS;GACT,YAAY,UAAU;IACpB,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAC9C,MAAM,eAAe;KACrB,OAAO;IACT;GACF;GACA,MAAK;GACL,UAAU;aAbZ,CAeE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,UAAD,EAAU,OAAO,QAAU,CAAA;GACxB,CAAA,GACL,oBAAC,MAAD;IACE,MAAK;IACL,WAAW,GACT,kEACA,CAAC,QAAQ,YACX;GACD,CAAA,CACE;MAEJ,QAAQ,YACP,oBAAC,OAAD;GAAK,IAAI;GAAW,WAAU;GAC3B;EACE,CAAA,CAEJ;;AAET"}
|
|
@@ -2,6 +2,7 @@ import { createPlugin, eagerComponent, lazyComponent } from "../registry.js";
|
|
|
2
2
|
import ButtonComponent from "./button.js";
|
|
3
3
|
import BadgeComponent from "./badge.js";
|
|
4
4
|
import CardComponent from "./card.js";
|
|
5
|
+
import CollapsibleComponent from "./collapsible.js";
|
|
5
6
|
import FloatingPanelComponent from "./floating-panel.js";
|
|
6
7
|
import FragmentComponent from "./fragment.js";
|
|
7
8
|
import GridComponent from "./grid.js";
|
|
@@ -22,6 +23,7 @@ var coreComponents = createPlugin({
|
|
|
22
23
|
button: eagerComponent(ButtonComponent),
|
|
23
24
|
card: eagerComponent(CardComponent),
|
|
24
25
|
chart: lazyComponent(() => import("./chart.js")),
|
|
26
|
+
collapsible: eagerComponent(CollapsibleComponent),
|
|
25
27
|
"floating-panel": eagerComponent(FloatingPanelComponent),
|
|
26
28
|
fragment: eagerComponent(FragmentComponent),
|
|
27
29
|
grid: eagerComponent(GridComponent),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../resources/js/core/components/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent, lazyComponent } from \"@lattice-php/lattice/core/registry\";\nimport type { RendererComponentModule } from \"@lattice-php/lattice/core/types\";\nimport BadgeComponent from \"./badge\";\nimport ButtonComponent from \"./button\";\nimport CardComponent from \"./card\";\nimport FloatingPanelComponent from \"./floating-panel\";\nimport FragmentComponent from \"./fragment\";\nimport GridComponent from \"./grid\";\nimport HeadingComponent from \"./heading\";\nimport IconComponent from \"./icon\";\nimport LinkComponent from \"./link\";\nimport ModalComponent from \"./modal\";\nimport RawBlockComponent from \"./raw-block\";\nimport SectionComponent from \"./section\";\nimport SegmentedControlComponent from \"./segmented-control\";\nimport StackComponent from \"./stack\";\nimport TabComponent, { TabsComponent } from \"./tabs\";\nimport TextComponent from \"./text\";\n\nexport const coreComponents = createPlugin({\n components: {\n badge: eagerComponent(BadgeComponent),\n button: eagerComponent(ButtonComponent),\n card: eagerComponent(CardComponent),\n chart: lazyComponent(\n () => import(\"./chart\") as unknown as Promise<RendererComponentModule<\"chart\">>,\n ),\n \"floating-panel\": eagerComponent(FloatingPanelComponent),\n fragment: eagerComponent(FragmentComponent),\n grid: eagerComponent(GridComponent),\n heading: eagerComponent(HeadingComponent),\n icon: eagerComponent(IconComponent),\n link: eagerComponent(LinkComponent),\n modal: eagerComponent(ModalComponent),\n \"raw-block\": eagerComponent(RawBlockComponent),\n section: eagerComponent(SectionComponent),\n \"segmented-control\": eagerComponent(SegmentedControlComponent),\n stack: eagerComponent(StackComponent),\n tab: eagerComponent(TabComponent),\n tabs: eagerComponent(TabsComponent),\n text: eagerComponent(TextComponent),\n },\n name: \"lattice/core\",\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../resources/js/core/components/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent, lazyComponent } from \"@lattice-php/lattice/core/registry\";\nimport type { RendererComponentModule } from \"@lattice-php/lattice/core/types\";\nimport BadgeComponent from \"./badge\";\nimport ButtonComponent from \"./button\";\nimport CardComponent from \"./card\";\nimport CollapsibleComponent from \"./collapsible\";\nimport FloatingPanelComponent from \"./floating-panel\";\nimport FragmentComponent from \"./fragment\";\nimport GridComponent from \"./grid\";\nimport HeadingComponent from \"./heading\";\nimport IconComponent from \"./icon\";\nimport LinkComponent from \"./link\";\nimport ModalComponent from \"./modal\";\nimport RawBlockComponent from \"./raw-block\";\nimport SectionComponent from \"./section\";\nimport SegmentedControlComponent from \"./segmented-control\";\nimport StackComponent from \"./stack\";\nimport TabComponent, { TabsComponent } from \"./tabs\";\nimport TextComponent from \"./text\";\n\nexport const coreComponents = createPlugin({\n components: {\n badge: eagerComponent(BadgeComponent),\n button: eagerComponent(ButtonComponent),\n card: eagerComponent(CardComponent),\n chart: lazyComponent(\n () => import(\"./chart\") as unknown as Promise<RendererComponentModule<\"chart\">>,\n ),\n collapsible: eagerComponent(CollapsibleComponent),\n \"floating-panel\": eagerComponent(FloatingPanelComponent),\n fragment: eagerComponent(FragmentComponent),\n grid: eagerComponent(GridComponent),\n heading: eagerComponent(HeadingComponent),\n icon: eagerComponent(IconComponent),\n link: eagerComponent(LinkComponent),\n modal: eagerComponent(ModalComponent),\n \"raw-block\": eagerComponent(RawBlockComponent),\n section: eagerComponent(SectionComponent),\n \"segmented-control\": eagerComponent(SegmentedControlComponent),\n stack: eagerComponent(StackComponent),\n tab: eagerComponent(TabComponent),\n tabs: eagerComponent(TabsComponent),\n text: eagerComponent(TextComponent),\n },\n name: \"lattice/core\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,IAAa,iBAAiB,aAAa;CACzC,YAAY;EACV,OAAO,eAAe,cAAc;EACpC,QAAQ,eAAe,eAAe;EACtC,MAAM,eAAe,aAAa;EAClC,OAAO,oBACC,OAAO,aACf;EACA,aAAa,eAAe,oBAAoB;EAChD,kBAAkB,eAAe,sBAAsB;EACvD,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,SAAS,eAAe,gBAAgB;EACxC,MAAM,eAAe,aAAa;EAClC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,aAAa,eAAe,iBAAiB;EAC7C,SAAS,eAAe,gBAAgB;EACxC,qBAAqB,eAAe,yBAAyB;EAC7D,OAAO,eAAe,cAAc;EACpC,KAAK,eAAe,YAAY;EAChC,MAAM,eAAe,aAAa;EAClC,MAAM,eAAe,aAAa;CACpC;CACA,MAAM;AACR,CAAC"}
|
|
@@ -12,6 +12,9 @@ var ModalComponent = ({ children, node }) => {
|
|
|
12
12
|
const description = node.props.description;
|
|
13
13
|
const closeLabel = node.props.closeLabel;
|
|
14
14
|
const [isOpen, setIsOpen] = useState(node.props.open === true);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (node.props.open === true) setIsOpen(true);
|
|
17
|
+
}, [node.props.open]);
|
|
15
18
|
useEffect(() => {
|
|
16
19
|
function open(event) {
|
|
17
20
|
if (node.id && matchesModal(event, node.id)) setIsOpen(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.js","names":[],"sources":["../../../resources/js/core/components/modal.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/core/components/dialog\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\n\ntype ModalEvent = CustomEvent<{\n modal: string | null;\n}>;\n\nfunction matchesModal(event: Event, modal: string): boolean {\n const target = (event as ModalEvent).detail?.modal;\n\n return target == null || target === modal;\n}\n\nconst ModalComponent: RendererComponent<\"modal\"> = ({ children, node }) => {\n const title = node.props.title ?? \"Dialog\";\n const description = node.props.description;\n const closeLabel = node.props.closeLabel;\n const [isOpen, setIsOpen] = useState(node.props.open === true);\n\n useEffect(() => {\n function open(event: Event): void {\n if (node.id && matchesModal(event, node.id)) {\n setIsOpen(true);\n }\n }\n\n function close(event: Event): void {\n if (!node.id || matchesModal(event, node.id)) {\n setIsOpen(false);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.openModal, open);\n window.addEventListener(LATTICE_EVENT.closeModal, close);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.openModal, open);\n window.removeEventListener(LATTICE_EVENT.closeModal, close);\n };\n }, [node.id]);\n\n return (\n <Dialog open={isOpen} onOpenChange={setIsOpen}>\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n className=\"max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg overflow-y-auto\"\n >\n <DialogHeader closeLabel={closeLabel} description={description} title={title} />\n <div className=\"mt-6 space-y-6\">{children}</div>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default ModalComponent;\n"],"mappings":";;;;;AASA,SAAS,aAAa,OAAc,OAAwB;CAC1D,MAAM,SAAU,MAAqB,QAAQ;CAE7C,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,kBAA8C,EAAE,UAAU,WAAW;CACzE,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK,MAAM,SAAS,IAAI;
|
|
1
|
+
{"version":3,"file":"modal.js","names":[],"sources":["../../../resources/js/core/components/modal.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/core/components/dialog\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/events/event-names\";\n\ntype ModalEvent = CustomEvent<{\n modal: string | null;\n}>;\n\nfunction matchesModal(event: Event, modal: string): boolean {\n const target = (event as ModalEvent).detail?.modal;\n\n return target == null || target === modal;\n}\n\nconst ModalComponent: RendererComponent<\"modal\"> = ({ children, node }) => {\n const title = node.props.title ?? \"Dialog\";\n const description = node.props.description;\n const closeLabel = node.props.closeLabel;\n const [isOpen, setIsOpen] = useState(node.props.open === true);\n\n // Honour server-driven open changes across re-renders, not just on mount. One\n // way on purpose: closing stays user/closeModal-driven so it never fights a\n // manual close, and the dep keeps it from re-firing while open stays true.\n useEffect(() => {\n if (node.props.open === true) {\n setIsOpen(true);\n }\n }, [node.props.open]);\n\n useEffect(() => {\n function open(event: Event): void {\n if (node.id && matchesModal(event, node.id)) {\n setIsOpen(true);\n }\n }\n\n function close(event: Event): void {\n if (!node.id || matchesModal(event, node.id)) {\n setIsOpen(false);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.openModal, open);\n window.addEventListener(LATTICE_EVENT.closeModal, close);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.openModal, open);\n window.removeEventListener(LATTICE_EVENT.closeModal, close);\n };\n }, [node.id]);\n\n return (\n <Dialog open={isOpen} onOpenChange={setIsOpen}>\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n className=\"max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg overflow-y-auto\"\n >\n <DialogHeader closeLabel={closeLabel} description={description} title={title} />\n <div className=\"mt-6 space-y-6\">{children}</div>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default ModalComponent;\n"],"mappings":";;;;;AASA,SAAS,aAAa,OAAc,OAAwB;CAC1D,MAAM,SAAU,MAAqB,QAAQ;CAE7C,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,kBAA8C,EAAE,UAAU,WAAW;CACzE,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK,MAAM,SAAS,IAAI;CAK7D,gBAAgB;EACd,IAAI,KAAK,MAAM,SAAS,MACtB,UAAU,IAAI;CAElB,GAAG,CAAC,KAAK,MAAM,IAAI,CAAC;CAEpB,gBAAgB;EACd,SAAS,KAAK,OAAoB;GAChC,IAAI,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GACxC,UAAU,IAAI;EAElB;EAEA,SAAS,MAAM,OAAoB;GACjC,IAAI,CAAC,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GACzC,UAAU,KAAK;EAEnB;EAEA,OAAO,iBAAiB,cAAc,WAAW,IAAI;EACrD,OAAO,iBAAiB,cAAc,YAAY,KAAK;EAEvD,aAAa;GACX,OAAO,oBAAoB,cAAc,WAAW,IAAI;GACxD,OAAO,oBAAoB,cAAc,YAAY,KAAK;EAC5D;CACF,GAAG,CAAC,KAAK,EAAE,CAAC;CAEZ,OACE,oBAAC,QAAD;EAAQ,MAAM;EAAQ,cAAc;YAClC,qBAAC,eAAD;GACE,GAAK,cAAc,CAAC,IAAI,EAAE,oBAAoB,KAAA,EAAU;GACxD,WAAU;aAFZ,CAIE,oBAAC,cAAD;IAA0B;IAAyB;IAAoB;GAAQ,CAAA,GAC/E,oBAAC,OAAD;IAAK,WAAU;IAAkB;GAAc,CAAA,CAClC;;CACT,CAAA;AAEZ"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { CopyableText } from "../../clipboard/copyable-text.js";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
//#region resources/js/core/components/text.tsx
|
|
4
5
|
var textAlignments = {
|
|
@@ -25,10 +26,16 @@ var textSizes = {
|
|
|
25
26
|
"4xl": "text-4xl leading-none"
|
|
26
27
|
};
|
|
27
28
|
var TextComponent = ({ node }) => {
|
|
28
|
-
|
|
29
|
+
const text = /* @__PURE__ */ jsx("p", {
|
|
29
30
|
className: cn("m-0", "max-w-2xl", textAlignments[node.props.align ?? "left"] ?? textAlignments.left, textColors[node.props.color], textSizes[node.props.size]),
|
|
30
31
|
children: node.props.text
|
|
31
32
|
});
|
|
33
|
+
if (!node.props.copyable) return text;
|
|
34
|
+
return /* @__PURE__ */ jsx(CopyableText, {
|
|
35
|
+
value: node.props.text,
|
|
36
|
+
label: node.props.text,
|
|
37
|
+
children: text
|
|
38
|
+
});
|
|
32
39
|
};
|
|
33
40
|
//#endregion
|
|
34
41
|
export { TextComponent as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","names":[],"sources":["../../../resources/js/core/components/text.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { Color, Size } from \"@lattice-php/lattice/types/generated\";\n\nconst textAlignments: Record<string, string> = {\n center: \"text-center\",\n left: \"text-left\",\n};\n\nconst textColors: Record<Color, string> = {\n default: \"text-lt-fg\",\n muted: \"text-lt-muted-fg\",\n primary: \"text-lt-primary\",\n success: \"text-lt-success\",\n info: \"text-lt-info\",\n warning: \"text-lt-warning\",\n danger: \"text-lt-danger\",\n};\n\nconst textSizes: Record<Size, string> = {\n xs: \"text-xs leading-5\",\n sm: \"text-sm leading-6\",\n md: \"text-base leading-7\",\n lg: \"text-lg leading-8\",\n xl: \"text-xl leading-8\",\n \"2xl\": \"text-2xl leading-9\",\n \"3xl\": \"text-3xl leading-10\",\n \"4xl\": \"text-4xl leading-none\",\n};\n\nconst TextComponent: RendererComponent<\"text\"> = ({ node }) => {\n const align = node.props.align ?? \"left\";\n\n
|
|
1
|
+
{"version":3,"file":"text.js","names":[],"sources":["../../../resources/js/core/components/text.tsx"],"sourcesContent":["import { CopyableText } from \"@lattice-php/lattice/clipboard\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { Color, Size } from \"@lattice-php/lattice/types/generated\";\n\nconst textAlignments: Record<string, string> = {\n center: \"text-center\",\n left: \"text-left\",\n};\n\nconst textColors: Record<Color, string> = {\n default: \"text-lt-fg\",\n muted: \"text-lt-muted-fg\",\n primary: \"text-lt-primary\",\n success: \"text-lt-success\",\n info: \"text-lt-info\",\n warning: \"text-lt-warning\",\n danger: \"text-lt-danger\",\n};\n\nconst textSizes: Record<Size, string> = {\n xs: \"text-xs leading-5\",\n sm: \"text-sm leading-6\",\n md: \"text-base leading-7\",\n lg: \"text-lg leading-8\",\n xl: \"text-xl leading-8\",\n \"2xl\": \"text-2xl leading-9\",\n \"3xl\": \"text-3xl leading-10\",\n \"4xl\": \"text-4xl leading-none\",\n};\n\nconst TextComponent: RendererComponent<\"text\"> = ({ node }) => {\n const align = node.props.align ?? \"left\";\n\n const text = (\n <p\n className={cn(\n \"m-0\",\n \"max-w-2xl\",\n textAlignments[align] ?? textAlignments.left,\n textColors[node.props.color],\n textSizes[node.props.size],\n )}\n >\n {node.props.text}\n </p>\n );\n\n if (!node.props.copyable) {\n return text;\n }\n\n return (\n <CopyableText value={node.props.text} label={node.props.text}>\n {text}\n </CopyableText>\n );\n};\n\nexport default TextComponent;\n"],"mappings":";;;;AAKA,IAAM,iBAAyC;CAC7C,QAAQ;CACR,MAAM;AACR;AAEA,IAAM,aAAoC;CACxC,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;CACT,MAAM;CACN,SAAS;CACT,QAAQ;AACV;AAEA,IAAM,YAAkC;CACtC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;AACT;AAEA,IAAM,iBAA4C,EAAE,WAAW;CAG7D,MAAM,OACJ,oBAAC,KAAD;EACE,WAAW,GACT,OACA,aACA,eAPQ,KAAK,MAAM,SAAS,WAOH,eAAe,MACxC,WAAW,KAAK,MAAM,QACtB,UAAU,KAAK,MAAM,KACvB;YAEC,KAAK,MAAM;CACX,CAAA;CAGL,IAAI,CAAC,KAAK,MAAM,UACd,OAAO;CAGT,OACE,oBAAC,cAAD;EAAc,OAAO,KAAK,MAAM;EAAM,OAAO,KAAK,MAAM;YACrD;CACW,CAAA;AAElB"}
|
|
@@ -153,8 +153,7 @@ function readStoredOverrides(storageKey, columns) {
|
|
|
153
153
|
const raw = window.localStorage.getItem(storageKey);
|
|
154
154
|
if (raw === null) return {};
|
|
155
155
|
const stored = JSON.parse(raw);
|
|
156
|
-
|
|
157
|
-
if (!isStoredColumnWidths(stored) || !sameColumnKeys(stored.columns, columnKeys)) {
|
|
156
|
+
if (!isStoredColumnWidths(stored)) {
|
|
158
157
|
removeStoredOverrides(storageKey);
|
|
159
158
|
return {};
|
|
160
159
|
}
|
|
@@ -197,9 +196,6 @@ function isStoredColumnWidths(value) {
|
|
|
197
196
|
const record = value;
|
|
198
197
|
return Array.isArray(record.columns) && record.columns.every((column) => typeof column === "string") && typeof record.overrides === "object" && record.overrides !== null && !Array.isArray(record.overrides);
|
|
199
198
|
}
|
|
200
|
-
function sameColumnKeys(stored, current) {
|
|
201
|
-
return stored.length === current.length && stored.every((key, index) => key === current[index]);
|
|
202
|
-
}
|
|
203
199
|
function sanitizeOverrides(overrides, columns) {
|
|
204
200
|
const next = {};
|
|
205
201
|
for (const column of columns) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-column-resizing.js","names":[],"sources":["../../resources/js/core/use-column-resizing.ts"],"sourcesContent":["import type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n buildColumnGridTemplate,\n defaultColumnWidthPx,\n maxColumnWidthPx,\n minColumnWidthPx,\n type SizableColumn,\n} from \"./column-sizing\";\n\ntype DragState = {\n key: string;\n maxWidth: number;\n startWidth: number;\n startX: number;\n};\n\ntype ResizeHandleProps = HTMLAttributes<HTMLDivElement> & {\n \"aria-label\": string;\n \"aria-orientation\": \"vertical\";\n \"aria-valuemax\": number;\n \"aria-valuemin\": number;\n \"aria-valuenow\": number;\n role: \"separator\";\n tabIndex: number;\n};\n\ntype StoredColumnWidths = {\n columns: string[];\n overrides: Record<string, number>;\n};\n\nconst emptyTracks: string[] = [];\n\nexport function useColumnResizing({\n columnGapPx = 0,\n columns,\n enabled,\n leadingTracks = emptyTracks,\n showIndicator = false,\n storageKey,\n trailingTracks = emptyTracks,\n}: {\n columnGapPx?: number;\n columns: SizableColumn[];\n enabled: boolean;\n leadingTracks?: string[];\n showIndicator?: boolean;\n storageKey?: string;\n trailingTracks?: string[];\n}) {\n const columnKeys = useMemo(() => columns.map((column) => column.key), [columns]);\n const [overrides, setOverrides] = useState<Record<string, number | undefined>>(() =>\n readStoredOverrides(storageKey, columns),\n );\n const overridesRef = useRef(overrides);\n const drag = useRef<DragState | null>(null);\n\n const gridTemplateColumns = useMemo(\n () =>\n buildColumnGridTemplate({\n columns,\n leadingTracks,\n trailingTracks,\n overrides: enabled ? overrides : {},\n }),\n [columns, enabled, leadingTracks, overrides, trailingTracks],\n );\n\n const setColumnWidth = useCallback(\n (column: SizableColumn, width: number, maxWidth?: number) => {\n setOverrides((current) => {\n const next = {\n ...current,\n [column.key]: Math.min(\n maxWidth ?? maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), width),\n ),\n };\n\n overridesRef.current = next;\n writeStoredOverrides(storageKey, columnKeys, next);\n\n return next;\n });\n },\n [columnKeys, storageKey],\n );\n\n const resetColumnWidth = useCallback(\n (column: SizableColumn) => {\n setOverrides((current) => {\n const next = { ...current };\n delete next[column.key];\n\n overridesRef.current = next;\n writeStoredOverrides(storageKey, columnKeys, next);\n\n return next;\n });\n },\n [columnKeys, storageKey],\n );\n\n const resetColumns = useCallback(() => {\n setOverrides({});\n overridesRef.current = {};\n writeStoredOverrides(storageKey, columnKeys, {});\n }, [columnKeys, storageKey]);\n\n const hasOverrides =\n enabled && Object.values(overrides).some((width) => typeof width === \"number\");\n\n const currentColumnWidth = useCallback(\n (column: SizableColumn): number =>\n overridesRef.current[column.key] ?? defaultColumnWidthPx(column),\n [],\n );\n\n const getResizeHandleProps = useCallback(\n (column: SizableColumn): ResizeHandleProps => {\n const max = maxColumnWidthPx(column);\n const min = minColumnWidthPx(column);\n const current = currentColumnWidth(column);\n const label = column.label ?? column.key;\n const indicatorClass = showIndicator ? \"after:bg-lt-border\" : \"after:bg-transparent\";\n\n const maxWidthForHandle = (handle: HTMLDivElement): number =>\n maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid: handle.parentElement?.parentElement,\n leadingTracks,\n trailingTracks,\n });\n\n const resizeBy = (handle: HTMLDivElement, delta: number): void =>\n setColumnWidth(column, current + delta, maxWidthForHandle(handle));\n\n return {\n \"aria-label\": `Resize ${label}`,\n \"aria-orientation\": \"vertical\",\n \"aria-valuemax\": max,\n \"aria-valuemin\": min,\n \"aria-valuenow\": current,\n className: `absolute inset-y-0 right-0 hidden w-2 cursor-col-resize touch-none items-stretch justify-center md:flex after:my-1 after:w-px ${indicatorClass} hover:after:bg-lt-border focus-visible:outline-none focus-visible:after:bg-lt-ring`,\n onDoubleClick: () => resetColumnWidth(column),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const step = event.shiftKey ? 32 : 8;\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n resizeBy(event.currentTarget, -step);\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n resizeBy(event.currentTarget, step);\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n setColumnWidth(column, min);\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n const handleMax = maxWidthForHandle(event.currentTarget);\n setColumnWidth(column, handleMax, handleMax);\n }\n\n if (event.key === \"Enter\" || event.key === \"Escape\") {\n event.preventDefault();\n resetColumnWidth(column);\n }\n },\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const parentWidth = event.currentTarget.parentElement?.getBoundingClientRect().width ?? 0;\n drag.current = {\n key: column.key,\n maxWidth: maxWidthForHandle(event.currentTarget),\n startWidth: parentWidth > 0 ? parentWidth : current,\n startX: event.clientX,\n };\n event.currentTarget.setPointerCapture?.(event.pointerId);\n event.preventDefault();\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (!enabled || active?.key !== column.key) {\n return;\n }\n\n setColumnWidth(\n column,\n active.startWidth + event.clientX - active.startX,\n active.maxWidth,\n );\n },\n onPointerUp: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (active?.key !== column.key) {\n return;\n }\n\n drag.current = null;\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n },\n role: \"separator\",\n tabIndex: 0,\n };\n },\n [\n columnGapPx,\n columns,\n currentColumnWidth,\n enabled,\n leadingTracks,\n resetColumnWidth,\n setColumnWidth,\n showIndicator,\n trailingTracks,\n ],\n );\n\n return {\n getResizeHandleProps,\n gridTemplateColumns,\n hasOverrides,\n resetColumns,\n resetColumnWidth,\n };\n}\n\nfunction maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid,\n leadingTracks,\n trailingTracks,\n}: {\n column: SizableColumn;\n columnGapPx: number;\n columns: SizableColumn[];\n grid: Element | null | undefined;\n leadingTracks: string[];\n trailingTracks: string[];\n}): number {\n const gridWidth = grid?.getBoundingClientRect().width ?? 0;\n\n if (gridWidth <= 0) {\n return maxColumnWidthPx(column);\n }\n\n const utilityWidth = [...leadingTracks, ...trailingTracks].reduce(\n (sum, track) => sum + fixedTrackWidthPx(track),\n 0,\n );\n const siblingMinWidth = columns.reduce(\n (sum, sibling) => (sibling.key === column.key ? sum : sum + minColumnWidthPx(sibling)),\n 0,\n );\n const trackCount = columns.length + leadingTracks.length + trailingTracks.length;\n const gapWidth = Math.max(0, trackCount - 1) * columnGapPx;\n const available = gridWidth - utilityWidth - siblingMinWidth - gapWidth;\n\n return Math.min(maxColumnWidthPx(column), Math.max(minColumnWidthPx(column), available));\n}\n\nfunction readStoredOverrides(\n storageKey: string | undefined,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n if (!storageKey || typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n\n if (raw === null) {\n return {};\n }\n\n const stored = JSON.parse(raw) as unknown;\n const columnKeys = columns.map((column) => column.key);\n\n if (!isStoredColumnWidths(stored) || !sameColumnKeys(stored.columns, columnKeys)) {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n\n const overrides = sanitizeOverrides(stored.overrides, columns);\n\n if (Object.keys(overrides).length === 0) {\n removeStoredOverrides(storageKey);\n }\n\n return overrides;\n } catch {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n}\n\nfunction writeStoredOverrides(\n storageKey: string | undefined,\n columnKeys: string[],\n overrides: Record<string, number | undefined>,\n): void {\n if (!storageKey || typeof window === \"undefined\") {\n return;\n }\n\n const stored: Record<string, number> = {};\n const knownKeys = new Set(columnKeys);\n\n for (const [key, value] of Object.entries(overrides)) {\n if (knownKeys.has(key) && typeof value === \"number\" && Number.isFinite(value)) {\n stored[key] = value;\n }\n }\n\n if (Object.keys(stored).length === 0) {\n removeStoredOverrides(storageKey);\n\n return;\n }\n\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({\n columns: columnKeys,\n overrides: stored,\n }),\n );\n } catch {\n return;\n }\n}\n\nfunction removeStoredOverrides(storageKey: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n return;\n }\n}\n\nfunction isStoredColumnWidths(value: unknown): value is StoredColumnWidths {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const record = value as Record<string, unknown>;\n\n return (\n Array.isArray(record.columns) &&\n record.columns.every((column) => typeof column === \"string\") &&\n typeof record.overrides === \"object\" &&\n record.overrides !== null &&\n !Array.isArray(record.overrides)\n );\n}\n\nfunction sameColumnKeys(stored: string[], current: string[]): boolean {\n return stored.length === current.length && stored.every((key, index) => key === current[index]);\n}\n\nfunction sanitizeOverrides(\n overrides: Record<string, unknown>,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n const next: Record<string, number | undefined> = {};\n\n for (const column of columns) {\n const value = overrides[column.key];\n\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n continue;\n }\n\n next[column.key] = Math.min(\n maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), value),\n );\n }\n\n return next;\n}\n\nfunction fixedTrackWidthPx(track: string): number {\n const value = track.trim();\n const px = value.match(/^([0-9.]+)px$/);\n\n if (px) {\n return Number.parseFloat(px[1]);\n }\n\n const rem = value.match(/^([0-9.]+)rem$/);\n\n if (rem) {\n return Number.parseFloat(rem[1]) * rootFontSizePx();\n }\n\n return 0;\n}\n\nfunction rootFontSizePx(): number {\n if (typeof window === \"undefined\") {\n return 16;\n }\n\n const parsed = Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize);\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-column-resizing.js","names":[],"sources":["../../resources/js/core/use-column-resizing.ts"],"sourcesContent":["import type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n buildColumnGridTemplate,\n defaultColumnWidthPx,\n maxColumnWidthPx,\n minColumnWidthPx,\n type SizableColumn,\n} from \"./column-sizing\";\n\ntype DragState = {\n key: string;\n maxWidth: number;\n startWidth: number;\n startX: number;\n};\n\ntype ResizeHandleProps = HTMLAttributes<HTMLDivElement> & {\n \"aria-label\": string;\n \"aria-orientation\": \"vertical\";\n \"aria-valuemax\": number;\n \"aria-valuemin\": number;\n \"aria-valuenow\": number;\n role: \"separator\";\n tabIndex: number;\n};\n\ntype StoredColumnWidths = {\n columns: string[];\n overrides: Record<string, number>;\n};\n\nconst emptyTracks: string[] = [];\n\nexport function useColumnResizing({\n columnGapPx = 0,\n columns,\n enabled,\n leadingTracks = emptyTracks,\n showIndicator = false,\n storageKey,\n trailingTracks = emptyTracks,\n}: {\n columnGapPx?: number;\n columns: SizableColumn[];\n enabled: boolean;\n leadingTracks?: string[];\n showIndicator?: boolean;\n storageKey?: string;\n trailingTracks?: string[];\n}) {\n const columnKeys = useMemo(() => columns.map((column) => column.key), [columns]);\n const [overrides, setOverrides] = useState<Record<string, number | undefined>>(() =>\n readStoredOverrides(storageKey, columns),\n );\n const overridesRef = useRef(overrides);\n const drag = useRef<DragState | null>(null);\n\n const gridTemplateColumns = useMemo(\n () =>\n buildColumnGridTemplate({\n columns,\n leadingTracks,\n trailingTracks,\n overrides: enabled ? overrides : {},\n }),\n [columns, enabled, leadingTracks, overrides, trailingTracks],\n );\n\n const setColumnWidth = useCallback(\n (column: SizableColumn, width: number, maxWidth?: number) => {\n setOverrides((current) => {\n const next = {\n ...current,\n [column.key]: Math.min(\n maxWidth ?? maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), width),\n ),\n };\n\n overridesRef.current = next;\n writeStoredOverrides(storageKey, columnKeys, next);\n\n return next;\n });\n },\n [columnKeys, storageKey],\n );\n\n const resetColumnWidth = useCallback(\n (column: SizableColumn) => {\n setOverrides((current) => {\n const next = { ...current };\n delete next[column.key];\n\n overridesRef.current = next;\n writeStoredOverrides(storageKey, columnKeys, next);\n\n return next;\n });\n },\n [columnKeys, storageKey],\n );\n\n const resetColumns = useCallback(() => {\n setOverrides({});\n overridesRef.current = {};\n writeStoredOverrides(storageKey, columnKeys, {});\n }, [columnKeys, storageKey]);\n\n const hasOverrides =\n enabled && Object.values(overrides).some((width) => typeof width === \"number\");\n\n const currentColumnWidth = useCallback(\n (column: SizableColumn): number =>\n overridesRef.current[column.key] ?? defaultColumnWidthPx(column),\n [],\n );\n\n const getResizeHandleProps = useCallback(\n (column: SizableColumn): ResizeHandleProps => {\n const max = maxColumnWidthPx(column);\n const min = minColumnWidthPx(column);\n const current = currentColumnWidth(column);\n const label = column.label ?? column.key;\n const indicatorClass = showIndicator ? \"after:bg-lt-border\" : \"after:bg-transparent\";\n\n const maxWidthForHandle = (handle: HTMLDivElement): number =>\n maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid: handle.parentElement?.parentElement,\n leadingTracks,\n trailingTracks,\n });\n\n const resizeBy = (handle: HTMLDivElement, delta: number): void =>\n setColumnWidth(column, current + delta, maxWidthForHandle(handle));\n\n return {\n \"aria-label\": `Resize ${label}`,\n \"aria-orientation\": \"vertical\",\n \"aria-valuemax\": max,\n \"aria-valuemin\": min,\n \"aria-valuenow\": current,\n className: `absolute inset-y-0 right-0 hidden w-2 cursor-col-resize touch-none items-stretch justify-center md:flex after:my-1 after:w-px ${indicatorClass} hover:after:bg-lt-border focus-visible:outline-none focus-visible:after:bg-lt-ring`,\n onDoubleClick: () => resetColumnWidth(column),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const step = event.shiftKey ? 32 : 8;\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n resizeBy(event.currentTarget, -step);\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n resizeBy(event.currentTarget, step);\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n setColumnWidth(column, min);\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n const handleMax = maxWidthForHandle(event.currentTarget);\n setColumnWidth(column, handleMax, handleMax);\n }\n\n if (event.key === \"Enter\" || event.key === \"Escape\") {\n event.preventDefault();\n resetColumnWidth(column);\n }\n },\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const parentWidth = event.currentTarget.parentElement?.getBoundingClientRect().width ?? 0;\n drag.current = {\n key: column.key,\n maxWidth: maxWidthForHandle(event.currentTarget),\n startWidth: parentWidth > 0 ? parentWidth : current,\n startX: event.clientX,\n };\n event.currentTarget.setPointerCapture?.(event.pointerId);\n event.preventDefault();\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (!enabled || active?.key !== column.key) {\n return;\n }\n\n setColumnWidth(\n column,\n active.startWidth + event.clientX - active.startX,\n active.maxWidth,\n );\n },\n onPointerUp: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (active?.key !== column.key) {\n return;\n }\n\n drag.current = null;\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n },\n role: \"separator\",\n tabIndex: 0,\n };\n },\n [\n columnGapPx,\n columns,\n currentColumnWidth,\n enabled,\n leadingTracks,\n resetColumnWidth,\n setColumnWidth,\n showIndicator,\n trailingTracks,\n ],\n );\n\n return {\n getResizeHandleProps,\n gridTemplateColumns,\n hasOverrides,\n resetColumns,\n resetColumnWidth,\n };\n}\n\nfunction maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid,\n leadingTracks,\n trailingTracks,\n}: {\n column: SizableColumn;\n columnGapPx: number;\n columns: SizableColumn[];\n grid: Element | null | undefined;\n leadingTracks: string[];\n trailingTracks: string[];\n}): number {\n const gridWidth = grid?.getBoundingClientRect().width ?? 0;\n\n if (gridWidth <= 0) {\n return maxColumnWidthPx(column);\n }\n\n const utilityWidth = [...leadingTracks, ...trailingTracks].reduce(\n (sum, track) => sum + fixedTrackWidthPx(track),\n 0,\n );\n const siblingMinWidth = columns.reduce(\n (sum, sibling) => (sibling.key === column.key ? sum : sum + minColumnWidthPx(sibling)),\n 0,\n );\n const trackCount = columns.length + leadingTracks.length + trailingTracks.length;\n const gapWidth = Math.max(0, trackCount - 1) * columnGapPx;\n const available = gridWidth - utilityWidth - siblingMinWidth - gapWidth;\n\n return Math.min(maxColumnWidthPx(column), Math.max(minColumnWidthPx(column), available));\n}\n\nfunction readStoredOverrides(\n storageKey: string | undefined,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n if (!storageKey || typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n\n if (raw === null) {\n return {};\n }\n\n const stored = JSON.parse(raw) as unknown;\n\n if (!isStoredColumnWidths(stored)) {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n\n const overrides = sanitizeOverrides(stored.overrides, columns);\n\n if (Object.keys(overrides).length === 0) {\n removeStoredOverrides(storageKey);\n }\n\n return overrides;\n } catch {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n}\n\nfunction writeStoredOverrides(\n storageKey: string | undefined,\n columnKeys: string[],\n overrides: Record<string, number | undefined>,\n): void {\n if (!storageKey || typeof window === \"undefined\") {\n return;\n }\n\n const stored: Record<string, number> = {};\n const knownKeys = new Set(columnKeys);\n\n for (const [key, value] of Object.entries(overrides)) {\n if (knownKeys.has(key) && typeof value === \"number\" && Number.isFinite(value)) {\n stored[key] = value;\n }\n }\n\n if (Object.keys(stored).length === 0) {\n removeStoredOverrides(storageKey);\n\n return;\n }\n\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({\n columns: columnKeys,\n overrides: stored,\n }),\n );\n } catch {\n return;\n }\n}\n\nfunction removeStoredOverrides(storageKey: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n return;\n }\n}\n\nfunction isStoredColumnWidths(value: unknown): value is StoredColumnWidths {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const record = value as Record<string, unknown>;\n\n return (\n Array.isArray(record.columns) &&\n record.columns.every((column) => typeof column === \"string\") &&\n typeof record.overrides === \"object\" &&\n record.overrides !== null &&\n !Array.isArray(record.overrides)\n );\n}\n\nfunction sanitizeOverrides(\n overrides: Record<string, unknown>,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n const next: Record<string, number | undefined> = {};\n\n for (const column of columns) {\n const value = overrides[column.key];\n\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n continue;\n }\n\n next[column.key] = Math.min(\n maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), value),\n );\n }\n\n return next;\n}\n\nfunction fixedTrackWidthPx(track: string): number {\n const value = track.trim();\n const px = value.match(/^([0-9.]+)px$/);\n\n if (px) {\n return Number.parseFloat(px[1]);\n }\n\n const rem = value.match(/^([0-9.]+)rem$/);\n\n if (rem) {\n return Number.parseFloat(rem[1]) * rootFontSizePx();\n }\n\n return 0;\n}\n\nfunction rootFontSizePx(): number {\n if (typeof window === \"undefined\") {\n return 16;\n }\n\n const parsed = Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize);\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ToggleableColumn = {
|
|
2
|
+
key: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
toggleable?: boolean | null;
|
|
5
|
+
hiddenByDefault?: boolean | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function useColumnVisibility<TColumn extends ToggleableColumn>({ columns, storageKey, }: {
|
|
8
|
+
columns: TColumn[];
|
|
9
|
+
storageKey?: string;
|
|
10
|
+
}): {
|
|
11
|
+
hasHidden: boolean;
|
|
12
|
+
hasToggleableColumns: boolean;
|
|
13
|
+
isVisible: (column: ToggleableColumn) => boolean;
|
|
14
|
+
resetVisibility: () => void;
|
|
15
|
+
setColumnVisible: (key: string, visible: boolean) => void;
|
|
16
|
+
toggleableColumns: TColumn[];
|
|
17
|
+
visibleColumns: TColumn[];
|
|
18
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
//#region resources/js/core/use-column-visibility.ts
|
|
3
|
+
function useColumnVisibility({ columns, storageKey }) {
|
|
4
|
+
const toggleableColumns = useMemo(() => columns.filter((column) => column.toggleable === true), [columns]);
|
|
5
|
+
const toggleableKeys = useMemo(() => toggleableColumns.map((column) => column.key), [toggleableColumns]);
|
|
6
|
+
const [overrides, setOverrides] = useState(() => readStoredVisibility(storageKey, toggleableKeys));
|
|
7
|
+
const isVisible = useCallback((column) => {
|
|
8
|
+
if (column.toggleable !== true) return true;
|
|
9
|
+
return overrides[column.key] ?? column.hiddenByDefault !== true;
|
|
10
|
+
}, [overrides]);
|
|
11
|
+
const visibleColumns = useMemo(() => columns.filter((column) => isVisible(column)), [columns, isVisible]);
|
|
12
|
+
const setColumnVisible = useCallback((key, visible) => {
|
|
13
|
+
setOverrides((current) => {
|
|
14
|
+
const next = {
|
|
15
|
+
...current,
|
|
16
|
+
[key]: visible
|
|
17
|
+
};
|
|
18
|
+
writeStoredVisibility(storageKey, toggleableKeys, next);
|
|
19
|
+
return next;
|
|
20
|
+
});
|
|
21
|
+
}, [storageKey, toggleableKeys]);
|
|
22
|
+
const resetVisibility = useCallback(() => {
|
|
23
|
+
setOverrides({});
|
|
24
|
+
writeStoredVisibility(storageKey, toggleableKeys, {});
|
|
25
|
+
}, [storageKey, toggleableKeys]);
|
|
26
|
+
const hasToggleableColumns = toggleableColumns.length > 0;
|
|
27
|
+
return {
|
|
28
|
+
hasHidden: toggleableColumns.some((column) => !isVisible(column)),
|
|
29
|
+
hasToggleableColumns,
|
|
30
|
+
isVisible,
|
|
31
|
+
resetVisibility,
|
|
32
|
+
setColumnVisible,
|
|
33
|
+
toggleableColumns,
|
|
34
|
+
visibleColumns
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function readStoredVisibility(storageKey, toggleableKeys) {
|
|
38
|
+
if (!storageKey || typeof window === "undefined") return {};
|
|
39
|
+
try {
|
|
40
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
41
|
+
if (raw === null) return {};
|
|
42
|
+
const stored = JSON.parse(raw);
|
|
43
|
+
if (!isStoredColumnVisibility(stored)) {
|
|
44
|
+
removeStoredVisibility(storageKey);
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
const known = new Set(toggleableKeys);
|
|
48
|
+
const overrides = {};
|
|
49
|
+
for (const [key, value] of Object.entries(stored.overrides)) if (known.has(key) && typeof value === "boolean") overrides[key] = value;
|
|
50
|
+
if (Object.keys(overrides).length === 0) removeStoredVisibility(storageKey);
|
|
51
|
+
return overrides;
|
|
52
|
+
} catch {
|
|
53
|
+
removeStoredVisibility(storageKey);
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function writeStoredVisibility(storageKey, toggleableKeys, overrides) {
|
|
58
|
+
if (!storageKey || typeof window === "undefined") return;
|
|
59
|
+
const known = new Set(toggleableKeys);
|
|
60
|
+
const stored = {};
|
|
61
|
+
for (const [key, value] of Object.entries(overrides)) if (known.has(key) && typeof value === "boolean") stored[key] = value;
|
|
62
|
+
if (Object.keys(stored).length === 0) {
|
|
63
|
+
removeStoredVisibility(storageKey);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
window.localStorage.setItem(storageKey, JSON.stringify({
|
|
68
|
+
columns: toggleableKeys,
|
|
69
|
+
overrides: stored
|
|
70
|
+
}));
|
|
71
|
+
} catch {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function removeStoredVisibility(storageKey) {
|
|
76
|
+
if (typeof window === "undefined") return;
|
|
77
|
+
try {
|
|
78
|
+
window.localStorage.removeItem(storageKey);
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isStoredColumnVisibility(value) {
|
|
84
|
+
if (typeof value !== "object" || value === null) return false;
|
|
85
|
+
const record = value;
|
|
86
|
+
return Array.isArray(record.columns) && record.columns.every((column) => typeof column === "string") && typeof record.overrides === "object" && record.overrides !== null && !Array.isArray(record.overrides);
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { useColumnVisibility };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=use-column-visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-column-visibility.js","names":[],"sources":["../../resources/js/core/use-column-visibility.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport type ToggleableColumn = {\n key: string;\n label?: string;\n toggleable?: boolean | null;\n hiddenByDefault?: boolean | null;\n};\n\ntype StoredColumnVisibility = {\n columns: string[];\n overrides: Record<string, boolean>;\n};\n\nexport function useColumnVisibility<TColumn extends ToggleableColumn>({\n columns,\n storageKey,\n}: {\n columns: TColumn[];\n storageKey?: string;\n}) {\n const toggleableColumns = useMemo(\n () => columns.filter((column) => column.toggleable === true),\n [columns],\n );\n const toggleableKeys = useMemo(\n () => toggleableColumns.map((column) => column.key),\n [toggleableColumns],\n );\n\n const [overrides, setOverrides] = useState<Record<string, boolean>>(() =>\n readStoredVisibility(storageKey, toggleableKeys),\n );\n\n const isVisible = useCallback(\n (column: ToggleableColumn): boolean => {\n if (column.toggleable !== true) {\n return true;\n }\n\n return overrides[column.key] ?? column.hiddenByDefault !== true;\n },\n [overrides],\n );\n\n const visibleColumns = useMemo(\n () => columns.filter((column) => isVisible(column)),\n [columns, isVisible],\n );\n\n const setColumnVisible = useCallback(\n (key: string, visible: boolean) => {\n setOverrides((current) => {\n const next = { ...current, [key]: visible };\n writeStoredVisibility(storageKey, toggleableKeys, next);\n\n return next;\n });\n },\n [storageKey, toggleableKeys],\n );\n\n const resetVisibility = useCallback(() => {\n setOverrides({});\n writeStoredVisibility(storageKey, toggleableKeys, {});\n }, [storageKey, toggleableKeys]);\n\n const hasToggleableColumns = toggleableColumns.length > 0;\n const hasHidden = toggleableColumns.some((column) => !isVisible(column));\n\n return {\n hasHidden,\n hasToggleableColumns,\n isVisible,\n resetVisibility,\n setColumnVisible,\n toggleableColumns,\n visibleColumns,\n };\n}\n\nfunction readStoredVisibility(\n storageKey: string | undefined,\n toggleableKeys: string[],\n): Record<string, boolean> {\n if (!storageKey || typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n\n if (raw === null) {\n return {};\n }\n\n const stored = JSON.parse(raw) as unknown;\n\n if (!isStoredColumnVisibility(stored)) {\n removeStoredVisibility(storageKey);\n\n return {};\n }\n\n const known = new Set(toggleableKeys);\n const overrides: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(stored.overrides)) {\n if (known.has(key) && typeof value === \"boolean\") {\n overrides[key] = value;\n }\n }\n\n if (Object.keys(overrides).length === 0) {\n removeStoredVisibility(storageKey);\n }\n\n return overrides;\n } catch {\n removeStoredVisibility(storageKey);\n\n return {};\n }\n}\n\nfunction writeStoredVisibility(\n storageKey: string | undefined,\n toggleableKeys: string[],\n overrides: Record<string, boolean>,\n): void {\n if (!storageKey || typeof window === \"undefined\") {\n return;\n }\n\n const known = new Set(toggleableKeys);\n const stored: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(overrides)) {\n if (known.has(key) && typeof value === \"boolean\") {\n stored[key] = value;\n }\n }\n\n if (Object.keys(stored).length === 0) {\n removeStoredVisibility(storageKey);\n\n return;\n }\n\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({ columns: toggleableKeys, overrides: stored }),\n );\n } catch {\n return;\n }\n}\n\nfunction removeStoredVisibility(storageKey: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n return;\n }\n}\n\nfunction isStoredColumnVisibility(value: unknown): value is StoredColumnVisibility {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const record = value as Record<string, unknown>;\n\n return (\n Array.isArray(record.columns) &&\n record.columns.every((column) => typeof column === \"string\") &&\n typeof record.overrides === \"object\" &&\n record.overrides !== null &&\n !Array.isArray(record.overrides)\n );\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -22,10 +22,10 @@ import { RealtimeListeners } from "./realtime/listeners.js";
|
|
|
22
22
|
import { createLayoutResolver, createPageResolver, pageComponentName, withVisitHeaders } from "./inertia.js";
|
|
23
23
|
import { useChat } from "./chat/use-chat.js";
|
|
24
24
|
import { chatPlugin } from "./chat/index.js";
|
|
25
|
+
import { copyToClipboard, useClipboard } from "./clipboard/index.js";
|
|
25
26
|
import { registry } from "./registry.js";
|
|
26
27
|
import { Toaster } from "./toast/toaster.js";
|
|
27
28
|
import { Provider } from "./provider.js";
|
|
28
29
|
import { createLatticeApp } from "./create-app.js";
|
|
29
|
-
import { copyToClipboard, useClipboard } from "./clipboard/index.js";
|
|
30
30
|
import { columnCell } from "./table/registry.js";
|
|
31
31
|
export { Callouts, EventBridge, Icon, IconRenderer, IconRendererProvider, LATTICE_EVENT, LATTICE_REF_HEADER, OutletContext, Provider, RealtimeListeners, Renderer, SchemaLayout, CollapsedContext as SidebarCollapsedContext, SpriteProvider, Toaster, builtinEffectHandlers, chatPlugin, columnCell, copyToClipboard, createLatticeApp, createLayoutResolver, createPageResolver, createPlugin, createRegistry, dispatchActionError, dispatchEffects, eagerComponent, effectHandler, extendRegistry, getActionEffects, initializeTheme, isActionEffect, layoutComponents, lazyComponent, mergeEffectHandlers, onCallout, onToast, pageComponentName, registry, showToast, updateAppearance, useAppearance, useChat, useClipboard, useColumnRegistry, useComponentRegistry, useEffectDispatcher, useCollapsed as useSidebarCollapsed, withHeaders, withRefHeader, withVisitHeaders };
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
|
-
import { Icon } from "../../../icons/sprite.js";
|
|
3
2
|
import { formatCell, resolveLink } from "../../format.js";
|
|
4
3
|
import { DateTime } from "../../../i18n/date-time.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { CopyableText } from "../../../clipboard/copyable-text.js";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
6
|
//#region resources/js/table/components/cells/text-cell.tsx
|
|
9
7
|
var TextCell = (args) => {
|
|
10
8
|
if (args.props.multiple) return /* @__PURE__ */ jsx(MultipleCell, { ...args });
|
|
@@ -44,7 +42,6 @@ function PlainTextCell({ column, props, row, value }) {
|
|
|
44
42
|
const dateProps = column.props?.date;
|
|
45
43
|
const href = resolveLink(column, row, value);
|
|
46
44
|
const text = formatCell(value, column);
|
|
47
|
-
const [copied, setCopied] = useState(false);
|
|
48
45
|
const content = href ? /* @__PURE__ */ jsx("a", {
|
|
49
46
|
className: "underline underline-offset-2",
|
|
50
47
|
href,
|
|
@@ -52,37 +49,17 @@ function PlainTextCell({ column, props, row, value }) {
|
|
|
52
49
|
target: props.link?.external ? "_blank" : void 0,
|
|
53
50
|
children: text
|
|
54
51
|
}) : text;
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
if (!copied) return;
|
|
57
|
-
const timeout = window.setTimeout(() => setCopied(false), 1500);
|
|
58
|
-
return () => window.clearTimeout(timeout);
|
|
59
|
-
}, [copied]);
|
|
60
|
-
function handleCopy() {
|
|
61
|
-
copyToClipboard(text);
|
|
62
|
-
setCopied(true);
|
|
63
|
-
}
|
|
64
52
|
if (dateProps && !href && !props.copyable && value !== null && value !== void 0) return /* @__PURE__ */ jsx(DateTime, {
|
|
65
53
|
value,
|
|
66
54
|
dateStyle: dateProps.dateStyle,
|
|
67
55
|
timeStyle: dateProps.timeStyle
|
|
68
56
|
});
|
|
69
57
|
if (!props.copyable) return content;
|
|
70
|
-
return /* @__PURE__ */
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
className: "inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs",
|
|
76
|
-
"aria-label": `${copied ? "Copied" : "Copy"} ${column.label}`,
|
|
77
|
-
onClick: handleCopy,
|
|
78
|
-
children: [copied ? /* @__PURE__ */ jsx(Icon, {
|
|
79
|
-
name: "check",
|
|
80
|
-
className: "size-lt-icon-xs"
|
|
81
|
-
}) : /* @__PURE__ */ jsx(Icon, {
|
|
82
|
-
name: "copy",
|
|
83
|
-
className: "size-lt-icon-xs"
|
|
84
|
-
}), copied ? "Copied" : "Copy"]
|
|
85
|
-
})]
|
|
58
|
+
return /* @__PURE__ */ jsx(CopyableText, {
|
|
59
|
+
value: text,
|
|
60
|
+
label: column.label,
|
|
61
|
+
testId: `copy-${column.key}`,
|
|
62
|
+
children: content
|
|
86
63
|
});
|
|
87
64
|
}
|
|
88
65
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"text-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/text-cell.tsx"],"sourcesContent":["import { CopyableText } from \"@lattice-php/lattice/clipboard\";\nimport { DateTime } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { ReactNode } 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\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 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 <CopyableText value={text} label={column.label} testId={`copy-${column.key}`}>\n {content}\n </CopyableText>\n );\n}\n"],"mappings":";;;;;;AAUA,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;CAErC,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,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,oBAAC,cAAD;EAAc,OAAO;EAAM,OAAO,OAAO;EAAO,QAAQ,QAAQ,OAAO;YACpE;CACW,CAAA;AAElB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ToggleableColumn } from '../../core/use-column-visibility';
|
|
2
|
+
export declare function ColumnVisibilityMenu({ columns, hasHidden, isVisible, onReset, onToggle, processing, visibleColumnCount, }: {
|
|
3
|
+
columns: ToggleableColumn[];
|
|
4
|
+
hasHidden: boolean;
|
|
5
|
+
isVisible: (column: ToggleableColumn) => boolean;
|
|
6
|
+
onReset: () => void;
|
|
7
|
+
onToggle: (key: string, visible: boolean) => void;
|
|
8
|
+
processing: boolean;
|
|
9
|
+
visibleColumnCount: number;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Icon } from "../../icons/sprite.js";
|
|
2
|
+
import { useT } from "../../i18n/instance.js";
|
|
3
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../../core/components/popover.js";
|
|
4
|
+
import { Checkbox } from "../../core/components/checkbox.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region resources/js/table/components/column-visibility-menu.tsx
|
|
7
|
+
function ColumnVisibilityMenu({ columns, hasHidden, isVisible, onReset, onToggle, processing, visibleColumnCount }) {
|
|
8
|
+
const { t } = useT("lattice");
|
|
9
|
+
return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
10
|
+
asChild: true,
|
|
11
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
12
|
+
type: "button",
|
|
13
|
+
"aria-label": t("table.columns.label", "Columns"),
|
|
14
|
+
"data-test": "table-columns-menu",
|
|
15
|
+
className: "relative inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg hover:bg-lt-muted hover:text-lt-fg disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lt-ring/50 data-[state=open]:bg-lt-muted data-[state=open]:text-lt-fg",
|
|
16
|
+
disabled: processing,
|
|
17
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
18
|
+
name: "columns-3",
|
|
19
|
+
"aria-hidden": "true",
|
|
20
|
+
className: "size-lt-icon-md"
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
24
|
+
align: "end",
|
|
25
|
+
className: "w-64 p-4",
|
|
26
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
27
|
+
className: "grid gap-3",
|
|
28
|
+
children: [columns.map((column) => {
|
|
29
|
+
const visible = isVisible(column);
|
|
30
|
+
const lockedLast = visible && visibleColumnCount <= 1;
|
|
31
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
32
|
+
className: "flex items-center gap-2 text-base text-lt-fg",
|
|
33
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
34
|
+
"data-test": `table-column-toggle-${column.key}`,
|
|
35
|
+
checked: visible,
|
|
36
|
+
disabled: lockedLast,
|
|
37
|
+
onCheckedChange: (next) => onToggle(column.key, next === true)
|
|
38
|
+
}), /* @__PURE__ */ jsx("span", { children: column.label ?? column.key })]
|
|
39
|
+
}, column.key);
|
|
40
|
+
}), hasHidden && /* @__PURE__ */ jsx("button", {
|
|
41
|
+
type: "button",
|
|
42
|
+
"data-test": "table-columns-reset",
|
|
43
|
+
className: "mt-1 justify-self-start text-sm text-lt-muted-fg hover:text-lt-fg",
|
|
44
|
+
onClick: onReset,
|
|
45
|
+
children: t("table.columns.reset", "Reset")
|
|
46
|
+
})]
|
|
47
|
+
})
|
|
48
|
+
})] });
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { ColumnVisibilityMenu };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=column-visibility-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-visibility-menu.js","names":[],"sources":["../../../resources/js/table/components/column-visibility-menu.tsx"],"sourcesContent":["import { Checkbox } from \"@lattice-php/lattice/core/components/checkbox\";\nimport type { ToggleableColumn } from \"@lattice-php/lattice/core/use-column-visibility\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@lattice-php/lattice/core/components/popover\";\n\nexport function ColumnVisibilityMenu({\n columns,\n hasHidden,\n isVisible,\n onReset,\n onToggle,\n processing,\n visibleColumnCount,\n}: {\n columns: ToggleableColumn[];\n hasHidden: boolean;\n isVisible: (column: ToggleableColumn) => boolean;\n onReset: () => void;\n onToggle: (key: string, visible: boolean) => void;\n processing: boolean;\n visibleColumnCount: number;\n}) {\n const { t } = useT(\"lattice\");\n const columnsLabel = t(\"table.columns.label\", \"Columns\");\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={columnsLabel}\n data-test=\"table-columns-menu\"\n className=\"relative inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg hover:bg-lt-muted hover:text-lt-fg disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lt-ring/50 data-[state=open]:bg-lt-muted data-[state=open]:text-lt-fg\"\n disabled={processing}\n >\n <Icon name=\"columns-3\" aria-hidden=\"true\" className=\"size-lt-icon-md\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-64 p-4\">\n <div className=\"grid gap-3\">\n {columns.map((column) => {\n const visible = isVisible(column);\n const lockedLast = visible && visibleColumnCount <= 1;\n\n return (\n <label key={column.key} className=\"flex items-center gap-2 text-base text-lt-fg\">\n <Checkbox\n data-test={`table-column-toggle-${column.key}`}\n checked={visible}\n disabled={lockedLast}\n onCheckedChange={(next) => onToggle(column.key, next === true)}\n />\n <span>{column.label ?? column.key}</span>\n </label>\n );\n })}\n {hasHidden && (\n <button\n type=\"button\"\n data-test=\"table-columns-reset\"\n className=\"mt-1 justify-self-start text-sm text-lt-muted-fg hover:text-lt-fg\"\n onClick={onReset}\n >\n {t(\"table.columns.reset\", \"Reset\")}\n </button>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";;;;;;AAUA,SAAgB,qBAAqB,EACnC,SACA,WACA,WACA,SACA,UACA,YACA,sBASC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAG5B,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;EAAgB,SAAA;YACd,oBAAC,UAAD;GACE,MAAK;GACL,cAPa,EAAE,uBAAuB,SAO1B;GACZ,aAAU;GACV,WAAU;GACV,UAAU;aAEV,oBAAC,MAAD;IAAM,MAAK;IAAY,eAAY;IAAO,WAAU;GAAmB,CAAA;EACjE,CAAA;CACM,CAAA,GAChB,oBAAC,gBAAD;EAAgB,OAAM;EAAM,WAAU;YACpC,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,QAAQ,KAAK,WAAW;IACvB,MAAM,UAAU,UAAU,MAAM;IAChC,MAAM,aAAa,WAAW,sBAAsB;IAEpD,OACE,qBAAC,SAAD;KAAwB,WAAU;eAAlC,CACE,oBAAC,UAAD;MACE,aAAW,uBAAuB,OAAO;MACzC,SAAS;MACT,UAAU;MACV,kBAAkB,SAAS,SAAS,OAAO,KAAK,SAAS,IAAI;KAC9D,CAAA,GACD,oBAAC,QAAD,EAAA,UAAO,OAAO,SAAS,OAAO,IAAU,CAAA,CACnC;OARK,OAAO,GAQZ;GAEX,CAAC,GACA,aACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,uBAAuB,OAAO;GAC3B,CAAA,CAEP;;CACS,CAAA,CACT,EAAA,CAAA;AAEb"}
|
|
@@ -3,6 +3,7 @@ import { Icon } from "../../icons/sprite.js";
|
|
|
3
3
|
import { useT } from "../../i18n/instance.js";
|
|
4
4
|
import { nodeIdentity } from "../../core/test-id.js";
|
|
5
5
|
import { useColumnResizing } from "../../core/use-column-resizing.js";
|
|
6
|
+
import { useColumnVisibility } from "../../core/use-column-visibility.js";
|
|
6
7
|
import { alignJustifyItems, alignText } from "../align.js";
|
|
7
8
|
import { getBulkActions } from "../bulk.js";
|
|
8
9
|
import { flattenColumns, getRowActions, getRowKey } from "../payload.js";
|
|
@@ -13,6 +14,7 @@ import { Checkbox } from "../../core/components/checkbox.js";
|
|
|
13
14
|
import { BulkBar } from "./bulk-bar.js";
|
|
14
15
|
import { ColumnFilterControl } from "./column-filter-control.js";
|
|
15
16
|
import { ColumnHeader } from "./column-header.js";
|
|
17
|
+
import { ColumnVisibilityMenu } from "./column-visibility-menu.js";
|
|
16
18
|
import { FilterBar, FilterMenu } from "./filter-bar.js";
|
|
17
19
|
import { FilterStackBar } from "./filter-stack-bar.js";
|
|
18
20
|
import { TablePagination } from "./pagination.js";
|
|
@@ -34,6 +36,11 @@ var TableComponent = ({ node }) => {
|
|
|
34
36
|
})), [rows]);
|
|
35
37
|
const selection = useTableSelection(rowEntries.map((entry) => entry.key));
|
|
36
38
|
const columnsByKey = useMemo(() => new Map(flattenColumns(columns).map((column) => [column.key, column])), [columns]);
|
|
39
|
+
const visibilityIdentity = nodeIdentity(node);
|
|
40
|
+
const { hasToggleableColumns, hasHidden, isVisible, resetVisibility, setColumnVisible, toggleableColumns, visibleColumns } = useColumnVisibility({
|
|
41
|
+
columns,
|
|
42
|
+
storageKey: visibilityIdentity ? `lattice:table-column-visibility:${visibilityIdentity}` : void 0
|
|
43
|
+
});
|
|
37
44
|
const currentPage = pagination.currentPage ?? state.page;
|
|
38
45
|
const lastPage = pagination.lastPage ?? currentPage;
|
|
39
46
|
const mode = pagination.mode ?? "table";
|
|
@@ -41,7 +48,7 @@ var TableComponent = ({ node }) => {
|
|
|
41
48
|
const hasNextPage = pagination.hasMore ?? currentPage < lastPage;
|
|
42
49
|
const hasActions = rowEntries.some((entry) => entry.actions.length > 0);
|
|
43
50
|
const striped = node.props?.striped === true;
|
|
44
|
-
const hasFilters =
|
|
51
|
+
const hasFilters = visibleColumns.some((column) => column.filter?.enabled);
|
|
45
52
|
const filterEntries = filters.map((clause, index) => ({
|
|
46
53
|
clause,
|
|
47
54
|
index
|
|
@@ -49,8 +56,8 @@ var TableComponent = ({ node }) => {
|
|
|
49
56
|
const filterDefinitions = useMemo(() => Array.isArray(node.props?.filters) ? node.props.filters : [], [node.props?.filters]);
|
|
50
57
|
const hasDedicatedFilters = filterDefinitions.length > 0;
|
|
51
58
|
const hasActiveFilters = filters.length > 0 || Object.keys(tableFilters).length > 0;
|
|
52
|
-
const hasTrailingUtility = hasActions || hasDedicatedFilters;
|
|
53
|
-
const sizingColumns = useMemo(() => getTableSizingColumns(
|
|
59
|
+
const hasTrailingUtility = hasActions || hasDedicatedFilters || hasToggleableColumns;
|
|
60
|
+
const sizingColumns = useMemo(() => getTableSizingColumns(visibleColumns), [visibleColumns]);
|
|
54
61
|
const utilityTracks = useMemo(() => getTableUtilityTracks(hasTrailingUtility, hasBulkActions), [hasTrailingUtility, hasBulkActions]);
|
|
55
62
|
const resizingEnabled = node.props?.resizableColumns === true;
|
|
56
63
|
const resizeStorageIdentity = nodeIdentity(node);
|
|
@@ -130,7 +137,7 @@ var TableComponent = ({ node }) => {
|
|
|
130
137
|
onCheckedChange: () => selection.toggleAll()
|
|
131
138
|
})
|
|
132
139
|
}),
|
|
133
|
-
|
|
140
|
+
visibleColumns.map((column, index) => /* @__PURE__ */ jsx(ColumnHeader, {
|
|
134
141
|
column,
|
|
135
142
|
processing,
|
|
136
143
|
resizeHandleProps: resizingEnabled ? getResizeHandleProps(sizingColumns[index]) : void 0,
|
|
@@ -140,16 +147,28 @@ var TableComponent = ({ node }) => {
|
|
|
140
147
|
hasTrailingUtility && /* @__PURE__ */ jsxs("div", {
|
|
141
148
|
className: "flex items-center justify-end gap-2 px-4 py-2 align-middle font-semibold text-lt-fg",
|
|
142
149
|
role: "columnheader",
|
|
143
|
-
children: [
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
children: [
|
|
151
|
+
hasDedicatedFilters && /* @__PURE__ */ jsx(FilterMenu, {
|
|
152
|
+
filters: filterDefinitions,
|
|
153
|
+
values: tableFilters,
|
|
154
|
+
processing,
|
|
155
|
+
onChange: setTableFilter,
|
|
156
|
+
onSearch: searchFilterOptions
|
|
157
|
+
}),
|
|
158
|
+
hasToggleableColumns && /* @__PURE__ */ jsx(ColumnVisibilityMenu, {
|
|
159
|
+
columns: toggleableColumns,
|
|
160
|
+
isVisible,
|
|
161
|
+
visibleColumnCount: visibleColumns.length,
|
|
162
|
+
hasHidden,
|
|
163
|
+
onToggle: setColumnVisible,
|
|
164
|
+
onReset: resetVisibility,
|
|
165
|
+
processing
|
|
166
|
+
}),
|
|
167
|
+
hasActions && /* @__PURE__ */ jsx("span", {
|
|
168
|
+
className: "sr-only",
|
|
169
|
+
children: node.props?.actionsLabel
|
|
170
|
+
})
|
|
171
|
+
]
|
|
153
172
|
})
|
|
154
173
|
]
|
|
155
174
|
}), hasFilters && /* @__PURE__ */ jsxs("div", {
|
|
@@ -161,7 +180,7 @@ var TableComponent = ({ node }) => {
|
|
|
161
180
|
className: "px-4 py-2",
|
|
162
181
|
role: "cell"
|
|
163
182
|
}),
|
|
164
|
-
|
|
183
|
+
visibleColumns.map((column) => /* @__PURE__ */ jsx("div", {
|
|
165
184
|
className: "min-w-0 px-2 py-2",
|
|
166
185
|
role: "cell",
|
|
167
186
|
children: column.filter?.enabled && /* @__PURE__ */ jsx(ColumnFilterControl, {
|
|
@@ -213,7 +232,7 @@ var TableComponent = ({ node }) => {
|
|
|
213
232
|
onCheckedChange: () => selection.toggle(key)
|
|
214
233
|
})
|
|
215
234
|
}),
|
|
216
|
-
|
|
235
|
+
visibleColumns.map((column) => /* @__PURE__ */ jsxs("div", {
|
|
217
236
|
className: cn("grid min-w-0 gap-1 overflow-hidden p-4 align-middle", alignText(column.align), alignJustifyItems(column.align)),
|
|
218
237
|
role: "cell",
|
|
219
238
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","names":[],"sources":["../../../resources/js/table/components/table.tsx"],"sourcesContent":["import { type ReactNode, useMemo } from \"react\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useColumnResizing } from \"@lattice-php/lattice/core/use-column-resizing\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { Checkbox } from \"@lattice-php/lattice/core/components/checkbox\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { alignJustifyItems, alignText } from \"../align\";\nimport type { TableNode } from \"../types\";\nimport { getBulkActions } from \"../bulk\";\nimport { flattenColumns, getRowActions, getRowKey } from \"../payload\";\nimport {\n getQueryParams,\n getTableSizingColumns,\n getTableUtilityTracks,\n getVisiblePages,\n} from \"../query\";\nimport { useTable } from \"../use-table\";\nimport { useTableSelection } from \"../use-table-selection\";\nimport { BulkBar } from \"./bulk-bar\";\nimport { ColumnFilterControl } from \"./column-filter-control\";\nimport { ColumnHeader } from \"./column-header\";\nimport { FilterBar, FilterMenu } from \"./filter-bar\";\nimport { FilterStackBar } from \"./filter-stack-bar\";\nimport { TablePagination } from \"./pagination\";\nimport { SortBar } from \"./sort-bar\";\nimport { TableActionNode } from \"./table-action-node\";\nimport { ColumnCell } from \"./table-cell\";\n\nconst TableComponent = ({ node }: { children?: ReactNode; node: TableNode }) => {\n const { t } = useT(\"lattice\");\n const {\n columns,\n rows,\n pagination,\n state,\n filters,\n tableFilters,\n addFilter,\n updateFilter,\n removeFilter,\n replaceColumnFilters,\n setTableFilter,\n resetFilters,\n searchFilterOptions,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n } = useTable(node);\n\n const bulkActions = useMemo(\n () => getBulkActions(node.props?.bulkActions),\n [node.props?.bulkActions],\n );\n const hasBulkActions = bulkActions.length > 0;\n const rowEntries = useMemo(\n () =>\n rows.map((row, index) => ({ row, actions: getRowActions(row), key: getRowKey(row, index) })),\n [rows],\n );\n const selection = useTableSelection(rowEntries.map((entry) => entry.key));\n\n const columnsByKey = useMemo(\n () => new Map(flattenColumns(columns).map((column) => [column.key, column])),\n [columns],\n );\n const currentPage = pagination.currentPage ?? state.page;\n const lastPage = pagination.lastPage ?? currentPage;\n const mode = pagination.mode ?? \"table\";\n const visiblePages = getVisiblePages(currentPage, lastPage);\n const hasNextPage = pagination.hasMore ?? currentPage < lastPage;\n const hasActions = rowEntries.some((entry) => entry.actions.length > 0);\n const striped = node.props?.striped === true;\n const hasFilters = columns.some((column) => column.filter?.enabled);\n const filterEntries = filters.map((clause, index) => ({ clause, index }));\n const filterDefinitions = useMemo(\n () => (Array.isArray(node.props?.filters) ? node.props.filters : []),\n [node.props?.filters],\n );\n const hasDedicatedFilters = filterDefinitions.length > 0;\n const hasActiveFilters = filters.length > 0 || Object.keys(tableFilters).length > 0;\n const hasTrailingUtility = hasActions || hasDedicatedFilters;\n const sizingColumns = useMemo(() => getTableSizingColumns(columns), [columns]);\n const utilityTracks = useMemo(\n () => getTableUtilityTracks(hasTrailingUtility, hasBulkActions),\n [hasTrailingUtility, hasBulkActions],\n );\n const resizingEnabled = node.props?.resizableColumns === true;\n const resizeStorageIdentity = nodeIdentity(node);\n const { getResizeHandleProps, gridTemplateColumns, hasOverrides, resetColumns } =\n useColumnResizing({\n columns: sizingColumns,\n enabled: resizingEnabled,\n leadingTracks: utilityTracks.leadingTracks,\n showIndicator: node.props?.resizeIndicator === true,\n storageKey:\n resizingEnabled && resizeStorageIdentity\n ? `lattice:table-columns:${resizeStorageIdentity}`\n : undefined,\n trailingTracks: utilityTracks.trailingTracks,\n });\n\n return (\n <div data-lattice-component={node.id} className=\"relative\">\n {hasOverrides && (\n <button\n aria-label={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n className=\"absolute right-1 top-1 z-10 hidden rounded-lt-sm p-1 text-lt-muted-fg hover:text-lt-fg md:inline-flex\"\n data-test=\"table-reset-columns\"\n onClick={resetColumns}\n title={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n type=\"button\"\n >\n <Icon name=\"rotate-ccw\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n <div className=\"overflow-x-auto rounded-lt-sm border border-lt-border\">\n {hasDedicatedFilters && hasActiveFilters && (\n <FilterBar\n filters={filterDefinitions}\n values={tableFilters}\n processing={processing}\n hasActiveFilters={hasActiveFilters}\n onChange={setTableFilter}\n onReset={resetFilters}\n />\n )}\n {hasBulkActions && selection.active && (\n <BulkBar\n actions={bulkActions}\n selectedKeys={selection.selectedKeys}\n allMatching={selection.allMatching}\n total={pagination.total ?? undefined}\n query={getQueryParams(state)}\n canSelectAllMatching={\n selection.allVisibleSelected &&\n !selection.allMatching &&\n pagination.total != null &&\n pagination.total > selection.selectedKeys.length\n }\n onSelectAllMatching={selection.selectAllMatching}\n onCompleted={selection.clear}\n />\n )}\n {filters.length > 0 && (\n <FilterStackBar\n filters={filters}\n columnsByKey={columnsByKey}\n processing={processing}\n onRemove={removeFilter}\n />\n )}\n {state.sorts.length > 0 && (\n <SortBar\n columnsByKey={columnsByKey}\n state={state}\n processing={processing}\n onClear={clearSort}\n />\n )}\n <div className=\"min-w-full text-base\" role=\"table\">\n <div className=\"border-b border-lt-border bg-lt-muted/50\" role=\"rowgroup\">\n <div\n className=\"hidden min-w-full md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center px-4 py-3\" role=\"columnheader\">\n <Checkbox\n aria-label={t(\"table.selectAllRows\", \"Select all rows\")}\n data-test=\"select-all\"\n checked={selection.allSelected}\n onCheckedChange={() => selection.toggleAll()}\n />\n </div>\n )}\n {columns.map((column, index) => (\n <ColumnHeader\n column={column}\n key={column.key}\n processing={processing}\n resizeHandleProps={\n resizingEnabled ? getResizeHandleProps(sizingColumns[index]) : undefined\n }\n sort={sort}\n state={state}\n />\n ))}\n {hasTrailingUtility && (\n <div\n className=\"flex items-center justify-end gap-2 px-4 py-2 align-middle font-semibold text-lt-fg\"\n role=\"columnheader\"\n >\n {hasDedicatedFilters && (\n <FilterMenu\n filters={filterDefinitions}\n values={tableFilters}\n processing={processing}\n onChange={setTableFilter}\n onSearch={searchFilterOptions}\n />\n )}\n {hasActions && <span className=\"sr-only\">{node.props?.actionsLabel}</span>}\n </div>\n )}\n </div>\n {hasFilters && (\n <div\n className=\"hidden min-w-full border-t border-lt-border md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n {columns.map((column) => (\n <div key={column.key} className=\"min-w-0 px-2 py-2\" role=\"cell\">\n {column.filter?.enabled && (\n <ColumnFilterControl\n column={column}\n clauses={filterEntries.filter((entry) => entry.clause.field === column.key)}\n processing={processing}\n onAdd={addFilter}\n onUpdate={updateFilter}\n onRemove={removeFilter}\n onReplace={replaceColumnFilters}\n onSearch={(query) => searchFilterOptions(column.key, query)}\n />\n )}\n </div>\n ))}\n {hasTrailingUtility && <div className=\"px-4 py-2\" role=\"cell\" />}\n </div>\n )}\n </div>\n <div role=\"rowgroup\">\n {!hasLoaded ? (\n <div className=\"p-4 text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{t(\"table.loading\", \"Loading rows...\")}</div>\n </div>\n ) : rowEntries.length === 0 ? (\n <div className=\"p-8 text-center text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{node.props?.emptyLabel}</div>\n </div>\n ) : (\n rowEntries.map(({ row, actions, key }) => {\n return (\n <div\n key={key}\n className={`grid grid-cols-1 border-b border-lt-border last:border-b-0 md:grid-cols-[var(--lattice-table-columns)] ${\n striped ? \"odd:bg-lt-muted/30\" : \"\"\n }`}\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center p-4\" role=\"cell\">\n <Checkbox\n aria-label={t(\"table.selectRow\", \"Select row {{key}}\", { key })}\n data-test={`select-row-${key}`}\n checked={selection.isSelected(key)}\n onCheckedChange={() => selection.toggle(key)}\n />\n </div>\n )}\n {columns.map((column) => (\n <div\n key={column.key}\n className={cn(\n \"grid min-w-0 gap-1 overflow-hidden p-4 align-middle\",\n alignText(column.align),\n alignJustifyItems(column.align),\n )}\n role=\"cell\"\n >\n <span\n aria-hidden=\"true\"\n className=\"text-xs font-medium text-lt-muted-fg md:hidden\"\n >\n {column.label}\n </span>\n <div\n data-slot=\"table-cell-content\"\n className=\"min-w-0 max-w-full overflow-hidden truncate\"\n >\n <ColumnCell column={column} row={row} />\n </div>\n </div>\n ))}\n {hasTrailingUtility && (\n <div\n className={cn(\n \"items-center justify-start gap-2 p-4 md:justify-end\",\n actions.length > 0 ? \"flex\" : \"hidden md:flex\",\n )}\n role=\"cell\"\n >\n {actions.map((action, actionIndex) => (\n <TableActionNode\n key={action.key ?? action.id ?? actionIndex}\n node={action}\n />\n ))}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n {hasLoaded && (\n <TablePagination\n pagination={pagination}\n currentPage={currentPage}\n processing={processing}\n mode={mode}\n hasNextPage={hasNextPage}\n visiblePages={visiblePages}\n infiniteLoaderRef={infiniteLoaderRef}\n onPage={goToPage}\n onLoadMore={loadMore}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport default TableComponent;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table.js","names":[],"sources":["../../../resources/js/table/components/table.tsx"],"sourcesContent":["import { type ReactNode, useMemo } from \"react\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useColumnResizing } from \"@lattice-php/lattice/core/use-column-resizing\";\nimport { useColumnVisibility } from \"@lattice-php/lattice/core/use-column-visibility\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { Checkbox } from \"@lattice-php/lattice/core/components/checkbox\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { alignJustifyItems, alignText } from \"../align\";\nimport type { TableNode } from \"../types\";\nimport { getBulkActions } from \"../bulk\";\nimport { flattenColumns, getRowActions, getRowKey } from \"../payload\";\nimport {\n getQueryParams,\n getTableSizingColumns,\n getTableUtilityTracks,\n getVisiblePages,\n} from \"../query\";\nimport { useTable } from \"../use-table\";\nimport { useTableSelection } from \"../use-table-selection\";\nimport { BulkBar } from \"./bulk-bar\";\nimport { ColumnFilterControl } from \"./column-filter-control\";\nimport { ColumnHeader } from \"./column-header\";\nimport { ColumnVisibilityMenu } from \"./column-visibility-menu\";\nimport { FilterBar, FilterMenu } from \"./filter-bar\";\nimport { FilterStackBar } from \"./filter-stack-bar\";\nimport { TablePagination } from \"./pagination\";\nimport { SortBar } from \"./sort-bar\";\nimport { TableActionNode } from \"./table-action-node\";\nimport { ColumnCell } from \"./table-cell\";\n\nconst TableComponent = ({ node }: { children?: ReactNode; node: TableNode }) => {\n const { t } = useT(\"lattice\");\n const {\n columns,\n rows,\n pagination,\n state,\n filters,\n tableFilters,\n addFilter,\n updateFilter,\n removeFilter,\n replaceColumnFilters,\n setTableFilter,\n resetFilters,\n searchFilterOptions,\n processing,\n hasLoaded,\n infiniteLoaderRef,\n sort,\n clearSort,\n goToPage,\n loadMore,\n } = useTable(node);\n\n const bulkActions = useMemo(\n () => getBulkActions(node.props?.bulkActions),\n [node.props?.bulkActions],\n );\n const hasBulkActions = bulkActions.length > 0;\n const rowEntries = useMemo(\n () =>\n rows.map((row, index) => ({ row, actions: getRowActions(row), key: getRowKey(row, index) })),\n [rows],\n );\n const selection = useTableSelection(rowEntries.map((entry) => entry.key));\n\n const columnsByKey = useMemo(\n () => new Map(flattenColumns(columns).map((column) => [column.key, column])),\n [columns],\n );\n const visibilityIdentity = nodeIdentity(node);\n const {\n hasToggleableColumns,\n hasHidden,\n isVisible,\n resetVisibility,\n setColumnVisible,\n toggleableColumns,\n visibleColumns,\n } = useColumnVisibility({\n columns,\n storageKey: visibilityIdentity\n ? `lattice:table-column-visibility:${visibilityIdentity}`\n : undefined,\n });\n const currentPage = pagination.currentPage ?? state.page;\n const lastPage = pagination.lastPage ?? currentPage;\n const mode = pagination.mode ?? \"table\";\n const visiblePages = getVisiblePages(currentPage, lastPage);\n const hasNextPage = pagination.hasMore ?? currentPage < lastPage;\n const hasActions = rowEntries.some((entry) => entry.actions.length > 0);\n const striped = node.props?.striped === true;\n const hasFilters = visibleColumns.some((column) => column.filter?.enabled);\n const filterEntries = filters.map((clause, index) => ({ clause, index }));\n const filterDefinitions = useMemo(\n () => (Array.isArray(node.props?.filters) ? node.props.filters : []),\n [node.props?.filters],\n );\n const hasDedicatedFilters = filterDefinitions.length > 0;\n const hasActiveFilters = filters.length > 0 || Object.keys(tableFilters).length > 0;\n const hasTrailingUtility = hasActions || hasDedicatedFilters || hasToggleableColumns;\n const sizingColumns = useMemo(() => getTableSizingColumns(visibleColumns), [visibleColumns]);\n const utilityTracks = useMemo(\n () => getTableUtilityTracks(hasTrailingUtility, hasBulkActions),\n [hasTrailingUtility, hasBulkActions],\n );\n const resizingEnabled = node.props?.resizableColumns === true;\n const resizeStorageIdentity = nodeIdentity(node);\n const { getResizeHandleProps, gridTemplateColumns, hasOverrides, resetColumns } =\n useColumnResizing({\n columns: sizingColumns,\n enabled: resizingEnabled,\n leadingTracks: utilityTracks.leadingTracks,\n showIndicator: node.props?.resizeIndicator === true,\n storageKey:\n resizingEnabled && resizeStorageIdentity\n ? `lattice:table-columns:${resizeStorageIdentity}`\n : undefined,\n trailingTracks: utilityTracks.trailingTracks,\n });\n\n return (\n <div data-lattice-component={node.id} className=\"relative\">\n {hasOverrides && (\n <button\n aria-label={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n className=\"absolute right-1 top-1 z-10 hidden rounded-lt-sm p-1 text-lt-muted-fg hover:text-lt-fg md:inline-flex\"\n data-test=\"table-reset-columns\"\n onClick={resetColumns}\n title={t(\"table.resetColumnWidths\", \"Reset column widths\")}\n type=\"button\"\n >\n <Icon name=\"rotate-ccw\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n <div className=\"overflow-x-auto rounded-lt-sm border border-lt-border\">\n {hasDedicatedFilters && hasActiveFilters && (\n <FilterBar\n filters={filterDefinitions}\n values={tableFilters}\n processing={processing}\n hasActiveFilters={hasActiveFilters}\n onChange={setTableFilter}\n onReset={resetFilters}\n />\n )}\n {hasBulkActions && selection.active && (\n <BulkBar\n actions={bulkActions}\n selectedKeys={selection.selectedKeys}\n allMatching={selection.allMatching}\n total={pagination.total ?? undefined}\n query={getQueryParams(state)}\n canSelectAllMatching={\n selection.allVisibleSelected &&\n !selection.allMatching &&\n pagination.total != null &&\n pagination.total > selection.selectedKeys.length\n }\n onSelectAllMatching={selection.selectAllMatching}\n onCompleted={selection.clear}\n />\n )}\n {filters.length > 0 && (\n <FilterStackBar\n filters={filters}\n columnsByKey={columnsByKey}\n processing={processing}\n onRemove={removeFilter}\n />\n )}\n {state.sorts.length > 0 && (\n <SortBar\n columnsByKey={columnsByKey}\n state={state}\n processing={processing}\n onClear={clearSort}\n />\n )}\n <div className=\"min-w-full text-base\" role=\"table\">\n <div className=\"border-b border-lt-border bg-lt-muted/50\" role=\"rowgroup\">\n <div\n className=\"hidden min-w-full md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center px-4 py-3\" role=\"columnheader\">\n <Checkbox\n aria-label={t(\"table.selectAllRows\", \"Select all rows\")}\n data-test=\"select-all\"\n checked={selection.allSelected}\n onCheckedChange={() => selection.toggleAll()}\n />\n </div>\n )}\n {visibleColumns.map((column, index) => (\n <ColumnHeader\n column={column}\n key={column.key}\n processing={processing}\n resizeHandleProps={\n resizingEnabled ? getResizeHandleProps(sizingColumns[index]) : undefined\n }\n sort={sort}\n state={state}\n />\n ))}\n {hasTrailingUtility && (\n <div\n className=\"flex items-center justify-end gap-2 px-4 py-2 align-middle font-semibold text-lt-fg\"\n role=\"columnheader\"\n >\n {hasDedicatedFilters && (\n <FilterMenu\n filters={filterDefinitions}\n values={tableFilters}\n processing={processing}\n onChange={setTableFilter}\n onSearch={searchFilterOptions}\n />\n )}\n {hasToggleableColumns && (\n <ColumnVisibilityMenu\n columns={toggleableColumns}\n isVisible={isVisible}\n visibleColumnCount={visibleColumns.length}\n hasHidden={hasHidden}\n onToggle={setColumnVisible}\n onReset={resetVisibility}\n processing={processing}\n />\n )}\n {hasActions && <span className=\"sr-only\">{node.props?.actionsLabel}</span>}\n </div>\n )}\n </div>\n {hasFilters && (\n <div\n className=\"hidden min-w-full border-t border-lt-border md:grid md:grid-cols-[var(--lattice-table-columns)]\"\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && <div className=\"px-4 py-2\" role=\"cell\" />}\n {visibleColumns.map((column) => (\n <div key={column.key} className=\"min-w-0 px-2 py-2\" role=\"cell\">\n {column.filter?.enabled && (\n <ColumnFilterControl\n column={column}\n clauses={filterEntries.filter((entry) => entry.clause.field === column.key)}\n processing={processing}\n onAdd={addFilter}\n onUpdate={updateFilter}\n onRemove={removeFilter}\n onReplace={replaceColumnFilters}\n onSearch={(query) => searchFilterOptions(column.key, query)}\n />\n )}\n </div>\n ))}\n {hasTrailingUtility && <div className=\"px-4 py-2\" role=\"cell\" />}\n </div>\n )}\n </div>\n <div role=\"rowgroup\">\n {!hasLoaded ? (\n <div className=\"p-4 text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{t(\"table.loading\", \"Loading rows...\")}</div>\n </div>\n ) : rowEntries.length === 0 ? (\n <div className=\"p-8 text-center text-lt-muted-fg\" role=\"row\">\n <div role=\"cell\">{node.props?.emptyLabel}</div>\n </div>\n ) : (\n rowEntries.map(({ row, actions, key }) => {\n return (\n <div\n key={key}\n className={`grid grid-cols-1 border-b border-lt-border last:border-b-0 md:grid-cols-[var(--lattice-table-columns)] ${\n striped ? \"odd:bg-lt-muted/30\" : \"\"\n }`}\n role=\"row\"\n style={{ \"--lattice-table-columns\": gridTemplateColumns } as never}\n >\n {hasBulkActions && (\n <div className=\"flex items-center p-4\" role=\"cell\">\n <Checkbox\n aria-label={t(\"table.selectRow\", \"Select row {{key}}\", { key })}\n data-test={`select-row-${key}`}\n checked={selection.isSelected(key)}\n onCheckedChange={() => selection.toggle(key)}\n />\n </div>\n )}\n {visibleColumns.map((column) => (\n <div\n key={column.key}\n className={cn(\n \"grid min-w-0 gap-1 overflow-hidden p-4 align-middle\",\n alignText(column.align),\n alignJustifyItems(column.align),\n )}\n role=\"cell\"\n >\n <span\n aria-hidden=\"true\"\n className=\"text-xs font-medium text-lt-muted-fg md:hidden\"\n >\n {column.label}\n </span>\n <div\n data-slot=\"table-cell-content\"\n className=\"min-w-0 max-w-full overflow-hidden truncate\"\n >\n <ColumnCell column={column} row={row} />\n </div>\n </div>\n ))}\n {hasTrailingUtility && (\n <div\n className={cn(\n \"items-center justify-start gap-2 p-4 md:justify-end\",\n actions.length > 0 ? \"flex\" : \"hidden md:flex\",\n )}\n role=\"cell\"\n >\n {actions.map((action, actionIndex) => (\n <TableActionNode\n key={action.key ?? action.id ?? actionIndex}\n node={action}\n />\n ))}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n {hasLoaded && (\n <TablePagination\n pagination={pagination}\n currentPage={currentPage}\n processing={processing}\n mode={mode}\n hasNextPage={hasNextPage}\n visiblePages={visiblePages}\n infiniteLoaderRef={infiniteLoaderRef}\n onPage={goToPage}\n onLoadMore={loadMore}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport default TableComponent;\n"],"mappings":"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"}
|
|
@@ -228,6 +228,11 @@ export type Choice = {
|
|
|
228
228
|
export type CloseModalEffect = {
|
|
229
229
|
readonly modal: string | null;
|
|
230
230
|
};
|
|
231
|
+
export type Collapsible = {
|
|
232
|
+
collapsed: boolean;
|
|
233
|
+
rememberState: boolean;
|
|
234
|
+
trigger: Node[];
|
|
235
|
+
};
|
|
231
236
|
export type Color = "default" | "muted" | "primary" | "success" | "info" | "warning" | "danger";
|
|
232
237
|
export type ColumnAlign = "start" | "center" | "end";
|
|
233
238
|
export type ColumnData = {
|
|
@@ -237,6 +242,8 @@ export type ColumnData = {
|
|
|
237
242
|
readonly width: ColumnWidth;
|
|
238
243
|
readonly align: ColumnAlign;
|
|
239
244
|
readonly sortable: boolean | null;
|
|
245
|
+
readonly toggleable: boolean | null;
|
|
246
|
+
readonly hiddenByDefault: boolean | null;
|
|
240
247
|
readonly filter: ColumnFilter | null;
|
|
241
248
|
readonly columns: ColumnData[] | null;
|
|
242
249
|
readonly props: Record<string, unknown> | null;
|
|
@@ -300,6 +307,11 @@ export type CoreNode = {
|
|
|
300
307
|
type: "chart";
|
|
301
308
|
key?: string;
|
|
302
309
|
props: Chart;
|
|
310
|
+
} | {
|
|
311
|
+
type: "collapsible";
|
|
312
|
+
key?: string;
|
|
313
|
+
props: Collapsible;
|
|
314
|
+
schema?: Node[];
|
|
303
315
|
} | {
|
|
304
316
|
type: "floating-panel";
|
|
305
317
|
key?: string;
|
|
@@ -1086,6 +1098,7 @@ export type TabsAlignment = "start" | "center" | "end" | "stretch";
|
|
|
1086
1098
|
export type Text = {
|
|
1087
1099
|
align: Align | null;
|
|
1088
1100
|
color: Color;
|
|
1101
|
+
copyable: boolean;
|
|
1089
1102
|
size: Size;
|
|
1090
1103
|
text: string;
|
|
1091
1104
|
};
|