laif-ds
Version:
Design System di Laif con componenti React basati su principi di Atomic Design
674 lines (673 loc) • 18.4 kB
JavaScript
"use client";
import { jsx as p, jsxs as C, Fragment as K } from "react/jsx-runtime";
import { useId as $, useRef as P, useCallback as h, useMemo as S, createContext as V, useState as w, useLayoutEffect as q, useEffect as E, useContext as _ } from "react";
import { createPortal as U } from "react-dom";
import { Button as O } from "./button.js";
import { Popover as W, PopoverTrigger as Y, PopoverContent as J } from "./popover.js";
import { TooltipProvider as G } from "./tooltip.js";
import { Typo as z } from "./typo.js";
import { cn as D } from "../../lib/utils.js";
import X from "../../node_modules/lucide-react/dist/esm/icons/pencil.js";
import Q from "../../node_modules/lucide-react/dist/esm/icons/ellipsis-vertical.js";
const M = V(void 0);
function Z(e) {
const r = _(M);
if (!r)
throw new Error("useDndMonitor must be used within a DndMonitorProvider");
const { registerMonitor: l, unregisterMonitor: t } = r;
E(() => (l(e), () => {
t(e);
}), [e, l, t]);
}
function L() {
const e = _(M);
if (!e)
throw new Error("useDndEvents must be used within a DndMonitorProvider");
const { activeIdRef: r, draggableDescribedById: l, triggerEvent: t } = e, u = h(
(i) => {
r.current = i, t("onDragStart", i);
},
[t, r]
), d = h(
(i, n) => {
t("onDragMove", i, n);
},
[t]
), g = h(
(i, n) => {
const c = i || r.current;
t("onDragOver", c, n);
},
[t, r]
), a = h(
(i, n) => {
t("onDragEnd", i, n);
},
[t]
), m = h(
(i) => {
t("onDragCancel", i);
},
[t]
);
return {
draggableDescribedById: l,
onDragStart: u,
onDragMove: d,
onDragOver: g,
onDragEnd: a,
onDragCancel: m
};
}
const ee = `
To pick up a draggable item, press the space bar.
While dragging, use the arrow keys to move the item.
Press space again to drop the item in its new position, or press escape to cancel.
`, re = {
onDragStart(e) {
return `Picked up draggable item ${e}.`;
},
onDragOver(e, r) {
return r ? `Draggable item ${e} was moved over droppable area ${r}.` : `Draggable item ${e} is no longer over a droppable area.`;
},
onDragEnd(e, r) {
return r ? `Draggable item ${e} was dropped over droppable area ${r}` : `Draggable item ${e} was dropped.`;
},
onDragCancel(e) {
return `Dragging was cancelled. Draggable item ${e} was dropped.`;
}
};
function te({
announcement: e,
ariaLiveType: r = "assertive",
className: l,
id: t,
ref: u,
...d
}) {
return /* @__PURE__ */ p(
"div",
{
"aria-live": r,
"aria-atomic": !0,
className: D(
"clip-[rect(0_0_0_0)] clip-path-[inset(100%)] fixed top-0 left-0 -m-px h-px w-px overflow-hidden border-0 p-0 whitespace-nowrap",
l
),
id: t,
ref: u,
role: "status",
...d,
children: e
}
);
}
function ne({
id: e,
value: r,
className: l,
ref: t,
...u
}) {
return /* @__PURE__ */ p("div", { id: e, className: D("hidden", l), ref: t, ...u, children: r });
}
function oe() {
const [e, r] = w("");
return { announce: h((t) => {
t != null && r(t);
}, []), announcement: e };
}
const ae = ({
announcements: e = re,
container: r,
hiddenTextDescribedById: l,
screenReaderInstructions: t = ee
}) => {
const { announce: u, announcement: d } = oe(), g = $(), [a, m] = w(!1);
if (E(() => {
m(!0);
}, []), Z(
S(
() => ({
onDragStart(n) {
u(e.onDragStart(n));
},
onDragMove(n, c) {
e.onDragMove && u(e.onDragMove(n, c));
},
onDragOver(n, c) {
u(e.onDragOver(n, c));
},
onDragEnd(n, c) {
u(e.onDragEnd(n, c));
},
onDragCancel(n) {
u(e.onDragCancel(n));
}
}),
[u, e]
)
), !a)
return null;
const i = /* @__PURE__ */ C(K, { children: [
/* @__PURE__ */ p(
ne,
{
id: l,
value: t
}
),
/* @__PURE__ */ p(te, { id: g, announcement: d })
] });
return r ? U(i, r) : i;
}, ve = ({
announcements: e,
screenReaderInstructions: r,
container: l,
children: t
}) => {
const u = $(), d = P([]), g = P(""), a = h(
(c) => {
d.current.push(c);
},
[]
), m = h(
(c) => {
d.current = d.current.filter(
(f) => f !== c
);
},
[]
), i = h(
(c, f, y) => {
for (const T of d.current) {
const s = T[c];
s && s(f, y);
}
},
[]
), n = S(
() => ({
activeIdRef: g,
draggableDescribedById: u,
registerMonitor: a,
unregisterMonitor: m,
triggerEvent: i
}),
[
g,
u,
a,
m,
i
]
);
return /* @__PURE__ */ p(G, { children: /* @__PURE__ */ C(M.Provider, { value: n, children: [
t,
/* @__PURE__ */ p(
ae,
{
announcements: e,
screenReaderInstructions: r,
container: l,
hiddenTextDescribedById: u
}
)
] }) });
}, N = {
CARD: "kanban-board-card"
}, A = 48, H = 28;
function I(e, r) {
e && (typeof e == "function" ? e(r) : e.current = r);
}
function j(e) {
const r = e.dataTransfer?.types;
return r ? Array.from(r).includes(N.CARD) : !1;
}
function F(e, r, l) {
const t = e.getBoundingClientRect(), u = r === "x" ? t.left : t.top, d = r === "x" ? t.right : t.bottom, g = l - u, a = d - l, m = r === "x" ? "scrollLeft" : "scrollTop", i = r === "x" ? e.scrollWidth - e.clientWidth : e.scrollHeight - e.clientHeight, n = e[m];
if (g < A && n > 0) {
const c = H * ((A - g) / A);
e[m] = n - Math.ceil(c);
return;
}
if (a < A && n < i) {
const c = H * ((A - a) / A);
e[m] = n + Math.ceil(c);
}
}
function xe({
className: e,
ref: r,
onDragOverCapture: l,
style: t,
...u
}) {
const d = P(null), [g, a] = w(null), m = P(null), i = P(null), n = h((s) => {
m.current !== s && (m.current = s, a(s));
}, []), c = h(() => {
const s = d.current;
if (!s) return;
if (t && Object.prototype.hasOwnProperty.call(t, "--kanban-column-min-height")) {
n(null);
return;
}
if (Array.from(
s.querySelectorAll('[data-kanban-column-list="true"]')
).some(
(k) => k.scrollHeight > k.clientHeight + 1
)) {
n(null);
return;
}
const o = Array.from(
s.querySelectorAll('[data-kanban-column="true"]')
);
if (!o.length) {
n(null);
return;
}
const b = s.style.getPropertyValue(
"--kanban-column-min-height"
);
b && s.style.setProperty("--kanban-column-min-height", "0px");
let x = 0;
for (const k of o)
x = Math.max(x, k.scrollHeight);
b && s.style.setProperty("--kanban-column-min-height", b);
const B = Math.ceil(x);
n(
Number.isFinite(B) && B > 0 ? B : 0
);
}, [n, t]), f = h(() => {
i.current === null && (i.current = requestAnimationFrame(() => {
i.current = null, c();
}));
}, [c]);
q(() => {
f();
}, [f]), E(() => {
const s = d.current;
if (!s) return;
const v = () => f(), R = new ResizeObserver(v);
R.observe(s);
const o = new MutationObserver(v);
return o.observe(s, { childList: !0, subtree: !0 }), window.addEventListener("resize", v), () => {
R.disconnect(), o.disconnect(), window.removeEventListener("resize", v), i.current !== null && cancelAnimationFrame(i.current);
};
}, [f]);
const y = h(
(s) => {
j(s) && d.current && F(d.current, "x", s.clientX), l?.(s);
},
[l]
), T = S(() => {
const s = t ? { ...t } : void 0, v = s && Object.prototype.hasOwnProperty.call(
s,
"--kanban-column-min-height"
);
return !v && g && s && (s["--kanban-column-min-height"] = `${g}px`), !v && g && !s ? {
"--kanban-column-min-height": `${g}px`
} : s;
}, [g, t]);
return /* @__PURE__ */ p(
"div",
{
className: D(
"relative flex h-full w-full flex-1 items-stretch gap-x-4 overflow-x-auto py-2 pr-2 select-none",
e
),
"data-kanban-board": "true",
draggable: !1,
onDragStart: (s) => {
s.preventDefault(), s.stopPropagation();
},
onDragOverCapture: y,
ref: (s) => {
d.current = s, I(r, s);
},
style: T,
...u
}
);
}
const se = "relative flex h-full min-w-[16rem] flex-[1_0_18rem] flex-col rounded-2xl border border-d-border/60 bg-d-sidebar/80 p-1.5 shadow-sm backdrop-blur transition-colors min-h-[var(--kanban-column-min-height,0px)]";
function ye({
className: e,
columnId: r,
disabled: l = !1,
onDropOverColumn: t,
ref: u,
...d
}) {
const [g, a] = w(!1), [m, i] = w(!1), { onDragEnd: n, onDragOver: c } = L();
return /* @__PURE__ */ p(
"section",
{
"aria-labelledby": `column-${r}-title`,
className: D(
se,
g && "border-d-primary/80 bg-d-primary/10 ring-d-primary/30 ring-2",
m && "border-d-destructive/70 bg-d-destructive/10 ring-d-destructive/20 ring-2",
e
),
"aria-disabled": l,
"data-kanban-column": "true",
draggable: !1,
onDragStart: (f) => {
f.preventDefault(), f.stopPropagation();
},
onDragLeave: () => {
a(!1), i(!1);
},
onDragOver: (f) => {
if (f.dataTransfer.types.includes(N.CARD)) {
if (l) {
a(!1), i(!0);
return;
}
f.preventDefault(), i(!1), a(!0), c("", r);
}
},
onDrop: (f) => {
if (f.dataTransfer.types.includes(N.CARD)) {
if (l) {
a(!1), i(!1);
return;
}
f.preventDefault(), a(!1), i(!1);
const y = f.dataTransfer.getData(N.CARD);
t?.(y), n("", r);
}
},
ref: u,
...d
}
);
}
function Ce({
className: e,
ref: r,
...l
}) {
return /* @__PURE__ */ p(
"div",
{
className: D("flex items-center justify-between px-2 py-1", e),
ref: r,
...l
}
);
}
function we({
className: e,
ref: r,
dropDisabled: l = !1,
onDragOverCapture: t,
...u
}) {
const d = P(null), g = h(
(a) => {
if (l) {
t?.(a);
return;
}
j(a) && d.current && F(d.current, "y", a.clientY), t?.(a);
},
[l, t]
);
return /* @__PURE__ */ p(
"ul",
{
className: D("min-h-0 flex-1 overflow-y-auto", e),
"data-kanban-column-list": "true",
onDragOverCapture: g,
ref: (a) => {
d.current = a, I(r, a);
},
...u
}
);
}
const ie = "-mb-[2px] rounded-xl border-b-2 border-t-2 border-b-transparent border-t-transparent px-2 py-1 last:mb-0 transition-colors";
function Ne({
cardId: e,
className: r,
dropDisabled: l = !1,
onDropOverListItem: t,
ref: u,
...d
}) {
const [g, a] = w("none"), { onDragOver: m, onDragEnd: i } = L();
return /* @__PURE__ */ p(
"li",
{
className: D(
ie,
g === "top" && "border-t-d-primary !border-t-[3px]",
g === "bottom" && "border-b-d-primary !border-b-[3px]",
r
),
onDragLeave: () => {
a("none");
},
onDragOver: (n) => {
if (!l && n.dataTransfer.types.includes(N.CARD)) {
n.preventDefault(), n.stopPropagation();
const c = n.currentTarget.getBoundingClientRect(), f = (c.top + c.bottom) / 2;
a(n.clientY <= f ? "top" : "bottom"), m("", e);
}
},
onDrop: (n) => {
if (l) return;
n.stopPropagation();
const c = n.dataTransfer.getData(N.CARD);
t?.(c, g), i(JSON.parse(c).id, e), a("none");
},
ref: u,
...d
}
);
}
const le = "p-2.5 text-start";
function Te({
className: e,
data: r,
isActive: l = !1,
dragDisabled: t = !1,
onEdit: u,
actions: d,
meta: g,
backgroundColor: a,
ref: m,
children: i,
...n
}) {
const [c, f] = w(!1), [y, T] = w(!1), { draggableDescribedById: s, onDragStart: v } = L(), R = u || d && d.length > 0;
return /* @__PURE__ */ C(
"div",
{
role: "button",
tabIndex: 0,
"aria-describedby": t ? void 0 : s,
"aria-roledescription": t ? void 0 : "draggable",
draggable: !t,
onDragStart: (o) => {
if (t) {
o.preventDefault(), o.stopPropagation();
return;
}
o.stopPropagation(), f(!0), o.dataTransfer.effectAllowed = "move", o.dataTransfer.setData(
N.CARD,
JSON.stringify(r)
);
const b = o.currentTarget.cloneNode(!0), x = o.currentTarget.getBoundingClientRect();
b.style.position = "absolute", b.style.top = "-9999px", b.style.width = `${x.width}px`, b.style.opacity = "0.8", document.body.appendChild(b), o.dataTransfer.setDragImage(
b,
x.width / 2,
x.height / 2
), setTimeout(() => document.body.removeChild(b), 0), o.currentTarget.blur(), v(r.id);
},
onDragEnd: () => {
f(!1);
},
onClick: (o) => {
c && (o.preventDefault(), o.stopPropagation());
},
onKeyDown: (o) => {
(o.key === "Enter" || o.key === " ") && o.preventDefault();
},
className: D(
"border-d-border text-d-card-foreground rounded-xl border shadow-sm",
!a && "bg-d-card/95",
le,
"focus-visible:ring-d-ring inline-flex w-full touch-manipulation flex-col gap-2 transition-all duration-200 focus-visible:ring-1 focus-visible:outline-none",
t ? "group/card relative cursor-default" : c ? "cursor-grabbing opacity-40 active:cursor-grabbing" : "group/card relative cursor-grab hover:-translate-y-0.5 hover:shadow-lg",
l && "rotate-1 transform shadow-lg",
e
),
style: {
backgroundColor: a ? `${a}18` : void 0,
borderColor: a ? `${a}35` : void 0,
...n.style
},
ref: m,
...n,
children: [
i,
g && g.length > 0 && /* @__PURE__ */ p("div", { className: "mt-1.5 flex flex-wrap gap-1.5", children: g.map((o, b) => /* @__PURE__ */ C(
"div",
{
className: "text-d-muted-foreground bg-d-muted/40 inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px]",
style: {
borderColor: a ? `${a}40` : void 0
},
children: [
/* @__PURE__ */ p("span", { className: "truncate font-medium", children: o.name }),
o.value && /* @__PURE__ */ C(K, { children: [
/* @__PURE__ */ p("span", { className: "opacity-60", children: "•" }),
/* @__PURE__ */ p("span", { className: "truncate opacity-80", children: o.value })
] })
]
},
b
)) }),
R && !c && /* @__PURE__ */ C(
"div",
{
className: D(
"bg-d-card border-d-border absolute top-2 right-2 items-center gap-1 rounded-md border p-0.5 shadow-sm",
y ? "flex" : "hidden group-focus-within/card:flex group-hover/card:flex"
),
children: [
u && /* @__PURE__ */ p(
O,
{
variant: "ghost",
size: "icon",
className: "hover:bg-d-accent size-6",
onClick: (o) => {
o.stopPropagation(), o.preventDefault(), c || u();
},
children: /* @__PURE__ */ p(X, { className: "size-3.5" })
}
),
d && d.length > 0 && /* @__PURE__ */ C(W, { open: y, onOpenChange: T, children: [
/* @__PURE__ */ p(Y, { asChild: !0, children: /* @__PURE__ */ p(
O,
{
variant: "ghost",
size: "icon",
className: "hover:bg-d-accent size-6",
onClick: (o) => {
o.stopPropagation();
},
children: /* @__PURE__ */ p(Q, { className: "size-3.5" })
}
) }),
/* @__PURE__ */ p(
J,
{
className: "w-48 p-1",
align: "end",
side: "bottom",
sideOffset: 8,
onClick: (o) => o.stopPropagation(),
children: /* @__PURE__ */ p("div", { className: "flex flex-col gap-0.5", children: d.map((o, b) => /* @__PURE__ */ C(
O,
{
variant: o.variant === "destructive" ? "ghost-destructive" : "ghost",
size: "sm",
className: "w-full justify-start gap-2",
onClick: (x) => {
x.stopPropagation(), x.preventDefault(), o.onClick(), T(!1);
},
children: [
o.icon && /* @__PURE__ */ p("span", { className: "size-4", children: o.icon }),
o.label
]
},
b
)) })
}
)
] })
]
}
)
]
}
);
}
function Ae({
className: e,
...r
}) {
return /* @__PURE__ */ p(
z,
{
variant: "small",
as: "h3",
className: D("text-sm font-semibold", e),
...r
}
);
}
function Pe({
className: e,
...r
}) {
return /* @__PURE__ */ p(
z,
{
variant: "caption",
as: "p",
className: D(
"text-d-muted-foreground leading-relaxed whitespace-pre-wrap",
e
),
...r
}
);
}
export {
xe as KanbanBoard,
ae as KanbanBoardAccessibility,
Te as KanbanBoardCard,
Pe as KanbanBoardCardDescription,
Ae as KanbanBoardCardTitle,
ye as KanbanBoardColumn,
Ce as KanbanBoardColumnHeader,
we as KanbanBoardColumnList,
Ne as KanbanBoardColumnListItem,
M as KanbanBoardContext,
ne as KanbanBoardHiddenText,
te as KanbanBoardLiveRegion,
ve as KanbanBoardProvider,
re as defaultAnnouncements,
ee as defaultScreenReaderInstructions,
se as kanbanBoardColumnClassNames,
ie as kanbanBoardColumnListItemClassNames,
oe as useAnnouncement,
L as useDndEvents
};