hazo_ui 6.4.0 → 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/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 rides along so a drop *onto a card* resolves to that card's
9025
- // section, not just its column (kanban_column.tsx's section bands cover
9026
- // the gaps between cards, but the cards themselves are the sortable).
9027
- data: { columnKey: item.columnKey, sectionKey: item.sectionKey }
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 = {
@@ -9085,8 +9090,16 @@ function KanbanCard({
9085
9090
  }
9086
9091
  );
9087
9092
  }
9088
- function section_droppable_id(column_key, section_key) {
9089
- return `section:${column_key}::${section_key}`;
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
+ );
9090
9103
  }
9091
9104
  function group_items_by_section(items, sections) {
9092
9105
  const bySection = /* @__PURE__ */ new Map();
@@ -9106,11 +9119,13 @@ function KanbanColumn({
9106
9119
  emptyColumn,
9107
9120
  cardClassName,
9108
9121
  showEdit,
9109
- onEditRequest
9122
+ onEditRequest,
9123
+ laneKey,
9124
+ treeKey
9110
9125
  }) {
9111
9126
  const { setNodeRef, isOver } = useDroppable({
9112
- id: `column:${column.key}`,
9113
- data: { columnKey: column.key, isColumn: true }
9127
+ id: tree_droppable_id("column", treeKey, laneKey, column.key),
9128
+ data: { columnKey: column.key, laneKey, isColumn: true }
9114
9129
  });
9115
9130
  const sections = column.sections;
9116
9131
  const { bySection, unmatched } = React27.useMemo(
@@ -9156,6 +9171,8 @@ function KanbanColumn({
9156
9171
  KanbanColumnHead,
9157
9172
  {
9158
9173
  columnKey: column.key,
9174
+ laneKey,
9175
+ treeKey,
9159
9176
  title: column.title,
9160
9177
  count: items.length,
9161
9178
  droppable: sections != null
@@ -9171,6 +9188,8 @@ function KanbanColumn({
9171
9188
  KanbanSectionBand,
9172
9189
  {
9173
9190
  columnKey: column.key,
9191
+ laneKey,
9192
+ treeKey,
9174
9193
  section,
9175
9194
  items: bySection.get(section.key) ?? [],
9176
9195
  emptyColumn,
@@ -9183,6 +9202,8 @@ function KanbanColumn({
9183
9202
  KanbanSectionStrip,
9184
9203
  {
9185
9204
  columnKey: column.key,
9205
+ laneKey,
9206
+ treeKey,
9186
9207
  section
9187
9208
  },
9188
9209
  section.key
@@ -9196,13 +9217,15 @@ function KanbanColumn({
9196
9217
  }
9197
9218
  function KanbanColumnHead({
9198
9219
  columnKey,
9220
+ laneKey,
9221
+ treeKey,
9199
9222
  title,
9200
9223
  count,
9201
9224
  droppable
9202
9225
  }) {
9203
9226
  const { setNodeRef, isOver } = useDroppable({
9204
- id: `columnhead:${columnKey}`,
9205
- data: { columnKey, isColumn: true },
9227
+ id: tree_droppable_id("columnhead", treeKey, laneKey, columnKey),
9228
+ data: { columnKey, laneKey, isColumn: true },
9206
9229
  disabled: !droppable
9207
9230
  });
9208
9231
  return /* @__PURE__ */ jsxs(
@@ -9223,14 +9246,16 @@ function KanbanColumnHead({
9223
9246
  }
9224
9247
  function KanbanSectionBand({
9225
9248
  columnKey,
9249
+ laneKey,
9250
+ treeKey,
9226
9251
  section,
9227
9252
  items,
9228
9253
  emptyColumn,
9229
9254
  renderCards
9230
9255
  }) {
9231
9256
  const { setNodeRef, isOver } = useDroppable({
9232
- id: section_droppable_id(columnKey, section.key),
9233
- data: { columnKey, sectionKey: section.key, isSection: true }
9257
+ id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
9258
+ data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
9234
9259
  });
9235
9260
  return /* @__PURE__ */ jsxs(
9236
9261
  "div",
@@ -9253,11 +9278,13 @@ function KanbanSectionBand({
9253
9278
  }
9254
9279
  function KanbanSectionStrip({
9255
9280
  columnKey,
9281
+ laneKey,
9282
+ treeKey,
9256
9283
  section
9257
9284
  }) {
9258
9285
  const { setNodeRef, isOver } = useDroppable({
9259
- id: section_droppable_id(columnKey, section.key),
9260
- data: { columnKey, sectionKey: section.key, isSection: true }
9286
+ id: section_droppable_id(columnKey, section.key, treeKey, laneKey),
9287
+ data: { columnKey, laneKey, sectionKey: section.key, isSection: true }
9261
9288
  });
9262
9289
  return /* @__PURE__ */ jsx(
9263
9290
  "div",
@@ -9271,6 +9298,54 @@ function KanbanSectionStrip({
9271
9298
  }
9272
9299
  );
9273
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
+ }
9274
9349
  var DEFAULT_PRIORITIES = ["P0", "P1", "P2", "P3"];
9275
9350
  function humanize(key) {
9276
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(" ");
@@ -9677,6 +9752,10 @@ function applyKanbanFilter(items, filter) {
9677
9752
  return true;
9678
9753
  });
9679
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
+ }
9680
9759
  function default_announcements(itemLabel) {
9681
9760
  return {
9682
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.`,
@@ -9685,38 +9764,50 @@ function default_announcements(itemLabel) {
9685
9764
  onDragCancel: ({ item, fromColumn }) => `Movement cancelled. ${itemLabel(item)} returned to ${fromColumn}.`
9686
9765
  };
9687
9766
  }
9688
- function group_items_by_column(items, overlay, columns) {
9767
+ function group_items_by_column(items, overlay, columns, lanes) {
9689
9768
  const out = /* @__PURE__ */ new Map();
9690
- for (const col of columns) out.set(col.key, []);
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), []);
9691
9772
  const overlay_inserts = /* @__PURE__ */ new Map();
9692
- for (const col of columns) overlay_inserts.set(col.key, []);
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
+ }
9693
9779
  for (const item of items) {
9694
9780
  const ov = overlay.get(item.id);
9695
9781
  if (ov) {
9696
- const bucket = overlay_inserts.get(ov.columnKey);
9782
+ const bucket = overlay_inserts.get(
9783
+ bucket_key(resolve_lane(ov.laneKey), ov.columnKey)
9784
+ );
9697
9785
  if (bucket) {
9698
- const placed = ov.sectionKey === item.sectionKey ? item : { ...item, sectionKey: ov.sectionKey };
9786
+ const placed = ov.sectionKey === item.sectionKey && ov.laneKey === item.laneKey ? item : { ...item, sectionKey: ov.sectionKey, laneKey: ov.laneKey };
9699
9787
  bucket.push({ item: placed, index: ov.index });
9700
9788
  }
9701
9789
  } else {
9702
- const bucket = out.get(item.columnKey);
9790
+ const bucket = out.get(
9791
+ bucket_key(resolve_lane(item.laneKey), item.columnKey)
9792
+ );
9703
9793
  if (bucket) bucket.push(item);
9704
9794
  }
9705
9795
  }
9706
- for (const col of columns) {
9707
- const inserts = overlay_inserts.get(col.key) ?? [];
9796
+ for (const [key, inserts] of overlay_inserts) {
9797
+ if (inserts.length === 0) continue;
9708
9798
  inserts.sort((a, b) => a.index - b.index);
9709
- const arr = out.get(col.key) ?? [];
9799
+ const arr = out.get(key) ?? [];
9710
9800
  for (const { item, index } of inserts) {
9711
9801
  const at = Math.max(0, Math.min(index, arr.length));
9712
9802
  arr.splice(at, 0, item);
9713
9803
  }
9714
- out.set(col.key, arr);
9804
+ out.set(key, arr);
9715
9805
  }
9716
9806
  return out;
9717
9807
  }
9718
9808
  function HazoUiKanban({
9719
9809
  columns,
9810
+ lanes,
9720
9811
  items,
9721
9812
  renderCard,
9722
9813
  onMove,
@@ -9764,7 +9855,7 @@ function HazoUiKanban({
9764
9855
  const next = new Map(prev);
9765
9856
  for (const [item_id, pos] of prev.entries()) {
9766
9857
  const item = items.find((i) => i.id === item_id);
9767
- if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey) {
9858
+ if (item && item.columnKey === pos.columnKey && item.sectionKey === pos.sectionKey && item.laneKey === pos.laneKey) {
9768
9859
  next.delete(item_id);
9769
9860
  changed = true;
9770
9861
  }
@@ -9773,8 +9864,8 @@ function HazoUiKanban({
9773
9864
  });
9774
9865
  }, [items, overlay]);
9775
9866
  const grouped = React27.useMemo(
9776
- () => group_items_by_column(items, overlay, columns),
9777
- [items, overlay, columns]
9867
+ () => group_items_by_column(items, overlay, columns, lanes),
9868
+ [items, overlay, columns, lanes]
9778
9869
  );
9779
9870
  const find_item = React27.useCallback(
9780
9871
  (id) => items.find((i) => i.id === id),
@@ -9784,6 +9875,13 @@ function HazoUiKanban({
9784
9875
  useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
9785
9876
  useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
9786
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
+ }, []);
9787
9885
  const merged_announcements = React27.useMemo(() => {
9788
9886
  const defaults = default_announcements(label_fn);
9789
9887
  return {
@@ -9812,7 +9910,7 @@ function HazoUiKanban({
9812
9910
  const id = String(active.id);
9813
9911
  const item = find_item(id);
9814
9912
  if (!item) return "";
9815
- const over_col_key = over ? over.data?.current?.columnKey ?? String(over.id).replace(/^column:/, "") : null;
9913
+ const over_col_key = over ? over.data?.current?.columnKey ?? item.columnKey : null;
9816
9914
  const col = over_col_key ? columns.find((c) => c.key === over_col_key) : null;
9817
9915
  return merged_announcements.onDragOver({
9818
9916
  item,
@@ -9827,10 +9925,13 @@ function HazoUiKanban({
9827
9925
  const item = find_item(id);
9828
9926
  if (!item) return "";
9829
9927
  const from_col = columns.find((c) => c.key === item.columnKey);
9830
- const over_col_key = over ? over.data?.current?.columnKey ?? String(over.id).replace(/^column:/, "") : null;
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;
9831
9930
  const to_col = over_col_key ? columns.find((c) => c.key === over_col_key) ?? from_col : from_col;
9832
- const target = over_col_key ? grouped.get(over_col_key) ?? [] : grouped.get(item.columnKey) ?? [];
9833
- const on_shell = !over || String(over.id).startsWith("column:") || String(over.id).startsWith("columnhead:") || String(over.id).startsWith("section:");
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:");
9834
9935
  const new_index = on_shell ? target.length : target.findIndex((it) => it.id === String(over.id));
9835
9936
  return merged_announcements.onDragEnd({
9836
9937
  item,
@@ -9850,7 +9951,7 @@ function HazoUiKanban({
9850
9951
  });
9851
9952
  }
9852
9953
  }),
9853
- [find_item, columns, grouped, merged_announcements]
9954
+ [find_item, columns, lanes, grouped, merged_announcements]
9854
9955
  );
9855
9956
  const handle_drag_start = React27.useCallback((event) => {
9856
9957
  set_active_id(String(event.active.id));
@@ -9877,31 +9978,35 @@ function HazoUiKanban({
9877
9978
  if (!event.over) return;
9878
9979
  const over_id = String(event.over.id);
9879
9980
  const over_data = event.over.data?.current;
9880
- const dest_column_key = over_data?.columnKey ?? over_id.replace(/^column:/, "");
9981
+ const dest_column_key = over_data?.columnKey ?? item.columnKey;
9881
9982
  const dest_column = columns.find((c) => c.key === dest_column_key);
9882
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;
9883
9987
  const dest_section_key = dest_column.sections ? over_data?.sectionKey ?? item.sectionKey : void 0;
9884
9988
  const dest_section = dest_column.sections?.find(
9885
9989
  (s) => s.key === dest_section_key
9886
9990
  );
9887
9991
  if (dest_column.accepts && !dest_column.accepts(item)) return;
9888
9992
  if (dest_section?.accepts && !dest_section.accepts(item)) return;
9889
- const dest_items_pre_overlay = grouped.get(dest_column_key) ?? [];
9993
+ const dest_items_pre_overlay = grouped.get(bucket_key(dest_lane_key, dest_column_key)) ?? [];
9890
9994
  let new_index;
9891
- if (over_data?.isColumn || over_data?.isSection) {
9995
+ if (over_data?.isColumn || over_data?.isSection || over_data?.isLane) {
9892
9996
  new_index = dest_items_pre_overlay.length;
9893
9997
  } else {
9894
9998
  const idx = dest_items_pre_overlay.findIndex((i) => i.id === over_id);
9895
9999
  new_index = idx === -1 ? dest_items_pre_overlay.length : idx;
9896
10000
  }
9897
10001
  const handle = make_revert_handle(active_id_str);
9898
- if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key) {
10002
+ if (item.columnKey === dest_column_key && item.sectionKey === dest_section_key && item.laneKey === dest_lane_key) {
9899
10003
  if (active_id_str === over_id) return;
9900
10004
  set_overlay((prev) => {
9901
10005
  const next = new Map(prev);
9902
10006
  next.set(active_id_str, {
9903
10007
  columnKey: dest_column_key,
9904
10008
  sectionKey: dest_section_key,
10009
+ laneKey: dest_lane_key,
9905
10010
  index: new_index
9906
10011
  });
9907
10012
  return next;
@@ -9911,6 +10016,7 @@ function HazoUiKanban({
9911
10016
  item,
9912
10017
  columnKey: dest_column_key,
9913
10018
  sectionKey: dest_section_key,
10019
+ laneKey: dest_lane_key,
9914
10020
  newIndex: new_index,
9915
10021
  revert: handle.revert
9916
10022
  };
@@ -9922,6 +10028,7 @@ function HazoUiKanban({
9922
10028
  next.set(active_id_str, {
9923
10029
  columnKey: dest_column_key,
9924
10030
  sectionKey: dest_section_key,
10031
+ laneKey: dest_lane_key,
9925
10032
  index: new_index
9926
10033
  });
9927
10034
  return next;
@@ -9933,12 +10040,14 @@ function HazoUiKanban({
9933
10040
  toColumn: dest_column_key,
9934
10041
  fromSection: item.sectionKey,
9935
10042
  toSection: dest_section_key,
10043
+ fromLane: item.laneKey,
10044
+ toLane: dest_lane_key,
9936
10045
  newIndex: new_index,
9937
10046
  revert: handle.revert
9938
10047
  };
9939
10048
  onMove?.(move_event);
9940
10049
  },
9941
- [find_item, columns, grouped, onMove, onReorder, make_revert_handle]
10050
+ [find_item, columns, lanes, grouped, onMove, onReorder, make_revert_handle]
9942
10051
  );
9943
10052
  const handle_drag_cancel = React27.useCallback(() => {
9944
10053
  set_active_id(null);
@@ -9949,13 +10058,56 @@ function HazoUiKanban({
9949
10058
  `(max-width: ${Math.max(0, mobileBreakpoint - 1)}px)`
9950
10059
  );
9951
10060
  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";
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
+ }
9953
10105
  return /* @__PURE__ */ jsxs(
9954
10106
  DndContext,
9955
10107
  {
9956
10108
  id: dnd_context_id,
9957
10109
  sensors,
9958
- collisionDetection: closestCorners,
10110
+ collisionDetection: collision_detection,
9959
10111
  onDragStart: handle_drag_start,
9960
10112
  onDragEnd: handle_drag_end,
9961
10113
  onDragCancel: handle_drag_cancel,
@@ -9964,43 +10116,33 @@ function HazoUiKanban({
9964
10116
  /* @__PURE__ */ jsxs("div", { className: cn("cls_hazo_kanban w-full", className), children: [
9965
10117
  /* @__PURE__ */ jsx("div", { className: cn("cls_hazo_kanban_mobile", mobile_classes), children: /* @__PURE__ */ jsxs(Tabs, { value: active_tab, onValueChange: set_active_tab, children: [
9966
10118
  /* @__PURE__ */ jsx(TabsList, { className: "grid w-full", style: { gridTemplateColumns: `repeat(${columns.length}, 1fr)` }, children: columns.map((col) => {
9967
- const count = (grouped.get(col.key) ?? []).length;
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;
9968
10123
  return /* @__PURE__ */ jsxs(TabsTrigger, { value: col.key, className: "flex flex-col gap-0.5", children: [
9969
10124
  /* @__PURE__ */ jsx("span", { className: "text-xs", children: col.title }),
9970
10125
  /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: count })
9971
10126
  ] }, col.key);
9972
10127
  }) }),
9973
- columns.map((col) => /* @__PURE__ */ jsx(TabsContent, { value: col.key, className: "mt-3", children: /* @__PURE__ */ jsx(
9974
- KanbanColumn,
9975
- {
9976
- column: col,
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))
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))
9985
10132
  ] }) }),
9986
10133
  /* @__PURE__ */ jsx(
9987
10134
  "div",
9988
10135
  {
9989
- className: cn("cls_hazo_kanban_desktop gap-3", desktop_classes),
9990
- style: { gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))` },
9991
- children: columns.map((col) => /* @__PURE__ */ jsx(
9992
- KanbanColumn,
9993
- {
9994
- column: col,
9995
- items: grouped.get(col.key) ?? [],
9996
- renderCard,
9997
- emptyColumn,
9998
- cardClassName,
9999
- showEdit: show_edit,
10000
- onEditRequest: handle_edit_request
10001
- },
10002
- col.key
10003
- ))
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"))
10004
10146
  }
10005
10147
  ),
10006
10148
  /* @__PURE__ */ jsx(DragOverlay, { children: active_item ? /* @__PURE__ */ jsx(