@object-ui/plugin-kanban 3.1.2 → 3.1.4

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.
@@ -0,0 +1,396 @@
1
+ import { r as e, t } from "./plus-CAtTu4zt.js";
2
+ import { a as n, c as r, d as i, f as a, i as o, l as s, n as c, o as l, r as u, s as d, t as f, u as p } from "./sortable.esm-DzUCoMzQ.js";
3
+ import * as m from "react";
4
+ import { useDnd as h, useHasDndProvider as g } from "@object-ui/react";
5
+ import { Badge as _, Button as v, Card as y, CardContent as b, CardDescription as x, CardHeader as S, CardTitle as C, Input as w, ScrollArea as T } from "@object-ui/components";
6
+ //#region src/KanbanImpl.tsx
7
+ var E = e(), D = (...e) => e.filter(Boolean).join(" "), O = "Uncategorized";
8
+ function k(e, t) {
9
+ if (!t || t.length === 0) return {};
10
+ for (let n of t) {
11
+ let t = e[n.field];
12
+ if (t == null) continue;
13
+ let r = !1, i = String(t);
14
+ switch (n.operator) {
15
+ case "equals":
16
+ r = i === String(n.value);
17
+ break;
18
+ case "not_equals":
19
+ r = i !== String(n.value);
20
+ break;
21
+ case "contains":
22
+ r = i.toLowerCase().includes(String(n.value).toLowerCase());
23
+ break;
24
+ case "in":
25
+ r = Array.isArray(n.value) && n.value.includes(i);
26
+ break;
27
+ }
28
+ if (r) return {
29
+ ...n.backgroundColor ? { backgroundColor: n.backgroundColor } : {},
30
+ ...n.borderColor ? { borderColor: n.borderColor } : {}
31
+ };
32
+ }
33
+ return {};
34
+ }
35
+ function A({ card: e, onCardClick: t, conditionalFormatting: n }) {
36
+ let { attributes: r, listeners: i, setNodeRef: o, transform: s, transition: c, isDragging: l } = u({ id: e.id }), d = {
37
+ transform: a.Transform.toString(s),
38
+ transition: c,
39
+ opacity: l ? .5 : void 0
40
+ }, f = k(e, n);
41
+ return /* @__PURE__ */ (0, E.jsx)("div", {
42
+ ref: o,
43
+ style: d,
44
+ ...r,
45
+ ...i,
46
+ role: "listitem",
47
+ "aria-label": e.title,
48
+ onClick: () => t?.(e),
49
+ children: /* @__PURE__ */ (0, E.jsxs)(y, {
50
+ className: "mb-2 cursor-grab active:cursor-grabbing border-border border-l-4 border-l-primary/40 bg-card/60 hover:border-primary/40 hover:shadow-lg hover:shadow-primary/10 transition-all duration-300 group touch-manipulation",
51
+ style: f,
52
+ children: [
53
+ e.coverImage && /* @__PURE__ */ (0, E.jsx)("div", {
54
+ className: "w-full h-32 overflow-hidden rounded-t-lg",
55
+ children: /* @__PURE__ */ (0, E.jsx)("img", {
56
+ src: e.coverImage,
57
+ alt: "",
58
+ className: "w-full h-full object-cover",
59
+ loading: "lazy"
60
+ })
61
+ }),
62
+ /* @__PURE__ */ (0, E.jsxs)(S, {
63
+ className: "p-2 sm:p-4",
64
+ children: [/* @__PURE__ */ (0, E.jsx)(C, {
65
+ className: "text-xs sm:text-sm font-medium font-mono tracking-tight text-foreground group-hover:text-primary transition-colors",
66
+ children: e.title
67
+ }), e.description && /* @__PURE__ */ (0, E.jsx)(x, {
68
+ className: "text-xs text-muted-foreground font-mono line-clamp-2 sm:line-clamp-none",
69
+ children: e.description
70
+ })]
71
+ }),
72
+ e.badges && e.badges.length > 0 && /* @__PURE__ */ (0, E.jsx)(b, {
73
+ className: "p-2 sm:p-4 pt-0",
74
+ children: /* @__PURE__ */ (0, E.jsx)("div", {
75
+ className: "flex flex-wrap gap-1",
76
+ children: e.badges.map((e, t) => /* @__PURE__ */ (0, E.jsx)(_, {
77
+ variant: e.variant || "default",
78
+ className: "text-xs",
79
+ children: e.label
80
+ }, t))
81
+ })
82
+ })
83
+ ]
84
+ })
85
+ });
86
+ }
87
+ function j({ columnId: e, onAdd: n }) {
88
+ let [r, i] = m.useState(!1), [a, o] = m.useState(""), s = m.useRef(null), c = () => {
89
+ let t = a.trim();
90
+ t && (n(e, t), o("")), i(!1);
91
+ };
92
+ return r ? /* @__PURE__ */ (0, E.jsx)("div", {
93
+ className: "mt-2 space-y-2",
94
+ children: /* @__PURE__ */ (0, E.jsx)(w, {
95
+ ref: s,
96
+ value: a,
97
+ onChange: (e) => o(e.target.value),
98
+ onKeyDown: (e) => {
99
+ e.key === "Enter" ? (e.preventDefault(), c()) : e.key === "Escape" && (o(""), i(!1));
100
+ },
101
+ onBlur: c,
102
+ placeholder: "Enter card title...",
103
+ className: "text-sm",
104
+ autoFocus: !0
105
+ })
106
+ }) : /* @__PURE__ */ (0, E.jsxs)(v, {
107
+ variant: "ghost",
108
+ size: "sm",
109
+ className: "w-full mt-2 text-muted-foreground hover:text-foreground",
110
+ onClick: () => {
111
+ i(!0), setTimeout(() => s.current?.focus(), 0);
112
+ },
113
+ children: [/* @__PURE__ */ (0, E.jsx)(t, { className: "h-4 w-4 mr-1" }), "Add Card"]
114
+ });
115
+ }
116
+ function M({ column: e, cards: t, onCardClick: n, quickAdd: r, onQuickAdd: i, conditionalFormatting: a }) {
117
+ let s = t || [], { setNodeRef: c } = u({
118
+ id: e.id,
119
+ data: { type: "column" }
120
+ }), l = e.limit && s.length >= e.limit;
121
+ return /* @__PURE__ */ (0, E.jsxs)("div", {
122
+ ref: c,
123
+ role: "group",
124
+ "aria-label": e.title,
125
+ className: D("flex flex-col w-[85vw] sm:w-80 flex-shrink-0 rounded-lg border border-border bg-card/20 backdrop-blur-sm shadow-xl snap-start", e.className),
126
+ children: [/* @__PURE__ */ (0, E.jsx)("div", {
127
+ className: "p-3 sm:p-4 border-b border-border/50 bg-muted/30 rounded-t-lg",
128
+ children: /* @__PURE__ */ (0, E.jsxs)("div", {
129
+ className: "flex items-center justify-between",
130
+ children: [/* @__PURE__ */ (0, E.jsx)("h3", {
131
+ id: `kanban-col-${e.id}`,
132
+ className: "font-mono text-xs sm:text-sm font-semibold tracking-wider text-primary/90 uppercase truncate",
133
+ children: e.title
134
+ }), /* @__PURE__ */ (0, E.jsxs)("div", {
135
+ className: "flex items-center gap-2",
136
+ children: [/* @__PURE__ */ (0, E.jsxs)(_, {
137
+ variant: "secondary",
138
+ className: "text-xs font-mono tabular-nums",
139
+ children: [s.length, e.limit && ` / ${e.limit}`]
140
+ }), l && /* @__PURE__ */ (0, E.jsx)(_, {
141
+ variant: "destructive",
142
+ className: "text-xs",
143
+ children: "Full"
144
+ })]
145
+ })]
146
+ })
147
+ }), /* @__PURE__ */ (0, E.jsxs)(T, {
148
+ className: "flex-1 p-4",
149
+ children: [/* @__PURE__ */ (0, E.jsx)(f, {
150
+ items: s.map((e) => e.id),
151
+ strategy: o,
152
+ children: /* @__PURE__ */ (0, E.jsxs)("div", {
153
+ className: "space-y-2",
154
+ role: "list",
155
+ "aria-label": `${e.title} cards`,
156
+ children: [s.length === 0 && /* @__PURE__ */ (0, E.jsx)("div", {
157
+ className: "flex flex-col items-center justify-center py-8 text-muted-foreground/50",
158
+ children: /* @__PURE__ */ (0, E.jsx)("span", {
159
+ className: "text-xs font-mono",
160
+ children: "No cards"
161
+ })
162
+ }), s.map((e) => /* @__PURE__ */ (0, E.jsx)(A, {
163
+ card: e,
164
+ onCardClick: n,
165
+ conditionalFormatting: a
166
+ }, e.id))]
167
+ })
168
+ }), r && i && /* @__PURE__ */ (0, E.jsx)(j, {
169
+ columnId: e.id,
170
+ onAdd: i
171
+ })]
172
+ })]
173
+ });
174
+ }
175
+ function N({ children: e }) {
176
+ return /* @__PURE__ */ (0, E.jsx)(E.Fragment, { children: e(h()) });
177
+ }
178
+ function P({ columns: e, onCardMove: t, onCardClick: n, className: r, quickAdd: i, onQuickAdd: a, coverImageField: o, conditionalFormatting: s, swimlaneField: c }) {
179
+ return g() ? /* @__PURE__ */ (0, E.jsx)(N, { children: (l) => /* @__PURE__ */ (0, E.jsx)(F, {
180
+ columns: e,
181
+ onCardMove: t,
182
+ onCardClick: n,
183
+ className: r,
184
+ dnd: l,
185
+ quickAdd: i,
186
+ onQuickAdd: a,
187
+ coverImageField: o,
188
+ conditionalFormatting: s,
189
+ swimlaneField: c
190
+ }) }) : /* @__PURE__ */ (0, E.jsx)(F, {
191
+ columns: e,
192
+ onCardMove: t,
193
+ onCardClick: n,
194
+ className: r,
195
+ dnd: null,
196
+ quickAdd: i,
197
+ onQuickAdd: a,
198
+ coverImageField: o,
199
+ conditionalFormatting: s,
200
+ swimlaneField: c
201
+ });
202
+ }
203
+ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, quickAdd: g, onQuickAdd: _, coverImageField: v, conditionalFormatting: y, swimlaneField: b }) {
204
+ let [x, S] = m.useState(null), C = b ? `objectui:kanban-collapsed:${b}` : null, [w, T] = m.useState(() => {
205
+ if (!C) return /* @__PURE__ */ new Set();
206
+ try {
207
+ let e = localStorage.getItem(C);
208
+ if (e) {
209
+ let t = JSON.parse(e);
210
+ if (Array.isArray(t)) return new Set(t.filter((e) => typeof e == "string"));
211
+ }
212
+ } catch {}
213
+ return /* @__PURE__ */ new Set();
214
+ }), k = m.useMemo(() => (e || []).map((e) => ({
215
+ ...e,
216
+ cards: e.cards || []
217
+ })), [e]), [j, N] = m.useState(k);
218
+ m.useEffect(() => {
219
+ N(k);
220
+ }, [k]);
221
+ let P = m.useMemo(() => {
222
+ if (!b) return null;
223
+ let e = j.flatMap((e) => e.cards), t = /* @__PURE__ */ new Set();
224
+ return e.forEach((e) => {
225
+ let n = e[b];
226
+ t.add(n == null ? O : String(n));
227
+ }), Array.from(t).sort();
228
+ }, [j, b]), F = m.useCallback((e) => {
229
+ T((t) => {
230
+ let n = new Set(t);
231
+ if (n.has(e) ? n.delete(e) : n.add(e), C) try {
232
+ localStorage.setItem(C, JSON.stringify([...n]));
233
+ } catch {}
234
+ return n;
235
+ });
236
+ }, [C]), I = i(p(d, { activationConstraint: { distance: 5 } }), p(r, { activationConstraint: {
237
+ delay: 200,
238
+ tolerance: 5
239
+ } })), L = (e) => {
240
+ let { active: t } = e, n = z(t.id);
241
+ if (S(n), h && n) {
242
+ let e = B(n.id);
243
+ e && h.startDrag({
244
+ id: n.id,
245
+ type: "kanban-card",
246
+ data: n,
247
+ sourceId: e.id
248
+ });
249
+ }
250
+ }, R = (e) => {
251
+ let { active: n, over: r } = e;
252
+ if (S(null), !r) {
253
+ h && h.endDrag();
254
+ return;
255
+ }
256
+ let i = n.id, a = r.id;
257
+ if (i === a) {
258
+ h && h.endDrag();
259
+ return;
260
+ }
261
+ let o = B(i), s = B(a) || V(a);
262
+ if (!o || !s) {
263
+ h && h.endDrag();
264
+ return;
265
+ }
266
+ if (o.id === s.id) {
267
+ let e = [...o.cards], t = c(e, e.findIndex((e) => e.id === i), e.findIndex((e) => e.id === a));
268
+ N((e) => e.map((e) => e.id === o.id ? {
269
+ ...e,
270
+ cards: t
271
+ } : e));
272
+ } else {
273
+ let e = [...o.cards], n = [...s.cards], r = e.findIndex((e) => e.id === i), c = a === s.id ? n.length : n.findIndex((e) => e.id === a), [l] = e.splice(r, 1);
274
+ n.splice(c, 0, l), N((t) => t.map((t) => t.id === o.id ? {
275
+ ...t,
276
+ cards: e
277
+ } : t.id === s.id ? {
278
+ ...t,
279
+ cards: n
280
+ } : t)), t && t(i, o.id, s.id, c);
281
+ }
282
+ h && h.endDrag(s.id);
283
+ }, z = m.useCallback((e) => {
284
+ for (let t of j) {
285
+ let n = t.cards.find((t) => t.id === e);
286
+ if (n) return n;
287
+ }
288
+ return null;
289
+ }, [j]), B = m.useCallback((e) => j.find((t) => t.cards.some((t) => t.id === e)) || null, [j]), V = m.useCallback((e) => j.find((t) => t.id === e) || null, [j]);
290
+ return /* @__PURE__ */ (0, E.jsxs)(n, {
291
+ sensors: I,
292
+ collisionDetection: s,
293
+ onDragStart: L,
294
+ onDragEnd: R,
295
+ children: [
296
+ /* @__PURE__ */ (0, E.jsxs)("div", {
297
+ className: "flex sm:hidden items-center justify-between px-3 pb-2 text-xs text-muted-foreground",
298
+ children: [/* @__PURE__ */ (0, E.jsxs)("span", { children: [j.length, " columns"] }), /* @__PURE__ */ (0, E.jsx)("span", { children: "← Swipe to navigate →" })]
299
+ }),
300
+ P ? /* @__PURE__ */ (0, E.jsxs)("div", {
301
+ className: D("flex flex-col gap-1 p-2 sm:p-4 min-w-0 overflow-hidden", u),
302
+ role: "region",
303
+ "aria-label": "Kanban board with swimlanes",
304
+ children: [/* @__PURE__ */ (0, E.jsx)("div", {
305
+ className: "flex gap-3 sm:gap-4 pl-36 sm:pl-44 overflow-x-auto",
306
+ children: j.map((e) => /* @__PURE__ */ (0, E.jsxs)("div", {
307
+ className: "w-[85vw] sm:w-80 flex-shrink-0 text-center",
308
+ children: [/* @__PURE__ */ (0, E.jsx)("span", {
309
+ className: "font-mono text-xs sm:text-sm font-semibold tracking-wider text-primary/90 uppercase",
310
+ children: e.title
311
+ }), /* @__PURE__ */ (0, E.jsxs)("span", {
312
+ className: "ml-2 font-mono text-xs text-muted-foreground",
313
+ children: [
314
+ "(",
315
+ e.cards.length,
316
+ ")"
317
+ ]
318
+ })]
319
+ }, e.id))
320
+ }), P.map((e) => {
321
+ let t = w.has(e), n = j.reduce((t, n) => t + n.cards.filter((t) => (t[b] == null ? O : String(t[b])) === e).length, 0);
322
+ return /* @__PURE__ */ (0, E.jsxs)("div", {
323
+ className: "border rounded-lg bg-muted/10",
324
+ children: [/* @__PURE__ */ (0, E.jsxs)("button", {
325
+ className: "w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-muted/30 transition-colors",
326
+ onClick: () => F(e),
327
+ "aria-expanded": !t,
328
+ children: [
329
+ /* @__PURE__ */ (0, E.jsx)("span", {
330
+ className: D("transition-transform text-xs", t ? "" : "rotate-90"),
331
+ children: "▶"
332
+ }),
333
+ /* @__PURE__ */ (0, E.jsx)("span", {
334
+ className: "font-mono text-xs font-semibold text-muted-foreground uppercase tracking-wider",
335
+ children: e
336
+ }),
337
+ /* @__PURE__ */ (0, E.jsxs)("span", {
338
+ className: "font-mono text-xs text-muted-foreground",
339
+ children: [
340
+ "(",
341
+ n,
342
+ ")"
343
+ ]
344
+ })
345
+ ]
346
+ }), !t && /* @__PURE__ */ (0, E.jsx)("div", {
347
+ className: "flex gap-3 sm:gap-4 overflow-x-auto px-2 pb-3 pl-36 sm:pl-44",
348
+ children: j.map((t) => {
349
+ let n = t.cards.filter((t) => (t[b] == null ? O : String(t[b])) === e);
350
+ return /* @__PURE__ */ (0, E.jsx)("div", {
351
+ className: "w-[85vw] sm:w-80 flex-shrink-0 min-h-[60px] rounded-md bg-card/20 p-2",
352
+ children: /* @__PURE__ */ (0, E.jsx)(f, {
353
+ items: n.map((e) => e.id),
354
+ strategy: o,
355
+ children: /* @__PURE__ */ (0, E.jsx)("div", {
356
+ className: "space-y-2",
357
+ role: "list",
358
+ "aria-label": `${t.title} - ${e} cards`,
359
+ children: n.map((e) => /* @__PURE__ */ (0, E.jsx)(A, {
360
+ card: e,
361
+ onCardClick: a,
362
+ conditionalFormatting: y
363
+ }, e.id))
364
+ })
365
+ })
366
+ }, t.id);
367
+ })
368
+ })]
369
+ }, e);
370
+ })]
371
+ }) : /* @__PURE__ */ (0, E.jsx)("div", {
372
+ className: D("flex gap-3 sm:gap-4 overflow-x-auto snap-x snap-mandatory p-2 sm:p-4 bg-muted/10 rounded-lg [-webkit-overflow-scrolling:touch] min-w-0", u),
373
+ role: "region",
374
+ "aria-label": "Kanban board",
375
+ children: j.map((e) => /* @__PURE__ */ (0, E.jsx)(M, {
376
+ column: e,
377
+ cards: e.cards,
378
+ onCardClick: a,
379
+ quickAdd: g,
380
+ onQuickAdd: _,
381
+ conditionalFormatting: y
382
+ }, e.id))
383
+ }),
384
+ /* @__PURE__ */ (0, E.jsx)(l, { children: /* @__PURE__ */ (0, E.jsx)("div", {
385
+ "aria-live": "assertive",
386
+ "aria-label": x ? `Dragging ${x.title}` : void 0,
387
+ children: x ? /* @__PURE__ */ (0, E.jsx)(A, {
388
+ card: x,
389
+ conditionalFormatting: y
390
+ }) : null
391
+ }) })
392
+ ]
393
+ });
394
+ }
395
+ //#endregion
396
+ export { P as default };
@@ -0,0 +1,7 @@
1
+ import { n as e } from "./plus-CAtTu4zt.js";
2
+ var t = e("chevron-down", [["path", {
3
+ d: "m6 9 6 6 6-6",
4
+ key: "qrunsl"
5
+ }]]);
6
+ //#endregion
7
+ export { t };