{"version":3,"file":"kanbanBoard.utils.mjs","names":[],"sources":["../../../../package/common/kanbanBoard/kanbanBoard.utils.ts"],"sourcesContent":["import { arrayMove, hasSortableData } from '@dnd-kit/sortable';\nimport {\n  closestCorners,\n  KeyboardCode,\n  type Announcements,\n  type ClientRect,\n  type CollisionDetection,\n  type DroppableContainer,\n  type KeyboardCoordinateGetter,\n  type UniqueIdentifier,\n} from '@dnd-kit/core';\n\nimport type { KanbanColumnDef } from './kanbanBoard.types';\n\nexport function columnsEqual(a: KanbanColumnDef[], b: KanbanColumnDef[]): boolean {\n  if (a.length !== b.length) return false;\n  return a.every((col, i) => {\n    const other = b[i];\n    return (\n      col.id === other.id &&\n      col.itemIds.length === other.itemIds.length &&\n      col.itemIds.every((itemId, j) => itemId === other.itemIds[j])\n    );\n  });\n}\n\nexport function findColumnForItem(columns: KanbanColumnDef[], itemId: string): number {\n  return columns.findIndex((col) => col.itemIds.includes(itemId));\n}\n\n/** Whether a drag's `active`/`over` participant is a whole column (vs. a card) — see `reorderableColumns`. */\nexport function isColumnDragData(data: unknown): boolean {\n  return Boolean(data && typeof data === 'object' && (data as { type?: string }).type === 'column');\n}\n\n/**\n * Reorders whole columns: moves `activeColumnId` to `overColumnId`'s position. Returns the same\n * `columns` reference, unchanged, when either id doesn't resolve to a column or they're the same\n * — callers can use that to skip a state update.\n */\nexport function moveColumn(\n  columns: KanbanColumnDef[],\n  activeColumnId: string,\n  overColumnId: string,\n): KanbanColumnDef[] {\n  const oldIndex = columns.findIndex((col) => col.id === activeColumnId);\n  const overIndex = columns.findIndex((col) => col.id === overColumnId);\n  if (oldIndex === -1 || overIndex === -1 || oldIndex === overIndex) return columns;\n\n  return arrayMove(columns, oldIndex, overIndex);\n}\n\n/**\n * Collision detection for the board's shared `DndContext`, which has to pick between two very\n * differently-scaled sets of droppables at once: individual cards / a column's own card list\n * (small, numerous) and whole columns (large, few). Plain `closestCorners` weighs every\n * registered droppable together regardless of what's actually being dragged, so while dragging a\n * column it competes against every card and card-list droppable it happens to fly over too — the\n * column-level target only wins when the pointer lands somewhere that geometrically favors it,\n * which reads as needing to \"wiggle it around\" before the right drop target lights up. This\n * restricts the candidates to only the same kind as whatever is being dragged: a column drag only\n * considers other columns, a card drag only considers cards and card lists.\n *\n * A card drag also lets the pointer pick the column, and `closestCorners` only the position within\n * it. Corners alone compare the dragged card's whole rect, so a wide card over a collapsed column\n * had its corners nearer the neighbours' cards, and landed beside the column under the pointer.\n * Without a pointer (the keyboard) or between columns, every column is a candidate as before.\n */\nexport const kanbanCollisionDetection: CollisionDetection = (args) => {\n  const draggingColumn = isColumnDragData(args.active.data.current);\n  const droppableContainers = args.droppableContainers.filter((container) =>\n    draggingColumn ? isColumnDragData(container.data.current) : !isColumnDragData(container.data.current),\n  );\n  const pointerX = args.pointerCoordinates?.x;\n  const lane =\n    draggingColumn || pointerX === undefined\n      ? undefined\n      : droppableContainers.find((container) => {\n          const rect = args.droppableRects.get(container.id);\n          return (\n            resolveColumnDropId(String(container.id)) !== null &&\n            rect &&\n            rect.left <= pointerX &&\n            pointerX <= rect.right\n          );\n        });\n  if (!lane) return closestCorners({ ...args, droppableContainers });\n\n  const laneColumnId = resolveColumnDropId(String(lane.id));\n  return closestCorners({\n    ...args,\n    droppableContainers: droppableContainers.filter(\n      (container) =>\n        container === lane ||\n        (hasSortableData(container) && container.data.current.sortable.containerId === laneColumnId),\n    ),\n  });\n};\n\n/**\n * Whether the auto-scroll may move `scroller`, an ancestor of the board such as the page, while\n * something is dragged: only toward a part of the board that is out of view. Nothing beyond the\n * board takes a drop, and a page left free to scroll carried the whole board off screen.\n */\nexport function scrollsTowardBoard(\n  scroller: { top: number; bottom: number },\n  board: { top: number; bottom: number },\n  dragged: { top: number; height: number },\n): boolean {\n  const goingDown = dragged.top + dragged.height / 2 > (scroller.top + scroller.bottom) / 2;\n  return goingDown ? board.bottom > scroller.bottom + 1 : board.top < scroller.top - 1;\n}\n\n/** Extracts the column id from a column droppable's `column-<id>` identifier, or `null` for a card id. */\nexport function resolveColumnDropId(overId: string): string | null {\n  return overId.startsWith('column-') ? overId.slice('column-'.length) : null;\n}\n\nexport interface DragGeometry {\n  /** The dragged card's current rect (translated by the drag delta), if measured. */\n  activeRect: ClientRect | null;\n  /** The rect of whatever `overId` refers to — a card, or a column's own droppable. */\n  overRect: ClientRect;\n}\n\n/**\n * Computes the columns that result from dragging `activeItemId` over `overId` (a card id, or a\n * `column-<id>` droppable id for empty column space). Returns the same `columns` reference,\n * unchanged, when the drag doesn't resolve to a valid source/destination — callers can use that\n * to skip a state update.\n *\n * `geometry` resolves cross-column drops that land on a card or gap with more than one possible\n * position (see the two branches below for what each one decides).\n */\nexport function moveItem(\n  columns: KanbanColumnDef[],\n  activeItemId: string,\n  overId: string,\n  geometry: DragGeometry,\n): KanbanColumnDef[] {\n  // Only the source/destination column(s) actually change, so only those get new object/array\n  // references — every other column keeps its exact `columns` reference. Cloning every column's\n  // `itemIds` up front (as this used to) cost O(total cards across the whole board) on *every*\n  // drag-over event, not just the couple of columns actually involved in the move.\n  const sourceColIndex = findColumnForItem(columns, activeItemId);\n  if (sourceColIndex === -1) return columns;\n\n  const destColId = resolveColumnDropId(overId);\n  const destColIndex =\n    destColId !== null ? columns.findIndex((col) => col.id === destColId) : findColumnForItem(columns, overId);\n  if (destColIndex === -1) return columns;\n\n  if (sourceColIndex === destColIndex) {\n    const col = columns[sourceColIndex];\n    const oldIndex = col.itemIds.indexOf(activeItemId);\n    if (oldIndex === -1) return columns;\n\n    if (destColId !== null) {\n      // over is the column's own droppable, not a card: nothing else claimed the collision,\n      // which happens hovering the empty gap above/below the cards, or — critically — an edge\n      // next to a disabled/pinned card with no other card nearby, since a disabled card's own\n      // droppable is excluded from collision candidates entirely. Without this branch, that\n      // case fell through to `col.itemIds.indexOf(overId)` below, which is always -1 for a\n      // `column-<id>` id (it's not a card id), silently no-op-ing instead of reordering.\n      const { activeRect, overRect } = geometry;\n      const isBelowCenter = Boolean(\n        activeRect && activeRect.top + activeRect.height / 2 > overRect.top + overRect.height / 2,\n      );\n      const targetIndex = isBelowCenter ? col.itemIds.length - 1 : 0;\n      if (targetIndex === oldIndex) return columns;\n\n      const next = [...columns];\n      next[sourceColIndex] = { ...col, itemIds: arrayMove(col.itemIds, oldIndex, targetIndex) };\n      return next;\n    }\n\n    const newIndex = col.itemIds.indexOf(overId);\n    if (newIndex === -1 || oldIndex === newIndex) return columns;\n\n    const next = [...columns];\n    next[sourceColIndex] = { ...col, itemIds: arrayMove(col.itemIds, oldIndex, newIndex) };\n    return next;\n  }\n\n  const sourceCol = columns[sourceColIndex];\n  const destCol = columns[destColIndex];\n  const destItemIds = [...destCol.itemIds];\n  const { activeRect, overRect } = geometry;\n\n  let insertAt: number;\n  if (destColId !== null) {\n    // Hovering the column's own droppable directly, rather than a specific card: the empty gap\n    // above the first card, the empty gap below the last card, or the whole area when the column\n    // has no cards at all. Comparing centers against the *container's* full-height rect is a\n    // coarse but reliable way to tell the top gap (insert at the start) from the bottom gap\n    // (append at the end) — treating every container hover as \"append\" put a card dropped just\n    // above the first item at the end of the column instead.\n    const isBelowCenter = Boolean(\n      activeRect && activeRect.top + activeRect.height / 2 > overRect.top + overRect.height / 2,\n    );\n    insertAt = isBelowCenter ? destItemIds.length : 0;\n  } else {\n    const overIndex = destItemIds.indexOf(overId);\n\n    // Only the last card's own drop zone extends past its bottom edge with nothing after it to\n    // compete for the collision, so it's the one case where the dragged card can end up \"after\"\n    // it. Requiring the dragged rect's *center* (not its top edge) to pass the hovered card's\n    // bottom edge is deliberately more forgiving than requiring the whole dragged card to clear it\n    // — that stricter version needs the user to drag a full card's height past the last item\n    // before it registers, which in practice almost never happens before the drop, silently\n    // landing the card second-to-last every time despite the live preview showing it last. A pure\n    // center-to-center comparison is too lenient in the other direction: the dragged rect's center\n    // still carries the grab offset from wherever in the source card it was originally picked up,\n    // so a low enough grab point reads as \"past\" well before the drag is visually past the card at\n    // all. Anchoring to the target's *bottom* edge (not its center) keeps that grab-offset problem\n    // from creeping back in while still being achievable in a normal drag.\n    const isLastItem = overIndex !== -1 && overIndex === destItemIds.length - 1;\n    const hasClearedItem = Boolean(\n      activeRect && activeRect.top + activeRect.height / 2 > overRect.top + overRect.height,\n    );\n    insertAt = overIndex === -1 ? destItemIds.length : isLastItem && hasClearedItem ? overIndex + 1 : overIndex;\n  }\n\n  destItemIds.splice(insertAt, 0, activeItemId);\n\n  const next = [...columns];\n  next[sourceColIndex] = { ...sourceCol, itemIds: sourceCol.itemIds.filter((id) => id !== activeItemId) };\n  next[destColIndex] = { ...destCol, itemIds: destItemIds };\n  return next;\n}\n\n/**\n * Where a drag has put the dragged card or column so far. The board keeps this rather than a copy\n * of `columns`, so a change the consumer makes mid-drag (a page appended by `onLoadMore`) still\n * shows, and is still there in what `onChange` receives on drop.\n */\nexport interface DragPlacement {\n  /** The dragged card's or column's id. */\n  id: string;\n  /** The column the card sits in, or `null` while a whole column is dragged. */\n  columnId: string | null;\n  index: number;\n}\n\n/** The position `id` holds in `columns`, as a placement to lay over a later `columns`. */\nexport function findPlacement(columns: KanbanColumnDef[], id: string, isColumn: boolean): DragPlacement | null {\n  if (isColumn) {\n    const index = columns.findIndex((col) => col.id === id);\n    return index === -1 ? null : { id, columnId: null, index };\n  }\n  const columnIndex = findColumnForItem(columns, id);\n  if (columnIndex === -1) return null;\n  const col = columns[columnIndex];\n  return { id, columnId: col.id, index: col.itemIds.indexOf(id) };\n}\n\n/**\n * Moves the dragged card or column to its placement in `columns`. Returns `columns` itself when\n * there is no placement, or when the card, the column, or its destination is no longer there.\n */\nexport function applyPlacement(columns: KanbanColumnDef[], placement: DragPlacement | null): KanbanColumnDef[] {\n  if (!placement) return columns;\n  const { id, columnId, index } = placement;\n\n  if (columnId === null) {\n    const oldIndex = columns.findIndex((col) => col.id === id);\n    return oldIndex === -1 ? columns : arrayMove(columns, oldIndex, index);\n  }\n\n  const sourceColIndex = findColumnForItem(columns, id);\n  const destColIndex = columns.findIndex((col) => col.id === columnId);\n  if (sourceColIndex === -1 || destColIndex === -1) return columns;\n\n  const next = [...columns];\n  const sourceCol = columns[sourceColIndex];\n  next[sourceColIndex] = { ...sourceCol, itemIds: sourceCol.itemIds.filter((itemId) => itemId !== id) };\n  const destItemIds = [...next[destColIndex].itemIds];\n  destItemIds.splice(index, 0, id);\n  next[destColIndex] = { ...next[destColIndex], itemIds: destItemIds };\n  return next;\n}\n\nconst FOCUS_STOP = '[data-kanban-handle], [data-kanban-card]';\n\n/**\n * Where an arrow key moves focus from a focused card or column handle while nothing is picked up.\n * It mirrors what the same keys do to a picked-up card: Up/Down within the column, Left/Right to\n * the nearest card in the next column with anything to focus, or from a handle to the next handle.\n * Returns `null` when `from` is not a card or handle, or there is nowhere to go.\n */\nexport function findArrowFocusTarget(board: HTMLElement, from: HTMLElement, key: string): HTMLElement | null {\n  if (!from.matches(FOCUS_STOP)) return null;\n  const columns = [...board.querySelectorAll<HTMLElement>(':scope > [data-kanban-column]')];\n  const columnIndex = columns.findIndex((column) => column.contains(from));\n  if (columnIndex === -1) return null;\n  const stopsIn = (column: HTMLElement) => [...column.querySelectorAll<HTMLElement>(FOCUS_STOP)];\n\n  if (key === 'ArrowUp' || key === 'ArrowDown') {\n    const stops = stopsIn(columns[columnIndex]);\n    return stops[stops.indexOf(from) + (key === 'ArrowDown' ? 1 : -1)] ?? null;\n  }\n  if (key !== 'ArrowLeft' && key !== 'ArrowRight') return null;\n\n  const direction = key === 'ArrowRight' ? 1 : -1;\n  const top = from.getBoundingClientRect().top;\n  const distance = (el: HTMLElement) => Math.abs(el.getBoundingClientRect().top - top);\n  for (let i = columnIndex + direction; i >= 0 && i < columns.length; i += direction) {\n    const stops = stopsIn(columns[i]);\n    const handle = stops.find((stop) => stop.hasAttribute('data-kanban-handle'));\n    const cards = stops.filter((stop) => stop.hasAttribute('data-kanban-card'));\n    if (handle && (from.hasAttribute('data-kanban-handle') || cards.length === 0)) return handle;\n    if (cards.length > 0) return cards.reduce((closest, card) => (distance(card) < distance(closest) ? card : closest));\n  }\n  return null;\n}\n\n/**\n * Builds screen-reader drag announcements against the columns layout as currently understood\n * (the live layout while a drag is in progress, or the settled `columns` prop otherwise).\n */\nexport function buildAnnouncements<T>(\n  columns: KanbanColumnDef[],\n  items: Record<string, T>,\n  getItemLabel: (item: T, id: string) => string,\n): Announcements {\n  function labelFor(id: string): string {\n    const item = items[id];\n    return item !== undefined ? getItemLabel(item, id) : id;\n  }\n\n  function describeOver(overId: string): string {\n    const destColId = resolveColumnDropId(overId);\n    if (destColId !== null) {\n      const col = columns.find((c) => c.id === destColId);\n      return col ? `the ${col.title} column` : 'a column';\n    }\n\n    const col = columns.find((c) => c.itemIds.includes(overId));\n    return col ? `${labelFor(overId)}, in the ${col.title} column` : labelFor(overId);\n  }\n\n  function columnTitle(id: string): string {\n    return columns.find((c) => c.id === id)?.title ?? id;\n  }\n\n  return {\n    onDragStart({ active }) {\n      if (isColumnDragData(active.data.current)) return `Picked up column ${columnTitle(String(active.id))}.`;\n      return `Picked up card ${labelFor(String(active.id))}.`;\n    },\n    onDragOver({ active, over }) {\n      if (isColumnDragData(active.data.current)) {\n        if (!over) return `Column ${columnTitle(String(active.id))} is no longer over a droppable area.`;\n        return `Column ${columnTitle(String(active.id))} is over column ${columnTitle(String(over.id))}.`;\n      }\n      if (!over) return `Card ${labelFor(String(active.id))} is no longer over a droppable area.`;\n      return `Card ${labelFor(String(active.id))} is over ${describeOver(String(over.id))}.`;\n    },\n    onDragEnd({ active, over }) {\n      if (isColumnDragData(active.data.current)) {\n        if (!over) return `Column ${columnTitle(String(active.id))} was dropped.`;\n        return `Column ${columnTitle(String(active.id))} was dropped over column ${columnTitle(String(over.id))}.`;\n      }\n      if (!over) return `Card ${labelFor(String(active.id))} was dropped.`;\n      return `Card ${labelFor(String(active.id))} was dropped over ${describeOver(String(over.id))}.`;\n    },\n    onDragCancel({ active }) {\n      if (isColumnDragData(active.data.current)) {\n        return `Dragging cancelled. Column ${columnTitle(String(active.id))} was returned to its original position.`;\n      }\n      return `Dragging cancelled. Card ${labelFor(String(active.id))} was returned to its original position.`;\n    },\n  };\n}\n\ninterface ContainerRect {\n  container: DroppableContainer;\n  rect: ClientRect;\n}\n\nfunction collectColumnItemRects(\n  containers: DroppableContainer[],\n  droppableRects: Map<UniqueIdentifier, ClientRect>,\n  containerId: UniqueIdentifier,\n): ContainerRect[] {\n  const entries: ContainerRect[] = [];\n  for (const container of containers) {\n    if (!hasSortableData(container)) continue;\n    if (container.data.current.sortable.containerId !== containerId) continue;\n    const rect = droppableRects.get(container.id);\n    if (!rect) continue;\n    entries.push({ container, rect });\n  }\n  return entries.sort((a, b) => a.rect.top - b.rect.top);\n}\n\n/**\n * Custom keyboard coordinate getter for the board's multi-column, multi-`SortableContext`\n * layout. dnd-kit's default `sortableKeyboardCoordinates` picks the geometrically closest\n * droppable across the *entire* board — cards and column containers alike — which is unreliable\n * once cards live inside independent per-column `SortableContext`s: up/down and left/right end up\n * interchangeable depending on incidental rect positions. This instead restricts up/down to\n * reordering within the active card's own column, and left/right to moving into the adjacent\n * column (landing on the closest card there by vertical position, or the column itself when\n * empty). Requires each `KanbanColumn`'s `SortableContext` to be given an explicit `id` matching\n * its column id, so a card's `sortable.containerId` can be correlated with its `column-<id>`\n * droppable.\n */\nexport const kanbanKeyboardCoordinateGetter: KeyboardCoordinateGetter = (event, { context }) => {\n  const { active, collisionRect, droppableRects, droppableContainers } = context;\n\n  if (!active || !collisionRect || !hasSortableData(active)) return undefined;\n\n  const isVertical = event.code === KeyboardCode.Down || event.code === KeyboardCode.Up;\n  const isHorizontal = event.code === KeyboardCode.Left || event.code === KeyboardCode.Right;\n  if (!isVertical && !isHorizontal) return undefined;\n\n  event.preventDefault();\n\n  const activeContainerId = active.data.current.sortable.containerId;\n  const allContainers = droppableContainers.getEnabled();\n\n  if (isColumnDragData(active.data.current)) {\n    // Reordering a whole column: only left/right matters, moving it within the top-level\n    // column `SortableContext` (siblings share its containerId, same as cards share their\n    // own column's). Up/down has nothing to do — columns don't have a \"column above/below\".\n    if (!isHorizontal) return undefined;\n\n    const direction = event.code === KeyboardCode.Right ? 1 : -1;\n    const siblings = collectColumnItemRects(allContainers, droppableRects, activeContainerId).sort(\n      (a, b) => a.rect.left - b.rect.left,\n    );\n    const currentIndex = siblings.findIndex((s) => s.container.id === active.id);\n    if (currentIndex === -1) return undefined;\n\n    const target = siblings[currentIndex + direction];\n    if (!target) return undefined;\n\n    return { x: target.rect.left, y: collisionRect.top };\n  }\n\n  if (isVertical) {\n    const direction = event.code === KeyboardCode.Down ? 1 : -1;\n    const siblings = collectColumnItemRects(allContainers, droppableRects, activeContainerId);\n    const currentIndex = siblings.findIndex((s) => s.container.id === active.id);\n    if (currentIndex === -1) return undefined;\n\n    const target = siblings[currentIndex + direction];\n    if (!target) return undefined;\n\n    return { x: collisionRect.left, y: target.rect.top };\n  }\n\n  const direction = event.code === KeyboardCode.Right ? 1 : -1;\n\n  const columns: ContainerRect[] = [];\n  for (const container of allContainers) {\n    const columnId = resolveColumnDropId(String(container.id));\n    if (columnId === null) continue;\n    const rect = droppableRects.get(container.id);\n    if (!rect) continue;\n    columns.push({ container, rect });\n  }\n  columns.sort((a, b) => a.rect.left - b.rect.left);\n\n  const activeColumnIndex = columns.findIndex((c) => resolveColumnDropId(String(c.container.id)) === activeContainerId);\n  if (activeColumnIndex === -1) return undefined;\n\n  const targetColumn = columns[activeColumnIndex + direction];\n  if (!targetColumn) return undefined;\n\n  const targetContainerId = resolveColumnDropId(String(targetColumn.container.id)) as UniqueIdentifier;\n  const targetItems = collectColumnItemRects(allContainers, droppableRects, targetContainerId);\n\n  let targetRect = targetColumn.rect;\n  if (targetItems.length > 0) {\n    targetRect = targetItems.reduce((closest, item) =>\n      Math.abs(item.rect.top - collisionRect.top) < Math.abs(closest.rect.top - collisionRect.top) ? item : closest,\n    ).rect;\n  }\n\n  return { x: targetRect.left, y: targetRect.top };\n};\n"],"mappings":"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"}