hazo_ui 6.5.0 → 6.8.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.d.cts CHANGED
@@ -565,6 +565,11 @@ interface CommandItem$1 {
565
565
  icon?: React$1.ReactNode;
566
566
  /** Optional group name for categorizing commands in the dropdown */
567
567
  group?: string;
568
+ /**
569
+ * Text inserted instead of a pill, for prefixes configured with
570
+ * `insert_as_text`. Defaults to `action`. Ignored by pill prefixes.
571
+ */
572
+ insert_text?: string;
568
573
  }
569
574
  /**
570
575
  * Configuration for a prefix trigger character
@@ -578,6 +583,14 @@ interface PrefixConfig {
578
583
  allow_free_text?: boolean;
579
584
  /** Custom color styling for this prefix's pills */
580
585
  color?: PrefixColor;
586
+ /**
587
+ * Insert the picked command as plain, editable text instead of a pill, and
588
+ * drop the trigger character with it. For `/`-style snippet menus, where the
589
+ * menu is a way to discover and type something rather than a reference to an
590
+ * entity — the inserted characters must survive as text (e.g. a formula's
591
+ * `SUM(`), and no `InsertedCommand` is reported for them.
592
+ */
593
+ insert_as_text?: boolean;
581
594
  }
582
595
  /**
583
596
  * Represents a command that has been inserted into the text
@@ -867,6 +880,8 @@ type PrefixConfigForParsing = {
867
880
  action_label: string;
868
881
  }[];
869
882
  color?: PrefixColor;
883
+ /** Text prefixes never produce pills, so they are skipped when parsing. */
884
+ insert_as_text?: boolean;
870
885
  };
871
886
  /**
872
887
  * Utility to parse plain text with commands into structured format
@@ -875,7 +890,7 @@ type PrefixConfigForParsing = {
875
890
  * @param prefixes - Prefix configurations to detect
876
891
  * @returns Parsed commands with positions
877
892
  */
878
- declare const parse_commands_from_text: (text: string, prefixes: PrefixConfigForParsing[]) => {
893
+ declare const parse_commands_from_text: (text: string, all_prefixes: PrefixConfigForParsing[]) => {
879
894
  action: string;
880
895
  action_label: string;
881
896
  prefix: string;
@@ -1902,6 +1917,17 @@ interface KanbanLane {
1902
1917
  title: string;
1903
1918
  /** Optional gate: returning false rejects a drop into this lane. */
1904
1919
  accepts?: (item: KanbanItem) => boolean;
1920
+ /**
1921
+ * Per-lane controls rendered in the lane heading, between the rule and the
1922
+ * count — an "add to this lane" button, an overflow menu, a lane filter.
1923
+ * Also rendered (right-aligned) on a `collapseWhenEmpty` lane's drop strip,
1924
+ * so a lane's actions do not disappear the moment it empties.
1925
+ *
1926
+ * The heading is a drop target but not a drag handle, so interactive nodes
1927
+ * here work without any `stopPropagation` dance — unlike controls rendered
1928
+ * inside a card by `renderCard`.
1929
+ */
1930
+ actions?: React$1.ReactNode;
1905
1931
  /**
1906
1932
  * When true and the lane currently holds no cards, it renders as a thin
1907
1933
  * full-width drop strip instead of a heading plus an empty column grid.
@@ -2031,6 +2057,22 @@ interface HazoUiKanbanProps<T extends KanbanItem = KanbanItem> {
2031
2057
  announcements?: Partial<KanbanAnnouncements>;
2032
2058
  /** Rendered when a column has zero items. Default: muted "—" placeholder. */
2033
2059
  emptyColumn?: React$1.ReactNode;
2060
+ /**
2061
+ * Rendered at the foot of every column body, below the cards (or below the
2062
+ * `emptyColumn` placeholder). Called once per rendered copy of a column, so
2063
+ * on a laned board it fires once per (lane, column) pair and `laneKey` says
2064
+ * which — that is what makes a per-lane "+ Add item" affordance possible
2065
+ * without the consumer having to reach into the board's internals.
2066
+ *
2067
+ * Return `null` for the columns that should not have one. The footer sits
2068
+ * inside the column's droppable but outside its `SortableContext`, so it
2069
+ * never participates in ordering and never becomes a drop target itself.
2070
+ */
2071
+ renderColumnFooter?: (ctx: {
2072
+ columnKey: string;
2073
+ /** `undefined` on a board without lanes. */
2074
+ laneKey?: string;
2075
+ }) => React$1.ReactNode;
2034
2076
  /** Class on the board root. */
2035
2077
  className?: string;
2036
2078
  /** Class on each card shell (the wrapper around renderCard output). */
@@ -2214,7 +2256,7 @@ declare function applyKanbanFilter<T extends KanbanItem>(items: T[], filter: Kan
2214
2256
  * event.revert() and the overlay entry is dropped.
2215
2257
  */
2216
2258
 
2217
- declare function HazoUiKanban<T extends KanbanItem = KanbanItem>({ columns, lanes, items, renderCard, onMove, onReorder, mobileBreakpoint, announcements, emptyColumn, className, cardClassName, itemLabel, editorFields, editorPriorities, editorTitle, renderCardEditor, hideEditorFooter, onCardSave, disableEdit, }: HazoUiKanbanProps<T>): React$1.JSX.Element;
2259
+ declare function HazoUiKanban<T extends KanbanItem = KanbanItem>({ columns, lanes, items, renderCard, onMove, onReorder, mobileBreakpoint, announcements, emptyColumn, renderColumnFooter, className, cardClassName, itemLabel, editorFields, editorPriorities, editorTitle, renderCardEditor, hideEditorFooter, onCardSave, disableEdit, }: HazoUiKanbanProps<T>): React$1.JSX.Element;
2218
2260
 
2219
2261
  declare const Table: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLTableElement> & React$1.RefAttributes<HTMLTableElement>>;
2220
2262
  declare const TableHeader: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLTableSectionElement> & React$1.RefAttributes<HTMLTableSectionElement>>;
package/dist/index.d.ts CHANGED
@@ -565,6 +565,11 @@ interface CommandItem$1 {
565
565
  icon?: React$1.ReactNode;
566
566
  /** Optional group name for categorizing commands in the dropdown */
567
567
  group?: string;
568
+ /**
569
+ * Text inserted instead of a pill, for prefixes configured with
570
+ * `insert_as_text`. Defaults to `action`. Ignored by pill prefixes.
571
+ */
572
+ insert_text?: string;
568
573
  }
569
574
  /**
570
575
  * Configuration for a prefix trigger character
@@ -578,6 +583,14 @@ interface PrefixConfig {
578
583
  allow_free_text?: boolean;
579
584
  /** Custom color styling for this prefix's pills */
580
585
  color?: PrefixColor;
586
+ /**
587
+ * Insert the picked command as plain, editable text instead of a pill, and
588
+ * drop the trigger character with it. For `/`-style snippet menus, where the
589
+ * menu is a way to discover and type something rather than a reference to an
590
+ * entity — the inserted characters must survive as text (e.g. a formula's
591
+ * `SUM(`), and no `InsertedCommand` is reported for them.
592
+ */
593
+ insert_as_text?: boolean;
581
594
  }
582
595
  /**
583
596
  * Represents a command that has been inserted into the text
@@ -867,6 +880,8 @@ type PrefixConfigForParsing = {
867
880
  action_label: string;
868
881
  }[];
869
882
  color?: PrefixColor;
883
+ /** Text prefixes never produce pills, so they are skipped when parsing. */
884
+ insert_as_text?: boolean;
870
885
  };
871
886
  /**
872
887
  * Utility to parse plain text with commands into structured format
@@ -875,7 +890,7 @@ type PrefixConfigForParsing = {
875
890
  * @param prefixes - Prefix configurations to detect
876
891
  * @returns Parsed commands with positions
877
892
  */
878
- declare const parse_commands_from_text: (text: string, prefixes: PrefixConfigForParsing[]) => {
893
+ declare const parse_commands_from_text: (text: string, all_prefixes: PrefixConfigForParsing[]) => {
879
894
  action: string;
880
895
  action_label: string;
881
896
  prefix: string;
@@ -1902,6 +1917,17 @@ interface KanbanLane {
1902
1917
  title: string;
1903
1918
  /** Optional gate: returning false rejects a drop into this lane. */
1904
1919
  accepts?: (item: KanbanItem) => boolean;
1920
+ /**
1921
+ * Per-lane controls rendered in the lane heading, between the rule and the
1922
+ * count — an "add to this lane" button, an overflow menu, a lane filter.
1923
+ * Also rendered (right-aligned) on a `collapseWhenEmpty` lane's drop strip,
1924
+ * so a lane's actions do not disappear the moment it empties.
1925
+ *
1926
+ * The heading is a drop target but not a drag handle, so interactive nodes
1927
+ * here work without any `stopPropagation` dance — unlike controls rendered
1928
+ * inside a card by `renderCard`.
1929
+ */
1930
+ actions?: React$1.ReactNode;
1905
1931
  /**
1906
1932
  * When true and the lane currently holds no cards, it renders as a thin
1907
1933
  * full-width drop strip instead of a heading plus an empty column grid.
@@ -2031,6 +2057,22 @@ interface HazoUiKanbanProps<T extends KanbanItem = KanbanItem> {
2031
2057
  announcements?: Partial<KanbanAnnouncements>;
2032
2058
  /** Rendered when a column has zero items. Default: muted "—" placeholder. */
2033
2059
  emptyColumn?: React$1.ReactNode;
2060
+ /**
2061
+ * Rendered at the foot of every column body, below the cards (or below the
2062
+ * `emptyColumn` placeholder). Called once per rendered copy of a column, so
2063
+ * on a laned board it fires once per (lane, column) pair and `laneKey` says
2064
+ * which — that is what makes a per-lane "+ Add item" affordance possible
2065
+ * without the consumer having to reach into the board's internals.
2066
+ *
2067
+ * Return `null` for the columns that should not have one. The footer sits
2068
+ * inside the column's droppable but outside its `SortableContext`, so it
2069
+ * never participates in ordering and never becomes a drop target itself.
2070
+ */
2071
+ renderColumnFooter?: (ctx: {
2072
+ columnKey: string;
2073
+ /** `undefined` on a board without lanes. */
2074
+ laneKey?: string;
2075
+ }) => React$1.ReactNode;
2034
2076
  /** Class on the board root. */
2035
2077
  className?: string;
2036
2078
  /** Class on each card shell (the wrapper around renderCard output). */
@@ -2214,7 +2256,7 @@ declare function applyKanbanFilter<T extends KanbanItem>(items: T[], filter: Kan
2214
2256
  * event.revert() and the overlay entry is dropped.
2215
2257
  */
2216
2258
 
2217
- declare function HazoUiKanban<T extends KanbanItem = KanbanItem>({ columns, lanes, items, renderCard, onMove, onReorder, mobileBreakpoint, announcements, emptyColumn, className, cardClassName, itemLabel, editorFields, editorPriorities, editorTitle, renderCardEditor, hideEditorFooter, onCardSave, disableEdit, }: HazoUiKanbanProps<T>): React$1.JSX.Element;
2259
+ declare function HazoUiKanban<T extends KanbanItem = KanbanItem>({ columns, lanes, items, renderCard, onMove, onReorder, mobileBreakpoint, announcements, emptyColumn, renderColumnFooter, className, cardClassName, itemLabel, editorFields, editorPriorities, editorTitle, renderCardEditor, hideEditorFooter, onCardSave, disableEdit, }: HazoUiKanbanProps<T>): React$1.JSX.Element;
2218
2260
 
2219
2261
  declare const Table: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLTableElement> & React$1.RefAttributes<HTMLTableElement>>;
2220
2262
  declare const TableHeader: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLTableSectionElement> & React$1.RefAttributes<HTMLTableSectionElement>>;
package/dist/index.js CHANGED
@@ -5585,6 +5585,9 @@ var insert_command_at_position = (editor, command, prefix, range, variant = "def
5585
5585
  color: color2
5586
5586
  }).run();
5587
5587
  };
5588
+ var insert_text_at_position = (editor, command, range) => {
5589
+ editor.chain().focus().deleteRange(range).insertContent(command.insert_text ?? command.action).run();
5590
+ };
5588
5591
  var get_variant_classes2 = (variant = "default") => {
5589
5592
  switch (variant) {
5590
5593
  case "outline":
@@ -5787,7 +5790,9 @@ var CommandPopover = ({
5787
5790
  CommandPopover.displayName = "CommandPopover";
5788
5791
 
5789
5792
  // src/components/hazo_ui_command/index.tsx
5790
- var parse_commands_from_text = (text, prefixes) => {
5793
+ var parse_commands_from_text = (text, all_prefixes) => {
5794
+ const prefixes = all_prefixes.filter((p) => !p.insert_as_text);
5795
+ if (prefixes.length === 0) return [];
5791
5796
  const result = [];
5792
5797
  const action_to_label = /* @__PURE__ */ new Map();
5793
5798
  for (const prefix_config of prefixes) {
@@ -6097,13 +6102,18 @@ var HazoUiTextbox = ({
6097
6102
  }
6098
6103
  }, [suggestion_state, editor]);
6099
6104
  React27.useEffect(() => {
6100
- if (is_controlled && editor && !editor.isFocused) {
6101
- const current_text = editor.getText();
6102
- if (value !== current_text) {
6103
- const content = text_to_tiptap_content(value || "", prefixes, pill_variant);
6104
- editor.commands.setContent(content, { emitUpdate: false });
6105
- }
6106
- }
6105
+ if (!is_controlled || !editor || editor.isFocused) return;
6106
+ if (value === editor.getText()) return;
6107
+ let cancelled = false;
6108
+ queueMicrotask(() => {
6109
+ if (cancelled || editor.isDestroyed || editor.isFocused) return;
6110
+ if (value === editor.getText()) return;
6111
+ const content = text_to_tiptap_content(value || "", prefixes, pill_variant);
6112
+ editor.commands.setContent(content, { emitUpdate: false });
6113
+ });
6114
+ return () => {
6115
+ cancelled = true;
6116
+ };
6107
6117
  }, [value, editor, is_controlled, prefixes, pill_variant]);
6108
6118
  React27.useEffect(() => {
6109
6119
  if (editor) {
@@ -6115,6 +6125,11 @@ var HazoUiTextbox = ({
6115
6125
  if (!editor || !suggestion_state) return;
6116
6126
  const prefix_config = prefixes.find((p) => p.char === suggestion_state.prefix);
6117
6127
  const prefix_color = prefix_config?.color;
6128
+ if (prefix_config?.insert_as_text) {
6129
+ insert_text_at_position(editor, command, suggestion_state.range);
6130
+ set_suggestion_state(null);
6131
+ return;
6132
+ }
6118
6133
  insert_command_at_position(
6119
6134
  editor,
6120
6135
  command,
@@ -6665,6 +6680,11 @@ var HazoUiTextarea = ({
6665
6680
  if (!editor || !suggestion_state) return;
6666
6681
  const prefix_config = prefixes.find((p) => p.char === suggestion_state.prefix);
6667
6682
  const prefix_color = prefix_config?.color;
6683
+ if (prefix_config?.insert_as_text) {
6684
+ insert_text_at_position(editor, command, suggestion_state.range);
6685
+ set_suggestion_state(null);
6686
+ return;
6687
+ }
6668
6688
  insert_command_at_position(
6669
6689
  editor,
6670
6690
  command,
@@ -9038,6 +9058,12 @@ function KanbanCard({
9038
9058
  backgroundColor: "hsl(var(--hazo-kanban-card-bg))",
9039
9059
  border: `1px solid hsl(var(--hazo-kanban-card-border))`,
9040
9060
  borderLeft: priority_var ? `4px solid hsl(var(${priority_var}))` : `1px solid hsl(var(--hazo-kanban-card-border))`,
9061
+ // Opt-in lift. A card whose background equals the column's (the case for
9062
+ // every palette where --card and --background resolve to the same value)
9063
+ // is separated by nothing but a 1px border, which reads as flat at a
9064
+ // glance. The fallback is `none`, so a consumer that never sets the token
9065
+ // renders exactly as before.
9066
+ boxShadow: "var(--hazo-kanban-card-shadow, none)",
9041
9067
  opacity: isDragging && !dragging ? 0.4 : 1,
9042
9068
  cursor: "grab"
9043
9069
  };
@@ -9046,6 +9072,9 @@ function KanbanCard({
9046
9072
  {
9047
9073
  ref: setNodeRef,
9048
9074
  style,
9075
+ "data-column-key": item.columnKey,
9076
+ "data-lane-key": item.laneKey,
9077
+ "data-section-key": item.sectionKey,
9049
9078
  className: cn(
9050
9079
  "cls_hazo_kanban_card group relative rounded-md p-3 mb-2 select-none",
9051
9080
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
@@ -9117,6 +9146,7 @@ function KanbanColumn({
9117
9146
  items,
9118
9147
  renderCard,
9119
9148
  emptyColumn,
9149
+ footer,
9120
9150
  cardClassName,
9121
9151
  showEdit,
9122
9152
  onEditRequest,
@@ -9162,6 +9192,8 @@ function KanbanColumn({
9162
9192
  "div",
9163
9193
  {
9164
9194
  ref: setNodeRef,
9195
+ "data-column-key": column.key,
9196
+ "data-lane-key": laneKey,
9165
9197
  className: cn(
9166
9198
  "cls_hazo_kanban_column flex flex-col rounded-md p-2",
9167
9199
  isOver && "cls_hazo_kanban_column_over bg-accent/30 ring-2 ring-ring/40"
@@ -9183,34 +9215,43 @@ function KanbanColumn({
9183
9215
  {
9184
9216
  items: ordered.map((i) => i.id),
9185
9217
  strategy: verticalListSortingStrategy,
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
- ] }) })
9218
+ children: /* @__PURE__ */ jsx(
9219
+ "div",
9220
+ {
9221
+ "data-column-key": column.key,
9222
+ "data-lane-key": laneKey,
9223
+ className: "cls_hazo_kanban_column_body flex-1 min-h-[40px]",
9224
+ 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: [
9225
+ expanded_sections.map((section) => /* @__PURE__ */ jsx(
9226
+ KanbanSectionBand,
9227
+ {
9228
+ columnKey: column.key,
9229
+ laneKey,
9230
+ treeKey,
9231
+ section,
9232
+ items: bySection.get(section.key) ?? [],
9233
+ emptyColumn,
9234
+ renderCards: render_cards
9235
+ },
9236
+ section.key
9237
+ )),
9238
+ unmatched.length > 0 && /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_section cls_hazo_kanban_section_unmatched", children: render_cards(unmatched) }),
9239
+ 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(
9240
+ KanbanSectionStrip,
9241
+ {
9242
+ columnKey: column.key,
9243
+ laneKey,
9244
+ treeKey,
9245
+ section
9246
+ },
9247
+ section.key
9248
+ )) })
9249
+ ] })
9250
+ }
9251
+ )
9212
9252
  }
9213
- )
9253
+ ),
9254
+ footer ? /* @__PURE__ */ jsx("div", { className: "cls_hazo_kanban_column_footer mt-1", children: footer }) : null
9214
9255
  ]
9215
9256
  }
9216
9257
  );
@@ -9232,6 +9273,8 @@ function KanbanColumnHead({
9232
9273
  "div",
9233
9274
  {
9234
9275
  ref: droppable ? setNodeRef : void 0,
9276
+ "data-column-key": columnKey,
9277
+ "data-lane-key": laneKey,
9235
9278
  className: cn(
9236
9279
  "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
9280
  droppable && "py-1",
@@ -9321,6 +9364,7 @@ function KanbanLaneHead({
9321
9364
  children: [
9322
9365
  /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_title text-xs font-semibold uppercase tracking-wider text-foreground", children: lane.title }),
9323
9366
  /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_rule h-px flex-1 bg-border" }),
9367
+ lane.actions ? /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_actions flex items-center gap-1", children: lane.actions }) : null,
9324
9368
  /* @__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
9369
  ]
9326
9370
  }
@@ -9334,15 +9378,18 @@ function KanbanLaneStrip({
9334
9378
  id: lane_droppable_id(lane.key, treeKey),
9335
9379
  data: { laneKey: lane.key, isLane: true }
9336
9380
  });
9337
- return /* @__PURE__ */ jsx(
9381
+ return /* @__PURE__ */ jsxs(
9338
9382
  "div",
9339
9383
  {
9340
9384
  ref: setNodeRef,
9341
9385
  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",
9386
+ "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",
9343
9387
  isOver && "cls_hazo_kanban_lane_strip_over border-solid bg-accent/30 text-foreground ring-1 ring-ring/30"
9344
9388
  ),
9345
- children: lane.title
9389
+ children: [
9390
+ /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_title", children: lane.title }),
9391
+ lane.actions ? /* @__PURE__ */ jsx("span", { className: "cls_hazo_kanban_lane_actions ml-auto flex items-center gap-1", children: lane.actions }) : null
9392
+ ]
9346
9393
  }
9347
9394
  );
9348
9395
  }
@@ -9815,6 +9862,7 @@ function HazoUiKanban({
9815
9862
  mobileBreakpoint = 640,
9816
9863
  announcements,
9817
9864
  emptyColumn = "\u2014",
9865
+ renderColumnFooter,
9818
9866
  className,
9819
9867
  cardClassName,
9820
9868
  itemLabel,
@@ -10068,7 +10116,7 @@ function HazoUiKanban({
10068
10116
  total += (grouped.get(bucket_key(lane_key, col.key)) ?? []).length;
10069
10117
  return total;
10070
10118
  }
10071
- function render_column(col, tree_key, lane_key) {
10119
+ function render_column(col, tree_key, lane_key, with_footer = true) {
10072
10120
  return /* @__PURE__ */ jsx(
10073
10121
  KanbanColumn,
10074
10122
  {
@@ -10078,6 +10126,7 @@ function HazoUiKanban({
10078
10126
  items: grouped.get(bucket_key(lane_key, col.key)) ?? [],
10079
10127
  renderCard,
10080
10128
  emptyColumn,
10129
+ footer: with_footer ? renderColumnFooter?.({ columnKey: col.key, laneKey: lane_key }) ?? null : null,
10081
10130
  cardClassName,
10082
10131
  showEdit: show_edit,
10083
10132
  onEditRequest: handle_edit_request
@@ -10098,8 +10147,8 @@ function HazoUiKanban({
10098
10147
  function render_unmatched_lane(tree_key, only_column) {
10099
10148
  const count = only_column ? (grouped.get(bucket_key(UNMATCHED_LANE_KEY, only_column.key)) ?? []).length : lane_total(UNMATCHED_LANE_KEY);
10100
10149
  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)
10150
+ 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(
10151
+ (col) => render_column(col, tree_key, UNMATCHED_LANE_KEY, false)
10103
10152
  ) }) });
10104
10153
  }
10105
10154
  return /* @__PURE__ */ jsxs(