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.cjs
CHANGED
|
@@ -9091,10 +9091,15 @@ function KanbanCard({
|
|
|
9091
9091
|
isDragging
|
|
9092
9092
|
} = sortable.useSortable({
|
|
9093
9093
|
id: item.id,
|
|
9094
|
-
// sectionKey
|
|
9095
|
-
// section, not just its column (
|
|
9096
|
-
// the gaps between cards, but the cards themselves
|
|
9097
|
-
|
|
9094
|
+
// sectionKey and laneKey ride along so a drop *onto a card* resolves to
|
|
9095
|
+
// that card's section and lane, not just its column (the section bands
|
|
9096
|
+
// and lane rows cover the gaps between cards, but the cards themselves
|
|
9097
|
+
// are the sortable).
|
|
9098
|
+
data: {
|
|
9099
|
+
columnKey: item.columnKey,
|
|
9100
|
+
sectionKey: item.sectionKey,
|
|
9101
|
+
laneKey: item.laneKey
|
|
9102
|
+
}
|
|
9098
9103
|
});
|
|
9099
9104
|
const priority_var = item.priority ? `--hazo-kanban-priority-${String(item.priority).toLowerCase()}` : null;
|
|
9100
9105
|
const style = {
|
|
@@ -9103,6 +9108,12 @@ function KanbanCard({
|
|
|
9103
9108
|
backgroundColor: "hsl(var(--hazo-kanban-card-bg))",
|
|
9104
9109
|
border: `1px solid hsl(var(--hazo-kanban-card-border))`,
|
|
9105
9110
|
borderLeft: priority_var ? `4px solid hsl(var(${priority_var}))` : `1px solid hsl(var(--hazo-kanban-card-border))`,
|
|
9111
|
+
// Opt-in lift. A card whose background equals the column's (the case for
|
|
9112
|
+
// every palette where --card and --background resolve to the same value)
|
|
9113
|
+
// is separated by nothing but a 1px border, which reads as flat at a
|
|
9114
|
+
// glance. The fallback is `none`, so a consumer that never sets the token
|
|
9115
|
+
// renders exactly as before.
|
|
9116
|
+
boxShadow: "var(--hazo-kanban-card-shadow, none)",
|
|
9106
9117
|
opacity: isDragging && !dragging ? 0.4 : 1,
|
|
9107
9118
|
cursor: "grab"
|
|
9108
9119
|
};
|
|
@@ -9111,6 +9122,9 @@ function KanbanCard({
|
|
|
9111
9122
|
{
|
|
9112
9123
|
ref: setNodeRef,
|
|
9113
9124
|
style,
|
|
9125
|
+
"data-column-key": item.columnKey,
|
|
9126
|
+
"data-lane-key": item.laneKey,
|
|
9127
|
+
"data-section-key": item.sectionKey,
|
|
9114
9128
|
className: cn(
|
|
9115
9129
|
"cls_hazo_kanban_card group relative rounded-md p-3 mb-2 select-none",
|
|
9116
9130
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
@@ -9155,8 +9169,16 @@ function KanbanCard({
|
|
|
9155
9169
|
}
|
|
9156
9170
|
);
|
|
9157
9171
|
}
|
|
9158
|
-
function
|
|
9159
|
-
return `
|
|
9172
|
+
function tree_droppable_id(prefix, tree_key, lane_key, rest) {
|
|
9173
|
+
return lane_key == null ? `${prefix}:${tree_key}::${rest}` : `${prefix}:${tree_key}::${lane_key}::${rest}`;
|
|
9174
|
+
}
|
|
9175
|
+
function section_droppable_id(column_key, section_key, tree_key, lane_key) {
|
|
9176
|
+
return tree_droppable_id(
|
|
9177
|
+
"section",
|
|
9178
|
+
tree_key,
|
|
9179
|
+
lane_key,
|
|
9180
|
+
`${column_key}::${section_key}`
|
|
9181
|
+
);
|
|
9160
9182
|
}
|
|
9161
9183
|
function group_items_by_section(items, sections) {
|
|
9162
9184
|
const bySection = /* @__PURE__ */ new Map();
|
|
@@ -9174,13 +9196,16 @@ function KanbanColumn({
|
|
|
9174
9196
|
items,
|
|
9175
9197
|
renderCard,
|
|
9176
9198
|
emptyColumn,
|
|
9199
|
+
footer,
|
|
9177
9200
|
cardClassName,
|
|
9178
9201
|
showEdit,
|
|
9179
|
-
onEditRequest
|
|
9202
|
+
onEditRequest,
|
|
9203
|
+
laneKey,
|
|
9204
|
+
treeKey
|
|
9180
9205
|
}) {
|
|
9181
9206
|
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9182
|
-
id:
|
|
9183
|
-
data: { columnKey: column.key, isColumn: true }
|
|
9207
|
+
id: tree_droppable_id("column", treeKey, laneKey, column.key),
|
|
9208
|
+
data: { columnKey: column.key, laneKey, isColumn: true }
|
|
9184
9209
|
});
|
|
9185
9210
|
const sections = column.sections;
|
|
9186
9211
|
const { bySection, unmatched } = React27__namespace.useMemo(
|
|
@@ -9217,6 +9242,8 @@ function KanbanColumn({
|
|
|
9217
9242
|
"div",
|
|
9218
9243
|
{
|
|
9219
9244
|
ref: setNodeRef,
|
|
9245
|
+
"data-column-key": column.key,
|
|
9246
|
+
"data-lane-key": laneKey,
|
|
9220
9247
|
className: cn(
|
|
9221
9248
|
"cls_hazo_kanban_column flex flex-col rounded-md p-2",
|
|
9222
9249
|
isOver && "cls_hazo_kanban_column_over bg-accent/30 ring-2 ring-ring/40"
|
|
@@ -9226,6 +9253,8 @@ function KanbanColumn({
|
|
|
9226
9253
|
KanbanColumnHead,
|
|
9227
9254
|
{
|
|
9228
9255
|
columnKey: column.key,
|
|
9256
|
+
laneKey,
|
|
9257
|
+
treeKey,
|
|
9229
9258
|
title: column.title,
|
|
9230
9259
|
count: items.length,
|
|
9231
9260
|
droppable: sections != null
|
|
@@ -9236,49 +9265,66 @@ function KanbanColumn({
|
|
|
9236
9265
|
{
|
|
9237
9266
|
items: ordered.map((i) => i.id),
|
|
9238
9267
|
strategy: sortable.verticalListSortingStrategy,
|
|
9239
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9268
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9269
|
+
"div",
|
|
9270
|
+
{
|
|
9271
|
+
"data-column-key": column.key,
|
|
9272
|
+
"data-lane-key": laneKey,
|
|
9273
|
+
className: "cls_hazo_kanban_column_body flex-1 min-h-[40px]",
|
|
9274
|
+
children: !sections ? items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_hazo_kanban_column_empty text-xs text-muted-foreground py-2 px-1", children: emptyColumn }) : render_cards(items) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9275
|
+
expanded_sections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
9276
|
+
KanbanSectionBand,
|
|
9277
|
+
{
|
|
9278
|
+
columnKey: column.key,
|
|
9279
|
+
laneKey,
|
|
9280
|
+
treeKey,
|
|
9281
|
+
section,
|
|
9282
|
+
items: bySection.get(section.key) ?? [],
|
|
9283
|
+
emptyColumn,
|
|
9284
|
+
renderCards: render_cards
|
|
9285
|
+
},
|
|
9286
|
+
section.key
|
|
9287
|
+
)),
|
|
9288
|
+
unmatched.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_hazo_kanban_section cls_hazo_kanban_section_unmatched", children: render_cards(unmatched) }),
|
|
9289
|
+
collapsed_sections.length > 0 && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
|
|
9290
|
+
KanbanSectionStrip,
|
|
9291
|
+
{
|
|
9292
|
+
columnKey: column.key,
|
|
9293
|
+
laneKey,
|
|
9294
|
+
treeKey,
|
|
9295
|
+
section
|
|
9296
|
+
},
|
|
9297
|
+
section.key
|
|
9298
|
+
)) })
|
|
9299
|
+
] })
|
|
9300
|
+
}
|
|
9301
|
+
)
|
|
9261
9302
|
}
|
|
9262
|
-
)
|
|
9303
|
+
),
|
|
9304
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cls_hazo_kanban_column_footer mt-1", children: footer }) : null
|
|
9263
9305
|
]
|
|
9264
9306
|
}
|
|
9265
9307
|
);
|
|
9266
9308
|
}
|
|
9267
9309
|
function KanbanColumnHead({
|
|
9268
9310
|
columnKey,
|
|
9311
|
+
laneKey,
|
|
9312
|
+
treeKey,
|
|
9269
9313
|
title,
|
|
9270
9314
|
count,
|
|
9271
9315
|
droppable
|
|
9272
9316
|
}) {
|
|
9273
9317
|
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9274
|
-
id:
|
|
9275
|
-
data: { columnKey, isColumn: true },
|
|
9318
|
+
id: tree_droppable_id("columnhead", treeKey, laneKey, columnKey),
|
|
9319
|
+
data: { columnKey, laneKey, isColumn: true },
|
|
9276
9320
|
disabled: !droppable
|
|
9277
9321
|
});
|
|
9278
9322
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9279
9323
|
"div",
|
|
9280
9324
|
{
|
|
9281
9325
|
ref: droppable ? setNodeRef : void 0,
|
|
9326
|
+
"data-column-key": columnKey,
|
|
9327
|
+
"data-lane-key": laneKey,
|
|
9282
9328
|
className: cn(
|
|
9283
9329
|
"cls_hazo_kanban_column_head mb-2 flex items-center justify-between rounded-sm px-1 text-xs uppercase tracking-wider text-muted-foreground",
|
|
9284
9330
|
droppable && "py-1",
|
|
@@ -9293,14 +9339,16 @@ function KanbanColumnHead({
|
|
|
9293
9339
|
}
|
|
9294
9340
|
function KanbanSectionBand({
|
|
9295
9341
|
columnKey,
|
|
9342
|
+
laneKey,
|
|
9343
|
+
treeKey,
|
|
9296
9344
|
section,
|
|
9297
9345
|
items,
|
|
9298
9346
|
emptyColumn,
|
|
9299
9347
|
renderCards
|
|
9300
9348
|
}) {
|
|
9301
9349
|
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9302
|
-
id: section_droppable_id(columnKey, section.key),
|
|
9303
|
-
data: { columnKey, sectionKey: section.key, isSection: true }
|
|
9350
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9351
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9304
9352
|
});
|
|
9305
9353
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9306
9354
|
"div",
|
|
@@ -9323,11 +9371,13 @@ function KanbanSectionBand({
|
|
|
9323
9371
|
}
|
|
9324
9372
|
function KanbanSectionStrip({
|
|
9325
9373
|
columnKey,
|
|
9374
|
+
laneKey,
|
|
9375
|
+
treeKey,
|
|
9326
9376
|
section
|
|
9327
9377
|
}) {
|
|
9328
9378
|
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9329
|
-
id: section_droppable_id(columnKey, section.key),
|
|
9330
|
-
data: { columnKey, sectionKey: section.key, isSection: true }
|
|
9379
|
+
id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
|
|
9380
|
+
data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
|
|
9331
9381
|
});
|
|
9332
9382
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9333
9383
|
"div",
|
|
@@ -9341,6 +9391,58 @@ function KanbanSectionStrip({
|
|
|
9341
9391
|
}
|
|
9342
9392
|
);
|
|
9343
9393
|
}
|
|
9394
|
+
function lane_droppable_id(lane_key, tree_key) {
|
|
9395
|
+
return `lane:${tree_key}::${lane_key}`;
|
|
9396
|
+
}
|
|
9397
|
+
function KanbanLaneHead({
|
|
9398
|
+
lane,
|
|
9399
|
+
count,
|
|
9400
|
+
treeKey
|
|
9401
|
+
}) {
|
|
9402
|
+
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9403
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9404
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9405
|
+
});
|
|
9406
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9407
|
+
"div",
|
|
9408
|
+
{
|
|
9409
|
+
ref: setNodeRef,
|
|
9410
|
+
className: cn(
|
|
9411
|
+
"cls_hazo_kanban_lane_head mb-2 flex items-center gap-3 rounded-sm px-1 py-1",
|
|
9412
|
+
isOver && "cls_hazo_kanban_lane_head_over bg-accent/30 ring-1 ring-ring/40"
|
|
9413
|
+
),
|
|
9414
|
+
children: [
|
|
9415
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_lane_title text-xs font-semibold uppercase tracking-wider text-foreground", children: lane.title }),
|
|
9416
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_lane_rule h-px flex-1 bg-border" }),
|
|
9417
|
+
lane.actions ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_lane_actions flex items-center gap-1", children: lane.actions }) : null,
|
|
9418
|
+
/* @__PURE__ */ jsxRuntime.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 })
|
|
9419
|
+
]
|
|
9420
|
+
}
|
|
9421
|
+
);
|
|
9422
|
+
}
|
|
9423
|
+
function KanbanLaneStrip({
|
|
9424
|
+
lane,
|
|
9425
|
+
treeKey
|
|
9426
|
+
}) {
|
|
9427
|
+
const { setNodeRef, isOver } = core$1.useDroppable({
|
|
9428
|
+
id: lane_droppable_id(lane.key, treeKey),
|
|
9429
|
+
data: { laneKey: lane.key, isLane: true }
|
|
9430
|
+
});
|
|
9431
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9432
|
+
"div",
|
|
9433
|
+
{
|
|
9434
|
+
ref: setNodeRef,
|
|
9435
|
+
className: cn(
|
|
9436
|
+
"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",
|
|
9437
|
+
isOver && "cls_hazo_kanban_lane_strip_over border-solid bg-accent/30 text-foreground ring-1 ring-ring/30"
|
|
9438
|
+
),
|
|
9439
|
+
children: [
|
|
9440
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_lane_title", children: lane.title }),
|
|
9441
|
+
lane.actions ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_hazo_kanban_lane_actions ml-auto flex items-center gap-1", children: lane.actions }) : null
|
|
9442
|
+
]
|
|
9443
|
+
}
|
|
9444
|
+
);
|
|
9445
|
+
}
|
|
9344
9446
|
var DEFAULT_PRIORITIES = ["P0", "P1", "P2", "P3"];
|
|
9345
9447
|
function humanize(key) {
|
|
9346
9448
|
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(" ");
|
|
@@ -9747,6 +9849,10 @@ function applyKanbanFilter(items, filter) {
|
|
|
9747
9849
|
return true;
|
|
9748
9850
|
});
|
|
9749
9851
|
}
|
|
9852
|
+
var UNMATCHED_LANE_KEY = "__hazo_lane_unmatched__";
|
|
9853
|
+
function bucket_key(lane_key, column_key) {
|
|
9854
|
+
return lane_key == null ? column_key : `${lane_key}\0${column_key}`;
|
|
9855
|
+
}
|
|
9750
9856
|
function default_announcements(itemLabel) {
|
|
9751
9857
|
return {
|
|
9752
9858
|
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.`,
|
|
@@ -9755,38 +9861,50 @@ function default_announcements(itemLabel) {
|
|
|
9755
9861
|
onDragCancel: ({ item, fromColumn }) => `Movement cancelled. ${itemLabel(item)} returned to ${fromColumn}.`
|
|
9756
9862
|
};
|
|
9757
9863
|
}
|
|
9758
|
-
function group_items_by_column(items, overlay, columns) {
|
|
9864
|
+
function group_items_by_column(items, overlay, columns, lanes) {
|
|
9759
9865
|
const out = /* @__PURE__ */ new Map();
|
|
9760
|
-
|
|
9866
|
+
const lane_keys = lanes ? [...lanes.map((l) => l.key), UNMATCHED_LANE_KEY] : [void 0];
|
|
9867
|
+
for (const lane_key of lane_keys)
|
|
9868
|
+
for (const col of columns) out.set(bucket_key(lane_key, col.key), []);
|
|
9761
9869
|
const overlay_inserts = /* @__PURE__ */ new Map();
|
|
9762
|
-
for (const
|
|
9870
|
+
for (const key of out.keys()) overlay_inserts.set(key, []);
|
|
9871
|
+
const declared = lanes ? new Set(lanes.map((l) => l.key)) : null;
|
|
9872
|
+
function resolve_lane(lane_key) {
|
|
9873
|
+
if (!declared) return void 0;
|
|
9874
|
+
return lane_key != null && declared.has(lane_key) ? lane_key : UNMATCHED_LANE_KEY;
|
|
9875
|
+
}
|
|
9763
9876
|
for (const item of items) {
|
|
9764
9877
|
const ov = overlay.get(item.id);
|
|
9765
9878
|
if (ov) {
|
|
9766
|
-
const bucket = overlay_inserts.get(
|
|
9879
|
+
const bucket = overlay_inserts.get(
|
|
9880
|
+
bucket_key(resolve_lane(ov.laneKey), ov.columnKey)
|
|
9881
|
+
);
|
|
9767
9882
|
if (bucket) {
|
|
9768
|
-
const placed = ov.sectionKey === item.sectionKey ? item : { ...item, sectionKey: ov.sectionKey };
|
|
9883
|
+
const placed = ov.sectionKey === item.sectionKey && ov.laneKey === item.laneKey ? item : { ...item, sectionKey: ov.sectionKey, laneKey: ov.laneKey };
|
|
9769
9884
|
bucket.push({ item: placed, index: ov.index });
|
|
9770
9885
|
}
|
|
9771
9886
|
} else {
|
|
9772
|
-
const bucket = out.get(
|
|
9887
|
+
const bucket = out.get(
|
|
9888
|
+
bucket_key(resolve_lane(item.laneKey), item.columnKey)
|
|
9889
|
+
);
|
|
9773
9890
|
if (bucket) bucket.push(item);
|
|
9774
9891
|
}
|
|
9775
9892
|
}
|
|
9776
|
-
for (const
|
|
9777
|
-
|
|
9893
|
+
for (const [key, inserts] of overlay_inserts) {
|
|
9894
|
+
if (inserts.length === 0) continue;
|
|
9778
9895
|
inserts.sort((a, b) => a.index - b.index);
|
|
9779
|
-
const arr = out.get(
|
|
9896
|
+
const arr = out.get(key) ?? [];
|
|
9780
9897
|
for (const { item, index } of inserts) {
|
|
9781
9898
|
const at = Math.max(0, Math.min(index, arr.length));
|
|
9782
9899
|
arr.splice(at, 0, item);
|
|
9783
9900
|
}
|
|
9784
|
-
out.set(
|
|
9901
|
+
out.set(key, arr);
|
|
9785
9902
|
}
|
|
9786
9903
|
return out;
|
|
9787
9904
|
}
|
|
9788
9905
|
function HazoUiKanban({
|
|
9789
9906
|
columns,
|
|
9907
|
+
lanes,
|
|
9790
9908
|
items,
|
|
9791
9909
|
renderCard,
|
|
9792
9910
|
onMove,
|
|
@@ -9794,6 +9912,7 @@ function HazoUiKanban({
|
|
|
9794
9912
|
mobileBreakpoint = 640,
|
|
9795
9913
|
announcements,
|
|
9796
9914
|
emptyColumn = "\u2014",
|
|
9915
|
+
renderColumnFooter,
|
|
9797
9916
|
className,
|
|
9798
9917
|
cardClassName,
|
|
9799
9918
|
itemLabel,
|
|
@@ -9834,7 +9953,7 @@ function HazoUiKanban({
|
|
|
9834
9953
|
const next = new Map(prev);
|
|
9835
9954
|
for (const [item_id, pos] of prev.entries()) {
|
|
9836
9955
|
const item = items.find((i) => i.id === item_id);
|
|
9837
|
-
if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey) {
|
|
9956
|
+
if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey && item.laneKey === pos.laneKey) {
|
|
9838
9957
|
next.delete(item_id);
|
|
9839
9958
|
changed = true;
|
|
9840
9959
|
}
|
|
@@ -9843,8 +9962,8 @@ function HazoUiKanban({
|
|
|
9843
9962
|
});
|
|
9844
9963
|
}, [items, overlay]);
|
|
9845
9964
|
const grouped = React27__namespace.useMemo(
|
|
9846
|
-
() => group_items_by_column(items, overlay, columns),
|
|
9847
|
-
[items, overlay, columns]
|
|
9965
|
+
() => group_items_by_column(items, overlay, columns, lanes),
|
|
9966
|
+
[items, overlay, columns, lanes]
|
|
9848
9967
|
);
|
|
9849
9968
|
const find_item = React27__namespace.useCallback(
|
|
9850
9969
|
(id) => items.find((i) => i.id === id),
|
|
@@ -9854,6 +9973,13 @@ function HazoUiKanban({
|
|
|
9854
9973
|
core$1.useSensor(core$1.PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
9855
9974
|
core$1.useSensor(core$1.KeyboardSensor, { coordinateGetter: sortable.sortableKeyboardCoordinates })
|
|
9856
9975
|
);
|
|
9976
|
+
const collision_detection = React27__namespace.useCallback((args) => {
|
|
9977
|
+
const under_pointer = core$1.pointerWithin(args);
|
|
9978
|
+
if (under_pointer.length > 0) return under_pointer;
|
|
9979
|
+
const overlapping = core$1.rectIntersection(args);
|
|
9980
|
+
if (overlapping.length > 0) return overlapping;
|
|
9981
|
+
return core$1.closestCorners(args);
|
|
9982
|
+
}, []);
|
|
9857
9983
|
const merged_announcements = React27__namespace.useMemo(() => {
|
|
9858
9984
|
const defaults = default_announcements(label_fn);
|
|
9859
9985
|
return {
|
|
@@ -9882,7 +10008,7 @@ function HazoUiKanban({
|
|
|
9882
10008
|
const id = String(active.id);
|
|
9883
10009
|
const item = find_item(id);
|
|
9884
10010
|
if (!item) return "";
|
|
9885
|
-
const over_col_key = over ? over.data?.current?.columnKey ??
|
|
10011
|
+
const over_col_key = over ? over.data?.current?.columnKey ?? item.columnKey : null;
|
|
9886
10012
|
const col = over_col_key ? columns.find((c) => c.key === over_col_key) : null;
|
|
9887
10013
|
return merged_announcements.onDragOver({
|
|
9888
10014
|
item,
|
|
@@ -9897,10 +10023,13 @@ function HazoUiKanban({
|
|
|
9897
10023
|
const item = find_item(id);
|
|
9898
10024
|
if (!item) return "";
|
|
9899
10025
|
const from_col = columns.find((c) => c.key === item.columnKey);
|
|
9900
|
-
const over_col_key = over
|
|
10026
|
+
const over_col_key = over?.data?.current?.columnKey ?? item.columnKey;
|
|
10027
|
+
const over_lane_key = lanes ? over?.data?.current?.laneKey ?? item.laneKey : void 0;
|
|
9901
10028
|
const to_col = over_col_key ? columns.find((c) => c.key === over_col_key) ?? from_col : from_col;
|
|
9902
|
-
const target =
|
|
9903
|
-
|
|
10029
|
+
const target = grouped.get(
|
|
10030
|
+
bucket_key(over_lane_key, over_col_key ?? item.columnKey)
|
|
10031
|
+
) ?? [];
|
|
10032
|
+
const on_shell = !over || String(over.id).startsWith("column:") || String(over.id).startsWith("columnhead:") || String(over.id).startsWith("section:") || String(over.id).startsWith("lane:");
|
|
9904
10033
|
const new_index = on_shell ? target.length : target.findIndex((it) => it.id === String(over.id));
|
|
9905
10034
|
return merged_announcements.onDragEnd({
|
|
9906
10035
|
item,
|
|
@@ -9920,7 +10049,7 @@ function HazoUiKanban({
|
|
|
9920
10049
|
});
|
|
9921
10050
|
}
|
|
9922
10051
|
}),
|
|
9923
|
-
[find_item, columns, grouped, merged_announcements]
|
|
10052
|
+
[find_item, columns, lanes, grouped, merged_announcements]
|
|
9924
10053
|
);
|
|
9925
10054
|
const handle_drag_start = React27__namespace.useCallback((event) => {
|
|
9926
10055
|
set_active_id(String(event.active.id));
|
|
@@ -9947,31 +10076,35 @@ function HazoUiKanban({
|
|
|
9947
10076
|
if (!event.over) return;
|
|
9948
10077
|
const over_id = String(event.over.id);
|
|
9949
10078
|
const over_data = event.over.data?.current;
|
|
9950
|
-
const dest_column_key = over_data?.columnKey ??
|
|
10079
|
+
const dest_column_key = over_data?.columnKey ?? item.columnKey;
|
|
9951
10080
|
const dest_column = columns.find((c) => c.key === dest_column_key);
|
|
9952
10081
|
if (!dest_column) return;
|
|
10082
|
+
const dest_lane_key = lanes ? over_data?.laneKey ?? item.laneKey : void 0;
|
|
10083
|
+
const dest_lane = lanes?.find((l) => l.key === dest_lane_key);
|
|
10084
|
+
if (lanes && dest_lane?.accepts && !dest_lane.accepts(item)) return;
|
|
9953
10085
|
const dest_section_key = dest_column.sections ? over_data?.sectionKey ?? item.sectionKey : void 0;
|
|
9954
10086
|
const dest_section = dest_column.sections?.find(
|
|
9955
10087
|
(s) => s.key === dest_section_key
|
|
9956
10088
|
);
|
|
9957
10089
|
if (dest_column.accepts && !dest_column.accepts(item)) return;
|
|
9958
10090
|
if (dest_section?.accepts && !dest_section.accepts(item)) return;
|
|
9959
|
-
const dest_items_pre_overlay = grouped.get(dest_column_key) ?? [];
|
|
10091
|
+
const dest_items_pre_overlay = grouped.get(bucket_key(dest_lane_key, dest_column_key)) ?? [];
|
|
9960
10092
|
let new_index;
|
|
9961
|
-
if (over_data?.isColumn || over_data?.isSection) {
|
|
10093
|
+
if (over_data?.isColumn || over_data?.isSection || over_data?.isLane) {
|
|
9962
10094
|
new_index = dest_items_pre_overlay.length;
|
|
9963
10095
|
} else {
|
|
9964
10096
|
const idx = dest_items_pre_overlay.findIndex((i) => i.id === over_id);
|
|
9965
10097
|
new_index = idx === -1 ? dest_items_pre_overlay.length : idx;
|
|
9966
10098
|
}
|
|
9967
10099
|
const handle = make_revert_handle(active_id_str);
|
|
9968
|
-
if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key) {
|
|
10100
|
+
if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key && item.laneKey === dest_lane_key) {
|
|
9969
10101
|
if (active_id_str === over_id) return;
|
|
9970
10102
|
set_overlay((prev) => {
|
|
9971
10103
|
const next = new Map(prev);
|
|
9972
10104
|
next.set(active_id_str, {
|
|
9973
10105
|
columnKey: dest_column_key,
|
|
9974
10106
|
sectionKey: dest_section_key,
|
|
10107
|
+
laneKey: dest_lane_key,
|
|
9975
10108
|
index: new_index
|
|
9976
10109
|
});
|
|
9977
10110
|
return next;
|
|
@@ -9981,6 +10114,7 @@ function HazoUiKanban({
|
|
|
9981
10114
|
item,
|
|
9982
10115
|
columnKey: dest_column_key,
|
|
9983
10116
|
sectionKey: dest_section_key,
|
|
10117
|
+
laneKey: dest_lane_key,
|
|
9984
10118
|
newIndex: new_index,
|
|
9985
10119
|
revert: handle.revert
|
|
9986
10120
|
};
|
|
@@ -9992,6 +10126,7 @@ function HazoUiKanban({
|
|
|
9992
10126
|
next.set(active_id_str, {
|
|
9993
10127
|
columnKey: dest_column_key,
|
|
9994
10128
|
sectionKey: dest_section_key,
|
|
10129
|
+
laneKey: dest_lane_key,
|
|
9995
10130
|
index: new_index
|
|
9996
10131
|
});
|
|
9997
10132
|
return next;
|
|
@@ -10003,12 +10138,14 @@ function HazoUiKanban({
|
|
|
10003
10138
|
toColumn: dest_column_key,
|
|
10004
10139
|
fromSection: item.sectionKey,
|
|
10005
10140
|
toSection: dest_section_key,
|
|
10141
|
+
fromLane: item.laneKey,
|
|
10142
|
+
toLane: dest_lane_key,
|
|
10006
10143
|
newIndex: new_index,
|
|
10007
10144
|
revert: handle.revert
|
|
10008
10145
|
};
|
|
10009
10146
|
onMove?.(move_event);
|
|
10010
10147
|
},
|
|
10011
|
-
[find_item, columns, grouped, onMove, onReorder, make_revert_handle]
|
|
10148
|
+
[find_item, columns, lanes, grouped, onMove, onReorder, make_revert_handle]
|
|
10012
10149
|
);
|
|
10013
10150
|
const handle_drag_cancel = React27__namespace.useCallback(() => {
|
|
10014
10151
|
set_active_id(null);
|
|
@@ -10019,13 +10156,57 @@ function HazoUiKanban({
|
|
|
10019
10156
|
`(max-width: ${Math.max(0, mobileBreakpoint - 1)}px)`
|
|
10020
10157
|
);
|
|
10021
10158
|
const mobile_classes = is_custom_breakpoint ? is_mobile_via_query ? "block" : "hidden" : "sm:hidden";
|
|
10022
|
-
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : "grid" : "hidden sm:grid";
|
|
10159
|
+
const desktop_classes = is_custom_breakpoint ? is_mobile_via_query ? "hidden" : lanes ? "block" : "grid" : lanes ? "hidden sm:block" : "hidden sm:grid";
|
|
10160
|
+
const grid_style = {
|
|
10161
|
+
gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))`
|
|
10162
|
+
};
|
|
10163
|
+
function lane_total(lane_key) {
|
|
10164
|
+
let total = 0;
|
|
10165
|
+
for (const col of columns)
|
|
10166
|
+
total += (grouped.get(bucket_key(lane_key, col.key)) ?? []).length;
|
|
10167
|
+
return total;
|
|
10168
|
+
}
|
|
10169
|
+
function render_column(col, tree_key, lane_key, with_footer = true) {
|
|
10170
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10171
|
+
KanbanColumn,
|
|
10172
|
+
{
|
|
10173
|
+
column: col,
|
|
10174
|
+
laneKey: lane_key,
|
|
10175
|
+
treeKey: tree_key,
|
|
10176
|
+
items: grouped.get(bucket_key(lane_key, col.key)) ?? [],
|
|
10177
|
+
renderCard,
|
|
10178
|
+
emptyColumn,
|
|
10179
|
+
footer: with_footer ? renderColumnFooter?.({ columnKey: col.key, laneKey: lane_key }) ?? null : null,
|
|
10180
|
+
cardClassName,
|
|
10181
|
+
showEdit: show_edit,
|
|
10182
|
+
onEditRequest: handle_edit_request
|
|
10183
|
+
},
|
|
10184
|
+
col.key
|
|
10185
|
+
);
|
|
10186
|
+
}
|
|
10187
|
+
function render_lane_row(lane, tree_key, only_column) {
|
|
10188
|
+
const count = only_column ? (grouped.get(bucket_key(lane.key, only_column.key)) ?? []).length : lane_total(lane.key);
|
|
10189
|
+
if (lane.collapseWhenEmpty && count === 0) {
|
|
10190
|
+
return /* @__PURE__ */ jsxRuntime.jsx(KanbanLaneStrip, { lane, treeKey: tree_key }, lane.key);
|
|
10191
|
+
}
|
|
10192
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cls_hazo_kanban_lane", children: [
|
|
10193
|
+
/* @__PURE__ */ jsxRuntime.jsx(KanbanLaneHead, { lane, count, treeKey: tree_key }),
|
|
10194
|
+
only_column ? render_column(only_column, tree_key, lane.key) : /* @__PURE__ */ jsxRuntime.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)) })
|
|
10195
|
+
] }, lane.key);
|
|
10196
|
+
}
|
|
10197
|
+
function render_unmatched_lane(tree_key, only_column) {
|
|
10198
|
+
const count = only_column ? (grouped.get(bucket_key(UNMATCHED_LANE_KEY, only_column.key)) ?? []).length : lane_total(UNMATCHED_LANE_KEY);
|
|
10199
|
+
if (count === 0) return null;
|
|
10200
|
+
return /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("div", { className: "cls_hazo_kanban_lane_grid grid gap-3", style: grid_style, children: columns.map(
|
|
10201
|
+
(col) => render_column(col, tree_key, UNMATCHED_LANE_KEY, false)
|
|
10202
|
+
) }) });
|
|
10203
|
+
}
|
|
10023
10204
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10024
10205
|
core$1.DndContext,
|
|
10025
10206
|
{
|
|
10026
10207
|
id: dnd_context_id,
|
|
10027
10208
|
sensors,
|
|
10028
|
-
collisionDetection:
|
|
10209
|
+
collisionDetection: collision_detection,
|
|
10029
10210
|
onDragStart: handle_drag_start,
|
|
10030
10211
|
onDragEnd: handle_drag_end,
|
|
10031
10212
|
onDragCancel: handle_drag_cancel,
|
|
@@ -10034,43 +10215,33 @@ function HazoUiKanban({
|
|
|
10034
10215
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("cls_hazo_kanban w-full", className), children: [
|
|
10035
10216
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("cls_hazo_kanban_mobile", mobile_classes), children: /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { value: active_tab, onValueChange: set_active_tab, children: [
|
|
10036
10217
|
/* @__PURE__ */ jsxRuntime.jsx(TabsList, { className: "grid w-full", style: { gridTemplateColumns: `repeat(${columns.length}, 1fr)` }, children: columns.map((col) => {
|
|
10037
|
-
const count =
|
|
10218
|
+
const count = lanes ? lanes.reduce(
|
|
10219
|
+
(n, lane) => n + (grouped.get(bucket_key(lane.key, col.key)) ?? []).length,
|
|
10220
|
+
(grouped.get(bucket_key(UNMATCHED_LANE_KEY, col.key)) ?? []).length
|
|
10221
|
+
) : (grouped.get(col.key) ?? []).length;
|
|
10038
10222
|
return /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: col.key, className: "flex flex-col gap-0.5", children: [
|
|
10039
10223
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: col.title }),
|
|
10040
10224
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: count })
|
|
10041
10225
|
] }, col.key);
|
|
10042
10226
|
}) }),
|
|
10043
|
-
columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: col.key, className: "mt-3", children: /* @__PURE__ */ jsxRuntime.
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
items: grouped.get(col.key) ?? [],
|
|
10048
|
-
renderCard,
|
|
10049
|
-
emptyColumn,
|
|
10050
|
-
cardClassName,
|
|
10051
|
-
showEdit: show_edit,
|
|
10052
|
-
onEditRequest: handle_edit_request
|
|
10053
|
-
}
|
|
10054
|
-
) }, col.key))
|
|
10227
|
+
columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: col.key, className: "mt-3", children: lanes ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cls_hazo_kanban_lanes flex flex-col gap-4", children: [
|
|
10228
|
+
lanes.map((lane) => render_lane_row(lane, "m", col)),
|
|
10229
|
+
render_unmatched_lane("m", col)
|
|
10230
|
+
] }) : render_column(col, "m") }, col.key))
|
|
10055
10231
|
] }) }),
|
|
10056
10232
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10057
10233
|
"div",
|
|
10058
10234
|
{
|
|
10059
|
-
className: cn(
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
showEdit: show_edit,
|
|
10070
|
-
onEditRequest: handle_edit_request
|
|
10071
|
-
},
|
|
10072
|
-
col.key
|
|
10073
|
-
))
|
|
10235
|
+
className: cn(
|
|
10236
|
+
"cls_hazo_kanban_desktop",
|
|
10237
|
+
lanes ? "space-y-4" : "gap-3",
|
|
10238
|
+
desktop_classes
|
|
10239
|
+
),
|
|
10240
|
+
style: lanes ? void 0 : grid_style,
|
|
10241
|
+
children: lanes ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10242
|
+
lanes.map((lane) => render_lane_row(lane, "d")),
|
|
10243
|
+
render_unmatched_lane("d")
|
|
10244
|
+
] }) : columns.map((col) => render_column(col, "d"))
|
|
10074
10245
|
}
|
|
10075
10246
|
),
|
|
10076
10247
|
/* @__PURE__ */ jsxRuntime.jsx(core$1.DragOverlay, { children: active_item ? /* @__PURE__ */ jsxRuntime.jsx(
|