@ablogcms/kanban 3.2.28-beta.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/dist/components/Board.d.ts +3 -0
- package/dist/components/BoardContainer.d.ts +7 -0
- package/dist/components/Card.d.ts +19 -0
- package/dist/components/DefaultCard.d.ts +3 -0
- package/dist/components/DefaultLaneHeader.d.ts +3 -0
- package/dist/components/DragOverlay/CardOverlay.d.ts +11 -0
- package/dist/components/DragOverlay/LaneOverlay.d.ts +7 -0
- package/dist/components/Lane.d.ts +32 -0
- package/dist/components/NewCard.d.ts +4 -0
- package/dist/components/NewLane.d.ts +3 -0
- package/dist/components/SortableLane.d.ts +30 -0
- package/dist/components/Tag.d.ts +6 -0
- package/dist/components/widgets/DeleteButton.d.ts +6 -0
- package/dist/components/widgets/EditableLabel.d.ts +8 -0
- package/dist/components.d.ts +2 -0
- package/dist/context/BoardContext.d.ts +10 -0
- package/dist/context/BoardReducer.d.ts +3 -0
- package/dist/helpers/LaneHelper.d.ts +40 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +981 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/index.d.ts +187 -0
- package/dist/utils/dndIds.d.ts +9 -0
- package/package.json +53 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,981 @@
|
|
|
1
|
+
// src/components/Board.tsx
|
|
2
|
+
import { useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
3
|
+
import { v4 as uuidv43 } from "uuid";
|
|
4
|
+
|
|
5
|
+
// src/context/BoardContext.tsx
|
|
6
|
+
import { createContext, useContext, useReducer } from "react";
|
|
7
|
+
|
|
8
|
+
// src/helpers/LaneHelper.ts
|
|
9
|
+
import { v4 as uuidv4 } from "uuid";
|
|
10
|
+
var LaneHelper = {
|
|
11
|
+
initialiseLanes: (state, { lanes }) => {
|
|
12
|
+
const newLanes = lanes.map((lane) => ({
|
|
13
|
+
...lane,
|
|
14
|
+
currentPage: 1,
|
|
15
|
+
cards: (lane.cards || []).map((c) => ({ ...c, laneId: lane.id }))
|
|
16
|
+
}));
|
|
17
|
+
return { ...state, lanes: newLanes };
|
|
18
|
+
},
|
|
19
|
+
paginateLane: (state, { laneId, newCards, nextPage }) => {
|
|
20
|
+
const updatedLanes = LaneHelper.appendCardsToLane(state, { laneId, newCards });
|
|
21
|
+
return {
|
|
22
|
+
...state,
|
|
23
|
+
lanes: updatedLanes.map((lane) => lane.id === laneId ? { ...lane, currentPage: nextPage } : lane)
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
appendCardsToLane: (state, { laneId, newCards, index }) => {
|
|
27
|
+
const lane = state.lanes.find((l) => l.id === laneId);
|
|
28
|
+
if (!lane) return state.lanes;
|
|
29
|
+
const existingIds = new Set(lane.cards.map((c) => c.id));
|
|
30
|
+
const cardsWithLaneId = newCards.map((c) => ({ ...c, laneId })).filter((c) => !existingIds.has(c.id));
|
|
31
|
+
return state.lanes.map((l) => {
|
|
32
|
+
if (l.id !== laneId) return l;
|
|
33
|
+
if (index !== void 0) {
|
|
34
|
+
const cards = [...l.cards];
|
|
35
|
+
cards.splice(index, 0, ...cardsWithLaneId);
|
|
36
|
+
return { ...l, cards };
|
|
37
|
+
}
|
|
38
|
+
return { ...l, cards: [...l.cards, ...cardsWithLaneId] };
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
appendCardToLane: (state, { laneId, card, index }) => {
|
|
42
|
+
const newLanes = LaneHelper.appendCardsToLane(state, { laneId, newCards: [card], index });
|
|
43
|
+
return { ...state, lanes: newLanes };
|
|
44
|
+
},
|
|
45
|
+
addLane: (state, lane) => {
|
|
46
|
+
const newLane = { id: uuidv4(), cards: [], ...lane };
|
|
47
|
+
return { ...state, lanes: [...state.lanes, newLane] };
|
|
48
|
+
},
|
|
49
|
+
removeCardFromLane: (state, { laneId, cardId }) => {
|
|
50
|
+
const lanes = state.lanes.map((lane) => {
|
|
51
|
+
if (lane.id !== laneId) return lane;
|
|
52
|
+
return { ...lane, cards: lane.cards.filter((card) => card.id !== cardId) };
|
|
53
|
+
});
|
|
54
|
+
return { ...state, lanes };
|
|
55
|
+
},
|
|
56
|
+
moveCardAcrossLanes: (state, { fromLaneId: fromLaneId2, toLaneId: toLaneId2, cardId, index }) => {
|
|
57
|
+
let cardToMove = null;
|
|
58
|
+
const interimLanes = state.lanes.map((lane) => {
|
|
59
|
+
if (lane.id !== fromLaneId2) return lane;
|
|
60
|
+
cardToMove = lane.cards.find((card) => card.id === cardId) || null;
|
|
61
|
+
return { ...lane, cards: lane.cards.filter((card) => card.id !== cardId) };
|
|
62
|
+
});
|
|
63
|
+
if (!cardToMove) return state;
|
|
64
|
+
const interimState = { ...state, lanes: interimLanes };
|
|
65
|
+
return LaneHelper.appendCardToLane(interimState, { laneId: toLaneId2, card: cardToMove, index });
|
|
66
|
+
},
|
|
67
|
+
updateCardsForLane: (state, { laneId, cards }) => {
|
|
68
|
+
const lanes = state.lanes.map((lane) => {
|
|
69
|
+
if (lane.id !== laneId) return lane;
|
|
70
|
+
return { ...lane, cards };
|
|
71
|
+
});
|
|
72
|
+
return { ...state, lanes };
|
|
73
|
+
},
|
|
74
|
+
updateLanes: (state, lanes) => {
|
|
75
|
+
return { ...state, lanes };
|
|
76
|
+
},
|
|
77
|
+
moveLane: (state, { oldIndex, newIndex }) => {
|
|
78
|
+
const lanes = [...state.lanes];
|
|
79
|
+
const [laneToMove] = lanes.splice(oldIndex, 1);
|
|
80
|
+
lanes.splice(newIndex, 0, laneToMove);
|
|
81
|
+
return { ...state, lanes };
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var LaneHelper_default = LaneHelper;
|
|
85
|
+
|
|
86
|
+
// src/context/BoardReducer.ts
|
|
87
|
+
var initialState = { lanes: [] };
|
|
88
|
+
function boardReducer(state, action) {
|
|
89
|
+
switch (action.type) {
|
|
90
|
+
case "LOAD_BOARD":
|
|
91
|
+
return LaneHelper_default.initialiseLanes(state, action.payload);
|
|
92
|
+
case "ADD_CARD":
|
|
93
|
+
return LaneHelper_default.appendCardToLane(state, action.payload);
|
|
94
|
+
case "REMOVE_CARD":
|
|
95
|
+
return LaneHelper_default.removeCardFromLane(state, action.payload);
|
|
96
|
+
case "MOVE_CARD":
|
|
97
|
+
return LaneHelper_default.moveCardAcrossLanes(state, action.payload);
|
|
98
|
+
case "UPDATE_CARDS":
|
|
99
|
+
return LaneHelper_default.updateCardsForLane(state, action.payload);
|
|
100
|
+
case "UPDATE_LANES":
|
|
101
|
+
return LaneHelper_default.updateLanes(state, action.payload);
|
|
102
|
+
case "PAGINATE_LANE":
|
|
103
|
+
return LaneHelper_default.paginateLane(state, action.payload);
|
|
104
|
+
case "MOVE_LANE":
|
|
105
|
+
return LaneHelper_default.moveLane(state, action.payload);
|
|
106
|
+
case "ADD_LANE":
|
|
107
|
+
return LaneHelper_default.addLane(state, action.payload);
|
|
108
|
+
default:
|
|
109
|
+
return state;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/context/BoardContext.tsx
|
|
114
|
+
import { jsx } from "react/jsx-runtime";
|
|
115
|
+
var BoardStateContext = createContext(null);
|
|
116
|
+
var BoardDispatchContext = createContext(null);
|
|
117
|
+
function BoardProvider({ initialData, children }) {
|
|
118
|
+
const [state, dispatch] = useReducer(
|
|
119
|
+
boardReducer,
|
|
120
|
+
initialData,
|
|
121
|
+
(data) => boardReducer(initialState, { type: "LOAD_BOARD", payload: data })
|
|
122
|
+
);
|
|
123
|
+
return /* @__PURE__ */ jsx(BoardStateContext.Provider, { value: state, children: /* @__PURE__ */ jsx(BoardDispatchContext.Provider, { value: dispatch, children }) });
|
|
124
|
+
}
|
|
125
|
+
function useBoardState() {
|
|
126
|
+
const ctx = useContext(BoardStateContext);
|
|
127
|
+
if (!ctx) throw new Error("useBoardState must be used within BoardProvider");
|
|
128
|
+
return ctx;
|
|
129
|
+
}
|
|
130
|
+
function useBoardDispatch() {
|
|
131
|
+
const ctx = useContext(BoardDispatchContext);
|
|
132
|
+
if (!ctx) throw new Error("useBoardDispatch must be used within BoardProvider");
|
|
133
|
+
return ctx;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/components/BoardContainer.tsx
|
|
137
|
+
import { useState as useState2, useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
138
|
+
import {
|
|
139
|
+
DndContext,
|
|
140
|
+
DragOverlay,
|
|
141
|
+
PointerSensor,
|
|
142
|
+
KeyboardSensor,
|
|
143
|
+
useSensor,
|
|
144
|
+
useSensors,
|
|
145
|
+
closestCorners
|
|
146
|
+
} from "@dnd-kit/core";
|
|
147
|
+
import {
|
|
148
|
+
SortableContext as SortableContext2,
|
|
149
|
+
horizontalListSortingStrategy,
|
|
150
|
+
sortableKeyboardCoordinates,
|
|
151
|
+
arrayMove
|
|
152
|
+
} from "@dnd-kit/sortable";
|
|
153
|
+
|
|
154
|
+
// src/components/SortableLane.tsx
|
|
155
|
+
import { useSortable as useSortable2 } from "@dnd-kit/sortable";
|
|
156
|
+
import { CSS as CSS2 } from "@dnd-kit/utilities";
|
|
157
|
+
|
|
158
|
+
// src/components/Lane.tsx
|
|
159
|
+
import { useState, useEffect, useRef, useCallback, useMemo } from "react";
|
|
160
|
+
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
161
|
+
import { useDroppable } from "@dnd-kit/core";
|
|
162
|
+
import { v4 as uuidv42 } from "uuid";
|
|
163
|
+
import Spinner from "@ablogcms/components/spinner";
|
|
164
|
+
|
|
165
|
+
// src/components/Card.tsx
|
|
166
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
167
|
+
import { useSortable } from "@dnd-kit/sortable";
|
|
168
|
+
|
|
169
|
+
// src/components/widgets/DeleteButton.tsx
|
|
170
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
171
|
+
function DeleteButton(props) {
|
|
172
|
+
return /* @__PURE__ */ jsx2("div", { className: "acms-admin-kanban-delete-wrapper", children: /* @__PURE__ */ jsx2("button", { type: "button", className: "acms-admin-kanban-delete-button", onClick: props.onClick, children: "x" }) });
|
|
173
|
+
}
|
|
174
|
+
var DeleteButton_default = DeleteButton;
|
|
175
|
+
|
|
176
|
+
// src/utils/dndIds.ts
|
|
177
|
+
var toLaneId = (id) => `lane:${id}`;
|
|
178
|
+
var toCardId = (id) => `card:${id}`;
|
|
179
|
+
var toDropLaneId = (id) => `droplane:${id}`;
|
|
180
|
+
var fromLaneId = (id) => id.replace(/^lane:/, "");
|
|
181
|
+
var fromCardId = (id) => id.replace(/^card:/, "");
|
|
182
|
+
var fromDropLaneId = (id) => id.replace(/^droplane:/, "");
|
|
183
|
+
var isLaneId = (id) => id.startsWith("lane:");
|
|
184
|
+
var isCardId = (id) => id.startsWith("card:");
|
|
185
|
+
var isDropLaneId = (id) => id.startsWith("droplane:");
|
|
186
|
+
|
|
187
|
+
// src/components/Card.tsx
|
|
188
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
189
|
+
function Card({
|
|
190
|
+
card,
|
|
191
|
+
laneId,
|
|
192
|
+
editable = false,
|
|
193
|
+
hideCardDeleteIcon = false,
|
|
194
|
+
customCardLayout = false,
|
|
195
|
+
components: components2,
|
|
196
|
+
tagStyle,
|
|
197
|
+
cardStyle = {},
|
|
198
|
+
draggable = false,
|
|
199
|
+
cardDraggable = true,
|
|
200
|
+
onCardClick,
|
|
201
|
+
onCardDelete = () => {
|
|
202
|
+
},
|
|
203
|
+
onRemoveCard
|
|
204
|
+
}) {
|
|
205
|
+
const isDraggingEnabled = draggable && cardDraggable;
|
|
206
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
207
|
+
id: toCardId(card.id),
|
|
208
|
+
disabled: !isDraggingEnabled
|
|
209
|
+
});
|
|
210
|
+
const style = {
|
|
211
|
+
transform: CSS.Transform.toString(transform),
|
|
212
|
+
transition,
|
|
213
|
+
opacity: isDragging ? 0 : 1
|
|
214
|
+
};
|
|
215
|
+
const handleRemoveCard = (e) => {
|
|
216
|
+
if (onRemoveCard) onRemoveCard(laneId, card.id);
|
|
217
|
+
onCardDelete(card.id, laneId);
|
|
218
|
+
e.stopPropagation();
|
|
219
|
+
};
|
|
220
|
+
const handleClick = (e) => {
|
|
221
|
+
if (onCardClick) onCardClick(card.id, card.metadata, laneId);
|
|
222
|
+
e.stopPropagation();
|
|
223
|
+
};
|
|
224
|
+
const handleDelete = () => {
|
|
225
|
+
if (onRemoveCard) onRemoveCard(laneId, card.id);
|
|
226
|
+
onCardDelete(card.id, laneId);
|
|
227
|
+
};
|
|
228
|
+
const wrapperStyle = customCardLayout ? { ...cardStyle, padding: 0 } : cardStyle;
|
|
229
|
+
return (
|
|
230
|
+
// ドラッグ有効時は useSortable の attributes/listeners が role/tabIndex/キーボード操作を提供する。
|
|
231
|
+
// 無効時のクリックはカード選択という補助的な操作のため、キーボード対応は必須にしていない(既存挙動を維持)。
|
|
232
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
|
|
233
|
+
/* @__PURE__ */ jsxs(
|
|
234
|
+
"article",
|
|
235
|
+
{
|
|
236
|
+
ref: setNodeRef,
|
|
237
|
+
className: "acms-admin-kanban-card",
|
|
238
|
+
"data-id": card.id,
|
|
239
|
+
style: { ...wrapperStyle, ...style },
|
|
240
|
+
onClick: handleClick,
|
|
241
|
+
...isDraggingEnabled ? { ...attributes, ...listeners } : {},
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ jsx3(components2.Card, { card, laneId, tagStyle, onDelete: handleDelete }),
|
|
244
|
+
editable && !hideCardDeleteIcon && /* @__PURE__ */ jsx3(DeleteButton_default, { onClick: handleRemoveCard })
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
var Card_default = Card;
|
|
251
|
+
|
|
252
|
+
// src/components/Lane.tsx
|
|
253
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
254
|
+
function Lane({
|
|
255
|
+
lane,
|
|
256
|
+
boardId: _boardId,
|
|
257
|
+
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
258
|
+
index: _index,
|
|
259
|
+
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
260
|
+
draggable = false,
|
|
261
|
+
cardDraggable = true,
|
|
262
|
+
collapsibleLanes = false,
|
|
263
|
+
editable = false,
|
|
264
|
+
hideCardDeleteIcon = false,
|
|
265
|
+
customCardLayout = false,
|
|
266
|
+
components: components2,
|
|
267
|
+
tagStyle,
|
|
268
|
+
cardStyle,
|
|
269
|
+
titleStyle,
|
|
270
|
+
labelStyle,
|
|
271
|
+
addCardTitle = "Add Card",
|
|
272
|
+
addCardLink,
|
|
273
|
+
onLaneScroll,
|
|
274
|
+
onCardClick,
|
|
275
|
+
onCardDelete = () => {
|
|
276
|
+
},
|
|
277
|
+
onCardAdd = () => {
|
|
278
|
+
},
|
|
279
|
+
onLaneClick,
|
|
280
|
+
laneSortFunction,
|
|
281
|
+
dragHandleListeners,
|
|
282
|
+
dragHandleAttributes
|
|
283
|
+
}) {
|
|
284
|
+
const dispatch = useBoardDispatch();
|
|
285
|
+
const [loading, setLoading] = useState(false);
|
|
286
|
+
const [addCardMode, setAddCardMode] = useState(false);
|
|
287
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
288
|
+
const scrollRef = useRef(null);
|
|
289
|
+
const { id, cards = [], style, droppable, currentPage = 1 } = lane;
|
|
290
|
+
const { isOver, setNodeRef: setDropRef } = useDroppable({
|
|
291
|
+
id: toDropLaneId(id),
|
|
292
|
+
disabled: droppable === false
|
|
293
|
+
});
|
|
294
|
+
const handleScroll = useCallback(
|
|
295
|
+
(evt) => {
|
|
296
|
+
const node = evt.target;
|
|
297
|
+
const elemScrollPosition = node.scrollHeight - node.scrollTop - node.clientHeight;
|
|
298
|
+
if (elemScrollPosition <= 0 && onLaneScroll && !loading) {
|
|
299
|
+
setLoading(true);
|
|
300
|
+
const nextPage = currentPage + 1;
|
|
301
|
+
onLaneScroll(nextPage, id).then((moreCards) => {
|
|
302
|
+
if (!moreCards || moreCards.length === 0) {
|
|
303
|
+
node.scrollTop -= 100;
|
|
304
|
+
} else {
|
|
305
|
+
dispatch({ type: "PAGINATE_LANE", payload: { laneId: id, newCards: moreCards, nextPage } });
|
|
306
|
+
}
|
|
307
|
+
setLoading(false);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
[currentPage, id, loading, onLaneScroll, dispatch]
|
|
312
|
+
);
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
const node = scrollRef.current;
|
|
315
|
+
if (node) {
|
|
316
|
+
node.addEventListener("scroll", handleScroll);
|
|
317
|
+
return () => node.removeEventListener("scroll", handleScroll);
|
|
318
|
+
}
|
|
319
|
+
}, [handleScroll]);
|
|
320
|
+
const removeCard = (laneId, cardId) => {
|
|
321
|
+
dispatch({ type: "REMOVE_CARD", payload: { laneId, cardId } });
|
|
322
|
+
};
|
|
323
|
+
const addNewCard = (params) => {
|
|
324
|
+
const newCardId = uuidv42();
|
|
325
|
+
setAddCardMode(false);
|
|
326
|
+
const card = { id: newCardId, laneId: id, ...params };
|
|
327
|
+
dispatch({ type: "ADD_CARD", payload: { laneId: id, card } });
|
|
328
|
+
onCardAdd(card, id);
|
|
329
|
+
};
|
|
330
|
+
const toggleLaneCollapsed = () => {
|
|
331
|
+
if (collapsibleLanes) setCollapsed((c) => !c);
|
|
332
|
+
};
|
|
333
|
+
const renderAddCardLink = () => {
|
|
334
|
+
if (addCardLink) {
|
|
335
|
+
return /* @__PURE__ */ jsx4(
|
|
336
|
+
"span",
|
|
337
|
+
{
|
|
338
|
+
role: "button",
|
|
339
|
+
tabIndex: 0,
|
|
340
|
+
onClick: () => setAddCardMode(true),
|
|
341
|
+
onKeyDown: (e) => {
|
|
342
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
343
|
+
e.preventDefault();
|
|
344
|
+
setAddCardMode(true);
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
children: addCardLink
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
return /* @__PURE__ */ jsx4("button", { type: "button", className: "acms-admin-kanban-add-card-link", onClick: () => setAddCardMode(true), children: addCardTitle });
|
|
352
|
+
};
|
|
353
|
+
const renderFooter = () => {
|
|
354
|
+
if (collapsibleLanes && cards.length > 0) {
|
|
355
|
+
return /* @__PURE__ */ jsx4(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
className: "acms-admin-kanban-lane-footer",
|
|
360
|
+
onClick: toggleLaneCollapsed,
|
|
361
|
+
"aria-label": collapsed ? "Expand" : "Collapse",
|
|
362
|
+
children: /* @__PURE__ */ jsx4("span", { className: collapsed ? "acms-admin-kanban-expand-btn" : "acms-admin-kanban-collapse-btn" })
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
};
|
|
368
|
+
const sortedCards = useMemo(() => {
|
|
369
|
+
const showableCards = collapsed ? [] : cards;
|
|
370
|
+
if (!laneSortFunction) return showableCards;
|
|
371
|
+
return [...showableCards].sort(laneSortFunction);
|
|
372
|
+
}, [cards, collapsed, laneSortFunction]);
|
|
373
|
+
const cardIds = useMemo(() => sortedCards.map((c) => toCardId(c.id)), [sortedCards]);
|
|
374
|
+
return (
|
|
375
|
+
// レーン全体のクリックは任意コールバック用の補助的なフックであり、内部にカード/ボタン等の
|
|
376
|
+
// インタラクティブ要素を含むため要素自体をボタン化しない(既存挙動を維持)。
|
|
377
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
|
378
|
+
/* @__PURE__ */ jsxs2(
|
|
379
|
+
"section",
|
|
380
|
+
{
|
|
381
|
+
style,
|
|
382
|
+
onClick: () => onLaneClick && onLaneClick(id),
|
|
383
|
+
draggable: false,
|
|
384
|
+
className: "acms-admin-kanban-lane",
|
|
385
|
+
children: [
|
|
386
|
+
/* @__PURE__ */ jsx4(
|
|
387
|
+
components2.LaneHeader,
|
|
388
|
+
{
|
|
389
|
+
lane,
|
|
390
|
+
titleStyle,
|
|
391
|
+
labelStyle,
|
|
392
|
+
dragHandleListeners,
|
|
393
|
+
dragHandleAttributes,
|
|
394
|
+
onToggleCollapsed: toggleLaneCollapsed
|
|
395
|
+
}
|
|
396
|
+
),
|
|
397
|
+
/* @__PURE__ */ jsxs2(
|
|
398
|
+
"div",
|
|
399
|
+
{
|
|
400
|
+
ref: (node) => {
|
|
401
|
+
scrollRef.current = node;
|
|
402
|
+
setDropRef(node);
|
|
403
|
+
},
|
|
404
|
+
className: `acms-admin-kanban-lane-scroll${isOver ? " acms-admin-kanban-lane-scroll-dragover" : ""}`,
|
|
405
|
+
children: [
|
|
406
|
+
/* @__PURE__ */ jsx4(SortableContext, { items: cardIds, strategy: verticalListSortingStrategy, children: sortedCards.map((card) => /* @__PURE__ */ jsx4(
|
|
407
|
+
Card_default,
|
|
408
|
+
{
|
|
409
|
+
card,
|
|
410
|
+
laneId: id,
|
|
411
|
+
draggable,
|
|
412
|
+
cardDraggable,
|
|
413
|
+
editable,
|
|
414
|
+
hideCardDeleteIcon,
|
|
415
|
+
customCardLayout,
|
|
416
|
+
components: components2,
|
|
417
|
+
tagStyle,
|
|
418
|
+
cardStyle,
|
|
419
|
+
onCardClick,
|
|
420
|
+
onCardDelete,
|
|
421
|
+
onRemoveCard: removeCard
|
|
422
|
+
},
|
|
423
|
+
card.id
|
|
424
|
+
)) }),
|
|
425
|
+
editable && !addCardMode && renderAddCardLink(),
|
|
426
|
+
addCardMode && /* @__PURE__ */ jsx4("span", { children: /* @__PURE__ */ jsx4(components2.NewCard, { laneId: id, onCancel: () => setAddCardMode(false), onAdd: addNewCard }) })
|
|
427
|
+
]
|
|
428
|
+
}
|
|
429
|
+
),
|
|
430
|
+
loading && /* @__PURE__ */ jsx4(Spinner, { size: 24, style: { display: "block", margin: "15px auto" } }),
|
|
431
|
+
renderFooter()
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
id
|
|
435
|
+
)
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
var Lane_default = Lane;
|
|
439
|
+
|
|
440
|
+
// src/components/SortableLane.tsx
|
|
441
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
442
|
+
function SortableLane({ lane, disabled = false, ...laneProps }) {
|
|
443
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable2({
|
|
444
|
+
id: toLaneId(lane.id),
|
|
445
|
+
disabled,
|
|
446
|
+
data: { type: "LANE", lane }
|
|
447
|
+
});
|
|
448
|
+
const style = {
|
|
449
|
+
transform: CSS2.Transform.toString(transform),
|
|
450
|
+
transition,
|
|
451
|
+
opacity: isDragging ? 0.3 : 1,
|
|
452
|
+
display: "inline-block"
|
|
453
|
+
};
|
|
454
|
+
return /* @__PURE__ */ jsx5("div", { ref: setNodeRef, style, children: /* @__PURE__ */ jsx5(
|
|
455
|
+
Lane_default,
|
|
456
|
+
{
|
|
457
|
+
lane,
|
|
458
|
+
dragHandleListeners: listeners,
|
|
459
|
+
dragHandleAttributes: attributes,
|
|
460
|
+
...laneProps
|
|
461
|
+
}
|
|
462
|
+
) });
|
|
463
|
+
}
|
|
464
|
+
var SortableLane_default = SortableLane;
|
|
465
|
+
|
|
466
|
+
// src/components/DragOverlay/CardOverlay.tsx
|
|
467
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
468
|
+
var overlayStyle = {
|
|
469
|
+
transform: "rotate(3deg)",
|
|
470
|
+
boxShadow: "0 5px 15px rgba(0,0,0,0.3)",
|
|
471
|
+
cursor: "grabbing"
|
|
472
|
+
};
|
|
473
|
+
function CardOverlay({ card, components: components2, tagStyle, cardStyle = {}, customCardLayout = false }) {
|
|
474
|
+
const wrapperStyle = customCardLayout ? { ...cardStyle, padding: 0, ...overlayStyle } : { ...cardStyle, ...overlayStyle };
|
|
475
|
+
return /* @__PURE__ */ jsx6("article", { className: "acms-admin-kanban-card", "data-id": card.id, style: wrapperStyle, children: /* @__PURE__ */ jsx6(components2.Card, { card, laneId: card.laneId, tagStyle, onDelete: () => {
|
|
476
|
+
} }) });
|
|
477
|
+
}
|
|
478
|
+
var CardOverlay_default = CardOverlay;
|
|
479
|
+
|
|
480
|
+
// src/components/DragOverlay/LaneOverlay.tsx
|
|
481
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
482
|
+
var overlayStyle2 = {
|
|
483
|
+
transform: "rotate(3deg)",
|
|
484
|
+
boxShadow: "0 5px 15px rgba(0,0,0,0.3)",
|
|
485
|
+
cursor: "grabbing",
|
|
486
|
+
opacity: 0.9
|
|
487
|
+
};
|
|
488
|
+
function LaneOverlay({ lane }) {
|
|
489
|
+
return /* @__PURE__ */ jsx7(
|
|
490
|
+
"section",
|
|
491
|
+
{
|
|
492
|
+
style: { ...lane.style || {}, ...overlayStyle2 },
|
|
493
|
+
className: "acms-admin-kanban-lane",
|
|
494
|
+
children: /* @__PURE__ */ jsx7("span", { style: { fontWeight: "bold", padding: "5px" }, children: lane.title })
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
var LaneOverlay_default = LaneOverlay;
|
|
499
|
+
|
|
500
|
+
// src/components/BoardContainer.tsx
|
|
501
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
502
|
+
function BoardContainer(props) {
|
|
503
|
+
const {
|
|
504
|
+
data,
|
|
505
|
+
id,
|
|
506
|
+
draggable = false,
|
|
507
|
+
laneDraggable = true,
|
|
508
|
+
style,
|
|
509
|
+
editable = false,
|
|
510
|
+
canAddLanes = false,
|
|
511
|
+
addLaneTitle = "+ Add another lane",
|
|
512
|
+
components: components2,
|
|
513
|
+
onDataChange = () => {
|
|
514
|
+
},
|
|
515
|
+
eventBusHandle,
|
|
516
|
+
handleLaneDragStart = () => {
|
|
517
|
+
},
|
|
518
|
+
handleLaneDragEnd = () => {
|
|
519
|
+
},
|
|
520
|
+
handleDragStart = () => {
|
|
521
|
+
},
|
|
522
|
+
handleDragEnd = () => {
|
|
523
|
+
}
|
|
524
|
+
} = props;
|
|
525
|
+
const state = useBoardState();
|
|
526
|
+
const dispatch = useBoardDispatch();
|
|
527
|
+
const [addLaneMode, setAddLaneMode] = useState2(false);
|
|
528
|
+
const [activeId, setActiveId] = useState2(null);
|
|
529
|
+
const [activeLaneId, setActiveLaneId] = useState2(null);
|
|
530
|
+
const prevStateRef = useRef2(state);
|
|
531
|
+
const prevDataRef = useRef2(data);
|
|
532
|
+
useEffect2(() => {
|
|
533
|
+
if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
|
|
534
|
+
dispatch({ type: "LOAD_BOARD", payload: data });
|
|
535
|
+
onDataChange(data);
|
|
536
|
+
prevDataRef.current = data;
|
|
537
|
+
}
|
|
538
|
+
}, [data, dispatch, onDataChange]);
|
|
539
|
+
useEffect2(() => {
|
|
540
|
+
if (state !== prevStateRef.current && prevStateRef.current.lanes.length > 0) {
|
|
541
|
+
onDataChange(state);
|
|
542
|
+
prevStateRef.current = state;
|
|
543
|
+
}
|
|
544
|
+
}, [state, onDataChange]);
|
|
545
|
+
useEffect2(() => {
|
|
546
|
+
if (!eventBusHandle) return;
|
|
547
|
+
const eventBus = {
|
|
548
|
+
publish: (event) => {
|
|
549
|
+
switch (event.type) {
|
|
550
|
+
case "ADD_CARD":
|
|
551
|
+
dispatch({ type: "ADD_CARD", payload: { laneId: event.laneId, card: event.card } });
|
|
552
|
+
break;
|
|
553
|
+
case "REMOVE_CARD":
|
|
554
|
+
dispatch({ type: "REMOVE_CARD", payload: { laneId: event.laneId, cardId: event.cardId } });
|
|
555
|
+
break;
|
|
556
|
+
case "REFRESH_BOARD":
|
|
557
|
+
dispatch({ type: "LOAD_BOARD", payload: event.data });
|
|
558
|
+
break;
|
|
559
|
+
case "MOVE_CARD":
|
|
560
|
+
dispatch({
|
|
561
|
+
type: "MOVE_CARD",
|
|
562
|
+
payload: {
|
|
563
|
+
fromLaneId: event.fromLaneId,
|
|
564
|
+
toLaneId: event.toLaneId,
|
|
565
|
+
cardId: event.cardId,
|
|
566
|
+
index: event.index
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
break;
|
|
570
|
+
case "UPDATE_LANES":
|
|
571
|
+
dispatch({ type: "UPDATE_LANES", payload: event.lanes });
|
|
572
|
+
break;
|
|
573
|
+
default:
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
eventBusHandle(eventBus);
|
|
579
|
+
}, [eventBusHandle, dispatch]);
|
|
580
|
+
const sensors = useSensors(
|
|
581
|
+
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
582
|
+
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
|
583
|
+
);
|
|
584
|
+
const findCardLane = useCallback2(
|
|
585
|
+
(cardId) => {
|
|
586
|
+
return state.lanes.find((lane) => lane.cards.some((c) => c.id === cardId));
|
|
587
|
+
},
|
|
588
|
+
[state.lanes]
|
|
589
|
+
);
|
|
590
|
+
const handleDragStartEvent = (event) => {
|
|
591
|
+
const { active } = event;
|
|
592
|
+
setActiveId(active.id);
|
|
593
|
+
if (isCardId(active.id)) {
|
|
594
|
+
const cardId = fromCardId(active.id);
|
|
595
|
+
const lane = findCardLane(cardId);
|
|
596
|
+
if (lane) {
|
|
597
|
+
setActiveLaneId(lane.id);
|
|
598
|
+
handleDragStart(cardId, lane.id);
|
|
599
|
+
}
|
|
600
|
+
} else if (isLaneId(active.id)) {
|
|
601
|
+
const laneId = fromLaneId(active.id);
|
|
602
|
+
handleLaneDragStart(laneId);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
const handleDragOver = useCallback2(
|
|
606
|
+
(event) => {
|
|
607
|
+
const { active, over } = event;
|
|
608
|
+
if (!over || !isCardId(active.id)) return;
|
|
609
|
+
if (active.id === over.id) return;
|
|
610
|
+
const activeCardId = fromCardId(active.id);
|
|
611
|
+
const overId = over.id;
|
|
612
|
+
let overLaneId;
|
|
613
|
+
let overIndex;
|
|
614
|
+
if (isLaneId(overId) || isDropLaneId(overId)) {
|
|
615
|
+
overLaneId = isLaneId(overId) ? fromLaneId(overId) : fromDropLaneId(overId);
|
|
616
|
+
const overLane = state.lanes.find((l) => l.id === overLaneId);
|
|
617
|
+
overIndex = overLane?.cards.length ?? 0;
|
|
618
|
+
} else if (isCardId(overId)) {
|
|
619
|
+
const overCardId = fromCardId(overId);
|
|
620
|
+
const overLane = state.lanes.find((l) => l.cards.some((c) => c.id === overCardId));
|
|
621
|
+
if (!overLane) return;
|
|
622
|
+
overLaneId = overLane.id;
|
|
623
|
+
overIndex = overLane.cards.findIndex((c) => c.id === overCardId);
|
|
624
|
+
} else {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const currentLaneId = activeLaneId || findCardLane(activeCardId)?.id;
|
|
628
|
+
if (!currentLaneId || currentLaneId === overLaneId) return;
|
|
629
|
+
const targetLane = state.lanes.find((l) => l.id === overLaneId);
|
|
630
|
+
if (targetLane?.droppable === false) return;
|
|
631
|
+
dispatch({
|
|
632
|
+
type: "MOVE_CARD",
|
|
633
|
+
payload: { fromLaneId: currentLaneId, toLaneId: overLaneId, cardId: activeCardId, index: overIndex }
|
|
634
|
+
});
|
|
635
|
+
setActiveLaneId(overLaneId);
|
|
636
|
+
},
|
|
637
|
+
[state.lanes, activeLaneId, findCardLane, dispatch]
|
|
638
|
+
);
|
|
639
|
+
const handleDragEndEvent = useCallback2(
|
|
640
|
+
(event) => {
|
|
641
|
+
const { active, over } = event;
|
|
642
|
+
if (over && isCardId(active.id)) {
|
|
643
|
+
const activeCardId = fromCardId(active.id);
|
|
644
|
+
if (isCardId(over.id)) {
|
|
645
|
+
const overCardId = fromCardId(over.id);
|
|
646
|
+
if (activeCardId !== overCardId) {
|
|
647
|
+
const lane = state.lanes.find((l) => l.cards.some((c) => c.id === activeCardId));
|
|
648
|
+
if (lane) {
|
|
649
|
+
const oldIndex = lane.cards.findIndex((c) => c.id === activeCardId);
|
|
650
|
+
const newIndex = lane.cards.findIndex((c) => c.id === overCardId);
|
|
651
|
+
if (oldIndex !== -1 && newIndex !== -1 && lane.cards[oldIndex]?.laneId === lane.cards[newIndex]?.laneId) {
|
|
652
|
+
const newCards = arrayMove(lane.cards, oldIndex, newIndex);
|
|
653
|
+
dispatch({ type: "UPDATE_CARDS", payload: { laneId: lane.id, cards: newCards } });
|
|
654
|
+
handleDragEnd(activeCardId, lane.id, lane.id, newIndex, lane.cards[oldIndex]);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (activeLaneId) {
|
|
660
|
+
const finalLane = state.lanes.find((l) => l.id === activeLaneId);
|
|
661
|
+
const cardDetails = finalLane?.cards.find((c) => c.id === activeCardId);
|
|
662
|
+
const originalLane = findCardLane(activeCardId);
|
|
663
|
+
if (cardDetails && originalLane && originalLane.id !== activeLaneId) {
|
|
664
|
+
const position = finalLane?.cards.findIndex((c) => c.id === activeCardId) ?? 0;
|
|
665
|
+
handleDragEnd(activeCardId, originalLane.id, activeLaneId, position, cardDetails);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
} else if (over && isLaneId(active.id)) {
|
|
669
|
+
const activeLaneIdStr = fromLaneId(active.id);
|
|
670
|
+
const overLaneIdStr = isLaneId(over.id) ? fromLaneId(over.id) : null;
|
|
671
|
+
if (overLaneIdStr && activeLaneIdStr !== overLaneIdStr) {
|
|
672
|
+
const oldIndex = state.lanes.findIndex((l) => l.id === activeLaneIdStr);
|
|
673
|
+
const newIndex = state.lanes.findIndex((l) => l.id === overLaneIdStr);
|
|
674
|
+
if (oldIndex !== -1 && newIndex !== -1) {
|
|
675
|
+
dispatch({ type: "MOVE_LANE", payload: { oldIndex, newIndex } });
|
|
676
|
+
const payload = state.lanes[oldIndex];
|
|
677
|
+
handleLaneDragEnd(activeLaneIdStr, newIndex, payload);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
setActiveId(null);
|
|
682
|
+
setActiveLaneId(null);
|
|
683
|
+
},
|
|
684
|
+
[state.lanes, activeLaneId, findCardLane, dispatch, handleDragEnd, handleLaneDragEnd]
|
|
685
|
+
);
|
|
686
|
+
const activeCard = useMemo2(() => {
|
|
687
|
+
if (!activeId || !isCardId(activeId)) return null;
|
|
688
|
+
const cardId = fromCardId(activeId);
|
|
689
|
+
const lane = findCardLane(cardId);
|
|
690
|
+
return lane?.cards.find((c) => c.id === cardId) ?? null;
|
|
691
|
+
}, [activeId, findCardLane]);
|
|
692
|
+
const activeLane = useMemo2(() => {
|
|
693
|
+
if (!activeId || !isLaneId(activeId)) return null;
|
|
694
|
+
return state.lanes.find((l) => l.id === fromLaneId(activeId)) ?? null;
|
|
695
|
+
}, [activeId, state.lanes]);
|
|
696
|
+
const laneIds = useMemo2(() => state.lanes.map((l) => toLaneId(l.id)), [state.lanes]);
|
|
697
|
+
const {
|
|
698
|
+
onLaneScroll,
|
|
699
|
+
onCardClick,
|
|
700
|
+
onCardDelete,
|
|
701
|
+
onCardAdd,
|
|
702
|
+
onLaneClick,
|
|
703
|
+
addCardLink,
|
|
704
|
+
laneSortFunction,
|
|
705
|
+
cardDraggable,
|
|
706
|
+
collapsibleLanes,
|
|
707
|
+
hideCardDeleteIcon,
|
|
708
|
+
customCardLayout,
|
|
709
|
+
tagStyle,
|
|
710
|
+
cardDragClass,
|
|
711
|
+
addCardTitle
|
|
712
|
+
} = props;
|
|
713
|
+
const passthroughProps = {
|
|
714
|
+
onLaneScroll,
|
|
715
|
+
onCardClick,
|
|
716
|
+
onCardDelete,
|
|
717
|
+
onCardAdd,
|
|
718
|
+
onLaneClick,
|
|
719
|
+
addCardLink,
|
|
720
|
+
laneSortFunction,
|
|
721
|
+
draggable,
|
|
722
|
+
cardDraggable,
|
|
723
|
+
collapsibleLanes,
|
|
724
|
+
editable,
|
|
725
|
+
canAddLanes,
|
|
726
|
+
hideCardDeleteIcon,
|
|
727
|
+
customCardLayout,
|
|
728
|
+
components: components2,
|
|
729
|
+
tagStyle,
|
|
730
|
+
handleDragStart,
|
|
731
|
+
handleDragEnd,
|
|
732
|
+
cardDragClass,
|
|
733
|
+
addCardTitle
|
|
734
|
+
};
|
|
735
|
+
const addNewLane = (params) => {
|
|
736
|
+
setAddLaneMode(false);
|
|
737
|
+
dispatch({ type: "ADD_LANE", payload: params });
|
|
738
|
+
};
|
|
739
|
+
const renderNewLane = () => /* @__PURE__ */ jsx8("span", { children: /* @__PURE__ */ jsx8(components2.NewLane, { onCancel: () => setAddLaneMode(false), onAdd: addNewLane }) });
|
|
740
|
+
const renderDragOverlayContent = () => {
|
|
741
|
+
if (activeCard) {
|
|
742
|
+
return /* @__PURE__ */ jsx8(
|
|
743
|
+
CardOverlay_default,
|
|
744
|
+
{
|
|
745
|
+
card: activeCard,
|
|
746
|
+
components: components2,
|
|
747
|
+
tagStyle: passthroughProps.tagStyle,
|
|
748
|
+
customCardLayout: passthroughProps.customCardLayout
|
|
749
|
+
}
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
if (activeLane) {
|
|
753
|
+
return /* @__PURE__ */ jsx8(LaneOverlay_default, { lane: activeLane });
|
|
754
|
+
}
|
|
755
|
+
return null;
|
|
756
|
+
};
|
|
757
|
+
return /* @__PURE__ */ jsxs3(
|
|
758
|
+
DndContext,
|
|
759
|
+
{
|
|
760
|
+
sensors,
|
|
761
|
+
collisionDetection: closestCorners,
|
|
762
|
+
onDragStart: handleDragStartEvent,
|
|
763
|
+
onDragOver: handleDragOver,
|
|
764
|
+
onDragEnd: handleDragEndEvent,
|
|
765
|
+
children: [
|
|
766
|
+
/* @__PURE__ */ jsxs3("div", { style, draggable: false, className: "acms-admin-kanban-board", "data-boardid": id, children: [
|
|
767
|
+
/* @__PURE__ */ jsx8(SortableContext2, { items: laneIds, strategy: horizontalListSortingStrategy, children: state.lanes.map((lane, index) => {
|
|
768
|
+
const isLaneDraggable = draggable && laneDraggable && (lane.movable === void 0 ? true : lane.movable);
|
|
769
|
+
return /* @__PURE__ */ jsx8(
|
|
770
|
+
SortableLane_default,
|
|
771
|
+
{
|
|
772
|
+
lane,
|
|
773
|
+
boardId: `TrelloBoard${id}`,
|
|
774
|
+
index,
|
|
775
|
+
disabled: !isLaneDraggable,
|
|
776
|
+
laneDraggable,
|
|
777
|
+
...passthroughProps
|
|
778
|
+
},
|
|
779
|
+
lane.id
|
|
780
|
+
);
|
|
781
|
+
}) }),
|
|
782
|
+
editable && canAddLanes && !addLaneMode && /* @__PURE__ */ jsx8(
|
|
783
|
+
"span",
|
|
784
|
+
{
|
|
785
|
+
role: "button",
|
|
786
|
+
tabIndex: 0,
|
|
787
|
+
style: { cursor: "pointer", padding: "10px", color: "#fff" },
|
|
788
|
+
onClick: () => setAddLaneMode(true),
|
|
789
|
+
onKeyDown: (e) => {
|
|
790
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
791
|
+
e.preventDefault();
|
|
792
|
+
setAddLaneMode(true);
|
|
793
|
+
}
|
|
794
|
+
},
|
|
795
|
+
children: addLaneTitle
|
|
796
|
+
}
|
|
797
|
+
),
|
|
798
|
+
addLaneMode && renderNewLane()
|
|
799
|
+
] }),
|
|
800
|
+
/* @__PURE__ */ jsx8(DragOverlay, { children: renderDragOverlayContent() })
|
|
801
|
+
]
|
|
802
|
+
}
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
var BoardContainer_default = BoardContainer;
|
|
806
|
+
|
|
807
|
+
// src/components/Tag.tsx
|
|
808
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
809
|
+
function Tag({ title, color, bgcolor, tagStyle }) {
|
|
810
|
+
const style = {
|
|
811
|
+
color: color || "white",
|
|
812
|
+
backgroundColor: bgcolor || "orange",
|
|
813
|
+
...tagStyle
|
|
814
|
+
};
|
|
815
|
+
return /* @__PURE__ */ jsx9("span", { className: "acms-admin-kanban-tag", style, children: title });
|
|
816
|
+
}
|
|
817
|
+
var Tag_default = Tag;
|
|
818
|
+
|
|
819
|
+
// src/components/DefaultCard.tsx
|
|
820
|
+
import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
821
|
+
function DefaultCard({ card, tagStyle }) {
|
|
822
|
+
const { title, description, label, tags } = card;
|
|
823
|
+
return /* @__PURE__ */ jsxs4("span", { children: [
|
|
824
|
+
/* @__PURE__ */ jsxs4("header", { className: "acms-admin-kanban-card-header", children: [
|
|
825
|
+
/* @__PURE__ */ jsx10("span", { className: "acms-admin-kanban-card-title", children: title }),
|
|
826
|
+
/* @__PURE__ */ jsx10("span", { className: "acms-admin-kanban-card-label", children: label })
|
|
827
|
+
] }),
|
|
828
|
+
/* @__PURE__ */ jsx10("div", { className: "acms-admin-kanban-card-detail", children: description }),
|
|
829
|
+
tags && /* @__PURE__ */ jsx10("div", { className: "acms-admin-kanban-card-footer", children: tags.map((tag) => /* @__PURE__ */ jsx10(Tag_default, { ...tag, tagStyle }, tag.title)) })
|
|
830
|
+
] });
|
|
831
|
+
}
|
|
832
|
+
var DefaultCard_default = DefaultCard;
|
|
833
|
+
|
|
834
|
+
// src/components/DefaultLaneHeader.tsx
|
|
835
|
+
import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
836
|
+
function DefaultLaneHeader({
|
|
837
|
+
lane,
|
|
838
|
+
titleStyle,
|
|
839
|
+
labelStyle,
|
|
840
|
+
dragHandleListeners,
|
|
841
|
+
dragHandleAttributes,
|
|
842
|
+
onToggleCollapsed
|
|
843
|
+
}) {
|
|
844
|
+
return /* @__PURE__ */ jsxs5(
|
|
845
|
+
"header",
|
|
846
|
+
{
|
|
847
|
+
className: "acms-admin-kanban-lane-header",
|
|
848
|
+
onDoubleClick: onToggleCollapsed,
|
|
849
|
+
...dragHandleListeners || {},
|
|
850
|
+
...dragHandleAttributes || {},
|
|
851
|
+
children: [
|
|
852
|
+
/* @__PURE__ */ jsx11("span", { className: "acms-admin-kanban-lane-title", style: titleStyle, children: lane.title }),
|
|
853
|
+
lane.label && /* @__PURE__ */ jsx11("span", { className: "acms-admin-kanban-lane-label", children: /* @__PURE__ */ jsx11("span", { style: labelStyle, children: lane.label }) })
|
|
854
|
+
]
|
|
855
|
+
}
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
var DefaultLaneHeader_default = DefaultLaneHeader;
|
|
859
|
+
|
|
860
|
+
// src/components/NewCard.tsx
|
|
861
|
+
import { useState as useState4 } from "react";
|
|
862
|
+
import { Button } from "@ablogcms/components/button";
|
|
863
|
+
|
|
864
|
+
// src/components/widgets/EditableLabel.tsx
|
|
865
|
+
import { useRef as useRef3, useState as useState3, useEffect as useEffect3 } from "react";
|
|
866
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
867
|
+
function EditableLabel({ onChange = () => {
|
|
868
|
+
}, placeholder = "", autoFocus = false }) {
|
|
869
|
+
const [text, setText] = useState3("");
|
|
870
|
+
const divRef = useRef3(null);
|
|
871
|
+
useEffect3(() => {
|
|
872
|
+
if (autoFocus && divRef.current) {
|
|
873
|
+
divRef.current.focus();
|
|
874
|
+
}
|
|
875
|
+
}, [autoFocus]);
|
|
876
|
+
const onTextChange = (ev) => {
|
|
877
|
+
setText(ev.currentTarget.innerText);
|
|
878
|
+
};
|
|
879
|
+
const onBlur = () => {
|
|
880
|
+
onChange(text);
|
|
881
|
+
};
|
|
882
|
+
const onPaste = (ev) => {
|
|
883
|
+
ev.preventDefault();
|
|
884
|
+
const pastedText = ev.clipboardData.getData("text");
|
|
885
|
+
document.execCommand("insertText", false, pastedText);
|
|
886
|
+
};
|
|
887
|
+
const className = `acms-admin-kanban-editable-label${text === "" ? " acms-admin-kanban-editable-label--has-placeholder" : ""}`;
|
|
888
|
+
return /* @__PURE__ */ jsx12(
|
|
889
|
+
"div",
|
|
890
|
+
{
|
|
891
|
+
ref: divRef,
|
|
892
|
+
contentEditable: true,
|
|
893
|
+
className,
|
|
894
|
+
onPaste,
|
|
895
|
+
onBlur,
|
|
896
|
+
onInput: onTextChange,
|
|
897
|
+
"data-placeholder": placeholder,
|
|
898
|
+
suppressContentEditableWarning: true
|
|
899
|
+
}
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
var EditableLabel_default = EditableLabel;
|
|
903
|
+
|
|
904
|
+
// src/components/NewCard.tsx
|
|
905
|
+
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
906
|
+
function NewCard({
|
|
907
|
+
laneId: _laneId,
|
|
908
|
+
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
909
|
+
onCancel,
|
|
910
|
+
onAdd
|
|
911
|
+
}) {
|
|
912
|
+
const [formData, setFormData] = useState4({ title: "", label: "", description: "" });
|
|
913
|
+
const updateField = (field, value) => {
|
|
914
|
+
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
915
|
+
};
|
|
916
|
+
const handleAdd = () => {
|
|
917
|
+
onAdd(formData);
|
|
918
|
+
};
|
|
919
|
+
return /* @__PURE__ */ jsxs6("div", { className: "acms-admin-kanban-new-lane", children: [
|
|
920
|
+
/* @__PURE__ */ jsxs6("div", { className: "acms-admin-kanban-card", children: [
|
|
921
|
+
/* @__PURE__ */ jsxs6("header", { className: "acms-admin-kanban-card-header", children: [
|
|
922
|
+
/* @__PURE__ */ jsx13("span", { className: "acms-admin-kanban-card-title", children: /* @__PURE__ */ jsx13(EditableLabel_default, { placeholder: "title", onChange: (val) => updateField("title", val), autoFocus: true }) }),
|
|
923
|
+
/* @__PURE__ */ jsx13("span", { className: "acms-admin-kanban-card-label", children: /* @__PURE__ */ jsx13(EditableLabel_default, { placeholder: "label", onChange: (val) => updateField("label", val) }) })
|
|
924
|
+
] }),
|
|
925
|
+
/* @__PURE__ */ jsx13("div", { className: "acms-admin-kanban-card-detail", children: /* @__PURE__ */ jsx13(EditableLabel_default, { placeholder: "description", onChange: (val) => updateField("description", val) }) })
|
|
926
|
+
] }),
|
|
927
|
+
/* @__PURE__ */ jsx13(Button, { type: "button", variant: "success", onClick: handleAdd, children: "Add" }),
|
|
928
|
+
/* @__PURE__ */ jsx13(Button, { type: "button", variant: "text", onClick: onCancel, children: "Cancel" })
|
|
929
|
+
] });
|
|
930
|
+
}
|
|
931
|
+
var NewCard_default = NewCard;
|
|
932
|
+
|
|
933
|
+
// src/components/NewLane.tsx
|
|
934
|
+
import { useState as useState5 } from "react";
|
|
935
|
+
import { Button as Button2 } from "@ablogcms/components/button";
|
|
936
|
+
import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
937
|
+
function NewLane({ onCancel, onAdd }) {
|
|
938
|
+
const [formData, setFormData] = useState5({ title: "" });
|
|
939
|
+
const updateField = (field, value) => {
|
|
940
|
+
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
941
|
+
};
|
|
942
|
+
const handleAdd = () => {
|
|
943
|
+
onAdd(formData);
|
|
944
|
+
};
|
|
945
|
+
return /* @__PURE__ */ jsxs7("div", { className: "acms-admin-kanban-new-lane", children: [
|
|
946
|
+
/* @__PURE__ */ jsx14("div", { className: "acms-admin-kanban-new-lane-title", children: /* @__PURE__ */ jsx14(EditableLabel_default, { placeholder: "title", onChange: (val) => updateField("title", val), autoFocus: true }) }),
|
|
947
|
+
/* @__PURE__ */ jsxs7("div", { className: "acms-admin-kanban-new-lane-buttons", children: [
|
|
948
|
+
/* @__PURE__ */ jsx14(Button2, { type: "button", variant: "success", onClick: handleAdd, children: "Add" }),
|
|
949
|
+
/* @__PURE__ */ jsx14(Button2, { type: "button", variant: "text", onClick: onCancel, children: "Cancel" })
|
|
950
|
+
] })
|
|
951
|
+
] });
|
|
952
|
+
}
|
|
953
|
+
var NewLane_default = NewLane;
|
|
954
|
+
|
|
955
|
+
// src/components.ts
|
|
956
|
+
var components = {
|
|
957
|
+
Card: DefaultCard_default,
|
|
958
|
+
LaneHeader: DefaultLaneHeader_default,
|
|
959
|
+
NewCard: NewCard_default,
|
|
960
|
+
NewLane: NewLane_default
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/components/Board.tsx
|
|
964
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
965
|
+
function Board(props) {
|
|
966
|
+
const boardId = useRef4(uuidv43()).current;
|
|
967
|
+
const components2 = useMemo3(() => ({ ...components, ...props.components }), [props.components]);
|
|
968
|
+
return /* @__PURE__ */ jsx15(BoardProvider, { initialData: props.data, children: /* @__PURE__ */ jsx15(BoardContainer_default, { ...props, id: boardId, components: components2 }) });
|
|
969
|
+
}
|
|
970
|
+
var Board_default = Board;
|
|
971
|
+
|
|
972
|
+
// src/index.ts
|
|
973
|
+
var index_default = Board_default;
|
|
974
|
+
export {
|
|
975
|
+
Board_default as Board,
|
|
976
|
+
Card_default as Card,
|
|
977
|
+
Lane_default as Lane,
|
|
978
|
+
Tag_default as Tag,
|
|
979
|
+
index_default as default
|
|
980
|
+
};
|
|
981
|
+
//# sourceMappingURL=index.mjs.map
|