laif-ds
Version:
Design System di Laif con componenti React basati su principi di Atomic Design
461 lines (460 loc) • 13.2 kB
JavaScript
"use client";
import { jsx as r, jsxs as m, Fragment as T } from "react/jsx-runtime";
import { cva as v } from "../../../node_modules/class-variance-authority/dist/index.js";
import { motion as K } from "framer-motion";
import f, { useEffect as $, Fragment as B } from "react";
import { getNameOrUrl as z, getExt as F, getMimeFromFile as U, imageExts as W, isFile as D, getFileMetadata as q, getFormatIcon as G, formatMetadata as X } from "../../../lib/file-preview.js";
import { Button as H } from "../button.js";
import { DropdownMenu as J, DropdownMenuTrigger as Q, DropdownMenuContent as Y, DropdownMenuSeparator as Z, DropdownMenuItem as ee } from "../dropdown-menu.js";
import { Icon as P } from "../icon.js";
import { Spinner as te } from "../spinner.js";
import { cn as x } from "../../../lib/utils.js";
const re = {
layout: !0,
initial: { opacity: 0, y: "100%" },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: "100%" }
}, ae = v(
"group/file ring-d-ring focus-visible:ring-d-accent relative flex items-center gap-1.5 overflow-hidden rounded-md transition-colors focus-within:ring focus-visible:ring focus-visible:outline-none",
{
variants: {
variant: {
default: "bg-d-card border-d-muted border",
outline: "border-d-border bg-transparent border hover:bg-d-accent/50 hover:border-d-foreground/70",
ghost: "bg-transparent hover:bg-d-accent/50"
},
size: {
default: "max-w-48 p-0.5 text-sm",
sm: "max-w-36 p-0.5 text-xs"
}
},
defaultVariants: {
variant: "default",
size: "default"
}
}
), V = v(
"aspect-square h-full shrink-0 rounded-sm",
{
variants: {
size: {
default: "min-h-10 max-w-10 bg-d-secondary",
sm: "min-h-8 max-w-8"
}
},
defaultVariants: {
size: "default"
}
}
), ne = v("", {
variants: {
size: {
default: "h-5 w-5",
sm: "h-4 w-4"
}
},
defaultVariants: {
size: "default"
}
}), ie = v(
"flex max-w-full overflow-hidden whitespace-nowrap",
{
variants: {
size: {
default: "text-sm",
sm: "text-xs"
}
},
defaultVariants: {
size: "default"
}
}
), oe = v("text-d-muted-foreground", {
variants: {
size: {
default: "text-sm",
sm: "text-xs"
}
},
defaultVariants: {
size: "default"
}
}), se = v(
"hover:bg-d-accent hover:text-d-accent-foreground data-[state=open]:bg-d-accent data-[state=open]:text-d-accent-foreground cursor-pointer focus-visible:bg-d-accent rounded-r-sm focus-visible:outline-none",
{
variants: {
size: {
default: "h-full min-h-10 px-0.5",
sm: "h-full min-h-8 px-0.5"
}
},
defaultVariants: {
size: "default"
}
}
), le = v(
"absolute flex self-start overflow-visible rounded-sm p-0.5 text-xs opacity-0 group-hover/file:opacity-100 before:absolute before:top-0 before:right-1/2 before:-z-10 before:h-[400%] before:w-[300%] before:translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:bg-radial before:from-50% before:to-transparent before:to-80% before:blur-xs before:content-[''] focus-visible:opacity-100",
{
variants: {
variant: {
default: "bg-d-card hover:bg-d-card before:from-d-card",
outline: "bg-d-background hover:bg-d-background before:from-d-background",
ghost: "before:from-d-background"
},
size: {
default: "top-1 right-1 !size-4.5",
sm: "top-1 right-1 !size-4"
}
},
defaultVariants: {
variant: "default",
size: "default"
}
}
), j = f.createContext({ variant: "default", size: "default" }), N = () => f.useContext(j), I = ({
sizeLabel: e,
formatLabel: a
}) => {
const { size: o } = N(), t = X(e, a);
return t ? /* @__PURE__ */ r(
"div",
{
className: oe({ size: o }),
"aria-label": `${e ? `Size: ${e}` : ""}${e && a ? ", " : ""}${a ? `Format: ${a}` : ""}`,
children: t
}
) : null;
}, ce = ({
fileUrl: e,
fileName: a
}) => {
const { size: o } = N(), [t, n] = f.useState(e), s = F(a);
f.useEffect(() => {
n(e);
}, [e]);
const c = () => {
n(void 0);
};
return t ? /* @__PURE__ */ r(
"img",
{
alt: a,
className: x(V({ size: o }), "object-cover"),
width: 40,
height: 40,
loading: "lazy",
onError: c,
decoding: "async",
src: t
}
) : /* @__PURE__ */ r(k, { ext: s, mimeType: "image/*" });
}, k = ({
className: e,
ext: a,
mimeType: o
}) => {
const { size: t } = N(), { iconName: n, colorClass: s } = G(a ?? "", o);
return /* @__PURE__ */ r(
"div",
{
className: x(
V({ size: t }),
"flex items-center justify-center",
e
),
"aria-hidden": "true",
children: /* @__PURE__ */ r(
P,
{
name: n,
className: x(ne({ size: t }), s),
"aria-hidden": "true"
}
)
}
);
}, de = ({
url: e,
onPreview: a,
onDownload: o,
onRemove: t,
disabled: n = !1
}) => {
const { size: s } = N(), [c, h] = f.useState(!1), [b, g] = f.useState(
null
), u = [
{
key: "preview",
cond: !!a,
icon: "Presentation",
label: "Anteprima",
onSelect: a
},
{
key: "download",
cond: !!o,
icon: "Download",
label: "Download",
onSelect: o
},
{
key: "remove",
cond: !!t,
icon: "Trash",
label: "Elimina",
onSelect: t,
danger: !0
}
], w = async (i) => {
if (i.onSelect && !b)
try {
const d = i.onSelect(e);
typeof d?.then == "function" && (g(i.key), await d);
} catch (d) {
console.error(d);
} finally {
g(null), h(!1);
}
};
return /* @__PURE__ */ m(J, { onOpenChange: (i) => h(i), open: c, children: [
/* @__PURE__ */ r(
Q,
{
disabled: n || !e,
className: se({ size: s }),
"aria-label": "File actions",
onClick: (i) => i.stopPropagation(),
onKeyDown: (i) => i.stopPropagation(),
children: /* @__PURE__ */ r(
P,
{
name: "ChevronDown",
className: x(s === "sm" ? "size-3" : "size-4"),
"aria-hidden": "true"
}
)
}
),
/* @__PURE__ */ r(
Y,
{
align: "end",
onClick: (i) => i.stopPropagation(),
onPointerDown: (i) => i.stopPropagation(),
children: u.filter((i) => i.cond).map((i, d, y) => /* @__PURE__ */ m(B, { children: [
i.danger && y.length > 1 && /* @__PURE__ */ r(Z, {}),
/* @__PURE__ */ m(
ee,
{
onSelect: (S) => {
S.preventDefault(), w(i);
},
variant: i.danger ? "destructive" : "default",
disabled: !!b,
children: [
b === i.key ? /* @__PURE__ */ r(te, { size: "sm" }) : /* @__PURE__ */ r(P, { name: i.icon, size: "sm" }),
/* @__PURE__ */ r("span", { children: i.label })
]
}
)
] }, i.key))
}
)
] });
}, O = ({
name: e,
className: a
}) => {
const { size: o } = N(), t = e.lastIndexOf("."), n = t > 0 && t < e.length - 1, s = n ? e.slice(0, t) : e, c = n ? e.slice(t + 1) : "";
return /* @__PURE__ */ m(
"span",
{
className: x(ie({ size: o }), a),
title: e,
children: [
/* @__PURE__ */ r("span", { className: "shrink-1 truncate", children: s }),
c && /* @__PURE__ */ r("span", { className: "w-fit", children: `.${c}` })
]
}
);
}, Pe = f.forwardRef(
(e, a) => {
const o = z(e.file), t = F(o), n = U(e.file), s = t === "csv" || n === "text/csv";
return n && n.startsWith("image/") || t && W.has(t) ? /* @__PURE__ */ r(fe, { ...e, ref: a }) : !s && (t === "txt" || t === "md" || n && n.startsWith("text/")) ? /* @__PURE__ */ r(ue, { ...e, ref: a }) : /* @__PURE__ */ r(me, { ...e, ref: a });
}
), L = f.forwardRef(
({
file: e,
clickable: a = !0,
onRemove: o,
onPreview: t,
onDownload: n,
showActionMenu: s = !1,
className: c,
defaultClassName: h,
children: b,
onClick: g,
variant: u = "default",
size: w = "default"
}, i) => {
const [d, y] = f.useState(
() => D(e) ? "" : e.url
);
$(() => {
if (D(e)) {
const l = URL.createObjectURL(e);
return y(l), () => {
URL.revokeObjectURL(l);
};
} else
y(e.url);
}, [e]);
const S = q(e), R = z(e), M = !s && !!g, p = a && (!!t || M), E = async (l) => {
if (M) {
try {
await g(l);
} catch (C) {
console.error(C);
}
return;
}
if (t) {
try {
await t(d);
} catch (C) {
console.error(C);
}
return;
}
}, A = (l) => {
p && (l.stopPropagation(), E(l));
}, _ = (l) => {
p && (l.stopPropagation(), (l.key === "Enter" || l.key === " ") && (l.preventDefault(), E(l)));
};
return /* @__PURE__ */ r(
K.div,
{
ref: i,
role: p ? "button" : "group",
tabIndex: p ? 0 : -1,
"aria-label": `File: ${R}`,
className: x(
ae({ variant: u, size: w }),
p && "cursor-pointer",
h,
c
),
onClick: p ? A : void 0,
onKeyDown: p ? _ : void 0,
...re,
children: /* @__PURE__ */ m(j.Provider, { value: { variant: u, size: w }, children: [
/* @__PURE__ */ m("div", { className: "flex h-full w-full min-w-0 items-center gap-1", children: [
b(d, S),
s && /* @__PURE__ */ r(
de,
{
url: d,
onPreview: t,
onDownload: n,
onRemove: o,
disabled: !d
}
)
] }),
!s && o ? /* @__PURE__ */ r(
H,
{
className: le({ variant: u, size: w }),
variant: "ghost",
size: "icon",
"aria-label": `Remove ${R}`,
disabled: !d,
onClick: (l) => {
l.stopPropagation(), d && o(d);
},
children: /* @__PURE__ */ r(P, { name: "X", className: "size-full", "aria-hidden": "true" })
}
) : null
] })
}
);
}
), fe = f.forwardRef(({ showThumbnail: e = !0, ...a }, o) => {
const t = z(a.file);
return /* @__PURE__ */ r(L, { ...a, ref: o, children: (n, s) => /* @__PURE__ */ m(T, { children: [
e ? /* @__PURE__ */ r(ce, { fileUrl: n, fileName: t }) : /* @__PURE__ */ r(k, { ext: F(t), mimeType: "image/*" }),
/* @__PURE__ */ m("div", { className: "mr-1 flex min-w-0 flex-1 flex-col gap-0.5", children: [
/* @__PURE__ */ r(O, { name: t, className: "inline-flex min-w-0 flex-1" }),
/* @__PURE__ */ r(
I,
{
sizeLabel: s.sizeLabel,
formatLabel: s.formatLabel
}
)
] })
] }) });
}), ue = f.forwardRef(({ file: e, showThumbnail: a = !0, ...o }, t) => {
const [n, s] = f.useState(null), c = z(e), h = o.size ?? "default";
$(() => {
if (D(e)) {
const g = new FileReader();
return g.onload = (u) => {
u.target?.result && s(
typeof u.target.result == "string" ? u.target.result.slice(0, 100) : ""
);
}, g.readAsText(e), () => {
g.abort();
};
} else
s(null);
}, [e]);
const b = "text/plain";
return /* @__PURE__ */ r(L, { ...o, ref: t, file: e, children: (g, u) => /* @__PURE__ */ m(T, { children: [
n && a ? /* @__PURE__ */ r(
"div",
{
className: x(
V({ size: h }),
"flex items-start justify-start overflow-hidden p-0.5 leading-tight",
h === "sm" ? "text-[7px]" : "text-[8px]"
),
title: n,
"aria-label": "Text preview",
role: "img",
children: n
}
) : /* @__PURE__ */ r(k, { mimeType: b }),
/* @__PURE__ */ m("div", { className: "mr-1 min-w-0 flex-1", children: [
/* @__PURE__ */ r(O, { name: c, className: "inline-flex min-w-0 flex-1" }),
/* @__PURE__ */ r(
I,
{
sizeLabel: u.sizeLabel,
formatLabel: u.formatLabel
}
)
] })
] }) });
}), me = f.forwardRef((e, a) => {
const o = z(e.file), t = F(o), n = U(e.file);
return /* @__PURE__ */ r(L, { ...e, ref: a, children: (s, c) => /* @__PURE__ */ m(T, { children: [
/* @__PURE__ */ r(k, { ext: t, mimeType: n }),
/* @__PURE__ */ m("div", { className: "mr-1 flex min-w-0 flex-1 flex-col gap-0.5", children: [
/* @__PURE__ */ r(O, { name: o, className: "inline-flex min-w-0 flex-1" }),
/* @__PURE__ */ r(
I,
{
sizeLabel: c.sizeLabel,
formatLabel: c.formatLabel
}
)
] })
] }) });
});
export {
Pe as FilePreview,
me as GenericFilePreview,
fe as ImageFilePreview,
ue as TextFilePreview
};