@object-ui/plugin-kanban 3.3.1 → 3.4.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/CHANGELOG.md +61 -0
- package/dist/{KanbanEnhanced-Do9ZB1Mh.js → KanbanEnhanced-4myt_u5S.js} +5 -5
- package/dist/{KanbanImpl-BdocXM5T.js → KanbanImpl-bLXoKZb7.js} +128 -126
- package/dist/index.js +66 -18
- package/dist/index.umd.cjs +4 -4
- package/dist/packages/plugin-kanban/src/KanbanImpl.d.ts.map +1 -1
- package/dist/packages/plugin-kanban/src/ObjectKanban.d.ts.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# @object-ui/plugin-kanban
|
|
2
2
|
|
|
3
|
+
## 3.4.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a2d7023: End-user feature batch — forms, designer history, import/export, and PWA offline sync.
|
|
8
|
+
|
|
9
|
+
**Forms (`@object-ui/fields`, `@object-ui/providers`)**
|
|
10
|
+
- `FileField`: native `<input capture="environment">` camera capture for mobile devices, plus a uploading-progress indicator driven by `UploadProvider`.
|
|
11
|
+
- `ImageField`: per-image inline crop/rotate via the lazy-loaded `ImageCropperDialog` (canvas-based, zero new deps).
|
|
12
|
+
- New `UploadProvider` in `@object-ui/providers` with pluggable adapters for S3 and Azure Blob (plus the default object-URL adapter for local previews). XHR-based with progress, abort, and retry.
|
|
13
|
+
- `LookupField`: `lookup.dependsOn: string | string[]` to chain dependent lookups (e.g. State depends on Country); the trigger is gated until parent values are present and the OData `$filter` is built automatically.
|
|
14
|
+
|
|
15
|
+
**Container-aware widget widths (`@object-ui/components`)**
|
|
16
|
+
- New `useResizeObserver(ref)` hook exposing `{ width, height }` of any element. SSR-safe; reads the initial size via `getBoundingClientRect`.
|
|
17
|
+
- `plugin-gantt` and `plugin-kanban` now react to their container size instead of `window.innerWidth`, so they behave correctly inside split panels and dashboards.
|
|
18
|
+
|
|
19
|
+
**Designer history (`@object-ui/plugin-designer`)**
|
|
20
|
+
- `useUndoRedo` (and therefore `useDesignerHistory`) gains `persistKey` + `storage` options to round-trip the undo/redo stack through `sessionStorage`, plus a `clearPersisted()` cleanup helper. Drafts now survive accidental tab refreshes.
|
|
21
|
+
- New `<HistoryPanel>` component renders the timeline visually with one-click jump-to-checkpoint via the new `jumpTo(index)` API.
|
|
22
|
+
|
|
23
|
+
**Import wizard (`@object-ui/plugin-grid`)**
|
|
24
|
+
- Saved column-mapping templates: name, save, re-apply, and delete via a new template bar in the mapping step. Persisted under `objectui:import-templates:${objectName}` (override via `templateStorageKey` / `templateStorage`).
|
|
25
|
+
- Inline validation correction: cells with errors in the preview step are now editable; corrections feed straight into the import without requiring a re-upload, with green-bar status indicators for fixed rows.
|
|
26
|
+
|
|
27
|
+
**PWA offline sync (`@object-ui/mobile`)**
|
|
28
|
+
- New `MemoryOfflineQueue` / `IndexedDbOfflineQueue` (`createOfflineQueue()` picks the best backend) backed by IndexedDB.
|
|
29
|
+
- `createOfflineDataSource(inner, { queue })` wraps any DataSource so mutations issued while offline (or that fail with a network-style error) are queued and replayed in order on reconnect. Includes `replay()`, `drop()`, `clear()`, `pending()`, an `onChange` notifier, and an opt-in `resolveConflict` hook for stale-write conflicts.
|
|
30
|
+
- New `useOfflineSync(source)` hook exposes `{ isOnline, pending, isReplaying, replay, drop, clear }` and auto-replays on the browser's `online` event.
|
|
31
|
+
- `getServiceWorkerSource(opts)` emits a customisable Service Worker that pre-caches the app shell, applies network-first to API requests, and broadcasts `REPLAY_QUEUE` to clients on Background Sync. `requestBackgroundSync(tag)` registers a one-shot sync from the page.
|
|
32
|
+
|
|
33
|
+
- b2be122: fix(mobile): round 2 — kanban readability, calendar default view, timeline dot clipping
|
|
34
|
+
|
|
35
|
+
**Kanban**
|
|
36
|
+
- Remove `font-mono` from card titles, descriptions, column headers, and empty-state labels — CRM cards no longer render in a monospace font.
|
|
37
|
+
- Constrain column body height (`max-h-full min-h-0` + `h-full` on the layout root) so `ScrollArea` activates and cards don't bleed past the viewport bottom.
|
|
38
|
+
- Opportunistically derive `description` (e.g. `$60K · Acme Corp · @owner`) and up to two `badges` (priority/severity/industry/rating) in `ObjectKanban` when the schema/source omits them, giving mobile cards more context at a glance.
|
|
39
|
+
|
|
40
|
+
**Calendar**
|
|
41
|
+
- `ObjectCalendar` previously hardcoded `view={schema.defaultView ?? 'month'}`, making the view-selector dropdown a no-op. Wire the `view` state through to the `<Calendar>` prop so user selection is respected.
|
|
42
|
+
- On mobile (viewport < 768 px) coerce `day` defaults to `month` via a synchronous lazy initialiser and a resize/orientation effect — avoids the useless 24-hour empty-hour grid for date-only events.
|
|
43
|
+
|
|
44
|
+
**Timeline**
|
|
45
|
+
- Add `ml-3` to the `<Timeline>` `<ol>` so the `absolute -left-3` marker dots are no longer clipped at the scroll-container edge.
|
|
46
|
+
|
|
47
|
+
- Updated dependencies [a2d7023]
|
|
48
|
+
- Updated dependencies [f1ca238]
|
|
49
|
+
- Updated dependencies [de881ef]
|
|
50
|
+
- @object-ui/components@3.4.0
|
|
51
|
+
- @object-ui/types@3.4.0
|
|
52
|
+
- @object-ui/core@3.4.0
|
|
53
|
+
- @object-ui/react@3.4.0
|
|
54
|
+
|
|
55
|
+
## 3.3.2
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- @object-ui/types@3.3.2
|
|
60
|
+
- @object-ui/core@3.3.2
|
|
61
|
+
- @object-ui/react@3.3.2
|
|
62
|
+
- @object-ui/components@3.3.2
|
|
63
|
+
|
|
3
64
|
## 3.3.1
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
|
@@ -592,10 +592,10 @@ function Y({ card: e, conditionalFormatting: t }) {
|
|
|
592
592
|
/* @__PURE__ */ (0, K.jsxs)(x, {
|
|
593
593
|
className: "p-4",
|
|
594
594
|
children: [/* @__PURE__ */ (0, K.jsx)(S, {
|
|
595
|
-
className: "text-sm font-medium
|
|
595
|
+
className: "text-sm font-medium tracking-tight text-foreground group-hover:text-primary transition-colors",
|
|
596
596
|
children: e.title
|
|
597
597
|
}), e.description && /* @__PURE__ */ (0, K.jsx)(b, {
|
|
598
|
-
className: "text-xs text-muted-foreground
|
|
598
|
+
className: "text-xs text-muted-foreground",
|
|
599
599
|
children: e.description
|
|
600
600
|
})]
|
|
601
601
|
}),
|
|
@@ -693,13 +693,13 @@ function Q({ column: e, cards: t, onToggle: n, enableVirtual: i, quickAdd: a, on
|
|
|
693
693
|
onClick: () => n(!e.collapsed),
|
|
694
694
|
children: e.collapsed ? /* @__PURE__ */ (0, K.jsx)(T, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, K.jsx)(r, { className: "h-4 w-4" })
|
|
695
695
|
}), !e.collapsed && /* @__PURE__ */ (0, K.jsxs)(K.Fragment, { children: [/* @__PURE__ */ (0, K.jsx)("h3", {
|
|
696
|
-
className: "
|
|
696
|
+
className: " text-sm font-semibold tracking-wider text-primary/90 uppercase truncate",
|
|
697
697
|
children: e.title
|
|
698
698
|
}), /* @__PURE__ */ (0, K.jsxs)("div", {
|
|
699
699
|
className: "flex items-center gap-2",
|
|
700
700
|
children: [
|
|
701
701
|
/* @__PURE__ */ (0, K.jsxs)("span", {
|
|
702
|
-
className: q("
|
|
702
|
+
className: q(" text-xs", m ? "text-destructive" : v ? "text-yellow-500" : "text-muted-foreground"),
|
|
703
703
|
children: [l.length, e.limit && ` / ${e.limit}`]
|
|
704
704
|
}),
|
|
705
705
|
m && /* @__PURE__ */ (0, K.jsx)(g, {
|
|
@@ -713,7 +713,7 @@ function Q({ column: e, cards: t, onToggle: n, enableVirtual: i, quickAdd: a, on
|
|
|
713
713
|
}), e.collapsed && /* @__PURE__ */ (0, K.jsxs)("div", {
|
|
714
714
|
className: "flex flex-col items-center gap-1",
|
|
715
715
|
children: [/* @__PURE__ */ (0, K.jsx)("span", {
|
|
716
|
-
className: "
|
|
716
|
+
className: " text-xs font-bold text-primary/90 [writing-mode:vertical-rl] rotate-180",
|
|
717
717
|
children: e.title
|
|
718
718
|
}), /* @__PURE__ */ (0, K.jsx)(g, {
|
|
719
719
|
variant: "secondary",
|
|
@@ -2,10 +2,10 @@ import { r as e, t } from "./plus-CHsXVJSY.js";
|
|
|
2
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-LJG1TjKd.js";
|
|
3
3
|
import * as m from "react";
|
|
4
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";
|
|
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, useResizeObserver as E } from "@object-ui/components";
|
|
6
6
|
//#region src/KanbanImpl.tsx
|
|
7
|
-
var
|
|
8
|
-
function
|
|
7
|
+
var D = e(), O = (...e) => e.filter(Boolean).join(" "), k = "Uncategorized";
|
|
8
|
+
function A(e, t) {
|
|
9
9
|
if (!t || t.length === 0) return {};
|
|
10
10
|
for (let n of t) {
|
|
11
11
|
let t = e[n.field];
|
|
@@ -32,13 +32,13 @@ function k(e, t) {
|
|
|
32
32
|
}
|
|
33
33
|
return {};
|
|
34
34
|
}
|
|
35
|
-
function
|
|
35
|
+
function j({ card: e, onCardClick: t, conditionalFormatting: n }) {
|
|
36
36
|
let { attributes: r, listeners: i, setNodeRef: o, transform: s, transition: c, isDragging: l } = u({ id: e.id }), d = {
|
|
37
37
|
transform: a.Transform.toString(s),
|
|
38
38
|
transition: c,
|
|
39
39
|
opacity: l ? .5 : void 0
|
|
40
|
-
}, f =
|
|
41
|
-
return /* @__PURE__ */ (0,
|
|
40
|
+
}, f = A(e, n);
|
|
41
|
+
return /* @__PURE__ */ (0, D.jsx)("div", {
|
|
42
42
|
ref: o,
|
|
43
43
|
style: d,
|
|
44
44
|
...r,
|
|
@@ -46,34 +46,34 @@ function A({ card: e, onCardClick: t, conditionalFormatting: n }) {
|
|
|
46
46
|
role: "listitem",
|
|
47
47
|
"aria-label": e.title,
|
|
48
48
|
onClick: () => t?.(e),
|
|
49
|
-
children: /* @__PURE__ */ (0,
|
|
49
|
+
children: /* @__PURE__ */ (0, D.jsxs)(y, {
|
|
50
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
51
|
style: f,
|
|
52
52
|
children: [
|
|
53
|
-
e.coverImage && /* @__PURE__ */ (0,
|
|
53
|
+
e.coverImage && /* @__PURE__ */ (0, D.jsx)("div", {
|
|
54
54
|
className: "w-full h-32 overflow-hidden rounded-t-lg",
|
|
55
|
-
children: /* @__PURE__ */ (0,
|
|
55
|
+
children: /* @__PURE__ */ (0, D.jsx)("img", {
|
|
56
56
|
src: e.coverImage,
|
|
57
57
|
alt: "",
|
|
58
58
|
className: "w-full h-full object-cover",
|
|
59
59
|
loading: "lazy"
|
|
60
60
|
})
|
|
61
61
|
}),
|
|
62
|
-
/* @__PURE__ */ (0,
|
|
62
|
+
/* @__PURE__ */ (0, D.jsxs)(S, {
|
|
63
63
|
className: "p-2 sm:p-4",
|
|
64
|
-
children: [/* @__PURE__ */ (0,
|
|
65
|
-
className: "text-xs sm:text-sm font-medium
|
|
64
|
+
children: [/* @__PURE__ */ (0, D.jsx)(C, {
|
|
65
|
+
className: "text-xs sm:text-sm font-medium tracking-tight text-foreground group-hover:text-primary transition-colors",
|
|
66
66
|
children: e.title
|
|
67
|
-
}), e.description && /* @__PURE__ */ (0,
|
|
68
|
-
className: "text-xs text-muted-foreground
|
|
67
|
+
}), e.description && /* @__PURE__ */ (0, D.jsx)(x, {
|
|
68
|
+
className: "text-xs text-muted-foreground line-clamp-2 sm:line-clamp-none",
|
|
69
69
|
children: e.description
|
|
70
70
|
})]
|
|
71
71
|
}),
|
|
72
|
-
e.badges && e.badges.length > 0 && /* @__PURE__ */ (0,
|
|
72
|
+
e.badges && e.badges.length > 0 && /* @__PURE__ */ (0, D.jsx)(b, {
|
|
73
73
|
className: "p-2 sm:p-4 pt-0",
|
|
74
|
-
children: /* @__PURE__ */ (0,
|
|
74
|
+
children: /* @__PURE__ */ (0, D.jsx)("div", {
|
|
75
75
|
className: "flex flex-wrap gap-1",
|
|
76
|
-
children: e.badges.map((e, t) => /* @__PURE__ */ (0,
|
|
76
|
+
children: e.badges.map((e, t) => /* @__PURE__ */ (0, D.jsx)(_, {
|
|
77
77
|
variant: e.variant || "default",
|
|
78
78
|
className: "text-xs",
|
|
79
79
|
children: e.label
|
|
@@ -84,14 +84,14 @@ function A({ card: e, onCardClick: t, conditionalFormatting: n }) {
|
|
|
84
84
|
})
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
function
|
|
87
|
+
function M({ columnId: e, onAdd: n }) {
|
|
88
88
|
let [r, i] = m.useState(!1), [a, o] = m.useState(""), s = m.useRef(null), c = () => {
|
|
89
89
|
let t = a.trim();
|
|
90
90
|
t && (n(e, t), o("")), i(!1);
|
|
91
91
|
};
|
|
92
|
-
return r ? /* @__PURE__ */ (0,
|
|
92
|
+
return r ? /* @__PURE__ */ (0, D.jsx)("div", {
|
|
93
93
|
className: "mt-2 space-y-2",
|
|
94
|
-
children: /* @__PURE__ */ (0,
|
|
94
|
+
children: /* @__PURE__ */ (0, D.jsx)(w, {
|
|
95
95
|
ref: s,
|
|
96
96
|
value: a,
|
|
97
97
|
onChange: (e) => o(e.target.value),
|
|
@@ -103,80 +103,81 @@ function j({ columnId: e, onAdd: n }) {
|
|
|
103
103
|
className: "text-sm",
|
|
104
104
|
autoFocus: !0
|
|
105
105
|
})
|
|
106
|
-
}) : /* @__PURE__ */ (0,
|
|
106
|
+
}) : /* @__PURE__ */ (0, D.jsxs)(v, {
|
|
107
107
|
variant: "ghost",
|
|
108
108
|
size: "sm",
|
|
109
109
|
className: "w-full mt-2 text-muted-foreground hover:text-foreground",
|
|
110
110
|
onClick: () => {
|
|
111
111
|
i(!0), setTimeout(() => s.current?.focus(), 0);
|
|
112
112
|
},
|
|
113
|
-
children: [/* @__PURE__ */ (0,
|
|
113
|
+
children: [/* @__PURE__ */ (0, D.jsx)(t, { className: "h-4 w-4 mr-1" }), "Add Card"]
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
|
-
function
|
|
117
|
-
let
|
|
116
|
+
function N({ column: e, cards: t, onCardClick: n, quickAdd: r, onQuickAdd: i, conditionalFormatting: a, columnStyle: s }) {
|
|
117
|
+
let c = t || [], { setNodeRef: l } = u({
|
|
118
118
|
id: e.id,
|
|
119
119
|
data: { type: "column" }
|
|
120
|
-
}),
|
|
121
|
-
return /* @__PURE__ */ (0,
|
|
122
|
-
ref:
|
|
120
|
+
}), d = e.limit && c.length >= e.limit, p = s && s.width != null ? "flex-shrink-0" : "w-[85vw] sm:w-80 flex-shrink-0";
|
|
121
|
+
return /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
122
|
+
ref: l,
|
|
123
123
|
role: "group",
|
|
124
124
|
"aria-label": e.title,
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
style: s,
|
|
126
|
+
className: O("flex flex-col rounded-lg border border-border bg-card/20 backdrop-blur-sm shadow-xl snap-start max-h-full min-h-0", p, e.className),
|
|
127
|
+
children: [/* @__PURE__ */ (0, D.jsx)("div", {
|
|
127
128
|
className: "p-3 sm:p-4 border-b border-border/50 bg-muted/30 rounded-t-lg",
|
|
128
|
-
children: /* @__PURE__ */ (0,
|
|
129
|
+
children: /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
129
130
|
className: "flex items-center justify-between",
|
|
130
|
-
children: [/* @__PURE__ */ (0,
|
|
131
|
+
children: [/* @__PURE__ */ (0, D.jsx)("h3", {
|
|
131
132
|
id: `kanban-col-${e.id}`,
|
|
132
|
-
className: "
|
|
133
|
+
className: " text-xs sm:text-sm font-semibold tracking-wider text-primary/90 uppercase truncate",
|
|
133
134
|
children: e.title
|
|
134
|
-
}), /* @__PURE__ */ (0,
|
|
135
|
+
}), /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
135
136
|
className: "flex items-center gap-2",
|
|
136
|
-
children: [/* @__PURE__ */ (0,
|
|
137
|
+
children: [/* @__PURE__ */ (0, D.jsxs)(_, {
|
|
137
138
|
variant: "secondary",
|
|
138
|
-
className: "text-xs
|
|
139
|
-
children: [
|
|
140
|
-
}),
|
|
139
|
+
className: "text-xs tabular-nums",
|
|
140
|
+
children: [c.length, e.limit && ` / ${e.limit}`]
|
|
141
|
+
}), d && /* @__PURE__ */ (0, D.jsx)(_, {
|
|
141
142
|
variant: "destructive",
|
|
142
143
|
className: "text-xs",
|
|
143
144
|
children: "Full"
|
|
144
145
|
})]
|
|
145
146
|
})]
|
|
146
147
|
})
|
|
147
|
-
}), /* @__PURE__ */ (0,
|
|
148
|
+
}), /* @__PURE__ */ (0, D.jsxs)(T, {
|
|
148
149
|
className: "flex-1 p-4",
|
|
149
|
-
children: [/* @__PURE__ */ (0,
|
|
150
|
-
items:
|
|
150
|
+
children: [/* @__PURE__ */ (0, D.jsx)(f, {
|
|
151
|
+
items: c.map((e) => e.id),
|
|
151
152
|
strategy: o,
|
|
152
|
-
children: /* @__PURE__ */ (0,
|
|
153
|
+
children: /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
153
154
|
className: "space-y-2",
|
|
154
155
|
role: "list",
|
|
155
156
|
"aria-label": `${e.title} cards`,
|
|
156
|
-
children: [
|
|
157
|
+
children: [c.length === 0 && /* @__PURE__ */ (0, D.jsx)("div", {
|
|
157
158
|
className: "flex flex-col items-center justify-center py-8 text-muted-foreground/50",
|
|
158
|
-
children: /* @__PURE__ */ (0,
|
|
159
|
-
className: "text-xs
|
|
159
|
+
children: /* @__PURE__ */ (0, D.jsx)("span", {
|
|
160
|
+
className: "text-xs",
|
|
160
161
|
children: "No cards"
|
|
161
162
|
})
|
|
162
|
-
}),
|
|
163
|
+
}), c.map((e) => /* @__PURE__ */ (0, D.jsx)(j, {
|
|
163
164
|
card: e,
|
|
164
165
|
onCardClick: n,
|
|
165
166
|
conditionalFormatting: a
|
|
166
167
|
}, e.id))]
|
|
167
168
|
})
|
|
168
|
-
}), r && i && /* @__PURE__ */ (0,
|
|
169
|
+
}), r && i && /* @__PURE__ */ (0, D.jsx)(M, {
|
|
169
170
|
columnId: e.id,
|
|
170
171
|
onAdd: i
|
|
171
172
|
})]
|
|
172
173
|
})]
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
|
-
function
|
|
176
|
-
return /* @__PURE__ */ (0,
|
|
176
|
+
function P({ children: e }) {
|
|
177
|
+
return /* @__PURE__ */ (0, D.jsx)(D.Fragment, { children: e(h()) });
|
|
177
178
|
}
|
|
178
|
-
function
|
|
179
|
-
return g() ? /* @__PURE__ */ (0,
|
|
179
|
+
function F({ columns: e, onCardMove: t, onCardClick: n, className: r, quickAdd: i, onQuickAdd: a, coverImageField: o, conditionalFormatting: s, swimlaneField: c }) {
|
|
180
|
+
return g() ? /* @__PURE__ */ (0, D.jsx)(P, { children: (l) => /* @__PURE__ */ (0, D.jsx)(I, {
|
|
180
181
|
columns: e,
|
|
181
182
|
onCardMove: t,
|
|
182
183
|
onCardClick: n,
|
|
@@ -187,7 +188,7 @@ function P({ columns: e, onCardMove: t, onCardClick: n, className: r, quickAdd:
|
|
|
187
188
|
coverImageField: o,
|
|
188
189
|
conditionalFormatting: s,
|
|
189
190
|
swimlaneField: c
|
|
190
|
-
}) }) : /* @__PURE__ */ (0,
|
|
191
|
+
}) }) : /* @__PURE__ */ (0, D.jsx)(I, {
|
|
191
192
|
columns: e,
|
|
192
193
|
onCardMove: t,
|
|
193
194
|
onCardClick: n,
|
|
@@ -200,46 +201,46 @@ function P({ columns: e, onCardMove: t, onCardClick: n, className: r, quickAdd:
|
|
|
200
201
|
swimlaneField: c
|
|
201
202
|
});
|
|
202
203
|
}
|
|
203
|
-
function
|
|
204
|
-
let [x, S] = m.useState(null), C = b ? `objectui:kanban-collapsed:${b}` : null, [
|
|
205
|
-
if (!
|
|
204
|
+
function I({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, quickAdd: g, onQuickAdd: _, coverImageField: v, conditionalFormatting: y, swimlaneField: b }) {
|
|
205
|
+
let [x, S] = m.useState(null), C = m.useRef(null), { width: w } = E(C), T = m.useMemo(() => w ? w < 480 ? { width: Math.max(w - 32, 220) } : w < 720 ? { width: 280 } : { width: 320 } : {}, [w]), A = b ? `objectui:kanban-collapsed:${b}` : null, [M, P] = m.useState(() => {
|
|
206
|
+
if (!A) return /* @__PURE__ */ new Set();
|
|
206
207
|
try {
|
|
207
|
-
let e = localStorage.getItem(
|
|
208
|
+
let e = localStorage.getItem(A);
|
|
208
209
|
if (e) {
|
|
209
210
|
let t = JSON.parse(e);
|
|
210
211
|
if (Array.isArray(t)) return new Set(t.filter((e) => typeof e == "string"));
|
|
211
212
|
}
|
|
212
213
|
} catch {}
|
|
213
214
|
return /* @__PURE__ */ new Set();
|
|
214
|
-
}),
|
|
215
|
+
}), F = m.useMemo(() => (e || []).map((e) => ({
|
|
215
216
|
...e,
|
|
216
217
|
cards: e.cards || []
|
|
217
|
-
})), [e]), [
|
|
218
|
+
})), [e]), [I, L] = m.useState(F);
|
|
218
219
|
m.useEffect(() => {
|
|
219
|
-
|
|
220
|
-
}, [
|
|
221
|
-
let
|
|
220
|
+
L(F);
|
|
221
|
+
}, [F]);
|
|
222
|
+
let R = m.useMemo(() => {
|
|
222
223
|
if (!b) return null;
|
|
223
|
-
let e =
|
|
224
|
+
let e = I.flatMap((e) => e.cards), t = /* @__PURE__ */ new Set();
|
|
224
225
|
return e.forEach((e) => {
|
|
225
226
|
let n = e[b];
|
|
226
|
-
t.add(n == null ?
|
|
227
|
+
t.add(n == null ? k : String(n));
|
|
227
228
|
}), Array.from(t).sort();
|
|
228
|
-
}, [
|
|
229
|
-
|
|
229
|
+
}, [I, b]), z = m.useCallback((e) => {
|
|
230
|
+
P((t) => {
|
|
230
231
|
let n = new Set(t);
|
|
231
|
-
if (n.has(e) ? n.delete(e) : n.add(e),
|
|
232
|
-
localStorage.setItem(
|
|
232
|
+
if (n.has(e) ? n.delete(e) : n.add(e), A) try {
|
|
233
|
+
localStorage.setItem(A, JSON.stringify([...n]));
|
|
233
234
|
} catch {}
|
|
234
235
|
return n;
|
|
235
236
|
});
|
|
236
|
-
}, [
|
|
237
|
+
}, [A]), B = i(p(d, { activationConstraint: { distance: 5 } }), p(r, { activationConstraint: {
|
|
237
238
|
delay: 200,
|
|
238
239
|
tolerance: 5
|
|
239
|
-
} })),
|
|
240
|
-
let { active: t } = e, n =
|
|
240
|
+
} })), V = (e) => {
|
|
241
|
+
let { active: t } = e, n = U(t.id);
|
|
241
242
|
if (S(n), h && n) {
|
|
242
|
-
let e =
|
|
243
|
+
let e = W(n.id);
|
|
243
244
|
e && h.startDrag({
|
|
244
245
|
id: n.id,
|
|
245
246
|
type: "kanban-card",
|
|
@@ -247,7 +248,7 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
247
248
|
sourceId: e.id
|
|
248
249
|
});
|
|
249
250
|
}
|
|
250
|
-
},
|
|
251
|
+
}, H = (e) => {
|
|
251
252
|
let { active: n, over: r } = e;
|
|
252
253
|
if (S(null), !r) {
|
|
253
254
|
h && h.endDrag();
|
|
@@ -258,20 +259,20 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
258
259
|
h && h.endDrag();
|
|
259
260
|
return;
|
|
260
261
|
}
|
|
261
|
-
let o =
|
|
262
|
+
let o = W(i), s = W(a) || G(a);
|
|
262
263
|
if (!o || !s) {
|
|
263
264
|
h && h.endDrag();
|
|
264
265
|
return;
|
|
265
266
|
}
|
|
266
267
|
if (o.id === s.id) {
|
|
267
268
|
let e = [...o.cards], t = c(e, e.findIndex((e) => e.id === i), e.findIndex((e) => e.id === a));
|
|
268
|
-
|
|
269
|
+
L((e) => e.map((e) => e.id === o.id ? {
|
|
269
270
|
...e,
|
|
270
271
|
cards: t
|
|
271
272
|
} : e));
|
|
272
273
|
} else {
|
|
273
274
|
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),
|
|
275
|
+
n.splice(c, 0, l), L((t) => t.map((t) => t.id === o.id ? {
|
|
275
276
|
...t,
|
|
276
277
|
cards: e
|
|
277
278
|
} : t.id === s.id ? {
|
|
@@ -280,36 +281,37 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
280
281
|
} : t)), t && t(i, o.id, s.id, c);
|
|
281
282
|
}
|
|
282
283
|
h && h.endDrag(s.id);
|
|
283
|
-
},
|
|
284
|
-
for (let t of
|
|
284
|
+
}, U = m.useCallback((e) => {
|
|
285
|
+
for (let t of I) {
|
|
285
286
|
let n = t.cards.find((t) => t.id === e);
|
|
286
287
|
if (n) return n;
|
|
287
288
|
}
|
|
288
289
|
return null;
|
|
289
|
-
}, [
|
|
290
|
-
return /* @__PURE__ */ (0,
|
|
291
|
-
sensors:
|
|
290
|
+
}, [I]), W = m.useCallback((e) => I.find((t) => t.cards.some((t) => t.id === e)) || null, [I]), G = m.useCallback((e) => I.find((t) => t.id === e) || null, [I]);
|
|
291
|
+
return /* @__PURE__ */ (0, D.jsxs)(n, {
|
|
292
|
+
sensors: B,
|
|
292
293
|
collisionDetection: s,
|
|
293
|
-
onDragStart:
|
|
294
|
-
onDragEnd:
|
|
295
|
-
children: [
|
|
296
|
-
|
|
294
|
+
onDragStart: V,
|
|
295
|
+
onDragEnd: H,
|
|
296
|
+
children: [/* @__PURE__ */ (0, D.jsxs)("div", {
|
|
297
|
+
ref: C,
|
|
298
|
+
className: "flex flex-col min-w-0 min-h-0 h-full",
|
|
299
|
+
children: [/* @__PURE__ */ (0, D.jsxs)("div", {
|
|
297
300
|
className: "flex sm:hidden items-center justify-between px-3 pb-2 text-xs text-muted-foreground",
|
|
298
|
-
children: [/* @__PURE__ */ (0,
|
|
299
|
-
}),
|
|
300
|
-
|
|
301
|
-
className: D("flex flex-col gap-1 p-2 sm:p-4 min-w-0 overflow-hidden", u),
|
|
301
|
+
children: [/* @__PURE__ */ (0, D.jsxs)("span", { children: [I.length, " columns"] }), /* @__PURE__ */ (0, D.jsx)("span", { children: "← Swipe to navigate →" })]
|
|
302
|
+
}), R ? /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
303
|
+
className: O("flex flex-col gap-1 p-2 sm:p-4 min-w-0 overflow-hidden", u),
|
|
302
304
|
role: "region",
|
|
303
305
|
"aria-label": "Kanban board with swimlanes",
|
|
304
|
-
children: [/* @__PURE__ */ (0,
|
|
306
|
+
children: [/* @__PURE__ */ (0, D.jsx)("div", {
|
|
305
307
|
className: "flex gap-3 sm:gap-4 pl-36 sm:pl-44 overflow-x-auto",
|
|
306
|
-
children:
|
|
308
|
+
children: I.map((e) => /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
307
309
|
className: "w-[85vw] sm:w-80 flex-shrink-0 text-center",
|
|
308
|
-
children: [/* @__PURE__ */ (0,
|
|
309
|
-
className: "
|
|
310
|
+
children: [/* @__PURE__ */ (0, D.jsx)("span", {
|
|
311
|
+
className: " text-xs sm:text-sm font-semibold tracking-wider text-primary/90 uppercase",
|
|
310
312
|
children: e.title
|
|
311
|
-
}), /* @__PURE__ */ (0,
|
|
312
|
-
className: "ml-2
|
|
313
|
+
}), /* @__PURE__ */ (0, D.jsxs)("span", {
|
|
314
|
+
className: "ml-2 text-xs text-muted-foreground",
|
|
313
315
|
children: [
|
|
314
316
|
"(",
|
|
315
317
|
e.cards.length,
|
|
@@ -317,25 +319,25 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
317
319
|
]
|
|
318
320
|
})]
|
|
319
321
|
}, e.id))
|
|
320
|
-
}),
|
|
321
|
-
let t =
|
|
322
|
-
return /* @__PURE__ */ (0,
|
|
322
|
+
}), R.map((e) => {
|
|
323
|
+
let t = M.has(e), n = I.reduce((t, n) => t + n.cards.filter((t) => (t[b] == null ? k : String(t[b])) === e).length, 0);
|
|
324
|
+
return /* @__PURE__ */ (0, D.jsxs)("div", {
|
|
323
325
|
className: "border rounded-lg bg-muted/10",
|
|
324
|
-
children: [/* @__PURE__ */ (0,
|
|
326
|
+
children: [/* @__PURE__ */ (0, D.jsxs)("button", {
|
|
325
327
|
className: "w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-muted/30 transition-colors",
|
|
326
|
-
onClick: () =>
|
|
328
|
+
onClick: () => z(e),
|
|
327
329
|
"aria-expanded": !t,
|
|
328
330
|
children: [
|
|
329
|
-
/* @__PURE__ */ (0,
|
|
330
|
-
className:
|
|
331
|
+
/* @__PURE__ */ (0, D.jsx)("span", {
|
|
332
|
+
className: O("transition-transform text-xs", t ? "" : "rotate-90"),
|
|
331
333
|
children: "▶"
|
|
332
334
|
}),
|
|
333
|
-
/* @__PURE__ */ (0,
|
|
334
|
-
className: "
|
|
335
|
+
/* @__PURE__ */ (0, D.jsx)("span", {
|
|
336
|
+
className: " text-xs font-semibold text-muted-foreground uppercase tracking-wider",
|
|
335
337
|
children: e
|
|
336
338
|
}),
|
|
337
|
-
/* @__PURE__ */ (0,
|
|
338
|
-
className: "
|
|
339
|
+
/* @__PURE__ */ (0, D.jsxs)("span", {
|
|
340
|
+
className: " text-xs text-muted-foreground",
|
|
339
341
|
children: [
|
|
340
342
|
"(",
|
|
341
343
|
n,
|
|
@@ -343,20 +345,20 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
343
345
|
]
|
|
344
346
|
})
|
|
345
347
|
]
|
|
346
|
-
}), !t && /* @__PURE__ */ (0,
|
|
348
|
+
}), !t && /* @__PURE__ */ (0, D.jsx)("div", {
|
|
347
349
|
className: "flex gap-3 sm:gap-4 overflow-x-auto px-2 pb-3 pl-36 sm:pl-44",
|
|
348
|
-
children:
|
|
349
|
-
let n = t.cards.filter((t) => (t[b] == null ?
|
|
350
|
-
return /* @__PURE__ */ (0,
|
|
350
|
+
children: I.map((t) => {
|
|
351
|
+
let n = t.cards.filter((t) => (t[b] == null ? k : String(t[b])) === e);
|
|
352
|
+
return /* @__PURE__ */ (0, D.jsx)("div", {
|
|
351
353
|
className: "w-[85vw] sm:w-80 flex-shrink-0 min-h-[60px] rounded-md bg-card/20 p-2",
|
|
352
|
-
children: /* @__PURE__ */ (0,
|
|
354
|
+
children: /* @__PURE__ */ (0, D.jsx)(f, {
|
|
353
355
|
items: n.map((e) => e.id),
|
|
354
356
|
strategy: o,
|
|
355
|
-
children: /* @__PURE__ */ (0,
|
|
357
|
+
children: /* @__PURE__ */ (0, D.jsx)("div", {
|
|
356
358
|
className: "space-y-2",
|
|
357
359
|
role: "list",
|
|
358
360
|
"aria-label": `${t.title} - ${e} cards`,
|
|
359
|
-
children: n.map((e) => /* @__PURE__ */ (0,
|
|
361
|
+
children: n.map((e) => /* @__PURE__ */ (0, D.jsx)(j, {
|
|
360
362
|
card: e,
|
|
361
363
|
onCardClick: a,
|
|
362
364
|
conditionalFormatting: y
|
|
@@ -368,29 +370,29 @@ function F({ columns: e, onCardMove: t, onCardClick: a, className: u, dnd: h, qu
|
|
|
368
370
|
})]
|
|
369
371
|
}, e);
|
|
370
372
|
})]
|
|
371
|
-
}) : /* @__PURE__ */ (0,
|
|
372
|
-
className:
|
|
373
|
+
}) : /* @__PURE__ */ (0, D.jsx)("div", {
|
|
374
|
+
className: O("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 min-h-0 h-full", u),
|
|
373
375
|
role: "region",
|
|
374
376
|
"aria-label": "Kanban board",
|
|
375
|
-
children:
|
|
377
|
+
children: I.map((e) => /* @__PURE__ */ (0, D.jsx)(N, {
|
|
376
378
|
column: e,
|
|
377
379
|
cards: e.cards,
|
|
378
380
|
onCardClick: a,
|
|
379
381
|
quickAdd: g,
|
|
380
382
|
onQuickAdd: _,
|
|
381
|
-
conditionalFormatting: y
|
|
383
|
+
conditionalFormatting: y,
|
|
384
|
+
columnStyle: T
|
|
382
385
|
}, e.id))
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
]
|
|
386
|
+
})]
|
|
387
|
+
}), /* @__PURE__ */ (0, D.jsx)(l, { children: /* @__PURE__ */ (0, D.jsx)("div", {
|
|
388
|
+
"aria-live": "assertive",
|
|
389
|
+
"aria-label": x ? `Dragging ${x.title}` : void 0,
|
|
390
|
+
children: x ? /* @__PURE__ */ (0, D.jsx)(j, {
|
|
391
|
+
card: x,
|
|
392
|
+
conditionalFormatting: y
|
|
393
|
+
}) : null
|
|
394
|
+
}) })]
|
|
393
395
|
});
|
|
394
396
|
}
|
|
395
397
|
//#endregion
|
|
396
|
-
export {
|
|
398
|
+
export { F as default };
|