@lattice-php/lattice 0.11.0 → 0.12.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/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/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/types/generated.d.ts +1 -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"}
|
|
@@ -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"}
|
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"}
|