hazo_ui 6.3.1 → 6.5.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/CHANGE_LOG.md +85 -0
- package/README.md +42 -0
- package/dist/index.cjs +371 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -4
- package/dist/index.d.ts +83 -4
- package/dist/index.js +372 -74
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import * as SelectPrimitive from '@radix-ui/react-select';
|
|
|
15
15
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
16
16
|
import { DayPicker } from 'react-day-picker';
|
|
17
17
|
import { format } from 'date-fns';
|
|
18
|
-
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter, closestCorners, DragOverlay, useDroppable } from '@dnd-kit/core';
|
|
18
|
+
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter, pointerWithin, rectIntersection, closestCorners, DragOverlay, useDroppable } from '@dnd-kit/core';
|
|
19
19
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
|
|
20
20
|
import { CSS } from '@dnd-kit/utilities';
|
|
21
21
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
@@ -9019,7 +9019,18 @@ function KanbanCard({
|
|
|
9019
9019
|
transform,
|
|
9020
9020
|
transition,
|
|
9021
9021
|
isDragging
|
|
9022
|
-
} = useSortable({
|
|
9022
|
+
} = useSortable({
|
|
9023
|
+
id: item.id,
|
|
9024
|
+
// sectionKey and laneKey ride along so a drop *onto a card* resolves to
|
|
9025
|
+
// that card's section and lane, not just its column (the section bands
|
|
9026
|
+
// and lane rows cover the gaps between cards, but the cards themselves
|
|
9027
|
+
// are the sortable).
|
|
9028
|
+
data: {
|
|
9029
|
+
columnKey: item.columnKey,
|
|
9030
|
+
sectionKey: item.sectionKey,
|
|
9031
|
+
laneKey: item.laneKey
|
|
9032
|
+
}
|
|
9033
|
+
});
|
|
9023
9034
|
const priority_var = item.priority ? `--hazo-kanban-priority-${String(item.priority).toLowerCase()}` : null;
|
|
9024
9035
|
const style = {
|
|
9025
9036
|
transform: CSS.Transform.toString(transform),
|
|
@@ -9079,6 +9090,28 @@ function KanbanCard({
|
|
|
9079
9090
|
}
|
|
9080
9091
|
);
|
|
9081
9092
|
}
|
|
9093
|
+
function tree_droppable_id(prefix, tree_key, lane_key, rest) {
|
|
9094
|
+
return lane_key == null ? `${prefix}:${tree_key}::${rest}` : `${prefix}:${tree_key}::${lane_key}::${rest}`;
|
|
9095
|
+
}
|
|
9096
|
+
function section_droppable_id(column_key, section_key, tree_key, lane_key) {
|
|
9097
|
+
return tree_droppable_id(
|
|
9098
|
+
"section",
|
|
9099
|
+
tree_key,
|
|
9100
|
+
lane_key,
|
|
9101
|
+
`${column_key}::${section_key}`
|
|
9102
|
+
);
|
|
9103
|
+
}
|
|
9104
|
+
function group_items_by_section(items, sections) {
|
|
9105
|
+
const bySection = /* @__PURE__ */ new Map();
|
|
9106
|
+
for (const section of sections) bySection.set(section.key, []);
|
|
9107
|
+
const unmatched = [];
|
|
9108
|
+
for (const item of items) {
|
|
9109
|
+
const bucket = item.sectionKey != null ? bySection.get(item.sectionKey) : void 0;
|
|
9110
|
+
if (bucket) bucket.push(item);
|
|
9111
|
+
else unmatched.push(item);
|
|
9112
|
+
}
|
|
9113
|
+
return { bySection, unmatched };
|
|
9114
|
+
}
|
|
9082
9115
|
function KanbanColumn({
|
|
9083
9116
|
column,
|
|
9084
9117
|
items,
|
|
@@ -9086,12 +9119,45 @@ function KanbanColumn({
|
|
|
9086
9119
|
emptyColumn,
|
|
9087
9120
|
cardClassName,
|
|
9088
9121
|
showEdit,
|
|
9089
|
-
onEditRequest
|
|
9122
|
+
onEditRequest,
|
|
9123
|
+
laneKey,
|
|
9124
|
+
treeKey
|
|
9090
9125
|
}) {
|
|
9091
9126
|
const { setNodeRef, isOver } = useDroppable({
|
|
9092
|
-
id:
|
|
9093
|
-
data: { columnKey: column.key, isColumn: true }
|
|
9127
|
+
id: tree_droppable_id("column", treeKey, laneKey, column.key),
|
|
9128
|
+
data: { columnKey: column.key, laneKey, isColumn: true }
|
|
9094
9129
|
});
|
|
9130
|
+
const sections = column.sections;
|
|
9131
|
+
const { bySection, unmatched } = React27.useMemo(
|
|
9132
|
+
() => sections ? group_items_by_section(items, sections) : { bySection: /* @__PURE__ */ new Map(), unmatched: items },
|
|
9133
|
+
[items, sections]
|
|
9134
|
+
);
|
|
9135
|
+
const ordered = React27.useMemo(() => {
|
|
9136
|
+
if (!sections) return items;
|
|
9137
|
+
const out = [];
|
|
9138
|
+
for (const section of sections) out.push(...bySection.get(section.key) ?? []);
|
|
9139
|
+
out.push(...unmatched);
|
|
9140
|
+
return out;
|
|
9141
|
+
}, [items, sections, bySection, unmatched]);
|
|
9142
|
+
function render_cards(list) {
|
|
9143
|
+
return list.map((item) => /* @__PURE__ */ jsx(
|
|
9144
|
+
KanbanCard,
|
|
9145
|
+
{
|
|
9146
|
+
item,
|
|
9147
|
+
renderCard,
|
|
9148
|
+
cardClassName,
|
|
9149
|
+
showEdit,
|
|
9150
|
+
onEditRequest
|
|
9151
|
+
},
|
|
9152
|
+
item.id
|
|
9153
|
+
));
|
|
9154
|
+
}
|
|
9155
|
+
const expanded_sections = (sections ?? []).filter(
|
|
9156
|
+
(s) => !(s.collapseWhenEmpty && (bySection.get(s.key) ?? []).length === 0)
|
|
9157
|
+
);
|
|
9158
|
+
const collapsed_sections = (sections ?? []).filter(
|
|
9159
|
+
(s) => s.collapseWhenEmpty && (bySection.get(s.key) ?? []).length === 0
|
|
9160
|
+
);
|
|
9095
9161
|
return /* @__PURE__ */ jsxs(
|
|
9096
9162
|
"div",
|
|
9097
9163
|
{
|
|
@@ -9101,32 +9167,185 @@ function KanbanColumn({
|
|
|
9101
9167
|
isOver && "cls_hazo_kanban_column_over bg-accent/30 ring-2 ring-ring/40"
|
|
9102
9168
|
),
|
|
9103
9169
|
children: [
|
|
9104
|
-
/* @__PURE__ */
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9170
|
+
/* @__PURE__ */ jsx(
|
|
9171
|
+
KanbanColumnHead,
|
|
9172
|
+
{
|
|
9173
|
+
columnKey: column.key,
|
|
9174
|
+
laneKey,
|
|
9175
|
+
treeKey,
|
|
9176
|
+
title: column.title,
|
|
9177
|
+
count: items.length,
|
|
9178
|
+
droppable: sections != null
|
|
9179
|
+
}
|
|
9180
|
+
),
|
|
9108
9181
|
/* @__PURE__ */ jsx(
|
|
9109
9182
|
SortableContext,
|
|
9110
9183
|
{
|
|
9111
|
-
items:
|
|
9184
|
+
items: ordered.map((i) => i.id),
|
|
9112
9185
|
strategy: verticalListSortingStrategy,
|
|
9113
|
-
children: /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_body flex-1 min-h-[40px]", children: items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_empty text-xs text-muted-foreground py-2 px-1", children: emptyColumn }) : items
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9186
|
+
children: /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_body flex-1 min-h-[40px]", children: !sections ? items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_empty text-xs text-muted-foreground py-2 px-1", children: emptyColumn }) : render_cards(items) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9187
|
+
expanded_sections.map((section) => /* @__PURE__ */ jsx(
|
|
9188
|
+
KanbanSectionBand,
|
|
9189
|
+
{
|
|
9190
|
+
columnKey: column.key,
|
|
9191
|
+
laneKey,
|
|
9192
|
+
treeKey,
|
|
9193
|
+
section,
|
|
9194
|
+
items: bySection.get(section.key) ?? [],
|
|
9195
|
+
emptyColumn,
|
|
9196
|
+
renderCards: render_cards
|
|
9197
|
+
},
|
|
9198
|
+
section.key
|
|
9199
|
+
)),
|
|
9200
|
+
unmatched.length > 0 && /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section cls_hazo_kanban_section_unmatched", children: render_cards(unmatched) }),
|
|
9201
|
+
collapsed_sections.length > 0 && /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section_strips mt-2 flex flex-wrap gap-1 border-t border-dashed border-border pt-2", children: collapsed_sections.map((section) => /* @__PURE__ */ jsx(
|
|
9202
|
+
KanbanSectionStrip,
|
|
9203
|
+
{
|
|
9204
|
+
columnKey: column.key,
|
|
9205
|
+
laneKey,
|
|
9206
|
+
treeKey,
|
|
9207
|
+
section
|
|
9208
|
+
},
|
|
9209
|
+
section.key
|
|
9210
|
+
)) })
|
|
9211
|
+
] }) })
|
|
9124
9212
|
}
|
|
9125
9213
|
)
|
|
9126
9214
|
]
|
|
9127
9215
|
}
|
|
9128
9216
|
);
|
|
9129
9217
|
}
|
|
9218
|
+
function KanbanColumnHead({
|
|
9219
|
+
columnKey,
|
|
9220
|
+
laneKey,
|
|
9221
|
+
treeKey,
|
|
9222
|
+
title,
|
|
9223
|
+
count,
|
|
9224
|
+
droppable
|
|
9225
|
+
}) {
|
|
9226
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9227
|
+
id: tree_droppable_id("columnhead", treeKey, laneKey, columnKey),
|
|
9228
|
+
data: { columnKey, laneKey, isColumn: true },
|
|
9229
|
+
disabled: !droppable
|
|
9230
|
+
});
|
|
9231
|
+
return /* @__PURE__ */ jsxs(
|
|
9232
|
+
"div",
|
|
9233
|
+
{
|
|
9234
|
+
ref: droppable ? setNodeRef : void 0,
|
|
9235
|
+
className: cn(
|
|
9236
|
+
"cls_hazo_kanban_column_head mb-2 flex items-center justify-between rounded-sm px-1 text-xs uppercase tracking-wider text-muted-foreground",
|
|
9237
|
+
droppable && "py-1",
|
|
9238
|
+
isOver && "cls_hazo_kanban_column_head_over bg-accent/30 text-foreground ring-1 ring-ring/40"
|
|
9239
|
+
),
|
|
9240
|
+
children: [
|
|
9241
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_column_title", children: title }),
|
|
9242
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_column_count rounded-full bg-muted px-2 py-0.5 text-foreground", children: count })
|
|
9243
|
+
]
|
|
9244
|
+
}
|
|
9245
|
+
);
|
|
9246
|
+
}
|
|
9247
|
+
function KanbanSectionBand({
|
|
9248
|
+
columnKey,
|
|
9249
|
+
laneKey,
|
|
9250
|
+
treeKey,
|
|
9251
|
+
section,
|
|
9252
|
+
items,
|
|
9253
|
+
emptyColumn,
|
|
9254
|
+
renderCards
|
|
9255
|
+
}) {
|
|
9256
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9257
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9258
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9259
|
+
});
|
|
9260
|
+
return /* @__PURE__ */ jsxs(
|
|
9261
|
+
"div",
|
|
9262
|
+
{
|
|
9263
|
+
ref: setNodeRef,
|
|
9264
|
+
className: cn(
|
|
9265
|
+
"cls_hazo_kanban_section rounded-sm",
|
|
9266
|
+
isOver && "cls_hazo_kanban_section_over bg-accent/20 ring-1 ring-ring/30"
|
|
9267
|
+
),
|
|
9268
|
+
children: [
|
|
9269
|
+
/* @__PURE__ */ jsxs("div", { className: "cls_hazo_kanban_section_head mt-2 mb-1 flex items-center gap-2 px-1 first:mt-0", children: [
|
|
9270
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_section_title text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: section.title }),
|
|
9271
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_section_rule h-px flex-1 bg-border" }),
|
|
9272
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_section_count text-[11px] tabular-nums text-muted-foreground", children: items.length })
|
|
9273
|
+
] }),
|
|
9274
|
+
/* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section_body min-h-[32px]", children: items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section_empty px-1 py-1 text-xs text-muted-foreground", children: emptyColumn }) : renderCards(items) })
|
|
9275
|
+
]
|
|
9276
|
+
}
|
|
9277
|
+
);
|
|
9278
|
+
}
|
|
9279
|
+
function KanbanSectionStrip({
|
|
9280
|
+
columnKey,
|
|
9281
|
+
laneKey,
|
|
9282
|
+
treeKey,
|
|
9283
|
+
section
|
|
9284
|
+
}) {
|
|
9285
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9286
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9287
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9288
|
+
});
|
|
9289
|
+
return /* @__PURE__ */ jsx(
|
|
9290
|
+
"div",
|
|
9291
|
+
{
|
|
9292
|
+
ref: setNodeRef,
|
|
9293
|
+
className: cn(
|
|
9294
|
+
"cls_hazo_kanban_section_strip rounded-full border border-dashed border-border px-2 py-0.5 text-[11px] text-muted-foreground",
|
|
9295
|
+
isOver && "cls_hazo_kanban_section_strip_over border-solid bg-accent/30 text-foreground ring-1 ring-ring/30"
|
|
9296
|
+
),
|
|
9297
|
+
children: section.title
|
|
9298
|
+
}
|
|
9299
|
+
);
|
|
9300
|
+
}
|
|
9301
|
+
function lane_droppable_id(lane_key, tree_key) {
|
|
9302
|
+
return `lane:${tree_key}::${lane_key}`;
|
|
9303
|
+
}
|
|
9304
|
+
function KanbanLaneHead({
|
|
9305
|
+
lane,
|
|
9306
|
+
count,
|
|
9307
|
+
treeKey
|
|
9308
|
+
}) {
|
|
9309
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9310
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9311
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9312
|
+
});
|
|
9313
|
+
return /* @__PURE__ */ jsxs(
|
|
9314
|
+
"div",
|
|
9315
|
+
{
|
|
9316
|
+
ref: setNodeRef,
|
|
9317
|
+
className: cn(
|
|
9318
|
+
"cls_hazo_kanban_lane_head mb-2 flex items-center gap-3 rounded-sm px-1 py-1",
|
|
9319
|
+
isOver && "cls_hazo_kanban_lane_head_over bg-accent/30 ring-1 ring-ring/40"
|
|
9320
|
+
),
|
|
9321
|
+
children: [
|
|
9322
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_title text-xs font-semibold uppercase tracking-wider text-foreground", children: lane.title }),
|
|
9323
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_rule h-px flex-1 bg-border" }),
|
|
9324
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_count rounded-full bg-muted px-2 py-0.5 text-[11px] tabular-nums text-foreground", children: count })
|
|
9325
|
+
]
|
|
9326
|
+
}
|
|
9327
|
+
);
|
|
9328
|
+
}
|
|
9329
|
+
function KanbanLaneStrip({
|
|
9330
|
+
lane,
|
|
9331
|
+
treeKey
|
|
9332
|
+
}) {
|
|
9333
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9334
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9335
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9336
|
+
});
|
|
9337
|
+
return /* @__PURE__ */ jsx(
|
|
9338
|
+
"div",
|
|
9339
|
+
{
|
|
9340
|
+
ref: setNodeRef,
|
|
9341
|
+
className: cn(
|
|
9342
|
+
"cls_hazo_kanban_lane_strip mb-2 rounded-md border border-dashed border-border px-2 py-1 text-[11px] uppercase tracking-wider text-muted-foreground",
|
|
9343
|
+
isOver && "cls_hazo_kanban_lane_strip_over border-solid bg-accent/30 text-foreground ring-1 ring-ring/30"
|
|
9344
|
+
),
|
|
9345
|
+
children: lane.title
|
|
9346
|
+
}
|
|
9347
|
+
);
|
|
9348
|
+
}
|
|
9130
9349
|
var DEFAULT_PRIORITIES = ["P0", "P1", "P2", "P3"];
|
|
9131
9350
|
function humanize(key) {
|
|
9132
9351
|
return key.replace(/[_\-]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").trim().split(" ").map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
|
|
@@ -9533,6 +9752,10 @@ function applyKanbanFilter(items, filter) {
|
|
|
9533
9752
|
return true;
|
|
9534
9753
|
});
|
|
9535
9754
|
}
|
|
9755
|
+
var UNMATCHED_LANE_KEY = "__hazo_lane_unmatched__";
|
|
9756
|
+
function bucket_key(lane_key, column_key) {
|
|
9757
|
+
return lane_key == null ? column_key : `${lane_key}\0${column_key}`;
|
|
9758
|
+
}
|
|
9536
9759
|
function default_announcements(itemLabel) {
|
|
9537
9760
|
return {
|
|
9538
9761
|
onDragStart: ({ item, fromColumn }) => `Picked up ${itemLabel(item)}. Currently in ${fromColumn}. Use arrow keys to choose a different column. Press space to drop, escape to cancel.`,
|
|
@@ -9541,37 +9764,50 @@ function default_announcements(itemLabel) {
|
|
|
9541
9764
|
onDragCancel: ({ item, fromColumn }) => `Movement cancelled. ${itemLabel(item)} returned to ${fromColumn}.`
|
|
9542
9765
|
};
|
|
9543
9766
|
}
|
|
9544
|
-
function group_items_by_column(items, overlay, columns) {
|
|
9767
|
+
function group_items_by_column(items, overlay, columns, lanes) {
|
|
9545
9768
|
const out = /* @__PURE__ */ new Map();
|
|
9546
|
-
|
|
9769
|
+
const lane_keys = lanes ? [...lanes.map((l) => l.key), UNMATCHED_LANE_KEY] : [void 0];
|
|
9770
|
+
for (const lane_key of lane_keys)
|
|
9771
|
+
for (const col of columns) out.set(bucket_key(lane_key, col.key), []);
|
|
9547
9772
|
const overlay_inserts = /* @__PURE__ */ new Map();
|
|
9548
|
-
for (const
|
|
9773
|
+
for (const key of out.keys()) overlay_inserts.set(key, []);
|
|
9774
|
+
const declared = lanes ? new Set(lanes.map((l) => l.key)) : null;
|
|
9775
|
+
function resolve_lane(lane_key) {
|
|
9776
|
+
if (!declared) return void 0;
|
|
9777
|
+
return lane_key != null && declared.has(lane_key) ? lane_key : UNMATCHED_LANE_KEY;
|
|
9778
|
+
}
|
|
9549
9779
|
for (const item of items) {
|
|
9550
9780
|
const ov = overlay.get(item.id);
|
|
9551
9781
|
if (ov) {
|
|
9552
|
-
const bucket = overlay_inserts.get(
|
|
9782
|
+
const bucket = overlay_inserts.get(
|
|
9783
|
+
bucket_key(resolve_lane(ov.laneKey), ov.columnKey)
|
|
9784
|
+
);
|
|
9553
9785
|
if (bucket) {
|
|
9554
|
-
|
|
9786
|
+
const placed = ov.sectionKey === item.sectionKey && ov.laneKey === item.laneKey ? item : { ...item, sectionKey: ov.sectionKey, laneKey: ov.laneKey };
|
|
9787
|
+
bucket.push({ item: placed, index: ov.index });
|
|
9555
9788
|
}
|
|
9556
9789
|
} else {
|
|
9557
|
-
const bucket = out.get(
|
|
9790
|
+
const bucket = out.get(
|
|
9791
|
+
bucket_key(resolve_lane(item.laneKey), item.columnKey)
|
|
9792
|
+
);
|
|
9558
9793
|
if (bucket) bucket.push(item);
|
|
9559
9794
|
}
|
|
9560
9795
|
}
|
|
9561
|
-
for (const
|
|
9562
|
-
|
|
9796
|
+
for (const [key, inserts] of overlay_inserts) {
|
|
9797
|
+
if (inserts.length === 0) continue;
|
|
9563
9798
|
inserts.sort((a, b) => a.index - b.index);
|
|
9564
|
-
const arr = out.get(
|
|
9799
|
+
const arr = out.get(key) ?? [];
|
|
9565
9800
|
for (const { item, index } of inserts) {
|
|
9566
9801
|
const at = Math.max(0, Math.min(index, arr.length));
|
|
9567
9802
|
arr.splice(at, 0, item);
|
|
9568
9803
|
}
|
|
9569
|
-
out.set(
|
|
9804
|
+
out.set(key, arr);
|
|
9570
9805
|
}
|
|
9571
9806
|
return out;
|
|
9572
9807
|
}
|
|
9573
9808
|
function HazoUiKanban({
|
|
9574
9809
|
columns,
|
|
9810
|
+
lanes,
|
|
9575
9811
|
items,
|
|
9576
9812
|
renderCard,
|
|
9577
9813
|
onMove,
|
|
@@ -9619,7 +9855,7 @@ function HazoUiKanban({
|
|
|
9619
9855
|
const next = new Map(prev);
|
|
9620
9856
|
for (const [item_id, pos] of prev.entries()) {
|
|
9621
9857
|
const item = items.find((i) => i.id === item_id);
|
|
9622
|
-
if (item && item.columnKey === pos.columnKey) {
|
|
9858
|
+
if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey && item.laneKey === pos.laneKey) {
|
|
9623
9859
|
next.delete(item_id);
|
|
9624
9860
|
changed = true;
|
|
9625
9861
|
}
|
|
@@ -9628,8 +9864,8 @@ function HazoUiKanban({
|
|
|
9628
9864
|
});
|
|
9629
9865
|
}, [items, overlay]);
|
|
9630
9866
|
const grouped = React27.useMemo(
|
|
9631
|
-
() => group_items_by_column(items, overlay, columns),
|
|
9632
|
-
[items, overlay, columns]
|
|
9867
|
+
() => group_items_by_column(items, overlay, columns, lanes),
|
|
9868
|
+
[items, overlay, columns, lanes]
|
|
9633
9869
|
);
|
|
9634
9870
|
const find_item = React27.useCallback(
|
|
9635
9871
|
(id) => items.find((i) => i.id === id),
|
|
@@ -9639,6 +9875,13 @@ function HazoUiKanban({
|
|
|
9639
9875
|
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
9640
9876
|
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
|
9641
9877
|
);
|
|
9878
|
+
const collision_detection = React27.useCallback((args) => {
|
|
9879
|
+
const under_pointer = pointerWithin(args);
|
|
9880
|
+
if (under_pointer.length > 0) return under_pointer;
|
|
9881
|
+
const overlapping = rectIntersection(args);
|
|
9882
|
+
if (overlapping.length > 0) return overlapping;
|
|
9883
|
+
return closestCorners(args);
|
|
9884
|
+
}, []);
|
|
9642
9885
|
const merged_announcements = React27.useMemo(() => {
|
|
9643
9886
|
const defaults = default_announcements(label_fn);
|
|
9644
9887
|
return {
|
|
@@ -9667,7 +9910,7 @@ function HazoUiKanban({
|
|
|
9667
9910
|
const id = String(active.id);
|
|
9668
9911
|
const item = find_item(id);
|
|
9669
9912
|
if (!item) return "";
|
|
9670
|
-
const over_col_key = over ? over.data?.current?.columnKey ??
|
|
9913
|
+
const over_col_key = over ? over.data?.current?.columnKey ?? item.columnKey : null;
|
|
9671
9914
|
const col = over_col_key ? columns.find((c) => c.key === over_col_key) : null;
|
|
9672
9915
|
return merged_announcements.onDragOver({
|
|
9673
9916
|
item,
|
|
@@ -9682,10 +9925,14 @@ function HazoUiKanban({
|
|
|
9682
9925
|
const item = find_item(id);
|
|
9683
9926
|
if (!item) return "";
|
|
9684
9927
|
const from_col = columns.find((c) => c.key === item.columnKey);
|
|
9685
|
-
const over_col_key = over
|
|
9928
|
+
const over_col_key = over?.data?.current?.columnKey ?? item.columnKey;
|
|
9929
|
+
const over_lane_key = lanes ? over?.data?.current?.laneKey ?? item.laneKey : void 0;
|
|
9686
9930
|
const to_col = over_col_key ? columns.find((c) => c.key === over_col_key) ?? from_col : from_col;
|
|
9687
|
-
const target =
|
|
9688
|
-
|
|
9931
|
+
const target = grouped.get(
|
|
9932
|
+
bucket_key(over_lane_key, over_col_key ?? item.columnKey)
|
|
9933
|
+
) ?? [];
|
|
9934
|
+
const on_shell = !over || String(over.id).startsWith("column:") || String(over.id).startsWith("columnhead:") || String(over.id).startsWith("section:") || String(over.id).startsWith("lane:");
|
|
9935
|
+
const new_index = on_shell ? target.length : target.findIndex((it) => it.id === String(over.id));
|
|
9689
9936
|
return merged_announcements.onDragEnd({
|
|
9690
9937
|
item,
|
|
9691
9938
|
fromColumn: from_col?.title ?? item.columnKey,
|
|
@@ -9704,7 +9951,7 @@ function HazoUiKanban({
|
|
|
9704
9951
|
});
|
|
9705
9952
|
}
|
|
9706
9953
|
}),
|
|
9707
|
-
[find_item, columns, grouped, merged_announcements]
|
|
9954
|
+
[find_item, columns, lanes, grouped, merged_announcements]
|
|
9708
9955
|
);
|
|
9709
9956
|
const handle_drag_start = React27.useCallback((event) => {
|
|
9710
9957
|
set_active_id(String(event.active.id));
|
|
@@ -9731,25 +9978,35 @@ function HazoUiKanban({
|
|
|
9731
9978
|
if (!event.over) return;
|
|
9732
9979
|
const over_id = String(event.over.id);
|
|
9733
9980
|
const over_data = event.over.data?.current;
|
|
9734
|
-
const dest_column_key = over_data?.columnKey ??
|
|
9981
|
+
const dest_column_key = over_data?.columnKey ?? item.columnKey;
|
|
9735
9982
|
const dest_column = columns.find((c) => c.key === dest_column_key);
|
|
9736
9983
|
if (!dest_column) return;
|
|
9984
|
+
const dest_lane_key = lanes ? over_data?.laneKey ?? item.laneKey : void 0;
|
|
9985
|
+
const dest_lane = lanes?.find((l) => l.key === dest_lane_key);
|
|
9986
|
+
if (lanes && dest_lane?.accepts && !dest_lane.accepts(item)) return;
|
|
9987
|
+
const dest_section_key = dest_column.sections ? over_data?.sectionKey ?? item.sectionKey : void 0;
|
|
9988
|
+
const dest_section = dest_column.sections?.find(
|
|
9989
|
+
(s) => s.key === dest_section_key
|
|
9990
|
+
);
|
|
9737
9991
|
if (dest_column.accepts && !dest_column.accepts(item)) return;
|
|
9738
|
-
|
|
9992
|
+
if (dest_section?.accepts && !dest_section.accepts(item)) return;
|
|
9993
|
+
const dest_items_pre_overlay = grouped.get(bucket_key(dest_lane_key, dest_column_key)) ?? [];
|
|
9739
9994
|
let new_index;
|
|
9740
|
-
if (over_data?.isColumn) {
|
|
9995
|
+
if (over_data?.isColumn || over_data?.isSection || over_data?.isLane) {
|
|
9741
9996
|
new_index = dest_items_pre_overlay.length;
|
|
9742
9997
|
} else {
|
|
9743
9998
|
const idx = dest_items_pre_overlay.findIndex((i) => i.id === over_id);
|
|
9744
9999
|
new_index = idx === -1 ? dest_items_pre_overlay.length : idx;
|
|
9745
10000
|
}
|
|
9746
10001
|
const handle = make_revert_handle(active_id_str);
|
|
9747
|
-
if (item.columnKey === dest_column_key) {
|
|
10002
|
+
if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key && item.laneKey === dest_lane_key) {
|
|
9748
10003
|
if (active_id_str === over_id) return;
|
|
9749
10004
|
set_overlay((prev) => {
|
|
9750
10005
|
const next = new Map(prev);
|
|
9751
10006
|
next.set(active_id_str, {
|
|
9752
10007
|
columnKey: dest_column_key,
|
|
10008
|
+
sectionKey: dest_section_key,
|
|
10009
|
+
laneKey: dest_lane_key,
|
|
9753
10010
|
index: new_index
|
|
9754
10011
|
});
|
|
9755
10012
|
return next;
|
|
@@ -9758,6 +10015,8 @@ function HazoUiKanban({
|
|
|
9758
10015
|
itemId: active_id_str,
|
|
9759
10016
|
item,
|
|
9760
10017
|
columnKey: dest_column_key,
|
|
10018
|
+
sectionKey: dest_section_key,
|
|
10019
|
+
laneKey: dest_lane_key,
|
|
9761
10020
|
newIndex: new_index,
|
|
9762
10021
|
revert: handle.revert
|
|
9763
10022
|
};
|
|
@@ -9768,6 +10027,8 @@ function HazoUiKanban({
|
|
|
9768
10027
|
const next = new Map(prev);
|
|
9769
10028
|
next.set(active_id_str, {
|
|
9770
10029
|
columnKey: dest_column_key,
|
|
10030
|
+
sectionKey: dest_section_key,
|
|
10031
|
+
laneKey: dest_lane_key,
|
|
9771
10032
|
index: new_index
|
|
9772
10033
|
});
|
|
9773
10034
|
return next;
|
|
@@ -9777,12 +10038,16 @@ function HazoUiKanban({
|
|
|
9777
10038
|
item,
|
|
9778
10039
|
fromColumn: item.columnKey,
|
|
9779
10040
|
toColumn: dest_column_key,
|
|
10041
|
+
fromSection: item.sectionKey,
|
|
10042
|
+
toSection: dest_section_key,
|
|
10043
|
+
fromLane: item.laneKey,
|
|
10044
|
+
toLane: dest_lane_key,
|
|
9780
10045
|
newIndex: new_index,
|
|
9781
10046
|
revert: handle.revert
|
|
9782
10047
|
};
|
|
9783
10048
|
onMove?.(move_event);
|
|
9784
10049
|
},
|
|
9785
|
-
[find_item, columns, grouped, onMove, onReorder, make_revert_handle]
|
|
10050
|
+
[find_item, columns, lanes, grouped, onMove, onReorder, make_revert_handle]
|
|
9786
10051
|
);
|
|
9787
10052
|
const handle_drag_cancel = React27.useCallback(() => {
|
|
9788
10053
|
set_active_id(null);
|
|
@@ -9793,13 +10058,56 @@ function HazoUiKanban({
|
|
|
9793
10058
|
`(max-width: ${Math.max(0, mobileBreakpoint - 1)}px)`
|
|
9794
10059
|
);
|
|
9795
10060
|
const mobile_classes = is_custom_breakpoint ? is_mobile_via_query ? "block" : "hidden" : "sm:hidden";
|
|
9796
|
-
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : "grid" : "hidden sm:grid";
|
|
10061
|
+
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : lanes ? "block" : "grid" : lanes ? "hidden sm:block" : "hidden sm:grid";
|
|
10062
|
+
const grid_style = {
|
|
10063
|
+
gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))`
|
|
10064
|
+
};
|
|
10065
|
+
function lane_total(lane_key) {
|
|
10066
|
+
let total = 0;
|
|
10067
|
+
for (const col of columns)
|
|
10068
|
+
total += (grouped.get(bucket_key(lane_key, col.key)) ?? []).length;
|
|
10069
|
+
return total;
|
|
10070
|
+
}
|
|
10071
|
+
function render_column(col, tree_key, lane_key) {
|
|
10072
|
+
return /* @__PURE__ */ jsx(
|
|
10073
|
+
KanbanColumn,
|
|
10074
|
+
{
|
|
10075
|
+
column: col,
|
|
10076
|
+
laneKey: lane_key,
|
|
10077
|
+
treeKey: tree_key,
|
|
10078
|
+
items: grouped.get(bucket_key(lane_key, col.key)) ?? [],
|
|
10079
|
+
renderCard,
|
|
10080
|
+
emptyColumn,
|
|
10081
|
+
cardClassName,
|
|
10082
|
+
showEdit: show_edit,
|
|
10083
|
+
onEditRequest: handle_edit_request
|
|
10084
|
+
},
|
|
10085
|
+
col.key
|
|
10086
|
+
);
|
|
10087
|
+
}
|
|
10088
|
+
function render_lane_row(lane, tree_key, only_column) {
|
|
10089
|
+
const count = only_column ? (grouped.get(bucket_key(lane.key, only_column.key)) ?? []).length : lane_total(lane.key);
|
|
10090
|
+
if (lane.collapseWhenEmpty && count === 0) {
|
|
10091
|
+
return /* @__PURE__ */ jsx(KanbanLaneStrip, { lane, treeKey: tree_key }, lane.key);
|
|
10092
|
+
}
|
|
10093
|
+
return /* @__PURE__ */ jsxs("div", { className: "cls_hazo_kanban_lane", children: [
|
|
10094
|
+
/* @__PURE__ */ jsx(KanbanLaneHead, { lane, count, treeKey: tree_key }),
|
|
10095
|
+
only_column ? render_column(only_column, tree_key, lane.key) : /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_lane_grid grid gap-3", style: grid_style, children: columns.map((col) => render_column(col, tree_key, lane.key)) })
|
|
10096
|
+
] }, lane.key);
|
|
10097
|
+
}
|
|
10098
|
+
function render_unmatched_lane(tree_key, only_column) {
|
|
10099
|
+
const count = only_column ? (grouped.get(bucket_key(UNMATCHED_LANE_KEY, only_column.key)) ?? []).length : lane_total(UNMATCHED_LANE_KEY);
|
|
10100
|
+
if (count === 0) return null;
|
|
10101
|
+
return /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_lane cls_hazo_kanban_lane_unmatched", children: only_column ? render_column(only_column, tree_key, UNMATCHED_LANE_KEY) : /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_lane_grid grid gap-3", style: grid_style, children: columns.map(
|
|
10102
|
+
(col) => render_column(col, tree_key, UNMATCHED_LANE_KEY)
|
|
10103
|
+
) }) });
|
|
10104
|
+
}
|
|
9797
10105
|
return /* @__PURE__ */ jsxs(
|
|
9798
10106
|
DndContext,
|
|
9799
10107
|
{
|
|
9800
10108
|
id: dnd_context_id,
|
|
9801
10109
|
sensors,
|
|
9802
|
-
collisionDetection:
|
|
10110
|
+
collisionDetection: collision_detection,
|
|
9803
10111
|
onDragStart: handle_drag_start,
|
|
9804
10112
|
onDragEnd: handle_drag_end,
|
|
9805
10113
|
onDragCancel: handle_drag_cancel,
|
|
@@ -9808,43 +10116,33 @@ function HazoUiKanban({
|
|
|
9808
10116
|
/* @__PURE__ */ jsxs("div", { className: cn("cls_hazo_kanban w-full", className), children: [
|
|
9809
10117
|
/* @__PURE__ */ jsx("div", { className: cn("cls_hazo_kanban_mobile", mobile_classes), children: /* @__PURE__ */ jsxs(Tabs, { value: active_tab, onValueChange: set_active_tab, children: [
|
|
9810
10118
|
/* @__PURE__ */ jsx(TabsList, { className: "grid w-full", style: { gridTemplateColumns: `repeat(${columns.length}, 1fr)` }, children: columns.map((col) => {
|
|
9811
|
-
const count =
|
|
10119
|
+
const count = lanes ? lanes.reduce(
|
|
10120
|
+
(n, lane) => n + (grouped.get(bucket_key(lane.key, col.key)) ?? []).length,
|
|
10121
|
+
(grouped.get(bucket_key(UNMATCHED_LANE_KEY, col.key)) ?? []).length
|
|
10122
|
+
) : (grouped.get(col.key) ?? []).length;
|
|
9812
10123
|
return /* @__PURE__ */ jsxs(TabsTrigger, { value: col.key, className: "flex flex-col gap-0.5", children: [
|
|
9813
10124
|
/* @__PURE__ */ jsx("span", { className: "text-xs", children: col.title }),
|
|
9814
10125
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: count })
|
|
9815
10126
|
] }, col.key);
|
|
9816
10127
|
}) }),
|
|
9817
|
-
columns.map((col) => /* @__PURE__ */ jsx(TabsContent, { value: col.key, className: "mt-3", children: /* @__PURE__ */
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
items: grouped.get(col.key) ?? [],
|
|
9822
|
-
renderCard,
|
|
9823
|
-
emptyColumn,
|
|
9824
|
-
cardClassName,
|
|
9825
|
-
showEdit: show_edit,
|
|
9826
|
-
onEditRequest: handle_edit_request
|
|
9827
|
-
}
|
|
9828
|
-
) }, col.key))
|
|
10128
|
+
columns.map((col) => /* @__PURE__ */ jsx(TabsContent, { value: col.key, className: "mt-3", children: lanes ? /* @__PURE__ */ jsxs("div", { className: "cls_hazo_kanban_lanes flex flex-col gap-4", children: [
|
|
10129
|
+
lanes.map((lane) => render_lane_row(lane, "m", col)),
|
|
10130
|
+
render_unmatched_lane("m", col)
|
|
10131
|
+
] }) : render_column(col, "m") }, col.key))
|
|
9829
10132
|
] }) }),
|
|
9830
10133
|
/* @__PURE__ */ jsx(
|
|
9831
10134
|
"div",
|
|
9832
10135
|
{
|
|
9833
|
-
className: cn(
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
showEdit: show_edit,
|
|
9844
|
-
onEditRequest: handle_edit_request
|
|
9845
|
-
},
|
|
9846
|
-
col.key
|
|
9847
|
-
))
|
|
10136
|
+
className: cn(
|
|
10137
|
+
"cls_hazo_kanban_desktop",
|
|
10138
|
+
lanes ? "space-y-4" : "gap-3",
|
|
10139
|
+
desktop_classes
|
|
10140
|
+
),
|
|
10141
|
+
style: lanes ? void 0 : grid_style,
|
|
10142
|
+
children: lanes ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
10143
|
+
lanes.map((lane) => render_lane_row(lane, "d")),
|
|
10144
|
+
render_unmatched_lane("d")
|
|
10145
|
+
] }) : columns.map((col) => render_column(col, "d"))
|
|
9848
10146
|
}
|
|
9849
10147
|
),
|
|
9850
10148
|
/* @__PURE__ */ jsx(DragOverlay, { children: active_item ? /* @__PURE__ */ jsx(
|