@ahrowe/ui 0.45.0 → 0.46.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.
Files changed (26) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/cjs-types/common/kanbanBoard/KanbanBoard.d.ts +1 -1
  3. package/dist/cjs-types/common/kanbanBoard/KanbanColumn.d.ts +21 -12
  4. package/dist/cjs-types/common/kanbanBoard/KanbanItem.d.ts +1 -1
  5. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.types.d.ts +23 -17
  6. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.utils.d.ts +47 -1
  7. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs +3 -2
  8. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs.map +1 -1
  9. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs +1 -1
  10. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs.map +1 -1
  11. package/dist/esm/common/kanbanBoard/KanbanItem.mjs +1 -1
  12. package/dist/esm/common/kanbanBoard/KanbanItem.mjs.map +1 -1
  13. package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs +1 -1
  14. package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs.map +1 -1
  15. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs +1 -1
  16. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs.map +1 -1
  17. package/dist/index.cjs +3 -2
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/style.css +1 -1
  20. package/dist/types/common/kanbanBoard/KanbanBoard.d.ts +1 -1
  21. package/dist/types/common/kanbanBoard/KanbanColumn.d.ts +21 -12
  22. package/dist/types/common/kanbanBoard/KanbanItem.d.ts +1 -1
  23. package/dist/types/common/kanbanBoard/kanbanBoard.types.d.ts +23 -17
  24. package/dist/types/common/kanbanBoard/kanbanBoard.utils.d.ts +47 -1
  25. package/docs/KanbanBoard.md +36 -18
  26. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @ahrowe/ui
2
2
 
3
+ ## 0.46.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c3be3c5: Arrow keys move focus between `KanbanBoard` cards, and between column titles with `reorderableColumns`, while nothing is picked up, and both draw the library's focus ring
8
+ - c3be3c5: `KanbanBoard` no longer collapses empty columns by default; pass `collapseEmptyColumns` to keep shrinking them to a narrow strip
9
+ - c3be3c5: With `dragHandle`, a `KanbanBoard` card's `data-drag-handle` element is also its keyboard handle, focusable and named with `getItemLabel` unless it has a name, and the card itself is no longer a button wrapped around its own controls
10
+ - c3be3c5: A `KanbanBoard` given a height, such as `style={{ height: '100%' }}` in a parent with one, fills it and scrolls each column on its own, with `onLoadMore` working there as well as with `columnMaxHeight`
11
+
12
+ ### Patch Changes
13
+
14
+ - c3be3c5: Space and Enter pressed in a control inside a `KanbanBoard` card, such as a button or an input, reach that control instead of picking the card up
15
+ - c3be3c5: A collapsed `KanbanBoard` column shows its whole title, with the count and header actions wrapping below it instead of cutting the title to a single letter
16
+ - c3be3c5: A `KanbanBoard` column being dragged shows its whole header, count and actions included, instead of a shorter bar with only the title
17
+ - c3be3c5: `KanbanBoard`'s `dragHandle` restricts mouse and touch drags to the handle again; a press anywhere on the card started one
18
+ - ef88ada: Fixed a `KanbanBoard` card staying behind when a column auto-scrolls under a pointer that holds still, and then dropping there instead of where the board showed it
19
+ - c3be3c5: `KanbanBoard` columns stretch to the height of the tallest one, so a card dropped in the empty space below a column's cards lands in that column instead of the one beside it
20
+ - c3be3c5: With `reorderableColumns`, a `KanbanBoard` header's own buttons answer Enter and Space instead of picking the column up: the column's title is now its keyboard handle, so the handle no longer wraps those buttons
21
+ - ef88ada: Fixed `KanbanBoard` losing the cards `onLoadMore` loaded during a drag, and asking for more pages over and over until the drop
22
+ - c3be3c5: Dragging a `KanbanBoard` card near the bottom of the window scrolls the page only toward a part of the board that is out of view, instead of on past the board until it was off screen
23
+ - c3be3c5: A card dragged on a `KanbanBoard` lands in the column under the pointer, including a collapsed column narrower than the card
24
+ - c3be3c5: `KanbanBoard` with `collapseEmptyColumns` keeps every column's width still during a drag, instead of widening each collapsed column the moment a card is picked up; a column the drag empties or fills changes width after the drop
25
+
3
26
  ## 0.45.0
4
27
 
5
28
  ### Minor Changes
@@ -1,3 +1,3 @@
1
1
  import { KanbanBoardProps } from './kanbanBoard.types.js';
2
- declare function KanbanBoard<T = unknown>({ columns, items, renderItem, onChange, dragHandle, getItemLabel, getItemDisabled, renderEmptyColumn, renderColumnActions, reorderableColumns, collapseEmptyColumns, columnMaxHeight, onLoadMore, loadMoreThreshold, className, style, classNames, styles: slotStyles, ...rest }: KanbanBoardProps<T>): import("react").JSX.Element;
2
+ declare function KanbanBoard<T = unknown>({ columns, items, renderItem, onChange, dragHandle, getItemLabel, getItemDisabled, renderEmptyColumn, renderColumnActions, reorderableColumns, collapseEmptyColumns, columnMaxHeight, onLoadMore, loadMoreThreshold, onKeyDown, className, style, classNames, styles: slotStyles, ...rest }: KanbanBoardProps<T>): import("react").JSX.Element;
3
3
  export default KanbanBoard;
@@ -1,25 +1,21 @@
1
- import { ReactNode } from 'react';
2
- import { KanbanColumnProps } from './kanbanBoard.types.js';
1
+ import { HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import { DataProps, SlotClassNames, SlotStyles } from '../types/slots.types.js';
3
+ import { KanbanColumnProps, KanbanColumnSlots } from './kanbanBoard.types.js';
3
4
  interface KanbanColumnInternalProps<T> extends KanbanColumnProps {
4
5
  itemIds: string[];
5
6
  items: Record<string, T>;
6
7
  renderItem: (item: T, id: string) => ReactNode;
7
8
  dragHandle?: boolean;
8
- /**
9
- * Keep the column at its normal flex width even when `itemIds` is empty. Used while a drag
10
- * is in progress: the empty-column collapse is driven by transient shadow state during a
11
- * drag, and letting the column shrink mid-drag shifts every column's layout underneath the
12
- * pointer, which can flip the collision target back and forth forever.
13
- */
14
- preserveSizeWhileEmpty?: boolean;
15
- /** Shrink to a narrow strip when empty — see `KanbanBoardProps.collapseEmptyColumns`. Defaults to `true`. */
16
- collapseEmptyColumns?: boolean;
9
+ /** Shrink to a narrow strip. The board decides when, see `KanbanBoardProps.collapseEmptyColumns`. */
10
+ collapsed?: boolean;
17
11
  /** Work-in-progress limit — see `KanbanColumnDef.maxItems`. Display-only. */
18
12
  maxItems?: number;
19
13
  /** Freezes the column — see `KanbanColumnDef.disabled`. */
20
14
  disabled?: boolean;
21
15
  /** Returns whether a specific card can't be picked up — see `KanbanBoardProps.getItemDisabled`. */
22
16
  getItemDisabled?: (item: T, id: string) => boolean;
17
+ /** Names a card's drag handle — see `KanbanBoardProps.getItemLabel`. */
18
+ getItemLabel?: (item: T, id: string) => string;
23
19
  /** Custom content shown when the column has no cards — see `KanbanBoardProps.renderEmptyColumn`. */
24
20
  emptyPlaceholder?: ReactNode;
25
21
  /** Custom header actions — see `KanbanBoardProps.renderColumnActions`. */
@@ -41,5 +37,18 @@ interface KanbanColumnInternalProps<T> extends KanbanColumnProps {
41
37
  /** Scroll distance from the bottom that triggers `onLoadMore` — see `KanbanBoardProps.loadMoreThreshold`. */
42
38
  loadMoreThreshold?: number;
43
39
  }
44
- declare function KanbanColumn<T>({ id, title, itemIds, items, renderItem, dragHandle, preserveSizeWhileEmpty, collapseEmptyColumns, maxItems, disabled, getItemDisabled, emptyPlaceholder, actions, reorderable, activeIsColumn, columnMaxHeight, hasMore, onLoadMore, loadMoreThreshold, className, style, classNames, styles: slotStyles, ...rest }: KanbanColumnInternalProps<T>): import("react").JSX.Element;
40
+ interface ColumnHeaderContentProps {
41
+ title: string;
42
+ count: number;
43
+ maxItems?: number;
44
+ actions?: ReactNode;
45
+ /** Makes the title the column's keyboard drag handle. */
46
+ titleProps?: HTMLAttributes<HTMLSpanElement> & DataProps & {
47
+ ref?: Ref<HTMLSpanElement>;
48
+ };
49
+ classNames?: SlotClassNames<KanbanColumnSlots>;
50
+ styles?: SlotStyles<KanbanColumnSlots>;
51
+ }
52
+ export declare function ColumnHeaderContent({ title, count, maxItems, actions, titleProps, classNames, styles: slotStyles, }: ColumnHeaderContentProps): import("react").JSX.Element;
53
+ declare function KanbanColumn<T>({ id, title, itemIds, items, renderItem, dragHandle, collapsed, maxItems, disabled, getItemDisabled, getItemLabel, emptyPlaceholder, actions, reorderable, activeIsColumn, columnMaxHeight, hasMore, onLoadMore, loadMoreThreshold, className, style, classNames, styles: slotStyles, ...rest }: KanbanColumnInternalProps<T>): import("react").JSX.Element;
45
54
  export default KanbanColumn;
@@ -1,3 +1,3 @@
1
1
  import { KanbanItemProps } from './kanbanBoard.types.js';
2
- declare function KanbanItem({ id, dragHandle, disabled, preventAsDropTarget, children }: KanbanItemProps): import("react").JSX.Element;
2
+ declare function KanbanItem({ id, label, dragHandle, disabled, preventAsDropTarget, children }: KanbanItemProps): import("react").JSX.Element;
3
3
  export default KanbanItem;
@@ -38,14 +38,17 @@ export interface KanbanBoardProps<T = unknown> extends Omit<HtmlProps, 'onChange
38
38
  */
39
39
  onChange: (columns: KanbanColumnDef[]) => void;
40
40
  /**
41
- * Restrict drag initiation to elements marked `data-drag-handle` within a card,
42
- * instead of the whole card. Use when `renderItem` includes interactive content
43
- * (buttons, inputs) that would otherwise have its clicks swallowed by the drag listener.
41
+ * Drag a card only by the element marked `data-drag-handle` inside it, with the mouse, touch
42
+ * and the keyboard, instead of by the whole card. The handle is made focusable and named with
43
+ * `getItemLabel` unless it has a name, and the card stops being a button. Use when `renderItem`
44
+ * includes controls (buttons, inputs): inside a card that is itself the button, a screen reader
45
+ * reads them as plain text.
44
46
  */
45
47
  dragHandle?: boolean;
46
48
  /**
47
49
  * Produce an accessible label for a card, announced to screen-reader users while dragging
48
- * (e.g. "Picked up <label>."). Defaults to the card's id when omitted.
50
+ * (e.g. "Picked up <label>."), and naming a `dragHandle` handle that has no name of its own.
51
+ * Defaults to the card's id when omitted.
49
52
  */
50
53
  getItemLabel?: (item: T, id: string) => string;
51
54
  /**
@@ -70,27 +73,28 @@ export interface KanbanBoardProps<T = unknown> extends Omit<HtmlProps, 'onChange
70
73
  */
71
74
  reorderableColumns?: boolean;
72
75
  /**
73
- * Shrink a column to a narrow strip once it has no cards, instead of keeping it at the same
74
- * width as every other column. Defaults to `true`. Set `false` to keep every column the same
75
- * width regardless of card count. The collapsed width itself is set via the
76
- * `--kanban-empty-column-width` CSS variable (falls back to `140px`) — override it theme-wide
77
- * via `ThemeProvider`'s `variables`, or per board via `style`.
76
+ * Shrink a column to a narrow strip while it has no cards. Defaults to `false`. Widths hold
77
+ * still during a drag: a column the drag empties or fills changes width after the drop. The
78
+ * collapsed width is set via the `--kanban-empty-column-width` CSS variable (falls back to
79
+ * `140px`): override it theme-wide via `ThemeProvider`'s `variables`, or per board via `style`.
78
80
  */
79
81
  collapseEmptyColumns?: boolean;
80
82
  /**
81
- * Bounds each column's height (any CSS length, e.g. `'70vh'`, `'600px'`) and makes its card
82
- * list scroll independently once content overflows, instead of growing the whole page. Leave
83
- * unset for the default unbounded height. Required for `onLoadMore` to ever trigger, since an
84
- * unbounded column never scrolls.
83
+ * Caps each column's card list at a length (any CSS length, e.g. `'70vh'`, `'600px'`), so a
84
+ * long column scrolls on its own instead of growing the page. To fill the space your layout
85
+ * gives the board instead, give the board a height (`style={{ height: '100%' }}` in a parent
86
+ * with one): its columns then scroll the same way.
85
87
  */
86
88
  columnMaxHeight?: string;
87
89
  /**
88
90
  * Called with a column's `id` when that column has `hasMore` set and its card list is scrolled
89
- * within `loadMoreThreshold` of the bottom — fetch and append the next page of items for it.
91
+ * within `loadMoreThreshold` of the bottom: fetch and append the next page of items for it.
90
92
  * `KanbanColumn` tracks its own in-flight state per column (shown as a spinner at the bottom of
91
- * the list), so overlapping calls for the same column are never made concurrently. Also
92
- * retried automatically if a loaded batch doesn't fill the column's visible height, since a
93
- * column shorter than its own viewport never generates a scroll event to trigger a next page.
93
+ * the list), so overlapping calls for the same column are never made concurrently. Also called
94
+ * while the column's cards leave empty space below them, since a column that doesn't overflow
95
+ * can't be scrolled. Paging all the way needs a column that scrolls: `columnMaxHeight`, or a
96
+ * board with a height. On a board that grows with its cards, a short column only fills up to
97
+ * the tallest one.
94
98
  */
95
99
  onLoadMore?: (columnId: string) => void | Promise<void>;
96
100
  /**
@@ -115,6 +119,8 @@ export interface KanbanColumnProps extends HtmlProps {
115
119
  }
116
120
  export interface KanbanItemProps {
117
121
  id: string;
122
+ /** Names the card's `[data-drag-handle]` when it has no `aria-label` of its own. */
123
+ label?: string;
118
124
  dragHandle?: boolean;
119
125
  /** Whether this card can't be picked up (column frozen, or the card itself is pinned). */
120
126
  disabled?: boolean;
@@ -20,8 +20,28 @@ export declare function moveColumn(columns: KanbanColumnDef[], activeColumnId: s
20
20
  * which reads as needing to "wiggle it around" before the right drop target lights up. This
21
21
  * restricts the candidates to only the same kind as whatever is being dragged: a column drag only
22
22
  * considers other columns, a card drag only considers cards and card lists.
23
+ *
24
+ * A card drag also lets the pointer pick the column, and `closestCorners` only the position within
25
+ * it. Corners alone compare the dragged card's whole rect, so a wide card over a collapsed column
26
+ * had its corners nearer the neighbours' cards, and landed beside the column under the pointer.
27
+ * Without a pointer (the keyboard) or between columns, every column is a candidate as before.
23
28
  */
24
29
  export declare const kanbanCollisionDetection: CollisionDetection;
30
+ /**
31
+ * Whether the auto-scroll may move `scroller`, an ancestor of the board such as the page, while
32
+ * something is dragged: only toward a part of the board that is out of view. Nothing beyond the
33
+ * board takes a drop, and a page left free to scroll carried the whole board off screen.
34
+ */
35
+ export declare function scrollsTowardBoard(scroller: {
36
+ top: number;
37
+ bottom: number;
38
+ }, board: {
39
+ top: number;
40
+ bottom: number;
41
+ }, dragged: {
42
+ top: number;
43
+ height: number;
44
+ }): boolean;
25
45
  /** Extracts the column id from a column droppable's `column-<id>` identifier, or `null` for a card id. */
26
46
  export declare function resolveColumnDropId(overId: string): string | null;
27
47
  export interface DragGeometry {
@@ -40,9 +60,35 @@ export interface DragGeometry {
40
60
  * position (see the two branches below for what each one decides).
41
61
  */
42
62
  export declare function moveItem(columns: KanbanColumnDef[], activeItemId: string, overId: string, geometry: DragGeometry): KanbanColumnDef[];
63
+ /**
64
+ * Where a drag has put the dragged card or column so far. The board keeps this rather than a copy
65
+ * of `columns`, so a change the consumer makes mid-drag (a page appended by `onLoadMore`) still
66
+ * shows, and is still there in what `onChange` receives on drop.
67
+ */
68
+ export interface DragPlacement {
69
+ /** The dragged card's or column's id. */
70
+ id: string;
71
+ /** The column the card sits in, or `null` while a whole column is dragged. */
72
+ columnId: string | null;
73
+ index: number;
74
+ }
75
+ /** The position `id` holds in `columns`, as a placement to lay over a later `columns`. */
76
+ export declare function findPlacement(columns: KanbanColumnDef[], id: string, isColumn: boolean): DragPlacement | null;
77
+ /**
78
+ * Moves the dragged card or column to its placement in `columns`. Returns `columns` itself when
79
+ * there is no placement, or when the card, the column, or its destination is no longer there.
80
+ */
81
+ export declare function applyPlacement(columns: KanbanColumnDef[], placement: DragPlacement | null): KanbanColumnDef[];
82
+ /**
83
+ * Where an arrow key moves focus from a focused card or column handle while nothing is picked up.
84
+ * It mirrors what the same keys do to a picked-up card: Up/Down within the column, Left/Right to
85
+ * the nearest card in the next column with anything to focus, or from a handle to the next handle.
86
+ * Returns `null` when `from` is not a card or handle, or there is nowhere to go.
87
+ */
88
+ export declare function findArrowFocusTarget(board: HTMLElement, from: HTMLElement, key: string): HTMLElement | null;
43
89
  /**
44
90
  * Builds screen-reader drag announcements against the columns layout as currently understood
45
- * (the live shadow layout while a drag is in progress, or the settled `columns` prop otherwise).
91
+ * (the live layout while a drag is in progress, or the settled `columns` prop otherwise).
46
92
  */
47
93
  export declare function buildAnnouncements<T>(columns: KanbanColumnDef[], items: Record<string, T>, getItemLabel: (item: T, id: string) => string): Announcements;
48
94
  /**
@@ -1,7 +1,8 @@
1
- "use client";import e from"./kanbanBoard.module.mjs";import t from"./KanbanColumn.mjs";import{buildAnnouncements as n,columnsEqual as r,isColumnDragData as i,kanbanCollisionDetection as a,kanbanKeyboardCoordinateGetter as o,moveColumn as s,moveItem as c}from"./kanbanBoard.utils.mjs";import{useMemo as l,useRef as u,useState as d}from"react";import f from"classnames";import{jsx as p,jsxs as m}from"react/jsx-runtime";import{DndContext as h,DragOverlay as g,KeyboardSensor as _,MouseSensor as v,TouchSensor as y,useSensor as b,useSensors as x}from"@dnd-kit/core";import{SortableContext as S,horizontalListSortingStrategy as C}from"@dnd-kit/sortable";var ee=(e,t)=>t,te={activationConstraint:{distance:8}},ne={activationConstraint:{delay:250,tolerance:5}},re={coordinateGetter:o},w={draggable:`
1
+ "use client";import e from"./kanbanBoard.module.mjs";import t,{ColumnHeaderContent as n}from"./KanbanColumn.mjs";import{applyPlacement as r,buildAnnouncements as i,columnsEqual as a,findArrowFocusTarget as o,findPlacement as s,isColumnDragData as c,kanbanCollisionDetection as ee,kanbanKeyboardCoordinateGetter as l,moveColumn as te,moveItem as ne,scrollsTowardBoard as re}from"./kanbanBoard.utils.mjs";import{useCallback as ie,useEffect as ae,useMemo as u,useRef as d,useState as f}from"react";import p from"classnames";import{jsx as m,jsxs as oe}from"react/jsx-runtime";import{DndContext as h,DragOverlay as g,KeyboardSensor as _,MouseSensor as v,TouchSensor as se,useSensor as y,useSensors as ce}from"@dnd-kit/core";import{SortableContext as le,horizontalListSortingStrategy as ue}from"@dnd-kit/sortable";var de=(e,t)=>t,fe={activationConstraint:{distance:8}},pe={activationConstraint:{delay:250,tolerance:5}},me={coordinateGetter:l},he={draggable:`
2
2
  To pick up a card or column, press space or enter.
3
+ Use the arrow keys to move between cards and columns.
3
4
  While dragging, use the arrow keys to move it — for a card, between positions and columns;
4
5
  for a column, left/right to reorder it.
5
6
  Press space or enter again to drop it, or press escape to cancel.
6
- `};function T({columns:o,items:T,renderItem:E,onChange:D,dragHandle:O,getItemLabel:k=ee,getItemDisabled:A,renderEmptyColumn:j,renderColumnActions:M,reorderableColumns:N,collapseEmptyColumns:P,columnMaxHeight:F,onLoadMore:I,loadMoreThreshold:L,className:R,style:z,classNames:ie,styles:B,...V}){let[H,U]=d(null),[W,G]=d(!1),[K,q]=d(null),J=u(null),Y=x(b(v,te),b(y,ne),b(_,re)),X=K??o,ae=l(()=>X.map(e=>e.id),[X]),Z=l(()=>n(X,T,k),[X,T,k]),oe=l(()=>({announcements:Z,screenReaderInstructions:w}),[Z]);function se({active:e}){U(String(e.id)),G(i(e.data.current)),q(o),J.current=null}function Q({active:e,over:t}){if(!t)return;if(i(e.data.current)){let n=String(e.id),r=String(t.id);q(e=>{let t=e??o,i=s(t,n,r);return i===t?e:i});return}let n=String(e.id),r=String(t.id),a=e.rect.current.translated??e.rect.current.initial,l=a?`${a.top}:${a.left}`:null;(l===null||l!==J.current)&&(J.current=l,q(e=>{let i=e??o,s=c(i,n,r,{activeRect:a,overRect:t.rect});return s===i?e:s}))}function ce({over:e}){if(U(null),G(!1),!e||!K){q(null);return}r(K,o)||D(K),q(null)}function le(){U(null),G(!1),q(null)}let $=H&&W?X.find(e=>e.id===H):void 0;return m(h,{sensors:Y,collisionDetection:a,onDragStart:se,onDragOver:Q,onDragEnd:ce,onDragCancel:le,accessibility:oe,children:[p(S,{id:`kanban-columns`,items:ae,strategy:C,children:p(`div`,{...V,className:f(e.board,R),style:z,children:X.map(e=>p(t,{id:e.id,title:e.title,itemIds:e.itemIds,maxItems:e.maxItems,disabled:e.disabled,getItemDisabled:A,emptyPlaceholder:j?.(e),actions:M?.(e),reorderable:N,activeIsColumn:H!==null&&W,collapseEmptyColumns:P,columnMaxHeight:F,hasMore:e.hasMore,onLoadMore:I?()=>I(e.id):void 0,loadMoreThreshold:L,items:T,renderItem:E,dragHandle:O,preserveSizeWhileEmpty:H!==null},e.id))})}),p(g,{children:$?p(`div`,{className:f(e.column,e.columnDragOverlay),children:p(`div`,{className:e.columnHeader,children:p(`span`,{className:e.columnHeaderTitle,children:$.title})})}):H&&!W&&T[H]!==void 0?p(`div`,{className:f(e.dragOverlay,ie?.dragOverlay),style:B?.dragOverlay,children:E(T[H],H)}):null})]})}export{T as default};
7
+ `};function b({columns:l,items:b,renderItem:x,onChange:ge,dragHandle:S,getItemLabel:C=de,getItemDisabled:w,renderEmptyColumn:T,renderColumnActions:E,reorderableColumns:D,collapseEmptyColumns:O=!1,columnMaxHeight:k,onLoadMore:A,loadMoreThreshold:j,onKeyDown:M,className:N,style:P,classNames:F,styles:I,...L}){let[R,z]=f(null),[B,V]=f(!1),[H,U]=f(null),W=d(null),G=d(null),K=d(null),q=ie(e=>{let t=G.current,n=K.current?.current.translated;if(!t||!n||t.contains(e))return!0;let r=e===document.scrollingElement?{top:0,bottom:window.innerHeight}:e.getBoundingClientRect();return re(r,t.getBoundingClientRect(),n)},[]),[,_e]=f(0),J=R!==null;ae(()=>{if(!J)return;let e=({target:e})=>{let t=G.current;if(!t||!(e instanceof Node)||!(e.contains(t)||t.contains(e)))return;W.current=null;let n=e===document?document.scrollingElement:e;n instanceof Element&&!q(n)&&_e(e=>e+1)};return window.addEventListener(`scroll`,e,{capture:!0,passive:!0}),()=>window.removeEventListener(`scroll`,e,{capture:!0})},[J,q]);let Y=ce(y(v,fe),y(se,pe),y(_,me)),X=u(()=>r(l,H),[l,H]),ve=u(()=>X.map(e=>e.id),[X]),ye=u(()=>new Set(O?l.filter(e=>e.itemIds.length===0).map(e=>e.id):[]),[l,O]),Z=u(()=>i(X,b,C),[X,b,C]),be=u(()=>({announcements:Z,screenReaderInstructions:he}),[Z]);function xe(e){if(M?.(e),e.defaultPrevented||R!==null||!G.current||!(e.target instanceof HTMLElement)||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)return;let t=o(G.current,e.target,e.key);t&&(e.preventDefault(),t.focus())}function Se({active:e}){z(String(e.id)),V(c(e.data.current)),K.current=e.rect,W.current=null}function Ce({active:e,over:t}){if(!t)return;if(c(e.data.current)){let n=String(e.id),i=String(t.id);U(e=>{let t=r(l,e),a=te(t,n,i);return a===t?e:s(a,n,!0)});return}let n=String(e.id),i=String(t.id),a=e.rect.current.translated??e.rect.current.initial,o=a?`${a.top}:${a.left}`:null;(o===null||o!==W.current)&&(W.current=o,U(e=>{let o=r(l,e),c=ne(o,n,i,{activeRect:a,overRect:t.rect});return c===o?e:s(c,n,!1)}))}function we({over:e}){Q(),e&&!a(X,l)&&ge(X)}function Q(){z(null),V(!1),U(null)}let $=R&&B?X.find(e=>e.id===R):void 0;return oe(h,{sensors:Y,collisionDetection:ee,onDragStart:Se,onDragOver:Ce,onDragEnd:we,onDragCancel:Q,accessibility:be,autoScroll:{canScroll:e=>q(e)},children:[m(le,{id:`kanban-columns`,items:ve,strategy:ue,children:m(`div`,{...L,ref:G,className:p(e.board,N),style:P,onKeyDown:xe,children:X.map(e=>m(t,{id:e.id,title:e.title,itemIds:e.itemIds,maxItems:e.maxItems,disabled:e.disabled,getItemDisabled:w,getItemLabel:C,emptyPlaceholder:T?.(e),actions:E?.(e),reorderable:D,activeIsColumn:R!==null&&B,collapsed:ye.has(e.id),columnMaxHeight:k,hasMore:e.hasMore,onLoadMore:A?()=>A(e.id):void 0,loadMoreThreshold:j,items:b,renderItem:x,dragHandle:S},e.id))})}),m(g,{children:$?m(`div`,{className:p(e.column,e.columnDragOverlay),inert:!0,children:m(`div`,{className:e.columnHeader,children:m(n,{title:$.title,count:$.itemIds.length,maxItems:$.maxItems,actions:E?.($)})})}):R&&!B&&b[R]!==void 0?m(`div`,{className:p(e.dragOverlay,F?.dragOverlay),style:I?.dragOverlay,children:x(b[R],R)}):null})]})}export{b as default};
7
8
  //# sourceMappingURL=KanbanBoard.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanBoard.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanBoard.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from 'react';\nimport {\n DndContext,\n DragOverlay,\n KeyboardSensor,\n MouseSensor,\n TouchSensor,\n useSensor,\n useSensors,\n type DragStartEvent,\n type DragOverEvent,\n type DragEndEvent,\n type ScreenReaderInstructions,\n} from '@dnd-kit/core';\nimport { SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortable';\nimport cx from 'classnames';\n\nimport type { KanbanBoardProps, KanbanColumnDef } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\nimport KanbanColumn from './KanbanColumn';\nimport {\n buildAnnouncements,\n columnsEqual,\n isColumnDragData,\n kanbanCollisionDetection,\n kanbanKeyboardCoordinateGetter,\n moveColumn,\n moveItem,\n} from './kanbanBoard.utils';\n\nconst defaultGetItemLabel = <T,>(_item: T, id: string): string => id;\n\n// Hoisted so these are referentially stable across renders — inline literals here would give\n// `useSensor` a new options object every render (including every dragOver during an active\n// drag), which defeats its own memoization and makes `sensors` a new array each time too.\n//\n// Mouse and touch are split (rather than one combined `PointerSensor`) because they need\n// different activation constraints: a small movement threshold for mouse starts a drag\n// immediately without interfering with clicks, but the same threshold on a touchscreen would\n// hijack an ordinary scroll gesture as soon as the finger moves a few pixels. Touch instead\n// requires a brief press-and-hold before a drag arms, so a normal swipe-to-scroll passes through\n// untouched — the same pattern `VirtualList`'s `longPressDelay` uses.\nconst MOUSE_SENSOR_OPTIONS = { activationConstraint: { distance: 8 } };\nconst TOUCH_SENSOR_OPTIONS = { activationConstraint: { delay: 250, tolerance: 5 } };\nconst KEYBOARD_SENSOR_OPTIONS = { coordinateGetter: kanbanKeyboardCoordinateGetter };\n\nconst SCREEN_READER_INSTRUCTIONS: ScreenReaderInstructions = {\n draggable: `\n To pick up a card or column, press space or enter.\n While dragging, use the arrow keys to move it — for a card, between positions and columns;\n for a column, left/right to reorder it.\n Press space or enter again to drop it, or press escape to cancel.\n `,\n};\n\nfunction KanbanBoard<T = unknown>({\n columns,\n items,\n renderItem,\n onChange,\n dragHandle,\n getItemLabel = defaultGetItemLabel,\n getItemDisabled,\n renderEmptyColumn,\n renderColumnActions,\n reorderableColumns,\n collapseEmptyColumns,\n columnMaxHeight,\n onLoadMore,\n loadMoreThreshold,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: KanbanBoardProps<T>) {\n const [activeId, setActiveId] = useState<string | null>(null);\n const [activeIsColumn, setActiveIsColumn] = useState(false);\n const [shadowColumns, setShadowColumns] = useState<KanbanColumnDef[] | null>(null);\n\n // Guards against a self-sustaining reorder loop: applying a card move reflows the columns\n // involved, which can shift a *different* card under an otherwise-stationary pointer. dnd-kit\n // then re-fires `dragOver` with that new `over`, even though the user hasn't moved anything —\n // and if the geometry decision for that new target flips back once applied, the two states\n // (or more) can bounce forever, purely from our own layout changes, eventually tripping React's\n // \"Maximum update depth exceeded\" guard. `activeRect` only changes when the dragged card's own\n // position actually moves (real pointer/keyboard input), so it's used here as a proxy for \"did\n // anything the user did actually change\" — a reorder is only applied once per distinct\n // `activeRect`, which lets a drag settle and then holds still instead of oscillating.\n const lastAppliedActiveRectKeyRef = useRef<string | null>(null);\n\n const sensors = useSensors(\n useSensor(MouseSensor, MOUSE_SENSOR_OPTIONS),\n useSensor(TouchSensor, TOUCH_SENSOR_OPTIONS),\n useSensor(KeyboardSensor, KEYBOARD_SENSOR_OPTIONS),\n );\n\n const displayColumns = shadowColumns ?? columns;\n\n // `SortableContext` memoizes its own derived `items`/context value keyed on this array's\n // *reference*, not its contents — an inline `.map()` here would hand it a new array every\n // render (including every `dragOver` while a drag is in progress, via `shadowColumns`), forcing\n // every column's own `useSortable` to recompute and its whole subtree to re-render on every\n // board render, not just when the column order actually changes. Same class of bug as the\n // sensor options and the `data`/`disabled` objects in `KanbanColumn.tsx`/`KanbanItem.tsx`.\n const columnIds = useMemo(() => displayColumns.map((col) => col.id), [displayColumns]);\n\n const announcements = useMemo(\n () => buildAnnouncements(displayColumns, items, getItemLabel),\n [displayColumns, items, getItemLabel],\n );\n\n const accessibility = useMemo(\n () => ({ announcements, screenReaderInstructions: SCREEN_READER_INSTRUCTIONS }),\n [announcements],\n );\n\n function handleDragStart({ active }: DragStartEvent) {\n setActiveId(String(active.id));\n setActiveIsColumn(isColumnDragData(active.data.current));\n // `moveItem`/`moveColumn` never mutate what's passed in, only returning new objects/arrays\n // for the column(s) actually touched — so seeding the shadow state directly with `columns`\n // (rather than a full deep clone) is safe, and skips an O(total cards) clone on every drag.\n setShadowColumns(columns);\n lastAppliedActiveRectKeyRef.current = null;\n }\n\n function handleDragOver({ active, over }: DragOverEvent) {\n if (!over) return;\n\n if (isColumnDragData(active.data.current)) {\n const activeColumnId = String(active.id);\n const overColumnId = String(over.id);\n\n setShadowColumns((prev) => {\n const base = prev ?? columns;\n const next = moveColumn(base, activeColumnId, overColumnId);\n return next === base ? prev : next;\n });\n return;\n }\n\n const activeItemId = String(active.id);\n const overId = String(over.id);\n const activeRect = active.rect.current.translated ?? active.rect.current.initial;\n\n const activeRectKey = activeRect ? `${activeRect.top}:${activeRect.left}` : null;\n if (activeRectKey !== null && activeRectKey === lastAppliedActiveRectKeyRef.current) {\n return;\n }\n lastAppliedActiveRectKeyRef.current = activeRectKey;\n\n setShadowColumns((prev) => {\n const base = prev ?? columns;\n const next = moveItem(base, activeItemId, overId, { activeRect, overRect: over.rect });\n return next === base ? prev : next;\n });\n }\n\n function handleDragEnd({ over }: DragEndEvent) {\n setActiveId(null);\n setActiveIsColumn(false);\n\n if (!over || !shadowColumns) {\n setShadowColumns(null);\n return;\n }\n\n if (!columnsEqual(shadowColumns, columns)) {\n onChange(shadowColumns);\n }\n setShadowColumns(null);\n }\n\n function handleDragCancel() {\n setActiveId(null);\n setActiveIsColumn(false);\n setShadowColumns(null);\n }\n\n const activeColumn = activeId && activeIsColumn ? displayColumns.find((col) => col.id === activeId) : undefined;\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={kanbanCollisionDetection}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n accessibility={accessibility}\n >\n <SortableContext id='kanban-columns' items={columnIds} strategy={horizontalListSortingStrategy}>\n <div {...rest} className={cx(styles.board, className)} style={style}>\n {displayColumns.map((col) => (\n <KanbanColumn\n key={col.id}\n id={col.id}\n title={col.title}\n itemIds={col.itemIds}\n maxItems={col.maxItems}\n disabled={col.disabled}\n getItemDisabled={getItemDisabled}\n emptyPlaceholder={renderEmptyColumn?.(col)}\n actions={renderColumnActions?.(col)}\n reorderable={reorderableColumns}\n activeIsColumn={activeId !== null && activeIsColumn}\n collapseEmptyColumns={collapseEmptyColumns}\n columnMaxHeight={columnMaxHeight}\n hasMore={col.hasMore}\n onLoadMore={onLoadMore ? () => onLoadMore(col.id) : undefined}\n loadMoreThreshold={loadMoreThreshold}\n items={items}\n renderItem={renderItem}\n dragHandle={dragHandle}\n preserveSizeWhileEmpty={activeId !== null}\n />\n ))}\n </div>\n </SortableContext>\n <DragOverlay>\n {activeColumn ? (\n <div className={cx(styles.column, styles.columnDragOverlay)}>\n <div className={styles.columnHeader}>\n <span className={styles.columnHeaderTitle}>{activeColumn.title}</span>\n </div>\n </div>\n ) : activeId && !activeIsColumn && items[activeId] !== undefined ? (\n <div className={cx(styles.dragOverlay, classNames?.dragOverlay)} style={slotStyles?.dragOverlay}>\n {renderItem(items[activeId], activeId)}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n );\n}\n\nexport default KanbanBoard;\n"],"mappings":"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"}
1
+ {"version":3,"file":"KanbanBoard.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanBoard.tsx"],"sourcesContent":["import type { KeyboardEvent } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n DndContext,\n DragOverlay,\n KeyboardSensor,\n MouseSensor,\n TouchSensor,\n useSensor,\n useSensors,\n type DragStartEvent,\n type DragOverEvent,\n type DragEndEvent,\n type Active,\n type ScreenReaderInstructions,\n} from '@dnd-kit/core';\nimport { SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortable';\nimport cx from 'classnames';\n\nimport type { KanbanBoardProps } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\nimport KanbanColumn, { ColumnHeaderContent } from './KanbanColumn';\nimport {\n applyPlacement,\n buildAnnouncements,\n columnsEqual,\n findArrowFocusTarget,\n findPlacement,\n isColumnDragData,\n kanbanCollisionDetection,\n kanbanKeyboardCoordinateGetter,\n moveColumn,\n moveItem,\n scrollsTowardBoard,\n type DragPlacement,\n} from './kanbanBoard.utils';\n\nconst defaultGetItemLabel = <T,>(_item: T, id: string): string => id;\n\n// Hoisted so these are referentially stable across renders — inline literals here would give\n// `useSensor` a new options object every render (including every dragOver during an active\n// drag), which defeats its own memoization and makes `sensors` a new array each time too.\n//\n// Mouse and touch are split (rather than one combined `PointerSensor`) because they need\n// different activation constraints: a small movement threshold for mouse starts a drag\n// immediately without interfering with clicks, but the same threshold on a touchscreen would\n// hijack an ordinary scroll gesture as soon as the finger moves a few pixels. Touch instead\n// requires a brief press-and-hold before a drag arms, so a normal swipe-to-scroll passes through\n// untouched — the same pattern `VirtualList`'s `longPressDelay` uses.\nconst MOUSE_SENSOR_OPTIONS = { activationConstraint: { distance: 8 } };\nconst TOUCH_SENSOR_OPTIONS = { activationConstraint: { delay: 250, tolerance: 5 } };\nconst KEYBOARD_SENSOR_OPTIONS = { coordinateGetter: kanbanKeyboardCoordinateGetter };\n\nconst SCREEN_READER_INSTRUCTIONS: ScreenReaderInstructions = {\n draggable: `\n To pick up a card or column, press space or enter.\n Use the arrow keys to move between cards and columns.\n While dragging, use the arrow keys to move it — for a card, between positions and columns;\n for a column, left/right to reorder it.\n Press space or enter again to drop it, or press escape to cancel.\n `,\n};\n\nfunction KanbanBoard<T = unknown>({\n columns,\n items,\n renderItem,\n onChange,\n dragHandle,\n getItemLabel = defaultGetItemLabel,\n getItemDisabled,\n renderEmptyColumn,\n renderColumnActions,\n reorderableColumns,\n collapseEmptyColumns = false,\n columnMaxHeight,\n onLoadMore,\n loadMoreThreshold,\n onKeyDown,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: KanbanBoardProps<T>) {\n const [activeId, setActiveId] = useState<string | null>(null);\n const [activeIsColumn, setActiveIsColumn] = useState(false);\n const [placement, setPlacement] = useState<DragPlacement | null>(null);\n\n // Guards against a self-sustaining reorder loop: applying a card move reflows the columns\n // involved, which can shift a *different* card under an otherwise-stationary pointer. dnd-kit\n // then re-fires `dragOver` with that new `over`, even though the user hasn't moved anything —\n // and if the geometry decision for that new target flips back once applied, the two states\n // (or more) can bounce forever, purely from our own layout changes, eventually tripping React's\n // \"Maximum update depth exceeded\" guard. `activeRect` only changes when the dragged card's own\n // position actually moves (real pointer/keyboard input), so it's used here as a proxy for \"did\n // anything the user did actually change\" — a reorder is only applied once per distinct\n // `activeRect`, which lets a drag settle and then holds still instead of oscillating.\n const lastAppliedActiveRectKeyRef = useRef<string | null>(null);\n\n const boardRef = useRef<HTMLDivElement>(null);\n\n // Lets an ancestor of the board (the page) auto-scroll only toward a part of the board out of\n // view. Left to dnd-kit, a card held near the bottom of the viewport scrolled the page on until\n // the board was gone; refused, dnd-kit moves on to the column's own list.\n const draggedRectRef = useRef<Active['rect'] | null>(null);\n const canScroll = useCallback((element: Element) => {\n const board = boardRef.current;\n const dragged = draggedRectRef.current?.current.translated;\n if (!board || !dragged || board.contains(element)) return true;\n const scroller =\n element === document.scrollingElement ? { top: 0, bottom: window.innerHeight } : element.getBoundingClientRect();\n return scrollsTowardBoard(scroller, board.getBoundingClientRect(), dragged);\n }, []);\n // dnd-kit asks `canScroll` only when it re-plans, which WebKit never prompts while the pointer\n // holds still, so the page scrolled on past the board there. A render hands dnd-kit a new\n // `canScroll`, which makes it re-plan: the scroll listener below asks for one when the page\n // should stop.\n const [, replanAutoScroll] = useState(0);\n\n // A scroll is input too: it moves the cards under a pointer that holds still, which is what the\n // auto-scroll at a column's edge does. Only a scroll that moves this board counts, so a scroller\n // elsewhere on the page cannot switch the guard off for the whole drag.\n const isDragging = activeId !== null;\n useEffect(() => {\n if (!isDragging) return;\n const handleScroll = ({ target }: Event) => {\n const board = boardRef.current;\n if (!board || !(target instanceof Node) || !(target.contains(board) || board.contains(target))) return;\n lastAppliedActiveRectKeyRef.current = null;\n const scroller = target === document ? document.scrollingElement : target;\n if (scroller instanceof Element && !canScroll(scroller)) replanAutoScroll((n) => n + 1);\n };\n // Capture, because a scroll event does not bubble, and the scroller can be any ancestor.\n window.addEventListener('scroll', handleScroll, { capture: true, passive: true });\n return () => window.removeEventListener('scroll', handleScroll, { capture: true });\n }, [isDragging, canScroll]);\n\n const sensors = useSensors(\n useSensor(MouseSensor, MOUSE_SENSOR_OPTIONS),\n useSensor(TouchSensor, TOUCH_SENSOR_OPTIONS),\n useSensor(KeyboardSensor, KEYBOARD_SENSOR_OPTIONS),\n );\n\n // Rebuilt from the live `columns` on every change rather than snapshotted at drag start: a page\n // `onLoadMore` appended mid-drag stayed invisible in the snapshot, so the column kept asking for\n // more, and the drop then handed the snapshot to `onChange`, discarding every page loaded since.\n const displayColumns = useMemo(() => applyPlacement(columns, placement), [columns, placement]);\n\n // `SortableContext` memoizes its own derived `items`/context value keyed on this array's\n // *reference*, not its contents — an inline `.map()` here would hand it a new array every\n // render (including every `dragOver` while a drag is in progress, via `placement`), forcing\n // every column's own `useSortable` to recompute and its whole subtree to re-render on every\n // board render, not just when the column order actually changes. Same class of bug as the\n // sensor options and the `data`/`disabled` objects in `KanbanColumn.tsx`/`KanbanItem.tsx`.\n const columnIds = useMemo(() => displayColumns.map((col) => col.id), [displayColumns]);\n\n // Read from `columns`, not `displayColumns`, so no column grows or shrinks during a drag: a\n // width change under the pointer moves the drop targets, and a column that shrank mid-drag once\n // fed a reorder loop. A column the drag empties or fills changes width once, after the drop.\n const collapsedColumnIds = useMemo(\n () => new Set(collapseEmptyColumns ? columns.filter((col) => col.itemIds.length === 0).map((col) => col.id) : []),\n [columns, collapseEmptyColumns],\n );\n\n const announcements = useMemo(\n () => buildAnnouncements(displayColumns, items, getItemLabel),\n [displayColumns, items, getItemLabel],\n );\n\n const accessibility = useMemo(\n () => ({ announcements, screenReaderInstructions: SCREEN_READER_INSTRUCTIONS }),\n [announcements],\n );\n\n function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n onKeyDown?.(event);\n if (event.defaultPrevented || activeId !== null || !boardRef.current || !(event.target instanceof HTMLElement))\n return;\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n const target = findArrowFocusTarget(boardRef.current, event.target, event.key);\n if (!target) return;\n event.preventDefault();\n target.focus();\n }\n\n function handleDragStart({ active }: DragStartEvent) {\n setActiveId(String(active.id));\n setActiveIsColumn(isColumnDragData(active.data.current));\n draggedRectRef.current = active.rect;\n lastAppliedActiveRectKeyRef.current = null;\n }\n\n function handleDragOver({ active, over }: DragOverEvent) {\n if (!over) return;\n\n if (isColumnDragData(active.data.current)) {\n const activeColumnId = String(active.id);\n const overColumnId = String(over.id);\n\n setPlacement((prev) => {\n const base = applyPlacement(columns, prev);\n const next = moveColumn(base, activeColumnId, overColumnId);\n return next === base ? prev : findPlacement(next, activeColumnId, true);\n });\n return;\n }\n\n const activeItemId = String(active.id);\n const overId = String(over.id);\n const activeRect = active.rect.current.translated ?? active.rect.current.initial;\n\n const activeRectKey = activeRect ? `${activeRect.top}:${activeRect.left}` : null;\n if (activeRectKey !== null && activeRectKey === lastAppliedActiveRectKeyRef.current) {\n return;\n }\n lastAppliedActiveRectKeyRef.current = activeRectKey;\n\n setPlacement((prev) => {\n const base = applyPlacement(columns, prev);\n const next = moveItem(base, activeItemId, overId, { activeRect, overRect: over.rect });\n return next === base ? prev : findPlacement(next, activeItemId, false);\n });\n }\n\n function handleDragEnd({ over }: DragEndEvent) {\n handleDragCancel();\n if (over && !columnsEqual(displayColumns, columns)) onChange(displayColumns);\n }\n\n function handleDragCancel() {\n setActiveId(null);\n setActiveIsColumn(false);\n setPlacement(null);\n }\n\n const activeColumn = activeId && activeIsColumn ? displayColumns.find((col) => col.id === activeId) : undefined;\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={kanbanCollisionDetection}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n accessibility={accessibility}\n // A new `canScroll` every render on purpose, see `replanAutoScroll`.\n autoScroll={{ canScroll: (element) => canScroll(element) }}\n >\n <SortableContext id='kanban-columns' items={columnIds} strategy={horizontalListSortingStrategy}>\n <div {...rest} ref={boardRef} className={cx(styles.board, className)} style={style} onKeyDown={handleKeyDown}>\n {displayColumns.map((col) => (\n <KanbanColumn\n key={col.id}\n id={col.id}\n title={col.title}\n itemIds={col.itemIds}\n maxItems={col.maxItems}\n disabled={col.disabled}\n getItemDisabled={getItemDisabled}\n getItemLabel={getItemLabel}\n emptyPlaceholder={renderEmptyColumn?.(col)}\n actions={renderColumnActions?.(col)}\n reorderable={reorderableColumns}\n activeIsColumn={activeId !== null && activeIsColumn}\n collapsed={collapsedColumnIds.has(col.id)}\n columnMaxHeight={columnMaxHeight}\n hasMore={col.hasMore}\n onLoadMore={onLoadMore ? () => onLoadMore(col.id) : undefined}\n loadMoreThreshold={loadMoreThreshold}\n items={items}\n renderItem={renderItem}\n dragHandle={dragHandle}\n />\n ))}\n </div>\n </SortableContext>\n <DragOverlay>\n {activeColumn ? (\n <div className={cx(styles.column, styles.columnDragOverlay)} inert>\n <div className={styles.columnHeader}>\n <ColumnHeaderContent\n title={activeColumn.title}\n count={activeColumn.itemIds.length}\n maxItems={activeColumn.maxItems}\n actions={renderColumnActions?.(activeColumn)}\n />\n </div>\n </div>\n ) : activeId && !activeIsColumn && items[activeId] !== undefined ? (\n <div className={cx(styles.dragOverlay, classNames?.dragOverlay)} style={slotStyles?.dragOverlay}>\n {renderItem(items[activeId], activeId)}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n );\n}\n\nexport default KanbanBoard;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";import e from"../loader/loader.mjs";import t from"./kanbanBoard.module.mjs";import n from"./KanbanItem.mjs";import{useCallback as r,useEffect as i,useRef as a,useState as o}from"react";import s from"classnames";import{jsx as c,jsxs as l}from"react/jsx-runtime";import{useDroppable as u}from"@dnd-kit/core";import{SortableContext as d,useSortable as f,verticalListSortingStrategy as p}from"@dnd-kit/sortable";import{CSS as m}from"@dnd-kit/utilities";var h={type:`column`},g={draggable:!0,droppable:!0};function _({id:_,title:v,itemIds:y,items:b,renderItem:x,dragHandle:S,preserveSizeWhileEmpty:C,collapseEmptyColumns:w=!0,maxItems:T,disabled:E,getItemDisabled:D,emptyPlaceholder:O,actions:k,reorderable:A,activeIsColumn:j,columnMaxHeight:M,hasMore:N,onLoadMore:P,loadMoreThreshold:F=100,className:I,style:L,classNames:R,styles:z,...B}){let V=`column-${_}`,{setNodeRef:H,isOver:U}=u({id:V,disabled:E}),W=w&&y.length===0&&!C,G=T!=null&&y.length>T,K=a(null),q=r(e=>{K.current=e,H(e)},[H]),J=a(!1),[Y,X]=o(!1),Z=r(()=>{P&&!J.current&&(J.current=!0,X(!0),Promise.resolve(P()).finally(()=>{J.current=!1,X(!1)}))},[P]),Q=r(e=>{if(!N)return;let t=e.currentTarget;t.scrollTop+t.clientHeight>=t.scrollHeight-F&&Z()},[N,F,Z]),$=a(``);i(()=>{if(!N||!M||Y)return;let e=K.current;if(!e||e.clientHeight===0||e.scrollHeight>e.clientHeight)return;let t=`${y.length}:${e.clientHeight}`;$.current!==t&&($.current=t,Z())},[N,M,Y,y.length,Z]);let{attributes:ee,listeners:te,setNodeRef:ne,transform:re,transition:ie,isDragging:ae,isOver:oe}=f({id:_,data:h,disabled:!A&&g});return l(`div`,{...B,ref:ne,id:_,className:s(t.column,U&&!j&&t.columnOver,oe&&t.columnDropTarget,W&&t.columnEmpty,G&&t.columnOverLimit,E&&t.columnDisabled,ae&&t.columnDragging,I),style:{transform:m.Transform.toString(re),transition:ie,...L},children:[l(`div`,{className:s(t.columnHeader,A&&t.columnHeaderReorderable,R?.header),style:z?.header,...A?ee:void 0,...A?te:void 0,children:[c(`span`,{className:t.columnHeaderTitle,children:v}),l(`div`,{className:t.columnHeaderTrailing,children:[T!=null&&l(`span`,{className:s(t.columnHeaderCount,G&&t.columnHeaderCountOver,R?.count),style:z?.count,children:[y.length,`/`,T]}),k!=null&&c(`div`,{className:s(t.columnHeaderActions,R?.actions),style:z?.actions,children:k})]})]}),c(d,{id:_,items:y,strategy:p,children:l(`div`,{ref:q,className:s(t.columnItems,R?.items),style:{maxHeight:M,overflowY:M?`auto`:void 0,...z?.items},onScroll:M?Q:void 0,children:[y.length===0&&O!=null?c(`div`,{className:s(t.columnPlaceholder,R?.placeholder),style:z?.placeholder,children:O}):null,y.map(e=>c(n,{id:e,dragHandle:S,disabled:E||b[e]!==void 0&&(D?.(b[e],e)??!1),preventAsDropTarget:E,children:b[e]===void 0?null:x(b[e],e)},e)),Y&&c(`div`,{className:s(t.columnLoadingIndicator,R?.loadingIndicator),style:z?.loadingIndicator,children:c(e,{size:`2.6em`})})]})})]})}export{_ as default};
1
+ "use client";import e from"../loader/loader.mjs";import t from"./kanbanBoard.module.mjs";import n from"./KanbanItem.mjs";import{useCallback as r,useEffect as i,useRef as a,useState as o}from"react";import s from"classnames";import{Fragment as c,jsx as l,jsxs as u}from"react/jsx-runtime";import{useDroppable as d}from"@dnd-kit/core";import{SortableContext as f,useSortable as p,verticalListSortingStrategy as m}from"@dnd-kit/sortable";import{CSS as h}from"@dnd-kit/utilities";var g={type:`column`},_={draggable:!0,droppable:!0};function v({title:e,count:n,maxItems:r,actions:i,titleProps:a,classNames:o,styles:d}){let f=r!=null&&n>r;return u(c,{children:[l(`span`,{...a,className:t.columnHeaderTitle,children:e}),u(`div`,{className:t.columnHeaderTrailing,children:[r!=null&&u(`span`,{className:s(t.columnHeaderCount,f&&t.columnHeaderCountOver,o?.count),style:d?.count,children:[n,`/`,r]}),i!=null&&l(`div`,{className:s(t.columnHeaderActions,o?.actions),style:d?.actions,children:i})]})]})}function y({id:c,title:y,itemIds:b,items:x,renderItem:S,dragHandle:C,collapsed:w,maxItems:T,disabled:E,getItemDisabled:D,getItemLabel:O,emptyPlaceholder:k,actions:A,reorderable:j,activeIsColumn:M,columnMaxHeight:N,hasMore:P,onLoadMore:F,loadMoreThreshold:I=100,className:L,style:R,classNames:z,styles:B,...V}){let H=`column-${c}`,{setNodeRef:U,isOver:W}=d({id:H,disabled:E}),G=T!=null&&b.length>T,K=a(null),q=r(e=>{K.current=e,U(e)},[U]),J=a(!1),[Y,X]=o(!1),Z=r(()=>{F&&!J.current&&(J.current=!0,X(!0),Promise.resolve(F()).finally(()=>{J.current=!1,X(!1)}))},[F]),Q=r(e=>{if(!P)return;let t=e.currentTarget;t.scrollTop+t.clientHeight>=t.scrollHeight-I&&Z()},[P,I,Z]),$=a(``);i(()=>{if(!P||Y)return;let e=K.current;if(!e||e.clientHeight===0)return;let t=e.lastElementChild,n=parseFloat(getComputedStyle(e).paddingBottom)||0;if((t?t.offsetTop+t.offsetHeight:0)+n>=e.clientHeight-1)return;let r=`${b.length}:${e.clientHeight}`;$.current!==r&&($.current=r,Z())},[P,Y,b.length,Z]);let{attributes:ee,listeners:te,setNodeRef:ne,setActivatorNodeRef:re,transform:ie,transition:ae,isDragging:oe,isOver:se}=p({id:c,data:g,disabled:!j&&_});return u(`div`,{...V,ref:ne,id:c,"data-kanban-column":``,className:s(t.column,W&&!M&&t.columnOver,se&&t.columnDropTarget,w&&t.columnCollapsed,G&&t.columnOverLimit,E&&t.columnDisabled,oe&&t.columnDragging,L),style:{transform:h.Transform.toString(ie),transition:ae,...R},children:[l(`div`,{className:s(t.columnHeader,j&&t.columnHeaderReorderable,z?.header),style:B?.header,...j?te:void 0,children:l(v,{title:y,count:b.length,maxItems:T,actions:A,titleProps:j?{...ee,ref:re,"data-kanban-handle":``}:void 0,classNames:z,styles:B})}),l(f,{id:c,items:b,strategy:m,children:u(`div`,{ref:q,className:s(t.columnItems,z?.items),style:{maxHeight:N,...B?.items},onScroll:Q,children:[b.length===0&&k!=null?l(`div`,{className:s(t.columnPlaceholder,z?.placeholder),style:B?.placeholder,children:k}):null,b.map(e=>l(n,{id:e,label:x[e]===void 0?void 0:O?.(x[e],e),dragHandle:C,disabled:E||x[e]!==void 0&&(D?.(x[e],e)??!1),preventAsDropTarget:E,children:x[e]===void 0?null:S(x[e],e)},e)),Y&&l(`div`,{className:s(t.columnLoadingIndicator,z?.loadingIndicator),style:B?.loadingIndicator,children:l(e,{size:`2.6em`})})]})})]})}export{v as ColumnHeaderContent,y as default};
2
2
  //# sourceMappingURL=KanbanColumn.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanColumn.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanColumn.tsx"],"sourcesContent":["import type { ReactNode, UIEvent } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useDroppable } from '@dnd-kit/core';\nimport { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport cx from 'classnames';\n\nimport type { KanbanColumnProps } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\nimport KanbanItem from './KanbanItem';\nimport Loader from '../loader';\n\n// Hoisted so these are referentially stable across renders — inline literals here would give\n// `useSortable` a new `data`/`disabled` object every render (every column re-renders on every\n// `dragOver` while a drag is in progress, via `shadowColumns`), which can spin dnd-kit's own\n// registration effect into a render loop that eventually trips React's \"Maximum update depth\n// exceeded\" guard. Same fix as the sensor options in `KanbanBoard.tsx`.\nconst COLUMN_SORTABLE_DATA = { type: 'column' };\nconst COLUMN_SORTABLE_DISABLED = { draggable: true, droppable: true };\n\ninterface KanbanColumnInternalProps<T> extends KanbanColumnProps {\n itemIds: string[];\n items: Record<string, T>;\n renderItem: (item: T, id: string) => ReactNode;\n dragHandle?: boolean;\n /**\n * Keep the column at its normal flex width even when `itemIds` is empty. Used while a drag\n * is in progress: the empty-column collapse is driven by transient shadow state during a\n * drag, and letting the column shrink mid-drag shifts every column's layout underneath the\n * pointer, which can flip the collision target back and forth forever.\n */\n preserveSizeWhileEmpty?: boolean;\n /** Shrink to a narrow strip when empty — see `KanbanBoardProps.collapseEmptyColumns`. Defaults to `true`. */\n collapseEmptyColumns?: boolean;\n /** Work-in-progress limit — see `KanbanColumnDef.maxItems`. Display-only. */\n maxItems?: number;\n /** Freezes the column — see `KanbanColumnDef.disabled`. */\n disabled?: boolean;\n /** Returns whether a specific card can't be picked up — see `KanbanBoardProps.getItemDisabled`. */\n getItemDisabled?: (item: T, id: string) => boolean;\n /** Custom content shown when the column has no cards — see `KanbanBoardProps.renderEmptyColumn`. */\n emptyPlaceholder?: ReactNode;\n /** Custom header actions — see `KanbanBoardProps.renderColumnActions`. */\n actions?: ReactNode;\n /** Allow the whole column to be dragged (by its header) to reorder it — see `KanbanBoardProps.reorderableColumns`. */\n reorderable?: boolean;\n /**\n * Whether the card currently being dragged (if any) is actually a column. Suppresses the\n * cards drop-target highlight, which otherwise lights up on every column a dragged column\n * passes over — that highlight means \"drop a card here\", which doesn't apply mid-column-drag.\n */\n activeIsColumn?: boolean;\n /** Bounds the column's height and makes its card list scroll — see `KanbanBoardProps.columnMaxHeight`. */\n columnMaxHeight?: string;\n /** Whether more items exist for this column — see `KanbanColumnDef.hasMore`. */\n hasMore?: boolean;\n /** Requests the next page for this column — see `KanbanBoardProps.onLoadMore`. */\n onLoadMore?: () => void | Promise<void>;\n /** Scroll distance from the bottom that triggers `onLoadMore` — see `KanbanBoardProps.loadMoreThreshold`. */\n loadMoreThreshold?: number;\n}\n\nfunction KanbanColumn<T>({\n id,\n title,\n itemIds,\n items,\n renderItem,\n dragHandle,\n preserveSizeWhileEmpty,\n collapseEmptyColumns = true,\n maxItems,\n disabled,\n getItemDisabled,\n emptyPlaceholder,\n actions,\n reorderable,\n activeIsColumn,\n columnMaxHeight,\n hasMore,\n onLoadMore,\n loadMoreThreshold = 100,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: KanbanColumnInternalProps<T>) {\n const droppableId = `column-${id}`;\n const { setNodeRef, isOver } = useDroppable({ id: droppableId, disabled });\n const isEmpty = collapseEmptyColumns && itemIds.length === 0 && !preserveSizeWhileEmpty;\n const isOverLimit = maxItems != null && itemIds.length > maxItems;\n\n const itemsRef = useRef<HTMLDivElement | null>(null);\n const setItemsRef = useCallback(\n (node: HTMLDivElement | null) => {\n itemsRef.current = node;\n setNodeRef(node);\n },\n [setNodeRef],\n );\n const isLoadingMoreRef = useRef(false);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n\n const triggerLoadMore = useCallback(() => {\n if (!onLoadMore || isLoadingMoreRef.current) return;\n isLoadingMoreRef.current = true;\n setIsLoadingMore(true);\n Promise.resolve(onLoadMore()).finally(() => {\n isLoadingMoreRef.current = false;\n setIsLoadingMore(false);\n });\n }, [onLoadMore]);\n\n const handleItemsScroll = useCallback(\n (event: UIEvent<HTMLDivElement>) => {\n if (!hasMore) return;\n const el = event.currentTarget;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - loadMoreThreshold) triggerLoadMore();\n },\n [hasMore, loadMoreThreshold, triggerLoadMore],\n );\n\n // The scroll trigger above can only fire once the list actually overflows and scrolls. A batch\n // smaller than the column's own visible height never generates a scroll event, which would\n // otherwise dead-end pagination after the first page. Re-probes at most once per (item count,\n // visible height) pair, so settled content can't re-ask a source that already ran dry.\n const fillProbeRef = useRef('');\n useEffect(() => {\n if (!hasMore || !columnMaxHeight || isLoadingMore) return;\n const el = itemsRef.current;\n if (!el || el.clientHeight === 0) return;\n if (el.scrollHeight > el.clientHeight) return;\n const probe = `${itemIds.length}:${el.clientHeight}`;\n if (fillProbeRef.current === probe) return;\n fillProbeRef.current = probe;\n triggerLoadMore();\n }, [hasMore, columnMaxHeight, isLoadingMore, itemIds.length, triggerLoadMore]);\n\n const {\n attributes: columnAttributes,\n listeners: columnListeners,\n setNodeRef: setColumnNodeRef,\n transform: columnTransform,\n transition: columnTransition,\n isDragging: isColumnDragging,\n isOver: isColumnOver,\n } = useSortable({\n id,\n data: COLUMN_SORTABLE_DATA,\n disabled: reorderable ? false : COLUMN_SORTABLE_DISABLED,\n });\n\n return (\n <div\n {...rest}\n ref={setColumnNodeRef}\n id={id}\n className={cx(\n styles.column,\n isOver && !activeIsColumn && styles.columnOver,\n isColumnOver && styles.columnDropTarget,\n isEmpty && styles.columnEmpty,\n isOverLimit && styles.columnOverLimit,\n disabled && styles.columnDisabled,\n isColumnDragging && styles.columnDragging,\n className,\n )}\n style={{ transform: CSS.Transform.toString(columnTransform), transition: columnTransition, ...style }}\n >\n <div\n className={cx(styles.columnHeader, reorderable && styles.columnHeaderReorderable, classNames?.header)}\n style={slotStyles?.header}\n {...(reorderable ? columnAttributes : undefined)}\n {...(reorderable ? columnListeners : undefined)}\n >\n <span className={styles.columnHeaderTitle}>{title}</span>\n <div className={styles.columnHeaderTrailing}>\n {maxItems != null && (\n <span\n className={cx(styles.columnHeaderCount, isOverLimit && styles.columnHeaderCountOver, classNames?.count)}\n style={slotStyles?.count}\n >\n {itemIds.length}/{maxItems}\n </span>\n )}\n {actions != null && (\n <div className={cx(styles.columnHeaderActions, classNames?.actions)} style={slotStyles?.actions}>\n {actions}\n </div>\n )}\n </div>\n </div>\n <SortableContext id={id} items={itemIds} strategy={verticalListSortingStrategy}>\n <div\n ref={setItemsRef}\n className={cx(styles.columnItems, classNames?.items)}\n style={{ maxHeight: columnMaxHeight, overflowY: columnMaxHeight ? 'auto' : undefined, ...slotStyles?.items }}\n onScroll={columnMaxHeight ? handleItemsScroll : undefined}\n >\n {itemIds.length === 0 && emptyPlaceholder != null ? (\n <div className={cx(styles.columnPlaceholder, classNames?.placeholder)} style={slotStyles?.placeholder}>\n {emptyPlaceholder}\n </div>\n ) : null}\n {itemIds.map((itemId) => (\n <KanbanItem\n key={itemId}\n id={itemId}\n dragHandle={dragHandle}\n disabled={\n disabled || (items[itemId] !== undefined && (getItemDisabled?.(items[itemId], itemId) ?? false))\n }\n preventAsDropTarget={disabled}\n >\n {items[itemId] !== undefined ? renderItem(items[itemId], itemId) : null}\n </KanbanItem>\n ))}\n {isLoadingMore && (\n <div\n className={cx(styles.columnLoadingIndicator, classNames?.loadingIndicator)}\n style={slotStyles?.loadingIndicator}\n >\n <Loader size='2.6em' />\n </div>\n )}\n </div>\n </SortableContext>\n </div>\n );\n}\n\nexport default KanbanColumn;\n"],"mappings":"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"}
1
+ {"version":3,"file":"KanbanColumn.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanColumn.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode, Ref, UIEvent } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useDroppable } from '@dnd-kit/core';\nimport { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport cx from 'classnames';\n\nimport type { DataProps, SlotClassNames, SlotStyles } from '../types/slots.types';\nimport type { KanbanColumnProps, KanbanColumnSlots } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\nimport KanbanItem from './KanbanItem';\nimport Loader from '../loader';\n\n// Hoisted so these are referentially stable across renders — inline literals here would give\n// `useSortable` a new `data`/`disabled` object every render (every column re-renders on every\n// `dragOver` while a drag is in progress, via the board's `placement`), which can spin dnd-kit's own\n// registration effect into a render loop that eventually trips React's \"Maximum update depth\n// exceeded\" guard. Same fix as the sensor options in `KanbanBoard.tsx`.\nconst COLUMN_SORTABLE_DATA = { type: 'column' };\nconst COLUMN_SORTABLE_DISABLED = { draggable: true, droppable: true };\n\ninterface KanbanColumnInternalProps<T> extends KanbanColumnProps {\n itemIds: string[];\n items: Record<string, T>;\n renderItem: (item: T, id: string) => ReactNode;\n dragHandle?: boolean;\n /** Shrink to a narrow strip. The board decides when, see `KanbanBoardProps.collapseEmptyColumns`. */\n collapsed?: boolean;\n /** Work-in-progress limit — see `KanbanColumnDef.maxItems`. Display-only. */\n maxItems?: number;\n /** Freezes the column — see `KanbanColumnDef.disabled`. */\n disabled?: boolean;\n /** Returns whether a specific card can't be picked up — see `KanbanBoardProps.getItemDisabled`. */\n getItemDisabled?: (item: T, id: string) => boolean;\n /** Names a card's drag handle — see `KanbanBoardProps.getItemLabel`. */\n getItemLabel?: (item: T, id: string) => string;\n /** Custom content shown when the column has no cards — see `KanbanBoardProps.renderEmptyColumn`. */\n emptyPlaceholder?: ReactNode;\n /** Custom header actions — see `KanbanBoardProps.renderColumnActions`. */\n actions?: ReactNode;\n /** Allow the whole column to be dragged (by its header) to reorder it — see `KanbanBoardProps.reorderableColumns`. */\n reorderable?: boolean;\n /**\n * Whether the card currently being dragged (if any) is actually a column. Suppresses the\n * cards drop-target highlight, which otherwise lights up on every column a dragged column\n * passes over — that highlight means \"drop a card here\", which doesn't apply mid-column-drag.\n */\n activeIsColumn?: boolean;\n /** Bounds the column's height and makes its card list scroll — see `KanbanBoardProps.columnMaxHeight`. */\n columnMaxHeight?: string;\n /** Whether more items exist for this column — see `KanbanColumnDef.hasMore`. */\n hasMore?: boolean;\n /** Requests the next page for this column — see `KanbanBoardProps.onLoadMore`. */\n onLoadMore?: () => void | Promise<void>;\n /** Scroll distance from the bottom that triggers `onLoadMore` — see `KanbanBoardProps.loadMoreThreshold`. */\n loadMoreThreshold?: number;\n}\n\ninterface ColumnHeaderContentProps {\n title: string;\n count: number;\n maxItems?: number;\n actions?: ReactNode;\n /** Makes the title the column's keyboard drag handle. */\n titleProps?: HTMLAttributes<HTMLSpanElement> & DataProps & { ref?: Ref<HTMLSpanElement> };\n classNames?: SlotClassNames<KanbanColumnSlots>;\n styles?: SlotStyles<KanbanColumnSlots>;\n}\n\n// Also rendered by the drag overlay: with the title alone, the overlay was shorter than the header\n// it covers, and the faded original showed below it.\nexport function ColumnHeaderContent({\n title,\n count,\n maxItems,\n actions,\n titleProps,\n classNames,\n styles: slotStyles,\n}: ColumnHeaderContentProps) {\n const isOverLimit = maxItems != null && count > maxItems;\n return (\n <>\n <span {...titleProps} className={styles.columnHeaderTitle}>\n {title}\n </span>\n <div className={styles.columnHeaderTrailing}>\n {maxItems != null && (\n <span\n className={cx(styles.columnHeaderCount, isOverLimit && styles.columnHeaderCountOver, classNames?.count)}\n style={slotStyles?.count}\n >\n {count}/{maxItems}\n </span>\n )}\n {actions != null && (\n <div className={cx(styles.columnHeaderActions, classNames?.actions)} style={slotStyles?.actions}>\n {actions}\n </div>\n )}\n </div>\n </>\n );\n}\n\nfunction KanbanColumn<T>({\n id,\n title,\n itemIds,\n items,\n renderItem,\n dragHandle,\n collapsed,\n maxItems,\n disabled,\n getItemDisabled,\n getItemLabel,\n emptyPlaceholder,\n actions,\n reorderable,\n activeIsColumn,\n columnMaxHeight,\n hasMore,\n onLoadMore,\n loadMoreThreshold = 100,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: KanbanColumnInternalProps<T>) {\n const droppableId = `column-${id}`;\n const { setNodeRef, isOver } = useDroppable({ id: droppableId, disabled });\n const isOverLimit = maxItems != null && itemIds.length > maxItems;\n\n const itemsRef = useRef<HTMLDivElement | null>(null);\n const setItemsRef = useCallback(\n (node: HTMLDivElement | null) => {\n itemsRef.current = node;\n setNodeRef(node);\n },\n [setNodeRef],\n );\n const isLoadingMoreRef = useRef(false);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n\n const triggerLoadMore = useCallback(() => {\n if (!onLoadMore || isLoadingMoreRef.current) return;\n isLoadingMoreRef.current = true;\n setIsLoadingMore(true);\n Promise.resolve(onLoadMore()).finally(() => {\n isLoadingMoreRef.current = false;\n setIsLoadingMore(false);\n });\n }, [onLoadMore]);\n\n const handleItemsScroll = useCallback(\n (event: UIEvent<HTMLDivElement>) => {\n if (!hasMore) return;\n const el = event.currentTarget;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - loadMoreThreshold) triggerLoadMore();\n },\n [hasMore, loadMoreThreshold, triggerLoadMore],\n );\n\n // The scroll trigger above can only fire once the list actually overflows and scrolls. A batch\n // smaller than the column's own visible height never generates a scroll event, which would\n // otherwise dead-end pagination after the first page. Re-probes at most once per (item count,\n // visible height) pair, so settled content can't re-ask a source that already ran dry.\n //\n // It asks while the cards leave empty space below them, not while the list fails to overflow:\n // on a board that grows with its cards no list ever overflows, and that rule loaded every page.\n // This one fills a short column up to the tallest and stops.\n const fillProbeRef = useRef('');\n useEffect(() => {\n if (!hasMore || isLoadingMore) return;\n const el = itemsRef.current;\n if (!el || el.clientHeight === 0) return;\n const last = el.lastElementChild as HTMLElement | null;\n const paddingBottom = parseFloat(getComputedStyle(el).paddingBottom) || 0;\n if ((last ? last.offsetTop + last.offsetHeight : 0) + paddingBottom >= el.clientHeight - 1) return;\n const probe = `${itemIds.length}:${el.clientHeight}`;\n if (fillProbeRef.current === probe) return;\n fillProbeRef.current = probe;\n triggerLoadMore();\n }, [hasMore, isLoadingMore, itemIds.length, triggerLoadMore]);\n\n const {\n attributes: columnAttributes,\n listeners: columnListeners,\n setNodeRef: setColumnNodeRef,\n setActivatorNodeRef: setColumnActivatorRef,\n transform: columnTransform,\n transition: columnTransition,\n isDragging: isColumnDragging,\n isOver: isColumnOver,\n } = useSortable({\n id,\n data: COLUMN_SORTABLE_DATA,\n disabled: reorderable ? false : COLUMN_SORTABLE_DISABLED,\n });\n\n return (\n <div\n {...rest}\n ref={setColumnNodeRef}\n id={id}\n data-kanban-column=''\n className={cx(\n styles.column,\n isOver && !activeIsColumn && styles.columnOver,\n isColumnOver && styles.columnDropTarget,\n collapsed && styles.columnCollapsed,\n isOverLimit && styles.columnOverLimit,\n disabled && styles.columnDisabled,\n isColumnDragging && styles.columnDragging,\n className,\n )}\n style={{ transform: CSS.Transform.toString(columnTransform), transition: columnTransition, ...style }}\n >\n {/* The whole header is the pointer grab area, but only the title is the keyboard handle: a\n focusable header was a button around the actions' own buttons, and the Enter meant for\n one of them picked the column up instead. */}\n <div\n className={cx(styles.columnHeader, reorderable && styles.columnHeaderReorderable, classNames?.header)}\n style={slotStyles?.header}\n {...(reorderable ? columnListeners : undefined)}\n >\n <ColumnHeaderContent\n title={title}\n count={itemIds.length}\n maxItems={maxItems}\n actions={actions}\n titleProps={\n reorderable ? { ...columnAttributes, ref: setColumnActivatorRef, 'data-kanban-handle': '' } : undefined\n }\n classNames={classNames}\n styles={slotStyles}\n />\n </div>\n <SortableContext id={id} items={itemIds} strategy={verticalListSortingStrategy}>\n <div\n ref={setItemsRef}\n className={cx(styles.columnItems, classNames?.items)}\n style={{ maxHeight: columnMaxHeight, ...slotStyles?.items }}\n onScroll={handleItemsScroll}\n >\n {itemIds.length === 0 && emptyPlaceholder != null ? (\n <div className={cx(styles.columnPlaceholder, classNames?.placeholder)} style={slotStyles?.placeholder}>\n {emptyPlaceholder}\n </div>\n ) : null}\n {itemIds.map((itemId) => (\n <KanbanItem\n key={itemId}\n id={itemId}\n label={items[itemId] !== undefined ? getItemLabel?.(items[itemId], itemId) : undefined}\n dragHandle={dragHandle}\n disabled={\n disabled || (items[itemId] !== undefined && (getItemDisabled?.(items[itemId], itemId) ?? false))\n }\n preventAsDropTarget={disabled}\n >\n {items[itemId] !== undefined ? renderItem(items[itemId], itemId) : null}\n </KanbanItem>\n ))}\n {isLoadingMore && (\n <div\n className={cx(styles.columnLoadingIndicator, classNames?.loadingIndicator)}\n style={slotStyles?.loadingIndicator}\n >\n <Loader size='2.6em' />\n </div>\n )}\n </div>\n </SortableContext>\n </div>\n );\n}\n\nexport default KanbanColumn;\n"],"mappings":"4dAkBA,IAAM,EAAuB,CAAE,KAAM,QAAS,EACxC,EAA2B,CAAE,UAAW,GAAM,UAAW,EAAK,EAoDpE,SAAgB,EAAoB,CAClC,QACA,QACA,WACA,UACA,aACA,aACA,OAAQ,GACmB,CAC3B,IAAM,EAAc,GAAY,MAAQ,EAAQ,EAChD,OACE,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,OAAD,CAAM,GAAI,EAAY,UAAW,EAAO,kBACrC,SAAA,CACG,CAAA,EACN,EAAC,MAAD,CAAK,UAAW,EAAO,qBAAvB,SAAA,CACG,GAAY,MACX,EAAC,OAAD,CACE,UAAW,EAAG,EAAO,kBAAmB,GAAe,EAAO,sBAAuB,GAAY,KAAK,EACtG,MAAO,GAAY,MAFrB,SAAA,CAIG,EAAM,IAAE,CACL,CAEP,CAAA,EAAA,GAAW,MACV,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,oBAAqB,GAAY,OAAO,EAAG,MAAO,GAAY,QACrF,SAAA,CACE,CAAA,CAEJ,CACL,CAAA,CAAA,CAAA,CAAA,CAEN,CAEA,SAAS,EAAgB,CACvB,KACA,QACA,UACA,QACA,aACA,aACA,YACA,WACA,WACA,kBACA,eACA,mBACA,UACA,cACA,iBACA,kBACA,UACA,aACA,oBAAoB,IACpB,YACA,QACA,aACA,OAAQ,EACR,GAAG,GAC4B,CAC/B,IAAM,EAAc,UAAU,IACxB,CAAE,aAAY,UAAW,EAAa,CAAE,GAAI,EAAa,UAAS,CAAC,EACnE,EAAc,GAAY,MAAQ,EAAQ,OAAS,EAEnD,EAAW,EAA8B,IAAI,EAC7C,EAAc,EACjB,GAAgC,CAC/B,EAAS,QAAU,EACnB,EAAW,CAAI,CACjB,EACA,CAAC,CAAU,CACb,EACM,EAAmB,EAAO,EAAK,EAC/B,CAAC,EAAe,GAAoB,EAAS,EAAK,EAElD,EAAkB,MAAkB,CACnC,GAAc,GAAiB,UACpC,EAAiB,QAAU,GAC3B,EAAiB,EAAI,EACrB,QAAQ,QAAQ,EAAW,CAAC,CAAC,CAAC,YAAc,CAC1C,EAAiB,QAAU,GAC3B,EAAiB,EAAK,CACxB,CAAC,EACH,EAAG,CAAC,CAAU,CAAC,EAET,EAAoB,EACvB,GAAmC,CAClC,GAAI,CAAC,EAAS,OACd,IAAM,EAAK,EAAM,cACb,EAAG,UAAY,EAAG,cAAgB,EAAG,aAAe,GAAmB,EAAgB,CAC7F,EACA,CAAC,EAAS,EAAmB,CAAe,CAC9C,EAUM,EAAe,EAAO,EAAE,EAC9B,MAAgB,CACd,GAAI,CAAC,GAAW,EAAe,OAC/B,IAAM,EAAK,EAAS,QACpB,GAAI,CAAC,GAAM,EAAG,eAAiB,EAAG,OAClC,IAAM,EAAO,EAAG,iBACV,EAAgB,WAAW,iBAAiB,CAAE,CAAC,CAAC,aAAa,GAAK,EACxE,IAAK,EAAO,EAAK,UAAY,EAAK,aAAe,GAAK,GAAiB,EAAG,aAAe,EAAG,OAC5F,IAAM,EAAQ,GAAG,EAAQ,OAAO,GAAG,EAAG,eAClC,EAAa,UAAY,IAC7B,EAAa,QAAU,EACvB,EAAgB,EAClB,EAAG,CAAC,EAAS,EAAe,EAAQ,OAAQ,CAAe,CAAC,EAE5D,GAAM,CACJ,WAAY,GACZ,UAAW,GACX,WAAY,GACZ,oBAAqB,GACrB,UAAW,GACX,WAAY,GACZ,WAAY,GACZ,OAAQ,IACN,EAAY,CACd,KACA,KAAM,EACN,SAAU,IAAsB,CAClC,CAAC,EAED,OACE,EAAC,MAAD,CACE,GAAI,EACJ,IAAK,GACD,KACJ,qBAAmB,GACnB,UAAW,EACT,EAAO,OACP,GAAU,CAAC,GAAkB,EAAO,WACpC,IAAgB,EAAO,iBACvB,GAAa,EAAO,gBACpB,GAAe,EAAO,gBACtB,GAAY,EAAO,eACnB,IAAoB,EAAO,eAC3B,CACF,EACA,MAAO,CAAE,UAAW,EAAI,UAAU,SAAS,EAAe,EAAG,WAAY,GAAkB,GAAG,CAAM,EAftG,SAAA,CAoBE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,aAAc,GAAe,EAAO,wBAAyB,GAAY,MAAM,EACpG,MAAO,GAAY,OACnB,GAAK,EAAc,GAAkB,IAAA,GAErC,SAAA,EAAC,EAAD,CACS,QACP,MAAO,EAAQ,OACL,WACD,UACT,WACE,EAAc,CAAE,GAAG,GAAkB,IAAK,GAAuB,qBAAsB,EAAG,EAAI,IAAA,GAEpF,aACZ,OAAQ,CACT,CAAA,CACE,CAAA,EACL,EAAC,EAAD,CAAqB,KAAI,MAAO,EAAS,SAAU,EACjD,SAAA,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAG,EAAO,YAAa,GAAY,KAAK,EACnD,MAAO,CAAE,UAAW,EAAiB,GAAG,GAAY,KAAM,EAC1D,SAAU,EAJZ,SAAA,CAMG,EAAQ,SAAW,GAAK,GAAoB,KAC3C,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,kBAAmB,GAAY,WAAW,EAAG,MAAO,GAAY,YACvF,SAAA,CACE,CAAA,EACH,KACH,EAAQ,IAAK,GACZ,EAAC,EAAD,CAEE,GAAI,EACJ,MAAO,EAAM,KAAY,IAAA,GAAoD,IAAA,GAAxC,IAAe,EAAM,GAAS,CAAM,EAC7D,aACZ,SACE,GAAa,EAAM,KAAY,IAAA,KAAc,IAAkB,EAAM,GAAS,CAAM,GAAK,IAE3F,oBAAqB,EAEpB,SAAA,EAAM,KAAY,IAAA,GAAgD,KAApC,EAAW,EAAM,GAAS,CAAM,CACrD,EAVL,CAUK,CACb,EACA,GACC,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,uBAAwB,GAAY,gBAAgB,EACzE,MAAO,GAAY,iBAEnB,SAAA,EAAC,EAAD,CAAQ,KAAK,OAAS,CAAA,CACnB,CAAA,CAEJ,GACU,CAAA,CACd,GAET"}
@@ -1,2 +1,2 @@
1
- "use client";import e from"./kanbanBoard.module.mjs";import t from"classnames";import{jsx as n}from"react/jsx-runtime";import{useSortable as r}from"@dnd-kit/sortable";import{CSS as i}from"@dnd-kit/utilities";var a={draggable:!0,droppable:!0},o={draggable:!0,droppable:!1};function s({id:s,dragHandle:c,disabled:l,preventAsDropTarget:u,children:d}){let{attributes:f,listeners:p,setNodeRef:m,transform:h,transition:g,isDragging:_}=r({id:s,disabled:l?u?a:o:void 0});function v(e){e.target.closest(`[data-drag-handle]`)&&p?.onPointerDown?.(e)}return n(`div`,{ref:m,style:{transform:i.Transform.toString(h),transition:g},className:t(e.item,c&&e.itemHandled,_&&e.itemDragging,l&&e.itemDisabled),...f,...p,onPointerDown:c?v:p?.onPointerDown,children:d})}export{s as default};
1
+ "use client";import e from"./kanbanBoard.module.mjs";import{useCallback as t,useLayoutEffect as n,useRef as r}from"react";import i from"classnames";import{jsx as a}from"react/jsx-runtime";import{useSortable as o}from"@dnd-kit/sortable";import{CSS as s}from"@dnd-kit/utilities";var c={draggable:!0,droppable:!0},l={draggable:!0,droppable:!1};function u({id:u,label:d,dragHandle:f,disabled:p,preventAsDropTarget:m,children:h}){let{attributes:g,listeners:_,setNodeRef:v,setActivatorNodeRef:y,transform:b,transition:x,isDragging:S}=o({id:u,disabled:p?m?c:l:void 0}),C=r(null),w=t(e=>{C.current=e,v(e),f||y(e)},[v,y,f]);n(()=>{if(!f)return;let e=C.current?.querySelector(`[data-drag-handle]`)??null;if(y(e),!e)return;e.tabIndex<0&&(e.tabIndex=0),e.tagName!==`BUTTON`&&!e.hasAttribute(`role`)&&e.setAttribute(`role`,`button`);let t=e.hasAttribute(`data-kanban-label`);d&&(t||!(e.hasAttribute(`aria-label`)||e.hasAttribute(`aria-labelledby`)))&&(e.setAttribute(`aria-label`,d),e.setAttribute(`data-kanban-label`,``)),e.setAttribute(`data-kanban-card`,``);for(let[t,n]of Object.entries(g))t!==`role`&&t!==`tabIndex`&&(n===void 0?e.removeAttribute(t):e.setAttribute(t,String(n)))});let T=f&&_?Object.fromEntries(Object.entries(_).map(([e,t])=>[e,e=>{e.target.closest(`[data-drag-handle]`)&&t(e)}])):_;return a(`div`,{ref:w,"data-kanban-card":f?void 0:``,style:{transform:s.Transform.toString(b),transition:x},className:i(e.item,f&&e.itemHandled,S&&e.itemDragging,p&&e.itemDisabled),...f?void 0:g,...T,children:h})}export{u as default};
2
2
  //# sourceMappingURL=KanbanItem.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanItem.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanItem.tsx"],"sourcesContent":["import type { PointerEvent as ReactPointerEvent, PointerEventHandler } from 'react';\nimport { useSortable } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport cx from 'classnames';\n\nimport type { KanbanItemProps } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\n\n// Hoisted so these are referentially stable across renders — an inline object literal here would\n// give `useSortable` a new `disabled` value every render (every card re-renders on every\n// `dragOver` while a drag is in progress, via `shadowColumns`), which can spin dnd-kit's own\n// registration effect into a render loop that eventually trips React's \"Maximum update depth\n// exceeded\" guard. Same fix as the sensor options in `KanbanBoard.tsx` and `data`/`disabled` in\n// `KanbanColumn.tsx`. Only two shapes are ever needed, so both are hoisted rather than memoized.\nconst ITEM_DISABLED_DRAG_AND_DROP = { draggable: true, droppable: true };\nconst ITEM_DISABLED_DRAG_ONLY = { draggable: true, droppable: false };\n\nfunction KanbanItem({ id, dragHandle, disabled, preventAsDropTarget, children }: KanbanItemProps) {\n const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({\n id,\n // The boolean shorthand only disables dragging *out* of the card — dnd-kit hard-codes\n // `droppable: false` for it either way (\"backwards compatibility\"). That's actually what we\n // want for a card pinned individually (`getItemDisabled`): it can't be dragged, but other\n // cards should still be able to land before/after it normally. Only a frozen *column*\n // (`preventAsDropTarget`) also disables droppable, so nothing can be dropped into it at all.\n disabled: disabled ? (preventAsDropTarget ? ITEM_DISABLED_DRAG_AND_DROP : ITEM_DISABLED_DRAG_ONLY) : undefined,\n });\n\n function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>) {\n if (!(event.target as HTMLElement).closest('[data-drag-handle]')) return;\n listeners?.onPointerDown?.(event);\n }\n\n return (\n <div\n ref={setNodeRef}\n style={{ transform: CSS.Transform.toString(transform), transition }}\n className={cx(\n styles.item,\n dragHandle && styles.itemHandled,\n isDragging && styles.itemDragging,\n disabled && styles.itemDisabled,\n )}\n {...attributes}\n {...listeners}\n onPointerDown={\n dragHandle ? handlePointerDown : (listeners?.onPointerDown as PointerEventHandler<HTMLDivElement> | undefined)\n }\n >\n {children}\n </div>\n );\n}\n\nexport default KanbanItem;\n"],"mappings":"gNAcA,IAAM,EAA8B,CAAE,UAAW,GAAM,UAAW,EAAK,EACjE,EAA0B,CAAE,UAAW,GAAM,UAAW,EAAM,EAEpE,SAAS,EAAW,CAAE,KAAI,aAAY,WAAU,sBAAqB,YAA6B,CAChG,GAAM,CAAE,aAAY,YAAW,aAAY,YAAW,aAAY,cAAe,EAAY,CAC3F,KAMA,SAAU,EAAY,EAAsB,EAA8B,EAA2B,IAAA,EACvG,CAAC,EAED,SAAS,EAAkB,EAA0C,CAC7D,EAAM,OAAuB,QAAQ,oBAAoB,GAC/D,GAAW,gBAAgB,CAAK,CAClC,CAEA,OACE,EAAC,MAAD,CACE,IAAK,EACL,MAAO,CAAE,UAAW,EAAI,UAAU,SAAS,CAAS,EAAG,YAAW,EAClE,UAAW,EACT,EAAO,KACP,GAAc,EAAO,YACrB,GAAc,EAAO,aACrB,GAAY,EAAO,YACrB,EACA,GAAI,EACJ,GAAI,EACJ,cACE,EAAa,EAAqB,GAAW,cAG9C,UACE,CAAA,CAET"}
1
+ {"version":3,"file":"KanbanItem.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/KanbanItem.tsx"],"sourcesContent":["import type { SyntheticEvent } from 'react';\nimport { useCallback, useLayoutEffect, useRef } from 'react';\nimport { useSortable } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport cx from 'classnames';\n\nimport type { KanbanItemProps } from './kanbanBoard.types';\nimport styles from './kanbanBoard.module.pcss';\n\n// Hoisted so these are referentially stable across renders — an inline object literal here would\n// give `useSortable` a new `disabled` value every render (every card re-renders on every\n// `dragOver` while a drag is in progress, via the board's `placement`), which can spin dnd-kit's own\n// registration effect into a render loop that eventually trips React's \"Maximum update depth\n// exceeded\" guard. Same fix as the sensor options in `KanbanBoard.tsx` and `data`/`disabled` in\n// `KanbanColumn.tsx`. Only two shapes are ever needed, so both are hoisted rather than memoized.\nconst ITEM_DISABLED_DRAG_AND_DROP = { draggable: true, droppable: true };\nconst ITEM_DISABLED_DRAG_ONLY = { draggable: true, droppable: false };\n\nfunction KanbanItem({ id, label, dragHandle, disabled, preventAsDropTarget, children }: KanbanItemProps) {\n const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({\n id,\n // The boolean shorthand only disables dragging *out* of the card — dnd-kit hard-codes\n // `droppable: false` for it either way (\"backwards compatibility\"). That's actually what we\n // want for a card pinned individually (`getItemDisabled`): it can't be dragged, but other\n // cards should still be able to land before/after it normally. Only a frozen *column*\n // (`preventAsDropTarget`) also disables droppable, so nothing can be dropped into it at all.\n disabled: disabled ? (preventAsDropTarget ? ITEM_DISABLED_DRAG_AND_DROP : ITEM_DISABLED_DRAG_ONLY) : undefined,\n });\n\n // Without an activator, dnd-kit starts a drag for a Space or Enter bubbling up from anything\n // inside the card, and cancels it: a button in the card could not be pressed, nor a space typed.\n const nodeRef = useRef<HTMLDivElement | null>(null);\n const setRefs = useCallback(\n (node: HTMLDivElement | null) => {\n nodeRef.current = node;\n setNodeRef(node);\n if (!dragHandle) setActivatorNodeRef(node);\n },\n [setNodeRef, setActivatorNodeRef, dragHandle],\n );\n\n // With `dragHandle`, the handle is the keyboard handle too, and the card a plain container: as a\n // button, the card wrapped its own controls, which a screen reader then reads as text. The\n // handle is the consumer's element, so it gets the drag semantics here rather than as props.\n // No dependencies: the consumer can re-render the handle at any time.\n useLayoutEffect(() => {\n if (!dragHandle) return;\n const handle = nodeRef.current?.querySelector<HTMLElement>('[data-drag-handle]') ?? null;\n setActivatorNodeRef(handle);\n if (!handle) return;\n if (handle.tabIndex < 0) handle.tabIndex = 0;\n if (handle.tagName !== 'BUTTON' && !handle.hasAttribute('role')) handle.setAttribute('role', 'button');\n const namedByUs = handle.hasAttribute('data-kanban-label');\n if (label && (namedByUs || !(handle.hasAttribute('aria-label') || handle.hasAttribute('aria-labelledby')))) {\n handle.setAttribute('aria-label', label);\n handle.setAttribute('data-kanban-label', '');\n }\n handle.setAttribute('data-kanban-card', '');\n for (const [name, value] of Object.entries(attributes)) {\n if (name === 'role' || name === 'tabIndex') continue;\n if (value === undefined) handle.removeAttribute(name);\n else handle.setAttribute(name, String(value));\n }\n });\n\n // dnd-kit's listeners are a new object every render, so wrapping them per render costs nothing.\n const handleListeners =\n dragHandle && listeners\n ? Object.fromEntries(\n Object.entries(listeners).map(([name, listener]) => [\n name,\n (event: SyntheticEvent) => {\n if ((event.target as HTMLElement).closest('[data-drag-handle]')) listener(event);\n },\n ]),\n )\n : listeners;\n\n return (\n <div\n ref={setRefs}\n data-kanban-card={dragHandle ? undefined : ''}\n style={{ transform: CSS.Transform.toString(transform), transition }}\n className={cx(\n styles.item,\n dragHandle && styles.itemHandled,\n isDragging && styles.itemDragging,\n disabled && styles.itemDisabled,\n )}\n {...(dragHandle ? undefined : attributes)}\n {...handleListeners}\n >\n {children}\n </div>\n );\n}\n\nexport default KanbanItem;\n"],"mappings":"qRAeA,IAAM,EAA8B,CAAE,UAAW,GAAM,UAAW,EAAK,EACjE,EAA0B,CAAE,UAAW,GAAM,UAAW,EAAM,EAEpE,SAAS,EAAW,CAAE,KAAI,QAAO,aAAY,WAAU,sBAAqB,YAA6B,CACvG,GAAM,CAAE,aAAY,YAAW,aAAY,sBAAqB,YAAW,aAAY,cAAe,EAAY,CAChH,KAMA,SAAU,EAAY,EAAsB,EAA8B,EAA2B,IAAA,EACvG,CAAC,EAIK,EAAU,EAA8B,IAAI,EAC5C,EAAU,EACb,GAAgC,CAC/B,EAAQ,QAAU,EAClB,EAAW,CAAI,EACV,GAAY,EAAoB,CAAI,CAC3C,EACA,CAAC,EAAY,EAAqB,CAAU,CAC9C,EAMA,MAAsB,CACpB,GAAI,CAAC,EAAY,OACjB,IAAM,EAAS,EAAQ,SAAS,cAA2B,oBAAoB,GAAK,KAEpF,GADA,EAAoB,CAAM,EACtB,CAAC,EAAQ,OACT,EAAO,SAAW,IAAG,EAAO,SAAW,GACvC,EAAO,UAAY,UAAY,CAAC,EAAO,aAAa,MAAM,GAAG,EAAO,aAAa,OAAQ,QAAQ,EACrG,IAAM,EAAY,EAAO,aAAa,mBAAmB,EACrD,IAAU,GAAa,EAAE,EAAO,aAAa,YAAY,GAAK,EAAO,aAAa,iBAAiB,MACrG,EAAO,aAAa,aAAc,CAAK,EACvC,EAAO,aAAa,oBAAqB,EAAE,GAE7C,EAAO,aAAa,mBAAoB,EAAE,EAC1C,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAU,EAC/C,IAAS,QAAU,IAAS,aAC5B,IAAU,IAAA,GAAW,EAAO,gBAAgB,CAAI,EAC/C,EAAO,aAAa,EAAM,OAAO,CAAK,CAAC,EAEhD,CAAC,EAGD,IAAM,EACJ,GAAc,EACV,OAAO,YACL,OAAO,QAAQ,CAAS,CAAC,CAAC,KAAK,CAAC,EAAM,KAAc,CAClD,EACC,GAA0B,CACpB,EAAM,OAAuB,QAAQ,oBAAoB,GAAG,EAAS,CAAK,CACjF,CACF,CAAC,CACH,EACA,EAEN,OACE,EAAC,MAAD,CACE,IAAK,EACL,mBAAkB,EAAa,IAAA,GAAY,GAC3C,MAAO,CAAE,UAAW,EAAI,UAAU,SAAS,CAAS,EAAG,YAAW,EAClE,UAAW,EACT,EAAO,KACP,GAAc,EAAO,YACrB,GAAc,EAAO,aACrB,GAAY,EAAO,YACrB,EACA,GAAK,EAAa,IAAA,GAAY,EAC9B,GAAI,EAEH,UACE,CAAA,CAET"}
@@ -1,2 +1,2 @@
1
- "use client";var e=`board_6KRdw`,t=`column_NrNeF`,n=`column-empty_5KYsJ`,r=`column-over_sO7oD`,i=`column-over-limit_QmeZF`,a=`column-drop-target_mznmc`,o=`column-disabled_ehcz3`,s=`column-items_xY5er`,c=`column-dragging_6F5TK`,l=`column-drag-overlay_ctehQ`,u=`column-header_PLeKG`,d=`column-header-reorderable_Jtgii`,f=`column-header-title_FQhHQ`,p=`column-header-count_3t83e`,m=`column-header-count-over_AkAdo`,h=`column-header-trailing_6625D`,g=`column-header-actions_XKY3t`,_=`column-placeholder_WGyF-`,v=`column-loading-indicator_2Q70t`,y=`item_T8CJK`,b=`item-dragging_iWurw`,x=`item-handled_l28gq`,S=`item-disabled_n8Nuq`,C=`dragOverlay_DSyKz`,w={board:e,column:t,"column-empty":`column-empty_5KYsJ`,columnEmpty:n,"column-over":`column-over_sO7oD`,columnOver:r,"column-over-limit":`column-over-limit_QmeZF`,columnOverLimit:i,"column-drop-target":`column-drop-target_mznmc`,columnDropTarget:a,"column-disabled":`column-disabled_ehcz3`,columnDisabled:o,"column-items":`column-items_xY5er`,columnItems:s,"column-dragging":`column-dragging_6F5TK`,columnDragging:c,"column-drag-overlay":`column-drag-overlay_ctehQ`,columnDragOverlay:l,"column-header":`column-header_PLeKG`,columnHeader:u,"column-header-reorderable":`column-header-reorderable_Jtgii`,columnHeaderReorderable:d,"column-header-title":`column-header-title_FQhHQ`,columnHeaderTitle:f,"column-header-count":`column-header-count_3t83e`,columnHeaderCount:p,"column-header-count-over":`column-header-count-over_AkAdo`,columnHeaderCountOver:m,"column-header-trailing":`column-header-trailing_6625D`,columnHeaderTrailing:h,"column-header-actions":`column-header-actions_XKY3t`,columnHeaderActions:g,"column-placeholder":`column-placeholder_WGyF-`,columnPlaceholder:_,"column-loading-indicator":`column-loading-indicator_2Q70t`,columnLoadingIndicator:v,item:y,"item-dragging":`item-dragging_iWurw`,itemDragging:b,"item-handled":`item-handled_l28gq`,itemHandled:x,"item-disabled":`item-disabled_n8Nuq`,itemDisabled:S,dragOverlay:C};export{e as board,t as column,o as columnDisabled,l as columnDragOverlay,c as columnDragging,a as columnDropTarget,n as columnEmpty,u as columnHeader,g as columnHeaderActions,p as columnHeaderCount,m as columnHeaderCountOver,d as columnHeaderReorderable,f as columnHeaderTitle,h as columnHeaderTrailing,s as columnItems,v as columnLoadingIndicator,r as columnOver,i as columnOverLimit,_ as columnPlaceholder,w as default,C as dragOverlay,y as item,S as itemDisabled,b as itemDragging,x as itemHandled};
1
+ "use client";var e=`board_6KRdw`,t=`column_NrNeF`,n=`column-collapsed_D0lOV`,r=`column-header_PLeKG`,i=`column-header-title_FQhHQ`,a=`column-over_sO7oD`,o=`column-over-limit_QmeZF`,s=`column-drop-target_mznmc`,c=`column-disabled_ehcz3`,l=`column-items_xY5er`,u=`column-dragging_6F5TK`,d=`column-drag-overlay_ctehQ`,f=`column-header-reorderable_Jtgii`,p=`column-header-count_3t83e`,m=`column-header-count-over_AkAdo`,h=`column-header-trailing_6625D`,g=`column-header-actions_XKY3t`,_=`column-placeholder_WGyF-`,v=`column-loading-indicator_2Q70t`,y=`item_T8CJK`,b=`item-dragging_iWurw`,x=`item-handled_l28gq`,S=`item-disabled_n8Nuq`,C=`dragOverlay_DSyKz`,w={board:e,column:t,"column-collapsed":`column-collapsed_D0lOV`,columnCollapsed:n,"column-header":`column-header_PLeKG`,columnHeader:r,"column-header-title":`column-header-title_FQhHQ`,columnHeaderTitle:i,"column-over":`column-over_sO7oD`,columnOver:a,"column-over-limit":`column-over-limit_QmeZF`,columnOverLimit:o,"column-drop-target":`column-drop-target_mznmc`,columnDropTarget:s,"column-disabled":`column-disabled_ehcz3`,columnDisabled:c,"column-items":`column-items_xY5er`,columnItems:l,"column-dragging":`column-dragging_6F5TK`,columnDragging:u,"column-drag-overlay":`column-drag-overlay_ctehQ`,columnDragOverlay:d,"column-header-reorderable":`column-header-reorderable_Jtgii`,columnHeaderReorderable:f,"column-header-count":`column-header-count_3t83e`,columnHeaderCount:p,"column-header-count-over":`column-header-count-over_AkAdo`,columnHeaderCountOver:m,"column-header-trailing":`column-header-trailing_6625D`,columnHeaderTrailing:h,"column-header-actions":`column-header-actions_XKY3t`,columnHeaderActions:g,"column-placeholder":`column-placeholder_WGyF-`,columnPlaceholder:_,"column-loading-indicator":`column-loading-indicator_2Q70t`,columnLoadingIndicator:v,item:y,"item-dragging":`item-dragging_iWurw`,itemDragging:b,"item-handled":`item-handled_l28gq`,itemHandled:x,"item-disabled":`item-disabled_n8Nuq`,itemDisabled:S,dragOverlay:C};export{e as board,t as column,n as columnCollapsed,c as columnDisabled,d as columnDragOverlay,u as columnDragging,s as columnDropTarget,r as columnHeader,g as columnHeaderActions,p as columnHeaderCount,m as columnHeaderCountOver,f as columnHeaderReorderable,i as columnHeaderTitle,h as columnHeaderTrailing,l as columnItems,v as columnLoadingIndicator,a as columnOver,o as columnOverLimit,_ as columnPlaceholder,w as default,C as dragOverlay,y as item,S as itemDisabled,b as itemDragging,x as itemHandled};
2
2
  //# sourceMappingURL=kanbanBoard.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"kanbanBoard.module.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/kanbanBoard.module.pcss"],"sourcesContent":[".board {\n display: flex;\n gap: var(--spacing-s);\n overflow-x: auto;\n align-items: flex-start;\n width: 100%;\n}\n\n.column {\n background: var(--background-accent-light);\n border-radius: var(--default-border-radius);\n box-shadow: var(--card-shadow);\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n border: 2px solid transparent;\n transition:\n border-color 0.15s ease,\n background 0.15s ease;\n\n &-empty {\n flex: 0 1 0;\n min-width: var(--kanban-empty-column-width, 140px);\n }\n\n &-over {\n border-color: var(--primary-lighter);\n background: var(--background-accent);\n }\n\n &-over-limit {\n border-color: var(--warn-color);\n }\n\n /* A whole column being dragged over this one, reordering — distinct from -over (a card being\n dropped into this column's card list), even though both are dashed-free solid borders here;\n kept as a separate class so consumers can restyle one without affecting the other. */\n &-drop-target {\n border-color: var(--primary-color);\n background: var(--background-accent);\n }\n\n /* Dims only the cards area, not the header — header actions (e.g. an \"add card\" button) are\n consumer-controlled and often meant to stay fully interactive even while the column itself\n is frozen for dragging, and opacity on an ancestor can't be undone by a child's own opacity. */\n &-disabled &-items {\n opacity: 0.6;\n }\n\n &-dragging {\n opacity: 0.4;\n }\n\n &-drag-overlay {\n cursor: grabbing;\n box-shadow:\n 0 10px 30px rgb(0 0 0 / 25%),\n var(--card-shadow);\n min-width: 220px;\n }\n\n &-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-s);\n padding: var(--spacing-m) var(--spacing-l);\n background: var(--background-accent);\n border-radius: var(--default-border-radius) var(--default-border-radius) 0 0;\n font-size: var(--header-small-font-size);\n font-weight: var(--header-font-weight);\n color: var(--text-color);\n border-bottom: 1px solid var(--border-color);\n\n &-reorderable {\n cursor: grab;\n -webkit-tap-highlight-color: transparent;\n touch-action: none;\n\n &:active {\n cursor: grabbing;\n }\n }\n\n &-title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &-count {\n flex-shrink: 0;\n font-size: var(--default-font-size);\n font-weight: var(--default-font-weight);\n color: var(--text-dark);\n\n &-over {\n color: var(--warn-color);\n font-weight: var(--header-font-weight);\n }\n }\n\n &-trailing {\n display: flex;\n align-items: center;\n gap: var(--spacing-s);\n flex-shrink: 0;\n }\n\n &-actions {\n display: flex;\n align-items: center;\n gap: var(--spacing-s);\n }\n }\n\n &-items {\n padding: var(--spacing-m);\n display: flex;\n flex-direction: column;\n gap: var(--spacing-m);\n min-height: 80px;\n flex: 1;\n }\n\n &-placeholder {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: var(--text-dark);\n font-size: var(--default-font-size);\n }\n\n &-loading-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-s) 0;\n }\n}\n\n.item {\n cursor: grab;\n touch-action: none;\n\n &:active {\n cursor: grabbing;\n }\n\n &-dragging {\n opacity: 0.4;\n }\n\n &-handled {\n cursor: default;\n touch-action: auto;\n\n &:active {\n cursor: default;\n }\n\n [data-drag-handle] {\n cursor: grab;\n -webkit-tap-highlight-color: transparent;\n touch-action: none;\n }\n\n [data-drag-handle]:active {\n cursor: grabbing;\n }\n }\n\n &-disabled {\n cursor: not-allowed;\n\n &:active {\n cursor: not-allowed;\n }\n\n [data-drag-handle] {\n cursor: not-allowed;\n }\n\n [data-drag-handle]:active {\n cursor: not-allowed;\n }\n }\n}\n\n.dragOverlay {\n border-radius: var(--default-border-radius);\n cursor: grabbing;\n box-shadow:\n 0 10px 30px rgb(0 0 0 / 25%),\n var(--card-shadow);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"kanbanBoard.module.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/kanbanBoard.module.pcss"],"sourcesContent":["/* Columns stretch to the tallest one, so the space below a column's cards is still its drop zone.\n Sized to its content, an empty column was a short box, and a card dropped below it landed in\n the neighbouring column. */\n.board {\n display: flex;\n gap: var(--spacing-s);\n overflow-x: auto;\n width: 100%;\n}\n\n.column {\n background: var(--background-accent-light);\n border-radius: var(--default-border-radius);\n box-shadow: var(--card-shadow);\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n border: 2px solid transparent;\n transition:\n border-color 0.15s ease,\n background 0.15s ease;\n\n &-collapsed {\n flex: 0 1 0;\n min-width: var(--kanban-empty-column-width, 140px);\n }\n\n /* Too narrow for the title beside the count and actions, which cut it to \"I…\": they wrap below. */\n &-collapsed &-header {\n flex-wrap: wrap;\n }\n\n &-collapsed &-header-title {\n white-space: normal;\n }\n\n &-over {\n border-color: var(--primary-lighter);\n background: var(--background-accent);\n }\n\n &-over-limit {\n border-color: var(--warn-color);\n }\n\n /* A whole column being dragged over this one, reordering — distinct from -over (a card being\n dropped into this column's card list), even though both are dashed-free solid borders here;\n kept as a separate class so consumers can restyle one without affecting the other. */\n &-drop-target {\n border-color: var(--primary-color);\n background: var(--background-accent);\n }\n\n /* Dims only the cards area, not the header — header actions (e.g. an \"add card\" button) are\n consumer-controlled and often meant to stay fully interactive even while the column itself\n is frozen for dragging, and opacity on an ancestor can't be undone by a child's own opacity. */\n &-disabled &-items {\n opacity: 0.6;\n }\n\n &-dragging {\n opacity: 0.4;\n }\n\n &-drag-overlay {\n cursor: grabbing;\n box-shadow:\n 0 10px 30px rgb(0 0 0 / 25%),\n var(--card-shadow);\n min-width: 220px;\n }\n\n &-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-s);\n padding: var(--spacing-m) var(--spacing-l);\n background: var(--background-accent);\n border-radius: var(--default-border-radius) var(--default-border-radius) 0 0;\n font-size: var(--header-small-font-size);\n font-weight: var(--header-font-weight);\n color: var(--text-color);\n border-bottom: 1px solid var(--border-color);\n\n &-reorderable {\n cursor: grab;\n -webkit-tap-highlight-color: transparent;\n touch-action: none;\n user-select: none;\n\n &:active {\n cursor: grabbing;\n }\n }\n\n &-title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &:focus-visible {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n border-radius: var(--default-border-radius);\n }\n }\n\n &-count {\n flex-shrink: 0;\n font-size: var(--default-font-size);\n font-weight: var(--default-font-weight);\n color: var(--text-dark);\n\n &-over {\n color: var(--warn-color);\n font-weight: var(--header-font-weight);\n }\n }\n\n &-trailing {\n display: flex;\n align-items: center;\n gap: var(--spacing-s);\n flex-shrink: 0;\n }\n\n &-actions {\n display: flex;\n align-items: center;\n gap: var(--spacing-s);\n }\n }\n\n /* Scrolls once something bounds it: `columnMaxHeight`, or a height given to the board. A board\n that grows with its cards never makes it overflow. `position` makes its cards' `offsetTop`\n relative to it, which the load-more probe measures. */\n &-items {\n position: relative;\n padding: var(--spacing-m);\n display: flex;\n flex-direction: column;\n gap: var(--spacing-m);\n min-height: 80px;\n flex: 1;\n overflow-y: auto;\n }\n\n &-placeholder {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n color: var(--text-dark);\n font-size: var(--default-font-size);\n }\n\n &-loading-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-s) 0;\n }\n}\n\n/* A press that can start a text selection lets Chromium scroll the page while the button is held\n near its edge, however far past the board. Where a press starts a drag, it cannot select. */\n.item {\n cursor: grab;\n touch-action: none;\n user-select: none;\n\n &:focus-visible {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n border-radius: var(--default-border-radius);\n }\n\n &:active {\n cursor: grabbing;\n }\n\n &-dragging {\n opacity: 0.4;\n }\n\n &-handled {\n cursor: default;\n touch-action: auto;\n user-select: auto;\n\n &:active {\n cursor: default;\n }\n\n [data-drag-handle] {\n cursor: grab;\n -webkit-tap-highlight-color: transparent;\n touch-action: none;\n user-select: none;\n\n &:focus-visible {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n border-radius: var(--default-border-radius);\n }\n }\n\n [data-drag-handle]:active {\n cursor: grabbing;\n }\n }\n\n &-disabled {\n cursor: not-allowed;\n\n &:active {\n cursor: not-allowed;\n }\n\n [data-drag-handle] {\n cursor: not-allowed;\n }\n\n [data-drag-handle]:active {\n cursor: not-allowed;\n }\n }\n}\n\n.dragOverlay {\n border-radius: var(--default-border-radius);\n cursor: grabbing;\n box-shadow:\n 0 10px 30px rgb(0 0 0 / 25%),\n var(--card-shadow);\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- "use client";import{KeyboardCode as e,closestCorners as t}from"@dnd-kit/core";import{arrayMove as n,hasSortableData as r}from"@dnd-kit/sortable";function i(e,t){return e.length===t.length&&e.every((e,n)=>{let r=t[n];return e.id===r.id&&e.itemIds.length===r.itemIds.length&&e.itemIds.every((e,t)=>e===r.itemIds[t])})}function a(e,t){return e.findIndex(e=>e.itemIds.includes(t))}function o(e){return!!(e&&typeof e==`object`&&e.type===`column`)}function s(e,t,r){let i=e.findIndex(e=>e.id===t),a=e.findIndex(e=>e.id===r);return i===-1||a===-1||i===a?e:n(e,i,a)}var c=e=>{let n=o(e.active.data.current),r=e.droppableContainers.filter(e=>n?o(e.data.current):!o(e.data.current));return t({...e,droppableContainers:r})};function l(e){return e.startsWith(`column-`)?e.slice(7):null}function u(e,t,r,i){let o=a(e,t);if(o===-1)return e;let s=l(r),c=s===null?a(e,r):e.findIndex(e=>e.id===s);if(c===-1)return e;if(o===c){let a=e[o],c=a.itemIds.indexOf(t);if(c===-1)return e;if(s!==null){let{activeRect:t,overRect:r}=i,s=t&&t.top+t.height/2>r.top+r.height/2?a.itemIds.length-1:0;if(s===c)return e;let l=[...e];return l[o]={...a,itemIds:n(a.itemIds,c,s)},l}let l=a.itemIds.indexOf(r);if(l===-1||c===l)return e;let u=[...e];return u[o]={...a,itemIds:n(a.itemIds,c,l)},u}let u=e[o],d=e[c],f=[...d.itemIds],{activeRect:p,overRect:m}=i,h;if(s!==null)h=p&&p.top+p.height/2>m.top+m.height/2?f.length:0;else{let e=f.indexOf(r),t=e!==-1&&e===f.length-1,n=!!(p&&p.top+p.height/2>m.top+m.height);h=e===-1?f.length:t&&n?e+1:e}f.splice(h,0,t);let g=[...e];return g[o]={...u,itemIds:u.itemIds.filter(e=>e!==t)},g[c]={...d,itemIds:f},g}function d(e,t,n){function r(e){let r=t[e];return r===void 0?e:n(r,e)}function i(t){let n=l(t);if(n!==null){let t=e.find(e=>e.id===n);return t?`the ${t.title} column`:`a column`}let i=e.find(e=>e.itemIds.includes(t));return i?`${r(t)}, in the ${i.title} column`:r(t)}function a(t){return e.find(e=>e.id===t)?.title??t}return{onDragStart({active:e}){return o(e.data.current)?`Picked up column ${a(String(e.id))}.`:`Picked up card ${r(String(e.id))}.`},onDragOver({active:e,over:t}){return o(e.data.current)?t?`Column ${a(String(e.id))} is over column ${a(String(t.id))}.`:`Column ${a(String(e.id))} is no longer over a droppable area.`:t?`Card ${r(String(e.id))} is over ${i(String(t.id))}.`:`Card ${r(String(e.id))} is no longer over a droppable area.`},onDragEnd({active:e,over:t}){return o(e.data.current)?t?`Column ${a(String(e.id))} was dropped over column ${a(String(t.id))}.`:`Column ${a(String(e.id))} was dropped.`:t?`Card ${r(String(e.id))} was dropped over ${i(String(t.id))}.`:`Card ${r(String(e.id))} was dropped.`},onDragCancel({active:e}){return o(e.data.current)?`Dragging cancelled. Column ${a(String(e.id))} was returned to its original position.`:`Dragging cancelled. Card ${r(String(e.id))} was returned to its original position.`}}}function f(e,t,n){let i=[];for(let a of e){if(!r(a)||a.data.current.sortable.containerId!==n)continue;let e=t.get(a.id);e&&i.push({container:a,rect:e})}return i.sort((e,t)=>e.rect.top-t.rect.top)}var p=(t,{context:n})=>{let{active:i,collisionRect:a,droppableRects:s,droppableContainers:c}=n;if(!i||!a||!r(i))return;let u=t.code===e.Down||t.code===e.Up,d=t.code===e.Left||t.code===e.Right;if(!u&&!d)return;t.preventDefault();let p=i.data.current.sortable.containerId,m=c.getEnabled();if(o(i.data.current)){if(!d)return;let n=t.code===e.Right?1:-1,r=f(m,s,p).sort((e,t)=>e.rect.left-t.rect.left),o=r.findIndex(e=>e.container.id===i.id);if(o===-1)return;let c=r[o+n];return c?{x:c.rect.left,y:a.top}:void 0}if(u){let n=t.code===e.Down?1:-1,r=f(m,s,p),o=r.findIndex(e=>e.container.id===i.id);if(o===-1)return;let c=r[o+n];return c?{x:a.left,y:c.rect.top}:void 0}let h=t.code===e.Right?1:-1,g=[];for(let e of m){if(l(String(e.id))===null)continue;let t=s.get(e.id);t&&g.push({container:e,rect:t})}g.sort((e,t)=>e.rect.left-t.rect.left);let _=g.findIndex(e=>l(String(e.container.id))===p);if(_===-1)return;let v=g[_+h];if(!v)return;let y=f(m,s,l(String(v.container.id))),b=v.rect;return y.length>0&&(b=y.reduce((e,t)=>Math.abs(t.rect.top-a.top)<Math.abs(e.rect.top-a.top)?t:e).rect),{x:b.left,y:b.top}};export{d as buildAnnouncements,i as columnsEqual,a as findColumnForItem,o as isColumnDragData,c as kanbanCollisionDetection,p as kanbanKeyboardCoordinateGetter,s as moveColumn,u as moveItem,l as resolveColumnDropId};
1
+ "use client";import{KeyboardCode as e,closestCorners as t}from"@dnd-kit/core";import{arrayMove as n,hasSortableData as r}from"@dnd-kit/sortable";function i(e,t){return e.length===t.length&&e.every((e,n)=>{let r=t[n];return e.id===r.id&&e.itemIds.length===r.itemIds.length&&e.itemIds.every((e,t)=>e===r.itemIds[t])})}function a(e,t){return e.findIndex(e=>e.itemIds.includes(t))}function o(e){return!!(e&&typeof e==`object`&&e.type===`column`)}function s(e,t,r){let i=e.findIndex(e=>e.id===t),a=e.findIndex(e=>e.id===r);return i===-1||a===-1||i===a?e:n(e,i,a)}var c=e=>{let n=o(e.active.data.current),i=e.droppableContainers.filter(e=>n?o(e.data.current):!o(e.data.current)),a=e.pointerCoordinates?.x,s=n||a===void 0?void 0:i.find(t=>{let n=e.droppableRects.get(t.id);return u(String(t.id))!==null&&n&&n.left<=a&&a<=n.right});if(!s)return t({...e,droppableContainers:i});let c=u(String(s.id));return t({...e,droppableContainers:i.filter(e=>e===s||r(e)&&e.data.current.sortable.containerId===c)})};function l(e,t,n){return n.top+n.height/2>(e.top+e.bottom)/2?t.bottom>e.bottom+1:t.top<e.top-1}function u(e){return e.startsWith(`column-`)?e.slice(7):null}function d(e,t,r,i){let o=a(e,t);if(o===-1)return e;let s=u(r),c=s===null?a(e,r):e.findIndex(e=>e.id===s);if(c===-1)return e;if(o===c){let a=e[o],c=a.itemIds.indexOf(t);if(c===-1)return e;if(s!==null){let{activeRect:t,overRect:r}=i,s=t&&t.top+t.height/2>r.top+r.height/2?a.itemIds.length-1:0;if(s===c)return e;let l=[...e];return l[o]={...a,itemIds:n(a.itemIds,c,s)},l}let l=a.itemIds.indexOf(r);if(l===-1||c===l)return e;let u=[...e];return u[o]={...a,itemIds:n(a.itemIds,c,l)},u}let l=e[o],d=e[c],f=[...d.itemIds],{activeRect:p,overRect:m}=i,h;if(s!==null)h=p&&p.top+p.height/2>m.top+m.height/2?f.length:0;else{let e=f.indexOf(r),t=e!==-1&&e===f.length-1,n=!!(p&&p.top+p.height/2>m.top+m.height);h=e===-1?f.length:t&&n?e+1:e}f.splice(h,0,t);let g=[...e];return g[o]={...l,itemIds:l.itemIds.filter(e=>e!==t)},g[c]={...d,itemIds:f},g}function f(e,t,n){if(n){let n=e.findIndex(e=>e.id===t);return n===-1?null:{id:t,columnId:null,index:n}}let r=a(e,t);if(r===-1)return null;let i=e[r];return{id:t,columnId:i.id,index:i.itemIds.indexOf(t)}}function p(e,t){if(!t)return e;let{id:r,columnId:i,index:o}=t;if(i===null){let t=e.findIndex(e=>e.id===r);return t===-1?e:n(e,t,o)}let s=a(e,r),c=e.findIndex(e=>e.id===i);if(s===-1||c===-1)return e;let l=[...e],u=e[s];l[s]={...u,itemIds:u.itemIds.filter(e=>e!==r)};let d=[...l[c].itemIds];return d.splice(o,0,r),l[c]={...l[c],itemIds:d},l}var m=`[data-kanban-handle], [data-kanban-card]`;function h(e,t,n){if(!t.matches(m))return null;let r=[...e.querySelectorAll(`:scope > [data-kanban-column]`)],i=r.findIndex(e=>e.contains(t));if(i===-1)return null;let a=e=>[...e.querySelectorAll(m)];if(n===`ArrowUp`||n===`ArrowDown`){let e=a(r[i]);return e[e.indexOf(t)+(n===`ArrowDown`?1:-1)]??null}if(n!==`ArrowLeft`&&n!==`ArrowRight`)return null;let o=n===`ArrowRight`?1:-1,s=t.getBoundingClientRect().top,c=e=>Math.abs(e.getBoundingClientRect().top-s);for(let e=i+o;e>=0&&e<r.length;e+=o){let n=a(r[e]),i=n.find(e=>e.hasAttribute(`data-kanban-handle`)),o=n.filter(e=>e.hasAttribute(`data-kanban-card`));if(i&&(t.hasAttribute(`data-kanban-handle`)||o.length===0))return i;if(o.length>0)return o.reduce((e,t)=>c(t)<c(e)?t:e)}return null}function g(e,t,n){function r(e){let r=t[e];return r===void 0?e:n(r,e)}function i(t){let n=u(t);if(n!==null){let t=e.find(e=>e.id===n);return t?`the ${t.title} column`:`a column`}let i=e.find(e=>e.itemIds.includes(t));return i?`${r(t)}, in the ${i.title} column`:r(t)}function a(t){return e.find(e=>e.id===t)?.title??t}return{onDragStart({active:e}){return o(e.data.current)?`Picked up column ${a(String(e.id))}.`:`Picked up card ${r(String(e.id))}.`},onDragOver({active:e,over:t}){return o(e.data.current)?t?`Column ${a(String(e.id))} is over column ${a(String(t.id))}.`:`Column ${a(String(e.id))} is no longer over a droppable area.`:t?`Card ${r(String(e.id))} is over ${i(String(t.id))}.`:`Card ${r(String(e.id))} is no longer over a droppable area.`},onDragEnd({active:e,over:t}){return o(e.data.current)?t?`Column ${a(String(e.id))} was dropped over column ${a(String(t.id))}.`:`Column ${a(String(e.id))} was dropped.`:t?`Card ${r(String(e.id))} was dropped over ${i(String(t.id))}.`:`Card ${r(String(e.id))} was dropped.`},onDragCancel({active:e}){return o(e.data.current)?`Dragging cancelled. Column ${a(String(e.id))} was returned to its original position.`:`Dragging cancelled. Card ${r(String(e.id))} was returned to its original position.`}}}function _(e,t,n){let i=[];for(let a of e){if(!r(a)||a.data.current.sortable.containerId!==n)continue;let e=t.get(a.id);e&&i.push({container:a,rect:e})}return i.sort((e,t)=>e.rect.top-t.rect.top)}var v=(t,{context:n})=>{let{active:i,collisionRect:a,droppableRects:s,droppableContainers:c}=n;if(!i||!a||!r(i))return;let l=t.code===e.Down||t.code===e.Up,d=t.code===e.Left||t.code===e.Right;if(!l&&!d)return;t.preventDefault();let f=i.data.current.sortable.containerId,p=c.getEnabled();if(o(i.data.current)){if(!d)return;let n=t.code===e.Right?1:-1,r=_(p,s,f).sort((e,t)=>e.rect.left-t.rect.left),o=r.findIndex(e=>e.container.id===i.id);if(o===-1)return;let c=r[o+n];return c?{x:c.rect.left,y:a.top}:void 0}if(l){let n=t.code===e.Down?1:-1,r=_(p,s,f),o=r.findIndex(e=>e.container.id===i.id);if(o===-1)return;let c=r[o+n];return c?{x:a.left,y:c.rect.top}:void 0}let m=t.code===e.Right?1:-1,h=[];for(let e of p){if(u(String(e.id))===null)continue;let t=s.get(e.id);t&&h.push({container:e,rect:t})}h.sort((e,t)=>e.rect.left-t.rect.left);let g=h.findIndex(e=>u(String(e.container.id))===f);if(g===-1)return;let v=h[g+m];if(!v)return;let y=_(p,s,u(String(v.container.id))),b=v.rect;return y.length>0&&(b=y.reduce((e,t)=>Math.abs(t.rect.top-a.top)<Math.abs(e.rect.top-a.top)?t:e).rect),{x:b.left,y:b.top}};export{p as applyPlacement,g as buildAnnouncements,i as columnsEqual,h as findArrowFocusTarget,a as findColumnForItem,f as findPlacement,o as isColumnDragData,c as kanbanCollisionDetection,v as kanbanKeyboardCoordinateGetter,s as moveColumn,d as moveItem,u as resolveColumnDropId,l as scrollsTowardBoard};
2
2
  //# sourceMappingURL=kanbanBoard.utils.mjs.map