hazo_ui 6.4.0 → 6.7.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 +118 -0
- package/README.md +42 -0
- package/dist/index.cjs +262 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -2
- package/dist/index.d.ts +69 -2
- package/dist/index.js +263 -92
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
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';
|
|
@@ -9021,10 +9021,15 @@ function KanbanCard({
|
|
|
9021
9021
|
isDragging
|
|
9022
9022
|
} = useSortable({
|
|
9023
9023
|
id: item.id,
|
|
9024
|
-
// sectionKey
|
|
9025
|
-
// section, not just its column (
|
|
9026
|
-
// the gaps between cards, but the cards themselves
|
|
9027
|
-
|
|
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
|
+
}
|
|
9028
9033
|
});
|
|
9029
9034
|
const priority_var = item.priority ? `--hazo-kanban-priority-${String(item.priority).toLowerCase()}` : null;
|
|
9030
9035
|
const style = {
|
|
@@ -9033,6 +9038,12 @@ function KanbanCard({
|
|
|
9033
9038
|
backgroundColor: "hsl(var(--hazo-kanban-card-bg))",
|
|
9034
9039
|
border: `1px solid hsl(var(--hazo-kanban-card-border))`,
|
|
9035
9040
|
borderLeft: priority_var ? `4px solid hsl(var(${priority_var}))` : `1px solid hsl(var(--hazo-kanban-card-border))`,
|
|
9041
|
+
// Opt-in lift. A card whose background equals the column's (the case for
|
|
9042
|
+
// every palette where --card and --background resolve to the same value)
|
|
9043
|
+
// is separated by nothing but a 1px border, which reads as flat at a
|
|
9044
|
+
// glance. The fallback is `none`, so a consumer that never sets the token
|
|
9045
|
+
// renders exactly as before.
|
|
9046
|
+
boxShadow: "var(--hazo-kanban-card-shadow, none)",
|
|
9036
9047
|
opacity: isDragging && !dragging ? 0.4 : 1,
|
|
9037
9048
|
cursor: "grab"
|
|
9038
9049
|
};
|
|
@@ -9041,6 +9052,9 @@ function KanbanCard({
|
|
|
9041
9052
|
{
|
|
9042
9053
|
ref: setNodeRef,
|
|
9043
9054
|
style,
|
|
9055
|
+
"data-column-key": item.columnKey,
|
|
9056
|
+
"data-lane-key": item.laneKey,
|
|
9057
|
+
"data-section-key": item.sectionKey,
|
|
9044
9058
|
className: cn(
|
|
9045
9059
|
"cls_hazo_kanban_card group relative rounded-md p-3 mb-2 select-none",
|
|
9046
9060
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
@@ -9085,8 +9099,16 @@ function KanbanCard({
|
|
|
9085
9099
|
}
|
|
9086
9100
|
);
|
|
9087
9101
|
}
|
|
9088
|
-
function
|
|
9089
|
-
return `
|
|
9102
|
+
function tree_droppable_id(prefix, tree_key, lane_key, rest) {
|
|
9103
|
+
return lane_key == null ? `${prefix}:${tree_key}::${rest}` : `${prefix}:${tree_key}::${lane_key}::${rest}`;
|
|
9104
|
+
}
|
|
9105
|
+
function section_droppable_id(column_key, section_key, tree_key, lane_key) {
|
|
9106
|
+
return tree_droppable_id(
|
|
9107
|
+
"section",
|
|
9108
|
+
tree_key,
|
|
9109
|
+
lane_key,
|
|
9110
|
+
`${column_key}::${section_key}`
|
|
9111
|
+
);
|
|
9090
9112
|
}
|
|
9091
9113
|
function group_items_by_section(items, sections) {
|
|
9092
9114
|
const bySection = /* @__PURE__ */ new Map();
|
|
@@ -9104,13 +9126,16 @@ function KanbanColumn({
|
|
|
9104
9126
|
items,
|
|
9105
9127
|
renderCard,
|
|
9106
9128
|
emptyColumn,
|
|
9129
|
+
footer,
|
|
9107
9130
|
cardClassName,
|
|
9108
9131
|
showEdit,
|
|
9109
|
-
onEditRequest
|
|
9132
|
+
onEditRequest,
|
|
9133
|
+
laneKey,
|
|
9134
|
+
treeKey
|
|
9110
9135
|
}) {
|
|
9111
9136
|
const { setNodeRef, isOver } = useDroppable({
|
|
9112
|
-
id:
|
|
9113
|
-
data: { columnKey: column.key, isColumn: true }
|
|
9137
|
+
id: tree_droppable_id("column", treeKey, laneKey, column.key),
|
|
9138
|
+
data: { columnKey: column.key, laneKey, isColumn: true }
|
|
9114
9139
|
});
|
|
9115
9140
|
const sections = column.sections;
|
|
9116
9141
|
const { bySection, unmatched } = React27.useMemo(
|
|
@@ -9147,6 +9172,8 @@ function KanbanColumn({
|
|
|
9147
9172
|
"div",
|
|
9148
9173
|
{
|
|
9149
9174
|
ref: setNodeRef,
|
|
9175
|
+
"data-column-key": column.key,
|
|
9176
|
+
"data-lane-key": laneKey,
|
|
9150
9177
|
className: cn(
|
|
9151
9178
|
"cls_hazo_kanban_column flex flex-col rounded-md p-2",
|
|
9152
9179
|
isOver && "cls_hazo_kanban_column_over bg-accent/30 ring-2 ring-ring/40"
|
|
@@ -9156,6 +9183,8 @@ function KanbanColumn({
|
|
|
9156
9183
|
KanbanColumnHead,
|
|
9157
9184
|
{
|
|
9158
9185
|
columnKey: column.key,
|
|
9186
|
+
laneKey,
|
|
9187
|
+
treeKey,
|
|
9159
9188
|
title: column.title,
|
|
9160
9189
|
count: items.length,
|
|
9161
9190
|
droppable: sections != null
|
|
@@ -9166,49 +9195,66 @@ function KanbanColumn({
|
|
|
9166
9195
|
{
|
|
9167
9196
|
items: ordered.map((i) => i.id),
|
|
9168
9197
|
strategy: verticalListSortingStrategy,
|
|
9169
|
-
children: /* @__PURE__ */ jsx(
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9198
|
+
children: /* @__PURE__ */ jsx(
|
|
9199
|
+
"div",
|
|
9200
|
+
{
|
|
9201
|
+
"data-column-key": column.key,
|
|
9202
|
+
"data-lane-key": laneKey,
|
|
9203
|
+
className: "cls_hazo_kanban_column_body flex-1 min-h-[40px]",
|
|
9204
|
+
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: [
|
|
9205
|
+
expanded_sections.map((section) => /* @__PURE__ */ jsx(
|
|
9206
|
+
KanbanSectionBand,
|
|
9207
|
+
{
|
|
9208
|
+
columnKey: column.key,
|
|
9209
|
+
laneKey,
|
|
9210
|
+
treeKey,
|
|
9211
|
+
section,
|
|
9212
|
+
items: bySection.get(section.key) ?? [],
|
|
9213
|
+
emptyColumn,
|
|
9214
|
+
renderCards: render_cards
|
|
9215
|
+
},
|
|
9216
|
+
section.key
|
|
9217
|
+
)),
|
|
9218
|
+
unmatched.length > 0 && /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section cls_hazo_kanban_section_unmatched", children: render_cards(unmatched) }),
|
|
9219
|
+
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(
|
|
9220
|
+
KanbanSectionStrip,
|
|
9221
|
+
{
|
|
9222
|
+
columnKey: column.key,
|
|
9223
|
+
laneKey,
|
|
9224
|
+
treeKey,
|
|
9225
|
+
section
|
|
9226
|
+
},
|
|
9227
|
+
section.key
|
|
9228
|
+
)) })
|
|
9229
|
+
] })
|
|
9230
|
+
}
|
|
9231
|
+
)
|
|
9191
9232
|
}
|
|
9192
|
-
)
|
|
9233
|
+
),
|
|
9234
|
+
footer ? /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_footer mt-1", children: footer }) : null
|
|
9193
9235
|
]
|
|
9194
9236
|
}
|
|
9195
9237
|
);
|
|
9196
9238
|
}
|
|
9197
9239
|
function KanbanColumnHead({
|
|
9198
9240
|
columnKey,
|
|
9241
|
+
laneKey,
|
|
9242
|
+
treeKey,
|
|
9199
9243
|
title,
|
|
9200
9244
|
count,
|
|
9201
9245
|
droppable
|
|
9202
9246
|
}) {
|
|
9203
9247
|
const { setNodeRef, isOver } = useDroppable({
|
|
9204
|
-
id:
|
|
9205
|
-
data: { columnKey, isColumn: true },
|
|
9248
|
+
id: tree_droppable_id("columnhead", treeKey, laneKey, columnKey),
|
|
9249
|
+
data: { columnKey, laneKey, isColumn: true },
|
|
9206
9250
|
disabled: !droppable
|
|
9207
9251
|
});
|
|
9208
9252
|
return /* @__PURE__ */ jsxs(
|
|
9209
9253
|
"div",
|
|
9210
9254
|
{
|
|
9211
9255
|
ref: droppable ? setNodeRef : void 0,
|
|
9256
|
+
"data-column-key": columnKey,
|
|
9257
|
+
"data-lane-key": laneKey,
|
|
9212
9258
|
className: cn(
|
|
9213
9259
|
"cls_hazo_kanban_column_head mb-2 flex items-center justify-between rounded-sm px-1 text-xs uppercase tracking-wider text-muted-foreground",
|
|
9214
9260
|
droppable && "py-1",
|
|
@@ -9223,14 +9269,16 @@ function KanbanColumnHead({
|
|
|
9223
9269
|
}
|
|
9224
9270
|
function KanbanSectionBand({
|
|
9225
9271
|
columnKey,
|
|
9272
|
+
laneKey,
|
|
9273
|
+
treeKey,
|
|
9226
9274
|
section,
|
|
9227
9275
|
items,
|
|
9228
9276
|
emptyColumn,
|
|
9229
9277
|
renderCards
|
|
9230
9278
|
}) {
|
|
9231
9279
|
const { setNodeRef, isOver } = useDroppable({
|
|
9232
|
-
id: section_droppable_id(columnKey, section.key),
|
|
9233
|
-
data: { columnKey, sectionKey: section.key, isSection: true }
|
|
9280
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9281
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9234
9282
|
});
|
|
9235
9283
|
return /* @__PURE__ */ jsxs(
|
|
9236
9284
|
"div",
|
|
@@ -9253,11 +9301,13 @@ function KanbanSectionBand({
|
|
|
9253
9301
|
}
|
|
9254
9302
|
function KanbanSectionStrip({
|
|
9255
9303
|
columnKey,
|
|
9304
|
+
laneKey,
|
|
9305
|
+
treeKey,
|
|
9256
9306
|
section
|
|
9257
9307
|
}) {
|
|
9258
9308
|
const { setNodeRef, isOver } = useDroppable({
|
|
9259
|
-
id: section_droppable_id(columnKey, section.key),
|
|
9260
|
-
data: { columnKey, sectionKey: section.key, isSection: true }
|
|
9309
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9310
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9261
9311
|
});
|
|
9262
9312
|
return /* @__PURE__ */ jsx(
|
|
9263
9313
|
"div",
|
|
@@ -9271,6 +9321,58 @@ function KanbanSectionStrip({
|
|
|
9271
9321
|
}
|
|
9272
9322
|
);
|
|
9273
9323
|
}
|
|
9324
|
+
function lane_droppable_id(lane_key, tree_key) {
|
|
9325
|
+
return `lane:${tree_key}::${lane_key}`;
|
|
9326
|
+
}
|
|
9327
|
+
function KanbanLaneHead({
|
|
9328
|
+
lane,
|
|
9329
|
+
count,
|
|
9330
|
+
treeKey
|
|
9331
|
+
}) {
|
|
9332
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9333
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9334
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9335
|
+
});
|
|
9336
|
+
return /* @__PURE__ */ jsxs(
|
|
9337
|
+
"div",
|
|
9338
|
+
{
|
|
9339
|
+
ref: setNodeRef,
|
|
9340
|
+
className: cn(
|
|
9341
|
+
"cls_hazo_kanban_lane_head mb-2 flex items-center gap-3 rounded-sm px-1 py-1",
|
|
9342
|
+
isOver && "cls_hazo_kanban_lane_head_over bg-accent/30 ring-1 ring-ring/40"
|
|
9343
|
+
),
|
|
9344
|
+
children: [
|
|
9345
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_title text-xs font-semibold uppercase tracking-wider text-foreground", children: lane.title }),
|
|
9346
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_rule h-px flex-1 bg-border" }),
|
|
9347
|
+
lane.actions ? /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_actions flex items-center gap-1", children: lane.actions }) : null,
|
|
9348
|
+
/* @__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 })
|
|
9349
|
+
]
|
|
9350
|
+
}
|
|
9351
|
+
);
|
|
9352
|
+
}
|
|
9353
|
+
function KanbanLaneStrip({
|
|
9354
|
+
lane,
|
|
9355
|
+
treeKey
|
|
9356
|
+
}) {
|
|
9357
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
9358
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9359
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9360
|
+
});
|
|
9361
|
+
return /* @__PURE__ */ jsxs(
|
|
9362
|
+
"div",
|
|
9363
|
+
{
|
|
9364
|
+
ref: setNodeRef,
|
|
9365
|
+
className: cn(
|
|
9366
|
+
"cls_hazo_kanban_lane_strip mb-2 flex items-center gap-3 rounded-md border border-dashed border-border px-2 py-1 text-[11px] uppercase tracking-wider text-muted-foreground",
|
|
9367
|
+
isOver && "cls_hazo_kanban_lane_strip_over border-solid bg-accent/30 text-foreground ring-1 ring-ring/30"
|
|
9368
|
+
),
|
|
9369
|
+
children: [
|
|
9370
|
+
/* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_title", children: lane.title }),
|
|
9371
|
+
lane.actions ? /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_actions ml-auto flex items-center gap-1", children: lane.actions }) : null
|
|
9372
|
+
]
|
|
9373
|
+
}
|
|
9374
|
+
);
|
|
9375
|
+
}
|
|
9274
9376
|
var DEFAULT_PRIORITIES = ["P0", "P1", "P2", "P3"];
|
|
9275
9377
|
function humanize(key) {
|
|
9276
9378
|
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(" ");
|
|
@@ -9677,6 +9779,10 @@ function applyKanbanFilter(items, filter) {
|
|
|
9677
9779
|
return true;
|
|
9678
9780
|
});
|
|
9679
9781
|
}
|
|
9782
|
+
var UNMATCHED_LANE_KEY = "__hazo_lane_unmatched__";
|
|
9783
|
+
function bucket_key(lane_key, column_key) {
|
|
9784
|
+
return lane_key == null ? column_key : `${lane_key}\0${column_key}`;
|
|
9785
|
+
}
|
|
9680
9786
|
function default_announcements(itemLabel) {
|
|
9681
9787
|
return {
|
|
9682
9788
|
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.`,
|
|
@@ -9685,38 +9791,50 @@ function default_announcements(itemLabel) {
|
|
|
9685
9791
|
onDragCancel: ({ item, fromColumn }) => `Movement cancelled. ${itemLabel(item)} returned to ${fromColumn}.`
|
|
9686
9792
|
};
|
|
9687
9793
|
}
|
|
9688
|
-
function group_items_by_column(items, overlay, columns) {
|
|
9794
|
+
function group_items_by_column(items, overlay, columns, lanes) {
|
|
9689
9795
|
const out = /* @__PURE__ */ new Map();
|
|
9690
|
-
|
|
9796
|
+
const lane_keys = lanes ? [...lanes.map((l) => l.key), UNMATCHED_LANE_KEY] : [void 0];
|
|
9797
|
+
for (const lane_key of lane_keys)
|
|
9798
|
+
for (const col of columns) out.set(bucket_key(lane_key, col.key), []);
|
|
9691
9799
|
const overlay_inserts = /* @__PURE__ */ new Map();
|
|
9692
|
-
for (const
|
|
9800
|
+
for (const key of out.keys()) overlay_inserts.set(key, []);
|
|
9801
|
+
const declared = lanes ? new Set(lanes.map((l) => l.key)) : null;
|
|
9802
|
+
function resolve_lane(lane_key) {
|
|
9803
|
+
if (!declared) return void 0;
|
|
9804
|
+
return lane_key != null && declared.has(lane_key) ? lane_key : UNMATCHED_LANE_KEY;
|
|
9805
|
+
}
|
|
9693
9806
|
for (const item of items) {
|
|
9694
9807
|
const ov = overlay.get(item.id);
|
|
9695
9808
|
if (ov) {
|
|
9696
|
-
const bucket = overlay_inserts.get(
|
|
9809
|
+
const bucket = overlay_inserts.get(
|
|
9810
|
+
bucket_key(resolve_lane(ov.laneKey), ov.columnKey)
|
|
9811
|
+
);
|
|
9697
9812
|
if (bucket) {
|
|
9698
|
-
const placed = ov.sectionKey === item.sectionKey ? item : { ...item, sectionKey: ov.sectionKey };
|
|
9813
|
+
const placed = ov.sectionKey === item.sectionKey && ov.laneKey === item.laneKey ? item : { ...item, sectionKey: ov.sectionKey, laneKey: ov.laneKey };
|
|
9699
9814
|
bucket.push({ item: placed, index: ov.index });
|
|
9700
9815
|
}
|
|
9701
9816
|
} else {
|
|
9702
|
-
const bucket = out.get(
|
|
9817
|
+
const bucket = out.get(
|
|
9818
|
+
bucket_key(resolve_lane(item.laneKey), item.columnKey)
|
|
9819
|
+
);
|
|
9703
9820
|
if (bucket) bucket.push(item);
|
|
9704
9821
|
}
|
|
9705
9822
|
}
|
|
9706
|
-
for (const
|
|
9707
|
-
|
|
9823
|
+
for (const [key, inserts] of overlay_inserts) {
|
|
9824
|
+
if (inserts.length === 0) continue;
|
|
9708
9825
|
inserts.sort((a, b) => a.index - b.index);
|
|
9709
|
-
const arr = out.get(
|
|
9826
|
+
const arr = out.get(key) ?? [];
|
|
9710
9827
|
for (const { item, index } of inserts) {
|
|
9711
9828
|
const at = Math.max(0, Math.min(index, arr.length));
|
|
9712
9829
|
arr.splice(at, 0, item);
|
|
9713
9830
|
}
|
|
9714
|
-
out.set(
|
|
9831
|
+
out.set(key, arr);
|
|
9715
9832
|
}
|
|
9716
9833
|
return out;
|
|
9717
9834
|
}
|
|
9718
9835
|
function HazoUiKanban({
|
|
9719
9836
|
columns,
|
|
9837
|
+
lanes,
|
|
9720
9838
|
items,
|
|
9721
9839
|
renderCard,
|
|
9722
9840
|
onMove,
|
|
@@ -9724,6 +9842,7 @@ function HazoUiKanban({
|
|
|
9724
9842
|
mobileBreakpoint = 640,
|
|
9725
9843
|
announcements,
|
|
9726
9844
|
emptyColumn = "\u2014",
|
|
9845
|
+
renderColumnFooter,
|
|
9727
9846
|
className,
|
|
9728
9847
|
cardClassName,
|
|
9729
9848
|
itemLabel,
|
|
@@ -9764,7 +9883,7 @@ function HazoUiKanban({
|
|
|
9764
9883
|
const next = new Map(prev);
|
|
9765
9884
|
for (const [item_id, pos] of prev.entries()) {
|
|
9766
9885
|
const item = items.find((i) => i.id === item_id);
|
|
9767
|
-
if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey) {
|
|
9886
|
+
if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey && item.laneKey === pos.laneKey) {
|
|
9768
9887
|
next.delete(item_id);
|
|
9769
9888
|
changed = true;
|
|
9770
9889
|
}
|
|
@@ -9773,8 +9892,8 @@ function HazoUiKanban({
|
|
|
9773
9892
|
});
|
|
9774
9893
|
}, [items, overlay]);
|
|
9775
9894
|
const grouped = React27.useMemo(
|
|
9776
|
-
() => group_items_by_column(items, overlay, columns),
|
|
9777
|
-
[items, overlay, columns]
|
|
9895
|
+
() => group_items_by_column(items, overlay, columns, lanes),
|
|
9896
|
+
[items, overlay, columns, lanes]
|
|
9778
9897
|
);
|
|
9779
9898
|
const find_item = React27.useCallback(
|
|
9780
9899
|
(id) => items.find((i) => i.id === id),
|
|
@@ -9784,6 +9903,13 @@ function HazoUiKanban({
|
|
|
9784
9903
|
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
9785
9904
|
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
|
9786
9905
|
);
|
|
9906
|
+
const collision_detection = React27.useCallback((args) => {
|
|
9907
|
+
const under_pointer = pointerWithin(args);
|
|
9908
|
+
if (under_pointer.length > 0) return under_pointer;
|
|
9909
|
+
const overlapping = rectIntersection(args);
|
|
9910
|
+
if (overlapping.length > 0) return overlapping;
|
|
9911
|
+
return closestCorners(args);
|
|
9912
|
+
}, []);
|
|
9787
9913
|
const merged_announcements = React27.useMemo(() => {
|
|
9788
9914
|
const defaults = default_announcements(label_fn);
|
|
9789
9915
|
return {
|
|
@@ -9812,7 +9938,7 @@ function HazoUiKanban({
|
|
|
9812
9938
|
const id = String(active.id);
|
|
9813
9939
|
const item = find_item(id);
|
|
9814
9940
|
if (!item) return "";
|
|
9815
|
-
const over_col_key = over ? over.data?.current?.columnKey ??
|
|
9941
|
+
const over_col_key = over ? over.data?.current?.columnKey ?? item.columnKey : null;
|
|
9816
9942
|
const col = over_col_key ? columns.find((c) => c.key === over_col_key) : null;
|
|
9817
9943
|
return merged_announcements.onDragOver({
|
|
9818
9944
|
item,
|
|
@@ -9827,10 +9953,13 @@ function HazoUiKanban({
|
|
|
9827
9953
|
const item = find_item(id);
|
|
9828
9954
|
if (!item) return "";
|
|
9829
9955
|
const from_col = columns.find((c) => c.key === item.columnKey);
|
|
9830
|
-
const over_col_key = over
|
|
9956
|
+
const over_col_key = over?.data?.current?.columnKey ?? item.columnKey;
|
|
9957
|
+
const over_lane_key = lanes ? over?.data?.current?.laneKey ?? item.laneKey : void 0;
|
|
9831
9958
|
const to_col = over_col_key ? columns.find((c) => c.key === over_col_key) ?? from_col : from_col;
|
|
9832
|
-
const target =
|
|
9833
|
-
|
|
9959
|
+
const target = grouped.get(
|
|
9960
|
+
bucket_key(over_lane_key, over_col_key ?? item.columnKey)
|
|
9961
|
+
) ?? [];
|
|
9962
|
+
const on_shell = !over || String(over.id).startsWith("column:") || String(over.id).startsWith("columnhead:") || String(over.id).startsWith("section:") || String(over.id).startsWith("lane:");
|
|
9834
9963
|
const new_index = on_shell ? target.length : target.findIndex((it) => it.id === String(over.id));
|
|
9835
9964
|
return merged_announcements.onDragEnd({
|
|
9836
9965
|
item,
|
|
@@ -9850,7 +9979,7 @@ function HazoUiKanban({
|
|
|
9850
9979
|
});
|
|
9851
9980
|
}
|
|
9852
9981
|
}),
|
|
9853
|
-
[find_item, columns, grouped, merged_announcements]
|
|
9982
|
+
[find_item, columns, lanes, grouped, merged_announcements]
|
|
9854
9983
|
);
|
|
9855
9984
|
const handle_drag_start = React27.useCallback((event) => {
|
|
9856
9985
|
set_active_id(String(event.active.id));
|
|
@@ -9877,31 +10006,35 @@ function HazoUiKanban({
|
|
|
9877
10006
|
if (!event.over) return;
|
|
9878
10007
|
const over_id = String(event.over.id);
|
|
9879
10008
|
const over_data = event.over.data?.current;
|
|
9880
|
-
const dest_column_key = over_data?.columnKey ??
|
|
10009
|
+
const dest_column_key = over_data?.columnKey ?? item.columnKey;
|
|
9881
10010
|
const dest_column = columns.find((c) => c.key === dest_column_key);
|
|
9882
10011
|
if (!dest_column) return;
|
|
10012
|
+
const dest_lane_key = lanes ? over_data?.laneKey ?? item.laneKey : void 0;
|
|
10013
|
+
const dest_lane = lanes?.find((l) => l.key === dest_lane_key);
|
|
10014
|
+
if (lanes && dest_lane?.accepts && !dest_lane.accepts(item)) return;
|
|
9883
10015
|
const dest_section_key = dest_column.sections ? over_data?.sectionKey ?? item.sectionKey : void 0;
|
|
9884
10016
|
const dest_section = dest_column.sections?.find(
|
|
9885
10017
|
(s) => s.key === dest_section_key
|
|
9886
10018
|
);
|
|
9887
10019
|
if (dest_column.accepts && !dest_column.accepts(item)) return;
|
|
9888
10020
|
if (dest_section?.accepts && !dest_section.accepts(item)) return;
|
|
9889
|
-
const dest_items_pre_overlay = grouped.get(dest_column_key) ?? [];
|
|
10021
|
+
const dest_items_pre_overlay = grouped.get(bucket_key(dest_lane_key, dest_column_key)) ?? [];
|
|
9890
10022
|
let new_index;
|
|
9891
|
-
if (over_data?.isColumn || over_data?.isSection) {
|
|
10023
|
+
if (over_data?.isColumn || over_data?.isSection || over_data?.isLane) {
|
|
9892
10024
|
new_index = dest_items_pre_overlay.length;
|
|
9893
10025
|
} else {
|
|
9894
10026
|
const idx = dest_items_pre_overlay.findIndex((i) => i.id === over_id);
|
|
9895
10027
|
new_index = idx === -1 ? dest_items_pre_overlay.length : idx;
|
|
9896
10028
|
}
|
|
9897
10029
|
const handle = make_revert_handle(active_id_str);
|
|
9898
|
-
if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key) {
|
|
10030
|
+
if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key && item.laneKey === dest_lane_key) {
|
|
9899
10031
|
if (active_id_str === over_id) return;
|
|
9900
10032
|
set_overlay((prev) => {
|
|
9901
10033
|
const next = new Map(prev);
|
|
9902
10034
|
next.set(active_id_str, {
|
|
9903
10035
|
columnKey: dest_column_key,
|
|
9904
10036
|
sectionKey: dest_section_key,
|
|
10037
|
+
laneKey: dest_lane_key,
|
|
9905
10038
|
index: new_index
|
|
9906
10039
|
});
|
|
9907
10040
|
return next;
|
|
@@ -9911,6 +10044,7 @@ function HazoUiKanban({
|
|
|
9911
10044
|
item,
|
|
9912
10045
|
columnKey: dest_column_key,
|
|
9913
10046
|
sectionKey: dest_section_key,
|
|
10047
|
+
laneKey: dest_lane_key,
|
|
9914
10048
|
newIndex: new_index,
|
|
9915
10049
|
revert: handle.revert
|
|
9916
10050
|
};
|
|
@@ -9922,6 +10056,7 @@ function HazoUiKanban({
|
|
|
9922
10056
|
next.set(active_id_str, {
|
|
9923
10057
|
columnKey: dest_column_key,
|
|
9924
10058
|
sectionKey: dest_section_key,
|
|
10059
|
+
laneKey: dest_lane_key,
|
|
9925
10060
|
index: new_index
|
|
9926
10061
|
});
|
|
9927
10062
|
return next;
|
|
@@ -9933,12 +10068,14 @@ function HazoUiKanban({
|
|
|
9933
10068
|
toColumn: dest_column_key,
|
|
9934
10069
|
fromSection: item.sectionKey,
|
|
9935
10070
|
toSection: dest_section_key,
|
|
10071
|
+
fromLane: item.laneKey,
|
|
10072
|
+
toLane: dest_lane_key,
|
|
9936
10073
|
newIndex: new_index,
|
|
9937
10074
|
revert: handle.revert
|
|
9938
10075
|
};
|
|
9939
10076
|
onMove?.(move_event);
|
|
9940
10077
|
},
|
|
9941
|
-
[find_item, columns, grouped, onMove, onReorder, make_revert_handle]
|
|
10078
|
+
[find_item, columns, lanes, grouped, onMove, onReorder, make_revert_handle]
|
|
9942
10079
|
);
|
|
9943
10080
|
const handle_drag_cancel = React27.useCallback(() => {
|
|
9944
10081
|
set_active_id(null);
|
|
@@ -9949,13 +10086,57 @@ function HazoUiKanban({
|
|
|
9949
10086
|
`(max-width: ${Math.max(0, mobileBreakpoint - 1)}px)`
|
|
9950
10087
|
);
|
|
9951
10088
|
const mobile_classes = is_custom_breakpoint ? is_mobile_via_query ? "block" : "hidden" : "sm:hidden";
|
|
9952
|
-
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : "grid" : "hidden sm:grid";
|
|
10089
|
+
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : lanes ? "block" : "grid" : lanes ? "hidden sm:block" : "hidden sm:grid";
|
|
10090
|
+
const grid_style = {
|
|
10091
|
+
gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))`
|
|
10092
|
+
};
|
|
10093
|
+
function lane_total(lane_key) {
|
|
10094
|
+
let total = 0;
|
|
10095
|
+
for (const col of columns)
|
|
10096
|
+
total += (grouped.get(bucket_key(lane_key, col.key)) ?? []).length;
|
|
10097
|
+
return total;
|
|
10098
|
+
}
|
|
10099
|
+
function render_column(col, tree_key, lane_key, with_footer = true) {
|
|
10100
|
+
return /* @__PURE__ */ jsx(
|
|
10101
|
+
KanbanColumn,
|
|
10102
|
+
{
|
|
10103
|
+
column: col,
|
|
10104
|
+
laneKey: lane_key,
|
|
10105
|
+
treeKey: tree_key,
|
|
10106
|
+
items: grouped.get(bucket_key(lane_key, col.key)) ?? [],
|
|
10107
|
+
renderCard,
|
|
10108
|
+
emptyColumn,
|
|
10109
|
+
footer: with_footer ? renderColumnFooter?.({ columnKey: col.key, laneKey: lane_key }) ?? null : null,
|
|
10110
|
+
cardClassName,
|
|
10111
|
+
showEdit: show_edit,
|
|
10112
|
+
onEditRequest: handle_edit_request
|
|
10113
|
+
},
|
|
10114
|
+
col.key
|
|
10115
|
+
);
|
|
10116
|
+
}
|
|
10117
|
+
function render_lane_row(lane, tree_key, only_column) {
|
|
10118
|
+
const count = only_column ? (grouped.get(bucket_key(lane.key, only_column.key)) ?? []).length : lane_total(lane.key);
|
|
10119
|
+
if (lane.collapseWhenEmpty && count === 0) {
|
|
10120
|
+
return /* @__PURE__ */ jsx(KanbanLaneStrip, { lane, treeKey: tree_key }, lane.key);
|
|
10121
|
+
}
|
|
10122
|
+
return /* @__PURE__ */ jsxs("div", { className: "cls_hazo_kanban_lane", children: [
|
|
10123
|
+
/* @__PURE__ */ jsx(KanbanLaneHead, { lane, count, treeKey: tree_key }),
|
|
10124
|
+
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)) })
|
|
10125
|
+
] }, lane.key);
|
|
10126
|
+
}
|
|
10127
|
+
function render_unmatched_lane(tree_key, only_column) {
|
|
10128
|
+
const count = only_column ? (grouped.get(bucket_key(UNMATCHED_LANE_KEY, only_column.key)) ?? []).length : lane_total(UNMATCHED_LANE_KEY);
|
|
10129
|
+
if (count === 0) return null;
|
|
10130
|
+
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, false) : /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_lane_grid grid gap-3", style: grid_style, children: columns.map(
|
|
10131
|
+
(col) => render_column(col, tree_key, UNMATCHED_LANE_KEY, false)
|
|
10132
|
+
) }) });
|
|
10133
|
+
}
|
|
9953
10134
|
return /* @__PURE__ */ jsxs(
|
|
9954
10135
|
DndContext,
|
|
9955
10136
|
{
|
|
9956
10137
|
id: dnd_context_id,
|
|
9957
10138
|
sensors,
|
|
9958
|
-
collisionDetection:
|
|
10139
|
+
collisionDetection: collision_detection,
|
|
9959
10140
|
onDragStart: handle_drag_start,
|
|
9960
10141
|
onDragEnd: handle_drag_end,
|
|
9961
10142
|
onDragCancel: handle_drag_cancel,
|
|
@@ -9964,43 +10145,33 @@ function HazoUiKanban({
|
|
|
9964
10145
|
/* @__PURE__ */ jsxs("div", { className: cn("cls_hazo_kanban w-full", className), children: [
|
|
9965
10146
|
/* @__PURE__ */ jsx("div", { className: cn("cls_hazo_kanban_mobile", mobile_classes), children: /* @__PURE__ */ jsxs(Tabs, { value: active_tab, onValueChange: set_active_tab, children: [
|
|
9966
10147
|
/* @__PURE__ */ jsx(TabsList, { className: "grid w-full", style: { gridTemplateColumns: `repeat(${columns.length}, 1fr)` }, children: columns.map((col) => {
|
|
9967
|
-
const count =
|
|
10148
|
+
const count = lanes ? lanes.reduce(
|
|
10149
|
+
(n, lane) => n + (grouped.get(bucket_key(lane.key, col.key)) ?? []).length,
|
|
10150
|
+
(grouped.get(bucket_key(UNMATCHED_LANE_KEY, col.key)) ?? []).length
|
|
10151
|
+
) : (grouped.get(col.key) ?? []).length;
|
|
9968
10152
|
return /* @__PURE__ */ jsxs(TabsTrigger, { value: col.key, className: "flex flex-col gap-0.5", children: [
|
|
9969
10153
|
/* @__PURE__ */ jsx("span", { className: "text-xs", children: col.title }),
|
|
9970
10154
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: count })
|
|
9971
10155
|
] }, col.key);
|
|
9972
10156
|
}) }),
|
|
9973
|
-
columns.map((col) => /* @__PURE__ */ jsx(TabsContent, { value: col.key, className: "mt-3", children: /* @__PURE__ */
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
items: grouped.get(col.key) ?? [],
|
|
9978
|
-
renderCard,
|
|
9979
|
-
emptyColumn,
|
|
9980
|
-
cardClassName,
|
|
9981
|
-
showEdit: show_edit,
|
|
9982
|
-
onEditRequest: handle_edit_request
|
|
9983
|
-
}
|
|
9984
|
-
) }, col.key))
|
|
10157
|
+
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: [
|
|
10158
|
+
lanes.map((lane) => render_lane_row(lane, "m", col)),
|
|
10159
|
+
render_unmatched_lane("m", col)
|
|
10160
|
+
] }) : render_column(col, "m") }, col.key))
|
|
9985
10161
|
] }) }),
|
|
9986
10162
|
/* @__PURE__ */ jsx(
|
|
9987
10163
|
"div",
|
|
9988
10164
|
{
|
|
9989
|
-
className: cn(
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
showEdit: show_edit,
|
|
10000
|
-
onEditRequest: handle_edit_request
|
|
10001
|
-
},
|
|
10002
|
-
col.key
|
|
10003
|
-
))
|
|
10165
|
+
className: cn(
|
|
10166
|
+
"cls_hazo_kanban_desktop",
|
|
10167
|
+
lanes ? "space-y-4" : "gap-3",
|
|
10168
|
+
desktop_classes
|
|
10169
|
+
),
|
|
10170
|
+
style: lanes ? void 0 : grid_style,
|
|
10171
|
+
children: lanes ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
10172
|
+
lanes.map((lane) => render_lane_row(lane, "d")),
|
|
10173
|
+
render_unmatched_lane("d")
|
|
10174
|
+
] }) : columns.map((col) => render_column(col, "d"))
|
|
10004
10175
|
}
|
|
10005
10176
|
),
|
|
10006
10177
|
/* @__PURE__ */ jsx(DragOverlay, { children: active_item ? /* @__PURE__ */ jsx(
|