UNPKG

laif-ds

Version:

Design System di Laif con componenti React basati su principi di Atomic Design

461 lines (460 loc) 13.2 kB
"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 };