react-dragdrop-kit 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +289 -337
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kanban.esm.js +1 -1
- package/dist/kanban.esm.js.map +1 -1
- package/dist/kanban.js +1 -1
- package/dist/kanban.js.map +1 -1
- package/dist/src/components/DragDropList.d.ts +1 -1
- package/dist/src/components/DraggableItemWrapper.d.ts +1 -1
- package/dist/src/hooks/useDragDropMonitor.d.ts +5 -2
- package/dist/src/kanban/types.d.ts +3 -1
- package/dist/src/kanban/utils/reorder.d.ts +6 -0
- package/dist/src/types/index.d.ts +5 -0
- package/dist/src/utils/order.d.ts +7 -0
- package/package.json +1 -1
package/dist/kanban.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kanban.esm.js","sources":["../src/kanban/context.ts","../src/kanban/components/KanbanColumnView.tsx","../src/kanban/components/KanbanCardView.tsx","../src/kanban/hooks/useKanbanDnd.ts","../src/kanban/components/KanbanBoard.tsx","../src/kanban/hooks/useAutoscroll.ts","../src/kanban/utils/dom.ts","../src/kanban/utils/dndMath.ts","../src/kanban/a11y/Announcer.tsx","../src/kanban/utils/reorder.ts"],"sourcesContent":["/**\n * Kanban Board Context\n *\n * Internal context for sharing board state between components.\n */\n\nimport { createContext, useContext } from 'react';\nimport type { KanbanBoardState, KanbanDragState } from './types';\n\nexport interface KanbanContextValue {\n state: KanbanBoardState;\n dragState: KanbanDragState;\n isDragDisabled?: (id: string, type: 'CARD' | 'COLUMN') => boolean;\n}\n\nexport const KanbanContext = createContext<KanbanContextValue | null>(null);\n\nexport function useKanbanContext(): KanbanContextValue {\n const context = useContext(KanbanContext);\n if (!context) {\n throw new Error('Kanban components must be used within KanbanBoard');\n }\n return context;\n}\n","/**\n * Kanban Column View (Headless)\n *\n * Headless component for rendering draggable columns with drop zones.\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanColumnViewProps, DragProvided, DragSnapshot } from '../types';\n\nconst KANBAN_COLUMN = 'kanban-column';\nconst KANBAN_COLUMN_DROP_ZONE = 'kanban-column-drop-zone';\n\nexport function KanbanColumnView({\n column,\n cardIds,\n children,\n isDragDisabled = false,\n index,\n}: KanbanColumnViewProps) {\n const columnRef = useRef<HTMLDivElement>(null);\n const dropZoneRef = useRef<HTMLDivElement>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n\n // Make column header draggable\n const createDraggableColumn = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return draggable({\n element,\n getInitialData: () => ({\n type: KANBAN_COLUMN,\n id: column.id,\n index,\n }),\n onDragStart: () => setIsDragging(true),\n onDrop: () => setIsDragging(false),\n });\n },\n [column.id, index, isDragDisabled]\n );\n\n // Make column header a drop target for column reordering\n const createColumnDropTarget = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return dropTargetForElements({\n element,\n getData: ({ input, element }) => {\n const data = { type: KANBAN_COLUMN, id: column.id, index };\n return attachClosestEdge(data, { input, element, allowedEdges: ['left', 'right'] });\n },\n canDrop: ({ source }) => source.data.type === KANBAN_COLUMN && source.data.id !== column.id,\n });\n },\n [column.id, index, isDragDisabled]\n );\n\n // Make card list area a drop zone for cards\n const createCardDropZone = useCallback(\n (element: HTMLElement) => {\n return dropTargetForElements({\n element,\n getData: () => ({\n type: KANBAN_COLUMN_DROP_ZONE,\n columnId: column.id,\n }),\n canDrop: ({ source }) => source.data.type === 'kanban-card',\n onDragEnter: () => setIsDraggingOver(true),\n onDragLeave: () => setIsDraggingOver(false),\n onDrop: () => setIsDraggingOver(false),\n });\n },\n [column.id]\n );\n\n useEffect(() => {\n const columnElement = columnRef.current;\n const dropZoneElement = dropZoneRef.current;\n if (!columnElement || !dropZoneElement) return;\n\n const cleanups = [\n createDraggableColumn(columnElement),\n createColumnDropTarget(columnElement),\n createCardDropZone(dropZoneElement),\n ];\n\n return () => {\n cleanups.forEach((cleanup) => cleanup());\n };\n }, [createDraggableColumn, createColumnDropTarget, createCardDropZone]);\n\n const provided: DragProvided = {\n draggableProps: {\n 'data-draggable-id': column.id,\n 'data-draggable-type': 'COLUMN',\n style: isDragging ? { opacity: 0.5 } : undefined,\n },\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable column',\n 'aria-label': `${column.title}, press space to pick up`,\n },\n innerRef: columnRef as React.RefObject<HTMLElement>,\n };\n\n const snapshot: DragSnapshot = {\n isDragging,\n isDraggingOver,\n };\n\n // Pass both refs through provided\n const providedWithDropZone = {\n ...provided,\n dropZoneRef,\n };\n\n return <>{children(providedWithDropZone as any, snapshot)}</>;\n}\n","/**\n * Kanban Card View (Headless)\n *\n * Headless component for rendering draggable cards.\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanCardViewProps, DragProvided, DragSnapshot } from '../types';\n\nconst KANBAN_CARD = 'kanban-card';\n\nexport function KanbanCardView({\n card,\n children,\n isDragDisabled = false,\n index,\n columnId,\n}: KanbanCardViewProps) {\n const cardRef = useRef<HTMLDivElement>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n\n const createDraggable = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return draggable({\n element,\n getInitialData: () => ({\n type: KANBAN_CARD,\n id: card.id,\n index,\n columnId,\n }),\n onDragStart: () => setIsDragging(true),\n onDrop: () => setIsDragging(false),\n });\n },\n [card.id, index, columnId, isDragDisabled]\n );\n\n const createDropTarget = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return dropTargetForElements({\n element,\n getData: ({ input, element }) => {\n const data = { type: KANBAN_CARD, id: card.id, index, columnId };\n return attachClosestEdge(data, { input, element, allowedEdges: ['top', 'bottom'] });\n },\n canDrop: ({ source }) => source.data.type === KANBAN_CARD && source.data.id !== card.id,\n onDragEnter: () => setIsDraggingOver(true),\n onDragLeave: () => setIsDraggingOver(false),\n onDrop: () => setIsDraggingOver(false),\n });\n },\n [card.id, index, columnId, isDragDisabled]\n );\n\n useEffect(() => {\n const element = cardRef.current;\n if (!element || isDragDisabled) return;\n\n return combine(createDraggable(element), createDropTarget(element));\n }, [createDraggable, createDropTarget, isDragDisabled]);\n\n const provided: DragProvided = {\n draggableProps: {\n 'data-draggable-id': card.id,\n 'data-draggable-type': 'CARD',\n style: isDragging ? { opacity: 0.5 } : undefined,\n },\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable card',\n 'aria-label': `${card.title}, press space to pick up`,\n },\n innerRef: cardRef as React.RefObject<HTMLElement>,\n };\n\n const snapshot: DragSnapshot = {\n isDragging,\n isDraggingOver,\n };\n\n return <>{children(provided, snapshot)}</>;\n}\n","/**\n * Core Kanban DnD Hook\n *\n * Main hook that manages drag-and-drop state for the Kanban board.\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanDragState, DropResult, DragLocation, KanbanBoardState } from '../types';\n\nconst KANBAN_CARD = 'kanban-card';\nconst KANBAN_COLUMN = 'kanban-column';\n\nexport interface UseKanbanDndOptions {\n onDragStart?: (draggable: { id: string; type: 'CARD' | 'COLUMN' }) => void;\n onDragEnd: (result: DropResult, stateBefore: KanbanBoardState) => void;\n state: KanbanBoardState;\n disabled?: boolean;\n}\n\nexport function useKanbanDnd({ onDragStart, onDragEnd, state, disabled }: UseKanbanDndOptions) {\n const [dragState, setDragState] = useState<KanbanDragState>({\n draggingId: null,\n draggingType: null,\n source: null,\n destination: null,\n });\n\n useEffect(() => {\n if (disabled) return;\n\n const cleanup = monitorForElements({\n onDragStart({ source }) {\n const typeRaw = source.data.type as string;\n const id = source.data.id as string;\n const columnId = source.data.columnId as string | undefined;\n const index = source.data.index as number;\n\n const type: 'CARD' | 'COLUMN' = typeRaw === KANBAN_CARD ? 'CARD' : 'COLUMN';\n\n const sourceLocation: DragLocation = {\n columnId: type === 'CARD' ? columnId : undefined,\n index,\n };\n\n setDragState({\n draggingId: id,\n draggingType: type,\n source: sourceLocation,\n destination: sourceLocation,\n });\n\n onDragStart?.({ id, type });\n },\n\n onDrop({ source, location }) {\n const sourceType = source.data.type as string;\n const sourceId = source.data.id as string;\n const sourceIndex = source.data.index as number;\n const sourceColumnId = source.data.columnId as string | undefined;\n\n // Find the drop target\n const dropTargets = location.current.dropTargets;\n\n let destination: DragLocation | undefined;\n\n if (sourceType === KANBAN_CARD) {\n // Card drop - find column drop target\n const columnTarget = dropTargets.find((target) =>\n target.data.type === 'kanban-column-drop-zone'\n );\n\n if (columnTarget) {\n const destColumnId = columnTarget.data.columnId as string;\n const cardTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_CARD && target.data.id !== sourceId\n );\n\n if (cardTarget) {\n // Dropping on another card\n const destIndex = cardTarget.data.index as number;\n const edge = extractClosestEdge(cardTarget);\n\n destination = {\n columnId: destColumnId,\n index: edge === 'bottom' ? destIndex + 1 : destIndex,\n };\n } else {\n // Dropping in empty column\n destination = {\n columnId: destColumnId,\n index: 0,\n };\n }\n }\n } else if (sourceType === KANBAN_COLUMN) {\n // Column drop\n const columnTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_COLUMN && target.data.id !== sourceId\n );\n\n if (columnTarget) {\n const destIndex = columnTarget.data.index as number;\n const edge = extractClosestEdge(columnTarget);\n\n destination = {\n index: edge === 'bottom' || edge === 'right' ? destIndex + 1 : destIndex,\n };\n }\n }\n\n const result: DropResult = {\n type: sourceType === KANBAN_CARD ? 'CARD' : 'COLUMN',\n source: {\n columnId: sourceColumnId,\n index: sourceIndex,\n },\n destination,\n draggableId: sourceId,\n };\n\n setDragState({\n draggingId: null,\n draggingType: null,\n source: null,\n destination: null,\n });\n\n onDragEnd(result, state);\n },\n });\n\n return cleanup;\n }, [disabled, onDragStart, onDragEnd, state]);\n\n return dragState;\n}\n","/**\n * Kanban Board Component\n *\n * High-level component that composes the Kanban board with all features.\n */\n\nimport React, { useMemo } from 'react';\nimport type { KanbanBoardProps } from '../types';\nimport { KanbanContext } from '../context';\nimport { KanbanColumnView } from './KanbanColumnView';\nimport { KanbanCardView } from './KanbanCardView';\nimport { useKanbanDnd } from '../hooks/useKanbanDnd';\n\nexport function KanbanBoard({\n state,\n onDragEnd,\n onDragStart,\n renderColumn,\n renderCard,\n getCardKey,\n getColumnKey,\n isDragDisabled,\n className,\n style,\n}: KanbanBoardProps) {\n const dragState = useKanbanDnd({\n state,\n onDragEnd,\n onDragStart,\n disabled: false,\n });\n\n const contextValue = useMemo(\n () => ({\n state,\n dragState,\n isDragDisabled,\n }),\n [state, dragState, isDragDisabled]\n );\n\n const defaultGetCardKey = (card: any) => card.id;\n const defaultGetColumnKey = (column: any) => column.id;\n\n const cardKeyExtractor = getCardKey || defaultGetCardKey;\n const columnKeyExtractor = getColumnKey || defaultGetColumnKey;\n\n return (\n <KanbanContext.Provider value={contextValue}>\n <div\n className={className}\n style={{\n display: 'flex',\n gap: '16px',\n ...style,\n }}\n >\n {state.columns.map((column, columnIndex) => (\n <KanbanColumnView\n key={columnKeyExtractor(column)}\n column={column}\n cardIds={column.cardIds}\n index={columnIndex}\n isDragDisabled={isDragDisabled?.(column.id, 'COLUMN')}\n >\n {(columnProvided, columnSnapshot) => (\n <div\n ref={columnProvided.innerRef as any}\n {...columnProvided.draggableProps}\n style={{\n minWidth: '250px',\n display: 'flex',\n flexDirection: 'column',\n ...columnProvided.draggableProps.style,\n }}\n >\n {/* Column header (draggable) */}\n <div {...columnProvided.dragHandleProps}>\n {renderColumn(column, columnProvided, columnSnapshot)}\n </div>\n\n {/* Card drop zone */}\n <div\n ref={(columnProvided as any).dropZoneRef}\n style={{\n flex: 1,\n minHeight: '100px',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n }}\n >\n {column.cardIds.map((cardId, cardIndex) => {\n const card = state.cards[cardId];\n if (!card) return null;\n\n return (\n <KanbanCardView\n key={cardKeyExtractor(card)}\n card={card}\n index={cardIndex}\n columnId={column.id}\n isDragDisabled={isDragDisabled?.(card.id, 'CARD')}\n >\n {(cardProvided, cardSnapshot) => (\n <div\n ref={cardProvided.innerRef as any}\n {...cardProvided.draggableProps}\n {...cardProvided.dragHandleProps}\n >\n {renderCard(card, cardProvided, cardSnapshot)}\n </div>\n )}\n </KanbanCardView>\n );\n })}\n </div>\n </div>\n )}\n </KanbanColumnView>\n ))}\n </div>\n </KanbanContext.Provider>\n );\n}\n","/**\n * Autoscroll Hook\n *\n * Automatically scrolls containers when dragging near edges.\n */\n\nimport { useEffect, useRef, useCallback } from 'react';\nimport type { AutoscrollConfig } from '../types';\nimport { isNearEdge, calculateScrollSpeed } from '../utils/dndMath';\nimport { getScrollParent, scrollBy, isScrollable } from '../utils/dom';\n\nconst DEFAULT_CONFIG: AutoscrollConfig = {\n threshold: 50, // px from edge\n maxSpeed: 20, // px per frame\n enabled: true,\n};\n\n/**\n * Hook for autoscrolling containers during drag\n */\nexport function useAutoscroll(\n containerRef: React.RefObject<HTMLElement>,\n isDragging: boolean,\n config: Partial<AutoscrollConfig> = {}\n) {\n const { threshold, maxSpeed, enabled } = { ...DEFAULT_CONFIG, ...config };\n const rafRef = useRef<number>();\n const lastMousePosRef = useRef<{ x: number; y: number } | null>(null);\n\n const handleMouseMove = useCallback(\n (event: MouseEvent) => {\n lastMousePosRef.current = { x: event.clientX, y: event.clientY };\n },\n []\n );\n\n const performScroll = useCallback(() => {\n if (!enabled || !isDragging || !containerRef.current || !lastMousePosRef.current) {\n return;\n }\n\n const container = containerRef.current;\n const scrollParent = getScrollParent(container);\n if (!scrollParent) return;\n\n const rect = scrollParent.getBoundingClientRect();\n const mousePos = lastMousePosRef.current;\n const scrollability = isScrollable(scrollParent);\n\n const nearEdge = isNearEdge(mousePos, rect, threshold);\n\n if (nearEdge.edge) {\n const speed = calculateScrollSpeed(nearEdge.distance, threshold, maxSpeed);\n\n const delta = { x: 0, y: 0 };\n\n if (scrollability.vertical) {\n if (nearEdge.edge === 'top') {\n delta.y = -speed;\n } else if (nearEdge.edge === 'bottom') {\n delta.y = speed;\n }\n }\n\n if (scrollability.horizontal) {\n if (nearEdge.edge === 'left') {\n delta.x = -speed;\n } else if (nearEdge.edge === 'right') {\n delta.x = speed;\n }\n }\n\n if (delta.x !== 0 || delta.y !== 0) {\n scrollBy(scrollParent, delta);\n }\n }\n\n rafRef.current = requestAnimationFrame(performScroll);\n }, [enabled, isDragging, containerRef, threshold, maxSpeed]);\n\n useEffect(() => {\n if (!enabled || !isDragging) {\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = undefined;\n }\n lastMousePosRef.current = null;\n return;\n }\n\n window.addEventListener('mousemove', handleMouseMove);\n rafRef.current = requestAnimationFrame(performScroll);\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [enabled, isDragging, handleMouseMove, performScroll]);\n}\n","/**\n * DOM Utilities\n *\n * Helper functions for DOM measurements and manipulation.\n */\n\n/**\n * Safely get bounding client rect for an element\n */\nexport function getBoundingRect(element: HTMLElement | null): DOMRect | null {\n if (!element) return null;\n return element.getBoundingClientRect();\n}\n\n/**\n * Get scrollable parent of an element\n */\nexport function getScrollParent(element: HTMLElement | null): HTMLElement | null {\n if (!element) return null;\n\n let parent = element.parentElement;\n\n while (parent) {\n const { overflow, overflowY } = window.getComputedStyle(parent);\n if (/(auto|scroll)/.test(overflow + overflowY)) {\n return parent;\n }\n parent = parent.parentElement;\n }\n\n return document.documentElement as HTMLElement;\n}\n\n/**\n * Scroll an element by a delta\n */\nexport function scrollBy(\n element: HTMLElement,\n delta: { x?: number; y?: number }\n): void {\n if (delta.x) {\n element.scrollLeft += delta.x;\n }\n if (delta.y) {\n element.scrollTop += delta.y;\n }\n}\n\n/**\n * Check if an element is scrollable\n */\nexport function isScrollable(element: HTMLElement): {\n vertical: boolean;\n horizontal: boolean;\n} {\n const { overflow, overflowY, overflowX } = window.getComputedStyle(element);\n\n const hasVerticalScroll = /(auto|scroll)/.test(overflow + overflowY);\n const hasHorizontalScroll = /(auto|scroll)/.test(overflow + overflowX);\n\n return {\n vertical: hasVerticalScroll && element.scrollHeight > element.clientHeight,\n horizontal: hasHorizontalScroll && element.scrollWidth > element.clientWidth,\n };\n}\n\n/**\n * Get element's scroll position\n */\nexport function getScrollPosition(element: HTMLElement): { x: number; y: number } {\n if (element === document.documentElement) {\n return {\n x: window.pageXOffset || document.documentElement.scrollLeft,\n y: window.pageYOffset || document.documentElement.scrollTop,\n };\n }\n\n return {\n x: element.scrollLeft,\n y: element.scrollTop,\n };\n}\n\n/**\n * Get maximum scroll for an element\n */\nexport function getMaxScroll(element: HTMLElement): { x: number; y: number } {\n return {\n x: element.scrollWidth - element.clientWidth,\n y: element.scrollHeight - element.clientHeight,\n };\n}\n\n/**\n * Clamp scroll position to valid range\n */\nexport function clampScroll(\n scroll: { x: number; y: number },\n maxScroll: { x: number; y: number }\n): { x: number; y: number } {\n return {\n x: Math.max(0, Math.min(scroll.x, maxScroll.x)),\n y: Math.max(0, Math.min(scroll.y, maxScroll.y)),\n };\n}\n\n/**\n * Get all data attributes from an element as an object\n */\nexport function getDataAttributes(element: HTMLElement): Record<string, string> {\n const data: Record<string, string> = {};\n for (const key in element.dataset) {\n data[key] = element.dataset[key] || '';\n }\n return data;\n}\n\n/**\n * Find closest ancestor with a data attribute\n */\nexport function findClosestWithData(\n element: HTMLElement | null,\n dataKey: string\n): HTMLElement | null {\n let current = element;\n while (current) {\n if (current.dataset[dataKey]) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n}\n","/**\n * DnD Math Utilities\n *\n * Helper functions for collision detection and positioning calculations.\n */\n\n/**\n * Calculate the distance from a point to a rectangle's edges\n */\nexport function distanceToEdge(\n point: { x: number; y: number },\n rect: DOMRect\n): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n return {\n top: point.y - rect.top,\n right: rect.right - point.x,\n bottom: rect.bottom - point.y,\n left: point.x - rect.left,\n };\n}\n\n/**\n * Get the closest edge of a rectangle to a point\n */\nexport function getClosestEdge(\n point: { x: number; y: number },\n rect: DOMRect\n): 'top' | 'right' | 'bottom' | 'left' {\n const distances = distanceToEdge(point, rect);\n const entries = Object.entries(distances) as Array<[keyof typeof distances, number]>;\n const sorted = entries.sort((a, b) => a[1] - b[1]);\n return sorted[0][0];\n}\n\n/**\n * Check if a point is within a threshold distance from an edge\n */\nexport function isNearEdge(\n point: { x: number; y: number },\n rect: DOMRect,\n threshold: number\n): { edge: 'top' | 'right' | 'bottom' | 'left' | null; distance: number } {\n const distances = distanceToEdge(point, rect);\n\n for (const [edge, distance] of Object.entries(distances)) {\n if (distance < threshold) {\n return {\n edge: edge as 'top' | 'right' | 'bottom' | 'left',\n distance,\n };\n }\n }\n\n return { edge: null, distance: Infinity };\n}\n\n/**\n * Calculate scroll speed based on distance from edge\n * Closer to edge = faster scroll\n */\nexport function calculateScrollSpeed(\n distance: number,\n threshold: number,\n maxSpeed: number\n): number {\n if (distance >= threshold) return 0;\n const ratio = (threshold - distance) / threshold;\n return ratio * maxSpeed;\n}\n\n/**\n * Check if a point is inside a rectangle\n */\nexport function isPointInRect(point: { x: number; y: number }, rect: DOMRect): boolean {\n return (\n point.x >= rect.left &&\n point.x <= rect.right &&\n point.y >= rect.top &&\n point.y <= rect.bottom\n );\n}\n\n/**\n * Calculate the center point of a rectangle\n */\nexport function getRectCenter(rect: DOMRect): { x: number; y: number } {\n return {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n}\n\n/**\n * Calculate vertical drop position based on mouse Y relative to element center\n */\nexport function getVerticalDropPosition(\n mouseY: number,\n elementRect: DOMRect\n): 'top' | 'bottom' {\n const center = getRectCenter(elementRect);\n return mouseY < center.y ? 'top' : 'bottom';\n}\n\n/**\n * Calculate horizontal drop position based on mouse X relative to element center\n */\nexport function getHorizontalDropPosition(\n mouseX: number,\n elementRect: DOMRect\n): 'left' | 'right' {\n const center = getRectCenter(elementRect);\n return mouseX < center.x ? 'left' : 'right';\n}\n","/**\n * Announcer Component\n *\n * Provides screen reader announcements for drag-and-drop operations.\n */\n\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\n\ninterface AnnouncerContextValue {\n announce: (message: string, politeness?: 'polite' | 'assertive') => void;\n}\n\nconst AnnouncerContext = createContext<AnnouncerContextValue | null>(null);\n\n/**\n * Hook to access the announcer context\n */\nexport function useAnnouncer(): AnnouncerContextValue {\n const context = useContext(AnnouncerContext);\n if (!context) {\n throw new Error('useAnnouncer must be used within AnnouncerProvider');\n }\n return context;\n}\n\n/**\n * Props for AnnouncerProvider\n */\nexport interface AnnouncerProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Default politeness level */\n politeness?: 'polite' | 'assertive';\n}\n\n/**\n * Provider component that creates a live region for screen reader announcements\n */\nexport function AnnouncerProvider({\n children,\n politeness = 'polite',\n}: AnnouncerProviderProps) {\n const politeRef = useRef<HTMLDivElement>(null);\n const assertiveRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n const announce = (message: string, announcePoliteness: 'polite' | 'assertive' = politeness) => {\n const regionRef = announcePoliteness === 'assertive' ? assertiveRef : politeRef;\n\n if (!regionRef.current) return;\n\n // Clear existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n // Clear the region first\n regionRef.current.textContent = '';\n\n // Set the new message after a brief delay to ensure screen readers pick it up\n timeoutRef.current = setTimeout(() => {\n if (regionRef.current) {\n regionRef.current.textContent = message;\n }\n }, 100);\n };\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n const value: AnnouncerContextValue = {\n announce,\n };\n\n return (\n <AnnouncerContext.Provider value={value}>\n {children}\n {/* Polite live region */}\n <div\n ref={politeRef}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n }}\n />\n {/* Assertive live region */}\n <div\n ref={assertiveRef}\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n }}\n />\n </AnnouncerContext.Provider>\n );\n}\n\n/**\n * Generate announcement messages for different drag events\n */\nexport const announcements = {\n onDragStart: (itemName: string, position: number, totalItems: number): string =>\n `Picked up ${itemName}. Position ${position + 1} of ${totalItems}.`,\n\n onDragMove: (itemName: string, newPosition: number, totalItems: number): string =>\n `${itemName} moved to position ${newPosition + 1} of ${totalItems}.`,\n\n onDragEnd: (itemName: string, from: string, to: string, position: number): string =>\n from === to\n ? `${itemName} dropped. Position ${position + 1} in ${to}.`\n : `${itemName} moved from ${from} to ${to}. Position ${position + 1}.`,\n\n onDragCancel: (itemName: string, column: string): string =>\n `Drag cancelled. ${itemName} returned to ${column}.`,\n\n onColumnMove: (columnName: string, position: number, totalColumns: number): string =>\n `${columnName} moved to position ${position + 1} of ${totalColumns}.`,\n};\n","/**\n * Kanban Reorder Utilities\n *\n * Functions for reordering cards and columns in a Kanban board.\n */\n\nimport type { KanbanBoardState, KanbanColumn, DragLocation } from '../types';\n\n/**\n * Reorder an array by moving an item from one index to another\n */\nexport function reorderArray<T>(list: T[], startIndex: number, endIndex: number): T[] {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n}\n\n/**\n * Move a card within the same column\n */\nexport function reorderCardInColumn(\n state: KanbanBoardState,\n columnId: string,\n startIndex: number,\n endIndex: number\n): KanbanBoardState {\n const column = state.columns.find((col) => col.id === columnId);\n if (!column) return state;\n\n const newCardIds = reorderArray(column.cardIds, startIndex, endIndex);\n\n return {\n ...state,\n columns: state.columns.map((col) =>\n col.id === columnId ? { ...col, cardIds: newCardIds } : col\n ),\n };\n}\n\n/**\n * Move a card from one column to another\n */\nexport function moveCardBetweenColumns(\n state: KanbanBoardState,\n source: DragLocation,\n destination: DragLocation,\n cardId: string\n): KanbanBoardState {\n const sourceColumn = state.columns.find((col) => col.id === source.columnId);\n const destColumn = state.columns.find((col) => col.id === destination.columnId);\n\n if (!sourceColumn || !destColumn) return state;\n\n // Remove from source\n const newSourceCardIds = [...sourceColumn.cardIds];\n newSourceCardIds.splice(source.index, 1);\n\n // Add to destination\n const newDestCardIds = [...destColumn.cardIds];\n newDestCardIds.splice(destination.index, 0, cardId);\n\n return {\n ...state,\n columns: state.columns.map((col) => {\n if (col.id === source.columnId) {\n return { ...col, cardIds: newSourceCardIds };\n }\n if (col.id === destination.columnId) {\n return { ...col, cardIds: newDestCardIds };\n }\n return col;\n }),\n };\n}\n\n/**\n * Reorder columns\n */\nexport function reorderColumns(\n state: KanbanBoardState,\n startIndex: number,\n endIndex: number\n): KanbanBoardState {\n return {\n ...state,\n columns: reorderArray(state.columns, startIndex, endIndex),\n };\n}\n\n/**\n * Apply a drag result to the board state\n * This is a convenience function that handles all reorder cases\n */\nexport function applyDragResult(\n state: KanbanBoardState,\n result: {\n type: 'CARD' | 'COLUMN';\n source: DragLocation;\n destination?: DragLocation;\n draggableId: string;\n }\n): KanbanBoardState {\n // No destination = drag canceled\n if (!result.destination) {\n return state;\n }\n\n const { source, destination, type } = result;\n\n // Column reorder\n if (type === 'COLUMN') {\n if (source.index === destination.index) {\n return state; // No change\n }\n return reorderColumns(state, source.index, destination.index);\n }\n\n // Card reorder\n if (type === 'CARD') {\n // Same column\n if (source.columnId === destination.columnId) {\n if (source.index === destination.index) {\n return state; // No change\n }\n return reorderCardInColumn(\n state,\n source.columnId!,\n source.index,\n destination.index\n );\n }\n\n // Different columns\n return moveCardBetweenColumns(state, source, destination, result.draggableId);\n }\n\n return state;\n}\n"],"names":["KanbanContext","createContext","KANBAN_COLUMN","KanbanColumnView","column","cardIds","children","isDragDisabled","index","columnRef","useRef","dropZoneRef","isDragging","setIsDragging","useState","isDraggingOver","setIsDraggingOver","createDraggableColumn","useCallback","element","draggable","getInitialData","type","id","onDragStart","onDrop","createColumnDropTarget","dropTargetForElements","getData","input","data","attachClosestEdge","allowedEdges","canDrop","source","createCardDropZone","columnId","onDragEnter","onDragLeave","useEffect","columnElement","current","dropZoneElement","cleanups","forEach","cleanup","provided","draggableProps","style","opacity","undefined","dragHandleProps","tabIndex","role","title","innerRef","snapshot","providedWithDropZone","Object","assign","React","createElement","Fragment","KANBAN_CARD","KanbanCardView","card","cardRef","createDraggable","createDropTarget","combine","useKanbanDnd","onDragEnd","state","disabled","dragState","setDragState","draggingId","draggingType","destination","monitorForElements","typeRaw","sourceLocation","location","sourceType","sourceId","sourceIndex","sourceColumnId","dropTargets","columnTarget","find","target","destColumnId","cardTarget","destIndex","extractClosestEdge","edge","result","draggableId","KanbanBoard","renderColumn","renderCard","getCardKey","getColumnKey","className","contextValue","useMemo","cardKeyExtractor","columnKeyExtractor","Provider","value","display","gap","columns","map","columnIndex","key","columnProvided","columnSnapshot","ref","minWidth","flexDirection","flex","minHeight","cardId","cardIndex","cards","cardProvided","cardSnapshot","DEFAULT_CONFIG","threshold","maxSpeed","enabled","useAutoscroll","containerRef","config","rafRef","lastMousePosRef","handleMouseMove","event","x","clientX","y","clientY","performScroll","scrollParent","parent","parentElement","overflow","overflowY","window","getComputedStyle","test","document","documentElement","getScrollParent","rect","getBoundingClientRect","mousePos","scrollability","overflowX","hasVerticalScroll","hasHorizontalScroll","vertical","scrollHeight","clientHeight","horizontal","scrollWidth","clientWidth","isScrollable","nearEdge","point","distances","top","right","bottom","left","distanceToEdge","distance","entries","Infinity","isNearEdge","speed","calculateScrollSpeed","delta","scrollLeft","scrollTop","scrollBy","requestAnimationFrame","addEventListener","removeEventListener","cancelAnimationFrame","AnnouncerContext","useAnnouncer","context","useContext","Error","AnnouncerProvider","politeness","politeRef","assertiveRef","timeoutRef","clearTimeout","announce","message","announcePoliteness","regionRef","textContent","setTimeout","position","width","height","padding","margin","clip","whiteSpace","border","announcements","itemName","totalItems","onDragMove","newPosition","from","to","onDragCancel","onColumnMove","columnName","totalColumns","reorderArray","list","startIndex","endIndex","Array","removed","splice","applyDragResult","reorderColumns","col","newCardIds","reorderCardInColumn","sourceColumn","destColumn","newSourceCardIds","newDestCardIds","moveCardBetweenColumns"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kanban.esm.js","sources":["../src/kanban/context.ts","../src/kanban/components/KanbanColumnView.tsx","../src/kanban/components/KanbanCardView.tsx","../src/kanban/utils/reorder.ts","../src/kanban/hooks/useKanbanDnd.ts","../src/kanban/components/KanbanBoard.tsx","../src/kanban/hooks/useAutoscroll.ts","../src/kanban/utils/dom.ts","../src/kanban/utils/dndMath.ts","../src/kanban/a11y/Announcer.tsx"],"sourcesContent":["/**\r\n * Kanban Board Context\r\n *\r\n * Internal context for sharing board state between components.\r\n */\r\n\r\nimport { createContext, useContext } from 'react';\r\nimport type { KanbanBoardState, KanbanDragState } from './types';\r\n\r\nexport interface KanbanContextValue {\r\n state: KanbanBoardState;\r\n dragState: KanbanDragState;\r\n isDragDisabled?: (id: string, type: 'CARD' | 'COLUMN') => boolean;\r\n}\r\n\r\nexport const KanbanContext = createContext<KanbanContextValue | null>(null);\r\n\r\nexport function useKanbanContext(): KanbanContextValue {\r\n const context = useContext(KanbanContext);\r\n if (!context) {\r\n throw new Error('Kanban components must be used within KanbanBoard');\r\n }\r\n return context;\r\n}\r\n","/**\r\n * Kanban Column View (Headless)\r\n *\r\n * Headless component for rendering draggable columns with drop zones.\r\n */\r\n\r\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\r\nimport type { KanbanColumnViewProps, DragProvided, DragSnapshot } from '../types';\r\n\r\nconst KANBAN_COLUMN = 'kanban-column';\r\nconst KANBAN_COLUMN_DROP_ZONE = 'kanban-column-drop-zone';\r\n\r\nexport function KanbanColumnView({\n column,\n cardIds,\n children,\n isDragDisabled = false,\n index,\r\n}: KanbanColumnViewProps) {\r\n const columnRef = useRef<HTMLDivElement>(null);\r\n const dropZoneRef = useRef<HTMLDivElement>(null);\r\n const [isDragging, setIsDragging] = useState(false);\r\n const [isDraggingOver, setIsDraggingOver] = useState(false);\r\n\r\n // Make column header draggable\r\n const createDraggableColumn = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return draggable({\r\n element,\r\n getInitialData: () => ({\r\n type: KANBAN_COLUMN,\r\n id: column.id,\r\n index,\r\n }),\r\n onDragStart: () => setIsDragging(true),\r\n onDrop: () => setIsDragging(false),\r\n });\r\n },\r\n [column.id, index, isDragDisabled]\r\n );\r\n\r\n // Make column header a drop target for column reordering\r\n const createColumnDropTarget = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return dropTargetForElements({\r\n element,\r\n getData: ({ input, element }) => {\r\n const data = { type: KANBAN_COLUMN, id: column.id, index };\r\n return attachClosestEdge(data, { input, element, allowedEdges: ['left', 'right'] });\r\n },\r\n canDrop: ({ source }) => source.data.type === KANBAN_COLUMN && source.data.id !== column.id,\r\n });\r\n },\r\n [column.id, index, isDragDisabled]\r\n );\r\n\r\n // Make card list area a drop zone for cards\r\n const createCardDropZone = useCallback(\r\n (element: HTMLElement) => {\r\n return dropTargetForElements({\r\n element,\r\n getData: () => ({\r\n type: KANBAN_COLUMN_DROP_ZONE,\r\n columnId: column.id,\r\n }),\r\n canDrop: ({ source }) => source.data.type === 'kanban-card',\r\n onDragEnter: () => setIsDraggingOver(true),\r\n onDragLeave: () => setIsDraggingOver(false),\r\n onDrop: () => setIsDraggingOver(false),\r\n });\r\n },\r\n [column.id]\r\n );\r\n\r\n useEffect(() => {\r\n const columnElement = columnRef.current;\r\n const dropZoneElement = dropZoneRef.current;\r\n if (!columnElement || !dropZoneElement) return;\r\n\r\n const cleanups = [\r\n createDraggableColumn(columnElement),\r\n createColumnDropTarget(columnElement),\r\n createCardDropZone(dropZoneElement),\r\n ];\r\n\r\n return () => {\r\n cleanups.forEach((cleanup) => cleanup());\r\n };\r\n }, [createDraggableColumn, createColumnDropTarget, createCardDropZone]);\r\n\r\n const provided: DragProvided = {\r\n draggableProps: {\r\n 'data-draggable-id': column.id,\r\n 'data-draggable-type': 'COLUMN',\r\n style: isDragging ? { opacity: 0.5 } : undefined,\r\n },\r\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable column',\n 'aria-label': `${column.title}, ${cardIds.length} cards, press space to pick up`,\n },\n innerRef: columnRef,\n dropZoneRef,\n };\n\r\n const snapshot: DragSnapshot = {\r\n isDragging,\r\n isDraggingOver,\r\n };\r\n\r\n // Pass both refs through provided\r\n return <>{children(provided, snapshot)}</>;\n}\n","/**\r\n * Kanban Card View (Headless)\r\n *\r\n * Headless component for rendering draggable cards.\r\n */\r\n\r\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\r\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\r\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\r\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\r\nimport type { KanbanCardViewProps, DragProvided, DragSnapshot } from '../types';\r\n\r\nconst KANBAN_CARD = 'kanban-card';\r\n\r\nexport function KanbanCardView({\r\n card,\r\n children,\r\n isDragDisabled = false,\r\n index,\r\n columnId,\r\n}: KanbanCardViewProps) {\r\n const cardRef = useRef<HTMLDivElement>(null);\r\n const [isDragging, setIsDragging] = useState(false);\r\n const [isDraggingOver, setIsDraggingOver] = useState(false);\r\n\r\n const createDraggable = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return draggable({\r\n element,\r\n getInitialData: () => ({\r\n type: KANBAN_CARD,\r\n id: card.id,\r\n index,\r\n columnId,\r\n }),\r\n onDragStart: () => setIsDragging(true),\r\n onDrop: () => setIsDragging(false),\r\n });\r\n },\r\n [card.id, index, columnId, isDragDisabled]\r\n );\r\n\r\n const createDropTarget = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return dropTargetForElements({\r\n element,\r\n getData: ({ input, element }) => {\r\n const data = { type: KANBAN_CARD, id: card.id, index, columnId };\r\n return attachClosestEdge(data, { input, element, allowedEdges: ['top', 'bottom'] });\r\n },\r\n canDrop: ({ source }) => source.data.type === KANBAN_CARD && source.data.id !== card.id,\r\n onDragEnter: () => setIsDraggingOver(true),\r\n onDragLeave: () => setIsDraggingOver(false),\r\n onDrop: () => setIsDraggingOver(false),\r\n });\r\n },\r\n [card.id, index, columnId, isDragDisabled]\r\n );\r\n\r\n useEffect(() => {\r\n const element = cardRef.current;\r\n if (!element || isDragDisabled) return;\r\n\r\n return combine(createDraggable(element), createDropTarget(element));\r\n }, [createDraggable, createDropTarget, isDragDisabled]);\r\n\r\n const provided: DragProvided = {\r\n draggableProps: {\r\n 'data-draggable-id': card.id,\r\n 'data-draggable-type': 'CARD',\r\n style: isDragging ? { opacity: 0.5 } : undefined,\r\n },\r\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable card',\n 'aria-label': `${card.title}, press space to pick up`,\n },\n innerRef: cardRef,\n };\n\r\n const snapshot: DragSnapshot = {\r\n isDragging,\r\n isDraggingOver,\r\n };\r\n\r\n return <>{children(provided, snapshot)}</>;\r\n}\r\n","/**\r\n * Kanban Reorder Utilities\r\n *\r\n * Functions for reordering cards and columns in a Kanban board.\r\n */\r\n\r\nimport type { KanbanBoardState, DragLocation } from '../types';\n\r\n/**\r\n * Reorder an array by moving an item from one index to another\r\n */\r\nexport function reorderArray<T>(list: T[], startIndex: number, endIndex: number): T[] {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n}\n\nexport function normalizeReorderDestinationIndex(params: {\n itemCount: number;\n sourceIndex: number;\n rawDestinationIndex: number;\n isSameList: boolean;\n}): number {\n const { itemCount, sourceIndex, rawDestinationIndex, isSameList } = params;\n\n if (itemCount <= 0) return 0;\n\n const maxRaw = itemCount;\n const clampedRaw = Math.max(0, Math.min(rawDestinationIndex, maxRaw));\n const adjusted = isSameList && sourceIndex < clampedRaw ? clampedRaw - 1 : clampedRaw;\n const maxFinal = isSameList ? itemCount - 1 : itemCount;\n\n return Math.max(0, Math.min(adjusted, maxFinal));\n}\n\r\n/**\r\n * Move a card within the same column\r\n */\r\nexport function reorderCardInColumn(\r\n state: KanbanBoardState,\r\n columnId: string,\r\n startIndex: number,\r\n endIndex: number\r\n): KanbanBoardState {\r\n const column = state.columns.find((col) => col.id === columnId);\r\n if (!column) return state;\r\n\r\n const newCardIds = reorderArray(column.cardIds, startIndex, endIndex);\r\n\r\n return {\r\n ...state,\r\n columns: state.columns.map((col) =>\r\n col.id === columnId ? { ...col, cardIds: newCardIds } : col\r\n ),\r\n };\r\n}\r\n\r\n/**\r\n * Move a card from one column to another\r\n */\r\nexport function moveCardBetweenColumns(\r\n state: KanbanBoardState,\r\n source: DragLocation,\r\n destination: DragLocation,\r\n cardId: string\r\n): KanbanBoardState {\r\n const sourceColumn = state.columns.find((col) => col.id === source.columnId);\r\n const destColumn = state.columns.find((col) => col.id === destination.columnId);\r\n\r\n if (!sourceColumn || !destColumn) return state;\r\n\r\n // Remove from source\r\n const newSourceCardIds = [...sourceColumn.cardIds];\r\n newSourceCardIds.splice(source.index, 1);\r\n\r\n // Add to destination\r\n const newDestCardIds = [...destColumn.cardIds];\r\n newDestCardIds.splice(destination.index, 0, cardId);\r\n\r\n return {\r\n ...state,\r\n columns: state.columns.map((col) => {\r\n if (col.id === source.columnId) {\r\n return { ...col, cardIds: newSourceCardIds };\r\n }\r\n if (col.id === destination.columnId) {\r\n return { ...col, cardIds: newDestCardIds };\r\n }\r\n return col;\r\n }),\r\n };\r\n}\r\n\r\n/**\r\n * Reorder columns\r\n */\r\nexport function reorderColumns(\r\n state: KanbanBoardState,\r\n startIndex: number,\r\n endIndex: number\r\n): KanbanBoardState {\r\n return {\r\n ...state,\r\n columns: reorderArray(state.columns, startIndex, endIndex),\r\n };\r\n}\r\n\r\n/**\r\n * Apply a drag result to the board state\r\n * This is a convenience function that handles all reorder cases\r\n */\r\nexport function applyDragResult(\r\n state: KanbanBoardState,\r\n result: {\r\n type: 'CARD' | 'COLUMN';\r\n source: DragLocation;\r\n destination?: DragLocation;\r\n draggableId: string;\r\n }\r\n): KanbanBoardState {\r\n // No destination = drag canceled\r\n if (!result.destination) {\r\n return state;\r\n }\r\n\r\n const { source, destination, type } = result;\r\n\r\n // Column reorder\r\n if (type === 'COLUMN') {\r\n if (source.index === destination.index) {\r\n return state; // No change\r\n }\r\n return reorderColumns(state, source.index, destination.index);\r\n }\r\n\r\n // Card reorder\r\n if (type === 'CARD') {\r\n // Same column\r\n if (source.columnId === destination.columnId) {\r\n if (source.index === destination.index) {\r\n return state; // No change\r\n }\r\n return reorderCardInColumn(\r\n state,\r\n source.columnId!,\r\n source.index,\r\n destination.index\r\n );\r\n }\r\n\r\n // Different columns\r\n return moveCardBetweenColumns(state, source, destination, result.draggableId);\r\n }\r\n\r\n return state;\r\n}\r\n","/**\r\n * Core Kanban DnD Hook\r\n *\r\n * Main hook that manages drag-and-drop state for the Kanban board.\r\n */\r\n\r\nimport { useState, useEffect } from 'react';\nimport { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanDragState, DropResult, DragLocation, KanbanBoardState } from '../types';\nimport { normalizeReorderDestinationIndex } from '../utils/reorder';\n\r\nconst KANBAN_CARD = 'kanban-card';\r\nconst KANBAN_COLUMN = 'kanban-column';\r\n\r\nexport interface UseKanbanDndOptions {\r\n onDragStart?: (draggable: { id: string; type: 'CARD' | 'COLUMN' }) => void;\r\n onDragEnd: (result: DropResult, stateBefore: KanbanBoardState) => void;\r\n state: KanbanBoardState;\r\n disabled?: boolean;\r\n}\r\n\r\nexport function useKanbanDnd({ onDragStart, onDragEnd, state, disabled }: UseKanbanDndOptions) {\r\n const [dragState, setDragState] = useState<KanbanDragState>({\r\n draggingId: null,\r\n draggingType: null,\r\n source: null,\r\n destination: null,\r\n });\r\n\r\n useEffect(() => {\r\n if (disabled) return;\r\n\r\n const cleanup = monitorForElements({\r\n onDragStart({ source }) {\r\n const typeRaw = source.data.type as string;\r\n const id = source.data.id as string;\r\n const columnId = source.data.columnId as string | undefined;\r\n const index = source.data.index as number;\r\n\r\n const type: 'CARD' | 'COLUMN' = typeRaw === KANBAN_CARD ? 'CARD' : 'COLUMN';\r\n\r\n const sourceLocation: DragLocation = {\r\n columnId: type === 'CARD' ? columnId : undefined,\r\n index,\r\n };\r\n\r\n setDragState({\r\n draggingId: id,\r\n draggingType: type,\r\n source: sourceLocation,\r\n destination: sourceLocation,\r\n });\r\n\r\n onDragStart?.({ id, type });\r\n },\r\n\r\n onDrop({ source, location }) {\n const sourceType = source.data.type as string;\n const sourceId = source.data.id as string;\n const sourceIndex = source.data.index as number;\n const sourceColumnId = source.data.columnId as string | undefined;\n\r\n // Find the drop target\r\n const dropTargets = location.current.dropTargets;\r\n\r\n let destination: DragLocation | undefined;\r\n\r\n if (sourceType === KANBAN_CARD) {\n // Card drop - find column drop target\n const columnTarget = dropTargets.find((target) =>\n target.data.type === 'kanban-column-drop-zone'\n );\n\n if (columnTarget) {\n const destColumnId = columnTarget.data.columnId as string;\n const sourceColumn = state.columns.find((column) => column.id === sourceColumnId);\n const destColumn = state.columns.find((column) => column.id === destColumnId);\n if (sourceColumn && destColumn) {\n const cardTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_CARD && target.data.id !== sourceId\n );\n\n let rawDestinationIndex = destColumn.cardIds.length;\n if (cardTarget) {\n // Dropping on another card\n const destIndex = cardTarget.data.index as number;\n const edge = extractClosestEdge(cardTarget.data);\n rawDestinationIndex = edge === 'bottom' ? destIndex + 1 : destIndex;\n }\n\n const isSameColumn = sourceColumnId === destColumnId;\n const normalizedIndex = normalizeReorderDestinationIndex({\n itemCount: isSameColumn ? sourceColumn.cardIds.length : destColumn.cardIds.length,\n sourceIndex,\n rawDestinationIndex,\n isSameList: isSameColumn,\n });\n\n destination = {\n columnId: destColumnId,\n index: normalizedIndex,\n };\n }\n }\n } else if (sourceType === KANBAN_COLUMN) {\n // Column drop\n const columnTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_COLUMN && target.data.id !== sourceId\n );\n\n if (columnTarget) {\n const destIndex = columnTarget.data.index as number;\n const edge = extractClosestEdge(columnTarget.data);\n const rawDestinationIndex =\n edge === 'bottom' || edge === 'right' ? destIndex + 1 : destIndex;\n\n destination = {\n index: normalizeReorderDestinationIndex({\n itemCount: state.columns.length,\n sourceIndex,\n rawDestinationIndex,\n isSameList: true,\n }),\n };\n }\n }\n\r\n const result: DropResult = {\r\n type: sourceType === KANBAN_CARD ? 'CARD' : 'COLUMN',\r\n source: {\r\n columnId: sourceColumnId,\r\n index: sourceIndex,\r\n },\r\n destination,\r\n draggableId: sourceId,\r\n };\r\n\r\n setDragState({\r\n draggingId: null,\r\n draggingType: null,\r\n source: null,\r\n destination: null,\r\n });\r\n\r\n onDragEnd(result, state);\r\n },\r\n });\r\n\r\n return cleanup;\r\n }, [disabled, onDragStart, onDragEnd, state]);\r\n\r\n return dragState;\r\n}\r\n","/**\r\n * Kanban Board Component\r\n *\r\n * High-level component that composes the Kanban board with all features.\r\n */\r\n\r\nimport React, { useMemo } from 'react';\nimport type { KanbanBoardProps, KanbanCard, KanbanColumn } from '../types';\nimport { KanbanContext } from '../context';\r\nimport { KanbanColumnView } from './KanbanColumnView';\r\nimport { KanbanCardView } from './KanbanCardView';\r\nimport { useKanbanDnd } from '../hooks/useKanbanDnd';\r\n\r\nexport function KanbanBoard({\r\n state,\r\n onDragEnd,\r\n onDragStart,\r\n renderColumn,\r\n renderCard,\r\n getCardKey,\r\n getColumnKey,\r\n isDragDisabled,\r\n className,\r\n style,\r\n}: KanbanBoardProps) {\r\n const dragState = useKanbanDnd({\r\n state,\r\n onDragEnd,\r\n onDragStart,\r\n disabled: false,\r\n });\r\n\r\n const contextValue = useMemo(\r\n () => ({\r\n state,\r\n dragState,\r\n isDragDisabled,\r\n }),\r\n [state, dragState, isDragDisabled]\r\n );\r\n\r\n const defaultGetCardKey = (card: KanbanCard) => card.id;\n const defaultGetColumnKey = (column: KanbanColumn) => column.id;\n\r\n const cardKeyExtractor = getCardKey || defaultGetCardKey;\r\n const columnKeyExtractor = getColumnKey || defaultGetColumnKey;\r\n\r\n return (\r\n <KanbanContext.Provider value={contextValue}>\r\n <div\r\n className={className}\r\n style={{\r\n display: 'flex',\r\n gap: '16px',\r\n ...style,\r\n }}\r\n >\r\n {state.columns.map((column, columnIndex) => (\r\n <KanbanColumnView\r\n key={columnKeyExtractor(column)}\r\n column={column}\r\n cardIds={column.cardIds}\r\n index={columnIndex}\r\n isDragDisabled={isDragDisabled?.(column.id, 'COLUMN')}\r\n >\r\n {(columnProvided, columnSnapshot) => (\r\n <div\n ref={columnProvided.innerRef}\n {...columnProvided.draggableProps}\n style={{\n minWidth: '250px',\n display: 'flex',\r\n flexDirection: 'column',\r\n ...columnProvided.draggableProps.style,\r\n }}\r\n >\r\n {/* Column header (draggable) */}\r\n <div {...columnProvided.dragHandleProps}>\r\n {renderColumn(column, columnProvided, columnSnapshot)}\r\n </div>\r\n\r\n {/* Card drop zone */}\r\n <div\n ref={columnProvided.dropZoneRef}\n style={{\n flex: 1,\n minHeight: '100px',\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: '8px',\r\n }}\r\n >\r\n {column.cardIds.map((cardId, cardIndex) => {\r\n const card = state.cards[cardId];\r\n if (!card) return null;\r\n\r\n return (\r\n <KanbanCardView\r\n key={cardKeyExtractor(card)}\r\n card={card}\r\n index={cardIndex}\r\n columnId={column.id}\r\n isDragDisabled={isDragDisabled?.(card.id, 'CARD')}\r\n >\r\n {(cardProvided, cardSnapshot) => (\n <div\n ref={cardProvided.innerRef}\n {...cardProvided.draggableProps}\n {...cardProvided.dragHandleProps}\n >\n {renderCard(card, cardProvided, cardSnapshot)}\r\n </div>\r\n )}\r\n </KanbanCardView>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n )}\r\n </KanbanColumnView>\r\n ))}\r\n </div>\r\n </KanbanContext.Provider>\r\n );\r\n}\r\n","/**\r\n * Autoscroll Hook\r\n *\r\n * Automatically scrolls containers when dragging near edges.\r\n */\r\n\r\nimport { useEffect, useRef, useCallback } from 'react';\r\nimport type { AutoscrollConfig } from '../types';\r\nimport { isNearEdge, calculateScrollSpeed } from '../utils/dndMath';\r\nimport { getScrollParent, scrollBy, isScrollable } from '../utils/dom';\r\n\r\nconst DEFAULT_CONFIG: AutoscrollConfig = {\r\n threshold: 50, // px from edge\r\n maxSpeed: 20, // px per frame\r\n enabled: true,\r\n};\r\n\r\n/**\r\n * Hook for autoscrolling containers during drag\r\n */\r\nexport function useAutoscroll(\r\n containerRef: React.RefObject<HTMLElement>,\r\n isDragging: boolean,\r\n config: Partial<AutoscrollConfig> = {}\r\n) {\r\n const { threshold, maxSpeed, enabled } = { ...DEFAULT_CONFIG, ...config };\r\n const rafRef = useRef<number>();\r\n const lastMousePosRef = useRef<{ x: number; y: number } | null>(null);\r\n\r\n const handleMouseMove = useCallback(\r\n (event: MouseEvent) => {\r\n lastMousePosRef.current = { x: event.clientX, y: event.clientY };\r\n },\r\n []\r\n );\r\n\r\n const performScroll = useCallback(() => {\r\n if (!enabled || !isDragging || !containerRef.current || !lastMousePosRef.current) {\r\n return;\r\n }\r\n\r\n const container = containerRef.current;\r\n const scrollParent = getScrollParent(container);\r\n if (!scrollParent) return;\r\n\r\n const rect = scrollParent.getBoundingClientRect();\r\n const mousePos = lastMousePosRef.current;\r\n const scrollability = isScrollable(scrollParent);\r\n\r\n const nearEdge = isNearEdge(mousePos, rect, threshold);\r\n\r\n if (nearEdge.edge) {\r\n const speed = calculateScrollSpeed(nearEdge.distance, threshold, maxSpeed);\r\n\r\n const delta = { x: 0, y: 0 };\r\n\r\n if (scrollability.vertical) {\r\n if (nearEdge.edge === 'top') {\r\n delta.y = -speed;\r\n } else if (nearEdge.edge === 'bottom') {\r\n delta.y = speed;\r\n }\r\n }\r\n\r\n if (scrollability.horizontal) {\r\n if (nearEdge.edge === 'left') {\r\n delta.x = -speed;\r\n } else if (nearEdge.edge === 'right') {\r\n delta.x = speed;\r\n }\r\n }\r\n\r\n if (delta.x !== 0 || delta.y !== 0) {\r\n scrollBy(scrollParent, delta);\r\n }\r\n }\r\n\r\n rafRef.current = requestAnimationFrame(performScroll);\r\n }, [enabled, isDragging, containerRef, threshold, maxSpeed]);\r\n\r\n useEffect(() => {\r\n if (!enabled || !isDragging) {\r\n if (rafRef.current) {\r\n cancelAnimationFrame(rafRef.current);\r\n rafRef.current = undefined;\r\n }\r\n lastMousePosRef.current = null;\r\n return;\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove);\r\n rafRef.current = requestAnimationFrame(performScroll);\r\n\r\n return () => {\r\n window.removeEventListener('mousemove', handleMouseMove);\r\n if (rafRef.current) {\r\n cancelAnimationFrame(rafRef.current);\r\n }\r\n };\r\n }, [enabled, isDragging, handleMouseMove, performScroll]);\r\n}\r\n","/**\r\n * DOM Utilities\r\n *\r\n * Helper functions for DOM measurements and manipulation.\r\n */\r\n\r\n/**\r\n * Safely get bounding client rect for an element\r\n */\r\nexport function getBoundingRect(element: HTMLElement | null): DOMRect | null {\r\n if (!element) return null;\r\n return element.getBoundingClientRect();\r\n}\r\n\r\n/**\r\n * Get scrollable parent of an element\r\n */\r\nexport function getScrollParent(element: HTMLElement | null): HTMLElement | null {\r\n if (!element) return null;\r\n\r\n let parent = element.parentElement;\r\n\r\n while (parent) {\r\n const { overflow, overflowY } = window.getComputedStyle(parent);\r\n if (/(auto|scroll)/.test(overflow + overflowY)) {\r\n return parent;\r\n }\r\n parent = parent.parentElement;\r\n }\r\n\r\n return document.documentElement as HTMLElement;\r\n}\r\n\r\n/**\r\n * Scroll an element by a delta\r\n */\r\nexport function scrollBy(\r\n element: HTMLElement,\r\n delta: { x?: number; y?: number }\r\n): void {\r\n if (delta.x) {\r\n element.scrollLeft += delta.x;\r\n }\r\n if (delta.y) {\r\n element.scrollTop += delta.y;\r\n }\r\n}\r\n\r\n/**\r\n * Check if an element is scrollable\r\n */\r\nexport function isScrollable(element: HTMLElement): {\r\n vertical: boolean;\r\n horizontal: boolean;\r\n} {\r\n const { overflow, overflowY, overflowX } = window.getComputedStyle(element);\r\n\r\n const hasVerticalScroll = /(auto|scroll)/.test(overflow + overflowY);\r\n const hasHorizontalScroll = /(auto|scroll)/.test(overflow + overflowX);\r\n\r\n return {\r\n vertical: hasVerticalScroll && element.scrollHeight > element.clientHeight,\r\n horizontal: hasHorizontalScroll && element.scrollWidth > element.clientWidth,\r\n };\r\n}\r\n\r\n/**\r\n * Get element's scroll position\r\n */\r\nexport function getScrollPosition(element: HTMLElement): { x: number; y: number } {\r\n if (element === document.documentElement) {\r\n return {\r\n x: window.pageXOffset || document.documentElement.scrollLeft,\r\n y: window.pageYOffset || document.documentElement.scrollTop,\r\n };\r\n }\r\n\r\n return {\r\n x: element.scrollLeft,\r\n y: element.scrollTop,\r\n };\r\n}\r\n\r\n/**\r\n * Get maximum scroll for an element\r\n */\r\nexport function getMaxScroll(element: HTMLElement): { x: number; y: number } {\r\n return {\r\n x: element.scrollWidth - element.clientWidth,\r\n y: element.scrollHeight - element.clientHeight,\r\n };\r\n}\r\n\r\n/**\r\n * Clamp scroll position to valid range\r\n */\r\nexport function clampScroll(\r\n scroll: { x: number; y: number },\r\n maxScroll: { x: number; y: number }\r\n): { x: number; y: number } {\r\n return {\r\n x: Math.max(0, Math.min(scroll.x, maxScroll.x)),\r\n y: Math.max(0, Math.min(scroll.y, maxScroll.y)),\r\n };\r\n}\r\n\r\n/**\r\n * Get all data attributes from an element as an object\r\n */\r\nexport function getDataAttributes(element: HTMLElement): Record<string, string> {\r\n const data: Record<string, string> = {};\r\n for (const key in element.dataset) {\r\n data[key] = element.dataset[key] || '';\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * Find closest ancestor with a data attribute\r\n */\r\nexport function findClosestWithData(\r\n element: HTMLElement | null,\r\n dataKey: string\r\n): HTMLElement | null {\r\n let current = element;\r\n while (current) {\r\n if (current.dataset[dataKey]) {\r\n return current;\r\n }\r\n current = current.parentElement;\r\n }\r\n return null;\r\n}\r\n","/**\r\n * DnD Math Utilities\r\n *\r\n * Helper functions for collision detection and positioning calculations.\r\n */\r\n\r\n/**\r\n * Calculate the distance from a point to a rectangle's edges\r\n */\r\nexport function distanceToEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect\r\n): {\r\n top: number;\r\n right: number;\r\n bottom: number;\r\n left: number;\r\n} {\r\n return {\r\n top: point.y - rect.top,\r\n right: rect.right - point.x,\r\n bottom: rect.bottom - point.y,\r\n left: point.x - rect.left,\r\n };\r\n}\r\n\r\n/**\r\n * Get the closest edge of a rectangle to a point\r\n */\r\nexport function getClosestEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect\r\n): 'top' | 'right' | 'bottom' | 'left' {\r\n const distances = distanceToEdge(point, rect);\r\n const entries = Object.entries(distances) as Array<[keyof typeof distances, number]>;\r\n const sorted = entries.sort((a, b) => a[1] - b[1]);\r\n return sorted[0][0];\r\n}\r\n\r\n/**\r\n * Check if a point is within a threshold distance from an edge\r\n */\r\nexport function isNearEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect,\r\n threshold: number\r\n): { edge: 'top' | 'right' | 'bottom' | 'left' | null; distance: number } {\r\n const distances = distanceToEdge(point, rect);\r\n\r\n for (const [edge, distance] of Object.entries(distances)) {\r\n if (distance < threshold) {\r\n return {\r\n edge: edge as 'top' | 'right' | 'bottom' | 'left',\r\n distance,\r\n };\r\n }\r\n }\r\n\r\n return { edge: null, distance: Infinity };\r\n}\r\n\r\n/**\r\n * Calculate scroll speed based on distance from edge\r\n * Closer to edge = faster scroll\r\n */\r\nexport function calculateScrollSpeed(\r\n distance: number,\r\n threshold: number,\r\n maxSpeed: number\r\n): number {\r\n if (distance >= threshold) return 0;\r\n const ratio = (threshold - distance) / threshold;\r\n return ratio * maxSpeed;\r\n}\r\n\r\n/**\r\n * Check if a point is inside a rectangle\r\n */\r\nexport function isPointInRect(point: { x: number; y: number }, rect: DOMRect): boolean {\r\n return (\r\n point.x >= rect.left &&\r\n point.x <= rect.right &&\r\n point.y >= rect.top &&\r\n point.y <= rect.bottom\r\n );\r\n}\r\n\r\n/**\r\n * Calculate the center point of a rectangle\r\n */\r\nexport function getRectCenter(rect: DOMRect): { x: number; y: number } {\r\n return {\r\n x: rect.left + rect.width / 2,\r\n y: rect.top + rect.height / 2,\r\n };\r\n}\r\n\r\n/**\r\n * Calculate vertical drop position based on mouse Y relative to element center\r\n */\r\nexport function getVerticalDropPosition(\r\n mouseY: number,\r\n elementRect: DOMRect\r\n): 'top' | 'bottom' {\r\n const center = getRectCenter(elementRect);\r\n return mouseY < center.y ? 'top' : 'bottom';\r\n}\r\n\r\n/**\r\n * Calculate horizontal drop position based on mouse X relative to element center\r\n */\r\nexport function getHorizontalDropPosition(\r\n mouseX: number,\r\n elementRect: DOMRect\r\n): 'left' | 'right' {\r\n const center = getRectCenter(elementRect);\r\n return mouseX < center.x ? 'left' : 'right';\r\n}\r\n","/**\r\n * Announcer Component\r\n *\r\n * Provides screen reader announcements for drag-and-drop operations.\r\n */\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\n\r\ninterface AnnouncerContextValue {\r\n announce: (message: string, politeness?: 'polite' | 'assertive') => void;\r\n}\r\n\r\nconst AnnouncerContext = createContext<AnnouncerContextValue | null>(null);\r\n\r\n/**\r\n * Hook to access the announcer context\r\n */\r\nexport function useAnnouncer(): AnnouncerContextValue {\r\n const context = useContext(AnnouncerContext);\r\n if (!context) {\r\n throw new Error('useAnnouncer must be used within AnnouncerProvider');\r\n }\r\n return context;\r\n}\r\n\r\n/**\r\n * Props for AnnouncerProvider\r\n */\r\nexport interface AnnouncerProviderProps {\r\n /** Child components */\r\n children: React.ReactNode;\r\n /** Default politeness level */\r\n politeness?: 'polite' | 'assertive';\r\n}\r\n\r\n/**\r\n * Provider component that creates a live region for screen reader announcements\r\n */\r\nexport function AnnouncerProvider({\r\n children,\r\n politeness = 'polite',\r\n}: AnnouncerProviderProps) {\r\n const politeRef = useRef<HTMLDivElement>(null);\r\n const assertiveRef = useRef<HTMLDivElement>(null);\r\n const timeoutRef = useRef<NodeJS.Timeout>();\r\n\r\n const announce = (message: string, announcePoliteness: 'polite' | 'assertive' = politeness) => {\r\n const regionRef = announcePoliteness === 'assertive' ? assertiveRef : politeRef;\r\n\r\n if (!regionRef.current) return;\r\n\r\n // Clear existing timeout\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n\r\n // Clear the region first\r\n regionRef.current.textContent = '';\r\n\r\n // Set the new message after a brief delay to ensure screen readers pick it up\r\n timeoutRef.current = setTimeout(() => {\r\n if (regionRef.current) {\r\n regionRef.current.textContent = message;\r\n }\r\n }, 100);\r\n };\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n };\r\n }, []);\r\n\r\n const value: AnnouncerContextValue = {\r\n announce,\r\n };\r\n\r\n return (\r\n <AnnouncerContext.Provider value={value}>\r\n {children}\r\n {/* Polite live region */}\r\n <div\r\n ref={politeRef}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n aria-atomic=\"true\"\r\n style={{\r\n position: 'absolute',\r\n width: '1px',\r\n height: '1px',\r\n padding: '0',\r\n margin: '-1px',\r\n overflow: 'hidden',\r\n clip: 'rect(0, 0, 0, 0)',\r\n whiteSpace: 'nowrap',\r\n border: '0',\r\n }}\r\n />\r\n {/* Assertive live region */}\r\n <div\r\n ref={assertiveRef}\r\n role=\"alert\"\r\n aria-live=\"assertive\"\r\n aria-atomic=\"true\"\r\n style={{\r\n position: 'absolute',\r\n width: '1px',\r\n height: '1px',\r\n padding: '0',\r\n margin: '-1px',\r\n overflow: 'hidden',\r\n clip: 'rect(0, 0, 0, 0)',\r\n whiteSpace: 'nowrap',\r\n border: '0',\r\n }}\r\n />\r\n </AnnouncerContext.Provider>\r\n );\r\n}\r\n\r\n/**\r\n * Generate announcement messages for different drag events\r\n */\r\nexport const announcements = {\r\n onDragStart: (itemName: string, position: number, totalItems: number): string =>\r\n `Picked up ${itemName}. Position ${position + 1} of ${totalItems}.`,\r\n\r\n onDragMove: (itemName: string, newPosition: number, totalItems: number): string =>\r\n `${itemName} moved to position ${newPosition + 1} of ${totalItems}.`,\r\n\r\n onDragEnd: (itemName: string, from: string, to: string, position: number): string =>\r\n from === to\r\n ? `${itemName} dropped. Position ${position + 1} in ${to}.`\r\n : `${itemName} moved from ${from} to ${to}. Position ${position + 1}.`,\r\n\r\n onDragCancel: (itemName: string, column: string): string =>\r\n `Drag cancelled. ${itemName} returned to ${column}.`,\r\n\r\n onColumnMove: (columnName: string, position: number, totalColumns: number): string =>\r\n `${columnName} moved to position ${position + 1} of ${totalColumns}.`,\r\n};\r\n"],"names":["KanbanContext","createContext","KANBAN_COLUMN","KanbanColumnView","column","cardIds","children","isDragDisabled","index","columnRef","useRef","dropZoneRef","isDragging","setIsDragging","useState","isDraggingOver","setIsDraggingOver","createDraggableColumn","useCallback","element","draggable","getInitialData","type","id","onDragStart","onDrop","createColumnDropTarget","dropTargetForElements","getData","input","data","attachClosestEdge","allowedEdges","canDrop","source","createCardDropZone","columnId","onDragEnter","onDragLeave","useEffect","columnElement","current","dropZoneElement","cleanups","forEach","cleanup","provided","draggableProps","style","opacity","undefined","dragHandleProps","tabIndex","role","title","length","innerRef","snapshot","React","createElement","Fragment","KANBAN_CARD","KanbanCardView","card","cardRef","createDraggable","createDropTarget","combine","reorderArray","list","startIndex","endIndex","result","Array","from","removed","splice","normalizeReorderDestinationIndex","params","itemCount","sourceIndex","rawDestinationIndex","isSameList","maxRaw","clampedRaw","Math","max","min","adjusted","maxFinal","applyDragResult","state","destination","Object","assign","columns","reorderColumns","find","col","newCardIds","map","reorderCardInColumn","cardId","sourceColumn","destColumn","newSourceCardIds","newDestCardIds","moveCardBetweenColumns","draggableId","useKanbanDnd","onDragEnd","disabled","dragState","setDragState","draggingId","draggingType","monitorForElements","typeRaw","sourceLocation","location","sourceType","sourceId","sourceColumnId","dropTargets","columnTarget","target","destColumnId","cardTarget","destIndex","extractClosestEdge","isSameColumn","normalizedIndex","edge","KanbanBoard","renderColumn","renderCard","getCardKey","getColumnKey","className","contextValue","useMemo","cardKeyExtractor","columnKeyExtractor","Provider","value","display","gap","columnIndex","key","columnProvided","columnSnapshot","ref","minWidth","flexDirection","flex","minHeight","cardIndex","cards","cardProvided","cardSnapshot","DEFAULT_CONFIG","threshold","maxSpeed","enabled","useAutoscroll","containerRef","config","rafRef","lastMousePosRef","handleMouseMove","event","x","clientX","y","clientY","performScroll","scrollParent","parent","parentElement","overflow","overflowY","window","getComputedStyle","test","document","documentElement","getScrollParent","rect","getBoundingClientRect","mousePos","scrollability","overflowX","hasVerticalScroll","hasHorizontalScroll","vertical","scrollHeight","clientHeight","horizontal","scrollWidth","clientWidth","isScrollable","nearEdge","point","distances","top","right","bottom","left","distanceToEdge","distance","entries","Infinity","isNearEdge","speed","calculateScrollSpeed","delta","scrollLeft","scrollTop","scrollBy","requestAnimationFrame","addEventListener","removeEventListener","cancelAnimationFrame","AnnouncerContext","useAnnouncer","context","useContext","Error","AnnouncerProvider","politeness","politeRef","assertiveRef","timeoutRef","clearTimeout","announce","message","announcePoliteness","regionRef","textContent","setTimeout","position","width","height","padding","margin","clip","whiteSpace","border","announcements","itemName","totalItems","onDragMove","newPosition","to","onDragCancel","onColumnMove","columnName","totalColumns"],"mappings":"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"}
|
package/dist/kanban.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react"),t=require("@atlaskit/pragmatic-drag-and-drop/element/adapter"),n=require("@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"),r=require("@atlaskit/pragmatic-drag-and-drop/combine");const a=e.createContext(null),o="kanban-column";function i({column:r,cardIds:a,children:i,isDragDisabled:d=!1,index:s}){const
|
|
1
|
+
"use strict";var e=require("react"),t=require("@atlaskit/pragmatic-drag-and-drop/element/adapter"),n=require("@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"),r=require("@atlaskit/pragmatic-drag-and-drop/combine");const a=e.createContext(null),o="kanban-column";function i({column:r,cardIds:a,children:i,isDragDisabled:d=!1,index:s}){const c=e.useRef(null),l=e.useRef(null),[u,g]=e.useState(!1),[m,p]=e.useState(!1),f=e.useCallback(e=>d?()=>{}:t.draggable({element:e,getInitialData:()=>({type:o,id:r.id,index:s}),onDragStart:()=>g(!0),onDrop:()=>g(!1)}),[r.id,s,d]),b=e.useCallback(e=>d?()=>{}:t.dropTargetForElements({element:e,getData:({input:e,element:t})=>{const a={type:o,id:r.id,index:s};return n.attachClosestEdge(a,{input:e,element:t,allowedEdges:["left","right"]})},canDrop:({source:e})=>e.data.type===o&&e.data.id!==r.id}),[r.id,s,d]),x=e.useCallback(e=>t.dropTargetForElements({element:e,getData:()=>({type:"kanban-column-drop-zone",columnId:r.id}),canDrop:({source:e})=>"kanban-card"===e.data.type,onDragEnter:()=>p(!0),onDragLeave:()=>p(!1),onDrop:()=>p(!1)}),[r.id]);e.useEffect(()=>{const e=c.current,t=l.current;if(!e||!t)return;const n=[f(e),b(e),x(t)];return()=>{n.forEach(e=>e())}},[f,b,x]);const D={draggableProps:{"data-draggable-id":r.id,"data-draggable-type":"COLUMN",style:u?{opacity:.5}:void 0},dragHandleProps:{tabIndex:0,role:"button","aria-roledescription":"draggable column","aria-label":`${r.title}, ${a.length} cards, press space to pick up`},innerRef:c,dropZoneRef:l},y={isDragging:u,isDraggingOver:m};return e.createElement(e.Fragment,null,i(D,y))}const d="kanban-card";function s({card:a,children:o,isDragDisabled:i=!1,index:s,columnId:c}){const l=e.useRef(null),[u,g]=e.useState(!1),[m,p]=e.useState(!1),f=e.useCallback(e=>i?()=>{}:t.draggable({element:e,getInitialData:()=>({type:d,id:a.id,index:s,columnId:c}),onDragStart:()=>g(!0),onDrop:()=>g(!1)}),[a.id,s,c,i]),b=e.useCallback(e=>i?()=>{}:t.dropTargetForElements({element:e,getData:({input:e,element:t})=>{const r={type:d,id:a.id,index:s,columnId:c};return n.attachClosestEdge(r,{input:e,element:t,allowedEdges:["top","bottom"]})},canDrop:({source:e})=>e.data.type===d&&e.data.id!==a.id,onDragEnter:()=>p(!0),onDragLeave:()=>p(!1),onDrop:()=>p(!1)}),[a.id,s,c,i]);e.useEffect(()=>{const e=l.current;if(e&&!i)return r.combine(f(e),b(e))},[f,b,i]);const x={draggableProps:{"data-draggable-id":a.id,"data-draggable-type":"CARD",style:u?{opacity:.5}:void 0},dragHandleProps:{tabIndex:0,role:"button","aria-roledescription":"draggable card","aria-label":`${a.title}, press space to pick up`},innerRef:l},D={isDragging:u,isDraggingOver:m};return e.createElement(e.Fragment,null,o(x,D))}function c(e,t,n){const r=Array.from(e),[a]=r.splice(t,1);return r.splice(n,0,a),r}function l(e){const{itemCount:t,sourceIndex:n,rawDestinationIndex:r,isSameList:a}=e;if(t<=0)return 0;const o=t,i=Math.max(0,Math.min(r,o)),d=a&&n<i?i-1:i,s=a?t-1:t;return Math.max(0,Math.min(d,s))}const u="kanban-card",g="kanban-column";function m({onDragStart:r,onDragEnd:a,state:o,disabled:i}){const[d,s]=e.useState({draggingId:null,draggingType:null,source:null,destination:null});return e.useEffect(()=>{if(i)return;return t.monitorForElements({onDragStart({source:e}){const t=e.data.type,n=e.data.id,a=e.data.columnId,o=e.data.index,i=t===u?"CARD":"COLUMN",d={columnId:"CARD"===i?a:void 0,index:o};s({draggingId:n,draggingType:i,source:d,destination:d}),null==r||r({id:n,type:i})},onDrop({source:e,location:t}){const r=e.data.type,i=e.data.id,d=e.data.index,c=e.data.columnId,m=t.current.dropTargets;let p;if(r===u){const e=m.find(e=>"kanban-column-drop-zone"===e.data.type);if(e){const t=e.data.columnId,r=o.columns.find(e=>e.id===c),a=o.columns.find(e=>e.id===t);if(r&&a){const e=m.find(e=>e.data.type===u&&e.data.id!==i);let o=a.cardIds.length;if(e){const t=e.data.index;o="bottom"===n.extractClosestEdge(e.data)?t+1:t}const s=c===t,g=l({itemCount:s?r.cardIds.length:a.cardIds.length,sourceIndex:d,rawDestinationIndex:o,isSameList:s});p={columnId:t,index:g}}}}else if(r===g){const e=m.find(e=>e.data.type===g&&e.data.id!==i);if(e){const t=e.data.index,r=n.extractClosestEdge(e.data),a="bottom"===r||"right"===r?t+1:t;p={index:l({itemCount:o.columns.length,sourceIndex:d,rawDestinationIndex:a,isSameList:!0})}}}const f={type:r===u?"CARD":"COLUMN",source:{columnId:c,index:d},destination:p,draggableId:i};s({draggingId:null,draggingType:null,source:null,destination:null}),a(f,o)}})},[i,r,a,o]),d}const p={threshold:50,maxSpeed:20,enabled:!0};const f=e.createContext(null);exports.AnnouncerProvider=function({children:t,politeness:n="polite"}){const r=e.useRef(null),a=e.useRef(null),o=e.useRef();e.useEffect(()=>()=>{o.current&&clearTimeout(o.current)},[]);const i={announce:(e,t=n)=>{const i="assertive"===t?a:r;i.current&&(o.current&&clearTimeout(o.current),i.current.textContent="",o.current=setTimeout(()=>{i.current&&(i.current.textContent=e)},100))}};return e.createElement(f.Provider,{value:i},t,e.createElement("div",{ref:r,role:"status","aria-live":"polite","aria-atomic":"true",style:{position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",border:"0"}}),e.createElement("div",{ref:a,role:"alert","aria-live":"assertive","aria-atomic":"true",style:{position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",border:"0"}}))},exports.KanbanBoard=function({state:t,onDragEnd:n,onDragStart:r,renderColumn:o,renderCard:d,getCardKey:c,getColumnKey:l,isDragDisabled:u,className:g,style:p}){const f=m({state:t,onDragEnd:n,onDragStart:r,disabled:!1}),b=e.useMemo(()=>({state:t,dragState:f,isDragDisabled:u}),[t,f,u]),x=c||(e=>e.id),D=l||(e=>e.id);return e.createElement(a.Provider,{value:b},e.createElement("div",{className:g,style:Object.assign({display:"flex",gap:"16px"},p)},t.columns.map((n,r)=>e.createElement(i,{key:D(n),column:n,cardIds:n.cardIds,index:r,isDragDisabled:null==u?void 0:u(n.id,"COLUMN")},(r,a)=>e.createElement("div",Object.assign({ref:r.innerRef},r.draggableProps,{style:Object.assign({minWidth:"250px",display:"flex",flexDirection:"column"},r.draggableProps.style)}),e.createElement("div",Object.assign({},r.dragHandleProps),o(n,r,a)),e.createElement("div",{ref:r.dropZoneRef,style:{flex:1,minHeight:"100px",display:"flex",flexDirection:"column",gap:"8px"}},n.cardIds.map((r,a)=>{const o=t.cards[r];return o?e.createElement(s,{key:x(o),card:o,index:a,columnId:n.id,isDragDisabled:null==u?void 0:u(o.id,"CARD")},(t,n)=>e.createElement("div",Object.assign({ref:t.innerRef},t.draggableProps,t.dragHandleProps),d(o,t,n))):null})))))))},exports.KanbanCardView=s,exports.KanbanColumnView=i,exports.announcements={onDragStart:(e,t,n)=>`Picked up ${e}. Position ${t+1} of ${n}.`,onDragMove:(e,t,n)=>`${e} moved to position ${t+1} of ${n}.`,onDragEnd:(e,t,n,r)=>t===n?`${e} dropped. Position ${r+1} in ${n}.`:`${e} moved from ${t} to ${n}. Position ${r+1}.`,onDragCancel:(e,t)=>`Drag cancelled. ${e} returned to ${t}.`,onColumnMove:(e,t,n)=>`${e} moved to position ${t+1} of ${n}.`},exports.applyDragResult=function(e,t){if(!t.destination)return e;const{source:n,destination:r,type:a}=t;return"COLUMN"===a?n.index===r.index?e:function(e,t,n){return Object.assign(Object.assign({},e),{columns:c(e.columns,t,n)})}(e,n.index,r.index):"CARD"===a?n.columnId===r.columnId?n.index===r.index?e:function(e,t,n,r){const a=e.columns.find(e=>e.id===t);if(!a)return e;const o=c(a.cardIds,n,r);return Object.assign(Object.assign({},e),{columns:e.columns.map(e=>e.id===t?Object.assign(Object.assign({},e),{cardIds:o}):e)})}(e,n.columnId,n.index,r.index):function(e,t,n,r){const a=e.columns.find(e=>e.id===t.columnId),o=e.columns.find(e=>e.id===n.columnId);if(!a||!o)return e;const i=[...a.cardIds];i.splice(t.index,1);const d=[...o.cardIds];return d.splice(n.index,0,r),Object.assign(Object.assign({},e),{columns:e.columns.map(e=>e.id===t.columnId?Object.assign(Object.assign({},e),{cardIds:i}):e.id===n.columnId?Object.assign(Object.assign({},e),{cardIds:d}):e)})}(e,n,r,t.draggableId):e},exports.reorderArray=c,exports.useAnnouncer=function(){const t=e.useContext(f);if(!t)throw new Error("useAnnouncer must be used within AnnouncerProvider");return t},exports.useAutoscroll=function(t,n,r={}){const{threshold:a,maxSpeed:o,enabled:i}=Object.assign(Object.assign({},p),r),d=e.useRef(),s=e.useRef(null),c=e.useCallback(e=>{s.current={x:e.clientX,y:e.clientY}},[]),l=e.useCallback(()=>{if(!(i&&n&&t.current&&s.current))return;const e=function(e){if(!e)return null;let t=e.parentElement;for(;t;){const{overflow:e,overflowY:n}=window.getComputedStyle(t);if(/(auto|scroll)/.test(e+n))return t;t=t.parentElement}return document.documentElement}(t.current);if(!e)return;const r=e.getBoundingClientRect(),c=s.current,u=function(e){const{overflow:t,overflowY:n,overflowX:r}=window.getComputedStyle(e),a=/(auto|scroll)/.test(t+n),o=/(auto|scroll)/.test(t+r);return{vertical:a&&e.scrollHeight>e.clientHeight,horizontal:o&&e.scrollWidth>e.clientWidth}}(e),g=function(e,t,n){const r=function(e,t){return{top:e.y-t.top,right:t.right-e.x,bottom:t.bottom-e.y,left:e.x-t.left}}(e,t);for(const[e,t]of Object.entries(r))if(t<n)return{edge:e,distance:t};return{edge:null,distance:1/0}}(c,r,a);if(g.edge){const t=function(e,t,n){return e>=t?0:(t-e)/t*n}(g.distance,a,o),n={x:0,y:0};u.vertical&&("top"===g.edge?n.y=-t:"bottom"===g.edge&&(n.y=t)),u.horizontal&&("left"===g.edge?n.x=-t:"right"===g.edge&&(n.x=t)),0===n.x&&0===n.y||function(e,t){t.x&&(e.scrollLeft+=t.x),t.y&&(e.scrollTop+=t.y)}(e,n)}d.current=requestAnimationFrame(l)},[i,n,t,a,o]);e.useEffect(()=>i&&n?(window.addEventListener("mousemove",c),d.current=requestAnimationFrame(l),()=>{window.removeEventListener("mousemove",c),d.current&&cancelAnimationFrame(d.current)}):(d.current&&(cancelAnimationFrame(d.current),d.current=void 0),void(s.current=null)),[i,n,c,l])},exports.useKanbanDnd=m;
|
|
2
2
|
//# sourceMappingURL=kanban.js.map
|
package/dist/kanban.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kanban.js","sources":["../src/kanban/context.ts","../src/kanban/components/KanbanColumnView.tsx","../src/kanban/components/KanbanCardView.tsx","../src/kanban/hooks/useKanbanDnd.ts","../src/kanban/hooks/useAutoscroll.ts","../src/kanban/a11y/Announcer.tsx","../src/kanban/utils/reorder.ts","../src/kanban/components/KanbanBoard.tsx","../src/kanban/utils/dom.ts","../src/kanban/utils/dndMath.ts"],"sourcesContent":["/**\n * Kanban Board Context\n *\n * Internal context for sharing board state between components.\n */\n\nimport { createContext, useContext } from 'react';\nimport type { KanbanBoardState, KanbanDragState } from './types';\n\nexport interface KanbanContextValue {\n state: KanbanBoardState;\n dragState: KanbanDragState;\n isDragDisabled?: (id: string, type: 'CARD' | 'COLUMN') => boolean;\n}\n\nexport const KanbanContext = createContext<KanbanContextValue | null>(null);\n\nexport function useKanbanContext(): KanbanContextValue {\n const context = useContext(KanbanContext);\n if (!context) {\n throw new Error('Kanban components must be used within KanbanBoard');\n }\n return context;\n}\n","/**\n * Kanban Column View (Headless)\n *\n * Headless component for rendering draggable columns with drop zones.\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanColumnViewProps, DragProvided, DragSnapshot } from '../types';\n\nconst KANBAN_COLUMN = 'kanban-column';\nconst KANBAN_COLUMN_DROP_ZONE = 'kanban-column-drop-zone';\n\nexport function KanbanColumnView({\n column,\n cardIds,\n children,\n isDragDisabled = false,\n index,\n}: KanbanColumnViewProps) {\n const columnRef = useRef<HTMLDivElement>(null);\n const dropZoneRef = useRef<HTMLDivElement>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n\n // Make column header draggable\n const createDraggableColumn = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return draggable({\n element,\n getInitialData: () => ({\n type: KANBAN_COLUMN,\n id: column.id,\n index,\n }),\n onDragStart: () => setIsDragging(true),\n onDrop: () => setIsDragging(false),\n });\n },\n [column.id, index, isDragDisabled]\n );\n\n // Make column header a drop target for column reordering\n const createColumnDropTarget = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return dropTargetForElements({\n element,\n getData: ({ input, element }) => {\n const data = { type: KANBAN_COLUMN, id: column.id, index };\n return attachClosestEdge(data, { input, element, allowedEdges: ['left', 'right'] });\n },\n canDrop: ({ source }) => source.data.type === KANBAN_COLUMN && source.data.id !== column.id,\n });\n },\n [column.id, index, isDragDisabled]\n );\n\n // Make card list area a drop zone for cards\n const createCardDropZone = useCallback(\n (element: HTMLElement) => {\n return dropTargetForElements({\n element,\n getData: () => ({\n type: KANBAN_COLUMN_DROP_ZONE,\n columnId: column.id,\n }),\n canDrop: ({ source }) => source.data.type === 'kanban-card',\n onDragEnter: () => setIsDraggingOver(true),\n onDragLeave: () => setIsDraggingOver(false),\n onDrop: () => setIsDraggingOver(false),\n });\n },\n [column.id]\n );\n\n useEffect(() => {\n const columnElement = columnRef.current;\n const dropZoneElement = dropZoneRef.current;\n if (!columnElement || !dropZoneElement) return;\n\n const cleanups = [\n createDraggableColumn(columnElement),\n createColumnDropTarget(columnElement),\n createCardDropZone(dropZoneElement),\n ];\n\n return () => {\n cleanups.forEach((cleanup) => cleanup());\n };\n }, [createDraggableColumn, createColumnDropTarget, createCardDropZone]);\n\n const provided: DragProvided = {\n draggableProps: {\n 'data-draggable-id': column.id,\n 'data-draggable-type': 'COLUMN',\n style: isDragging ? { opacity: 0.5 } : undefined,\n },\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable column',\n 'aria-label': `${column.title}, press space to pick up`,\n },\n innerRef: columnRef as React.RefObject<HTMLElement>,\n };\n\n const snapshot: DragSnapshot = {\n isDragging,\n isDraggingOver,\n };\n\n // Pass both refs through provided\n const providedWithDropZone = {\n ...provided,\n dropZoneRef,\n };\n\n return <>{children(providedWithDropZone as any, snapshot)}</>;\n}\n","/**\n * Kanban Card View (Headless)\n *\n * Headless component for rendering draggable cards.\n */\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanCardViewProps, DragProvided, DragSnapshot } from '../types';\n\nconst KANBAN_CARD = 'kanban-card';\n\nexport function KanbanCardView({\n card,\n children,\n isDragDisabled = false,\n index,\n columnId,\n}: KanbanCardViewProps) {\n const cardRef = useRef<HTMLDivElement>(null);\n const [isDragging, setIsDragging] = useState(false);\n const [isDraggingOver, setIsDraggingOver] = useState(false);\n\n const createDraggable = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return draggable({\n element,\n getInitialData: () => ({\n type: KANBAN_CARD,\n id: card.id,\n index,\n columnId,\n }),\n onDragStart: () => setIsDragging(true),\n onDrop: () => setIsDragging(false),\n });\n },\n [card.id, index, columnId, isDragDisabled]\n );\n\n const createDropTarget = useCallback(\n (element: HTMLElement) => {\n if (isDragDisabled) return () => {};\n\n return dropTargetForElements({\n element,\n getData: ({ input, element }) => {\n const data = { type: KANBAN_CARD, id: card.id, index, columnId };\n return attachClosestEdge(data, { input, element, allowedEdges: ['top', 'bottom'] });\n },\n canDrop: ({ source }) => source.data.type === KANBAN_CARD && source.data.id !== card.id,\n onDragEnter: () => setIsDraggingOver(true),\n onDragLeave: () => setIsDraggingOver(false),\n onDrop: () => setIsDraggingOver(false),\n });\n },\n [card.id, index, columnId, isDragDisabled]\n );\n\n useEffect(() => {\n const element = cardRef.current;\n if (!element || isDragDisabled) return;\n\n return combine(createDraggable(element), createDropTarget(element));\n }, [createDraggable, createDropTarget, isDragDisabled]);\n\n const provided: DragProvided = {\n draggableProps: {\n 'data-draggable-id': card.id,\n 'data-draggable-type': 'CARD',\n style: isDragging ? { opacity: 0.5 } : undefined,\n },\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable card',\n 'aria-label': `${card.title}, press space to pick up`,\n },\n innerRef: cardRef as React.RefObject<HTMLElement>,\n };\n\n const snapshot: DragSnapshot = {\n isDragging,\n isDraggingOver,\n };\n\n return <>{children(provided, snapshot)}</>;\n}\n","/**\n * Core Kanban DnD Hook\n *\n * Main hook that manages drag-and-drop state for the Kanban board.\n */\n\nimport { useState, useEffect } from 'react';\nimport { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanDragState, DropResult, DragLocation, KanbanBoardState } from '../types';\n\nconst KANBAN_CARD = 'kanban-card';\nconst KANBAN_COLUMN = 'kanban-column';\n\nexport interface UseKanbanDndOptions {\n onDragStart?: (draggable: { id: string; type: 'CARD' | 'COLUMN' }) => void;\n onDragEnd: (result: DropResult, stateBefore: KanbanBoardState) => void;\n state: KanbanBoardState;\n disabled?: boolean;\n}\n\nexport function useKanbanDnd({ onDragStart, onDragEnd, state, disabled }: UseKanbanDndOptions) {\n const [dragState, setDragState] = useState<KanbanDragState>({\n draggingId: null,\n draggingType: null,\n source: null,\n destination: null,\n });\n\n useEffect(() => {\n if (disabled) return;\n\n const cleanup = monitorForElements({\n onDragStart({ source }) {\n const typeRaw = source.data.type as string;\n const id = source.data.id as string;\n const columnId = source.data.columnId as string | undefined;\n const index = source.data.index as number;\n\n const type: 'CARD' | 'COLUMN' = typeRaw === KANBAN_CARD ? 'CARD' : 'COLUMN';\n\n const sourceLocation: DragLocation = {\n columnId: type === 'CARD' ? columnId : undefined,\n index,\n };\n\n setDragState({\n draggingId: id,\n draggingType: type,\n source: sourceLocation,\n destination: sourceLocation,\n });\n\n onDragStart?.({ id, type });\n },\n\n onDrop({ source, location }) {\n const sourceType = source.data.type as string;\n const sourceId = source.data.id as string;\n const sourceIndex = source.data.index as number;\n const sourceColumnId = source.data.columnId as string | undefined;\n\n // Find the drop target\n const dropTargets = location.current.dropTargets;\n\n let destination: DragLocation | undefined;\n\n if (sourceType === KANBAN_CARD) {\n // Card drop - find column drop target\n const columnTarget = dropTargets.find((target) =>\n target.data.type === 'kanban-column-drop-zone'\n );\n\n if (columnTarget) {\n const destColumnId = columnTarget.data.columnId as string;\n const cardTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_CARD && target.data.id !== sourceId\n );\n\n if (cardTarget) {\n // Dropping on another card\n const destIndex = cardTarget.data.index as number;\n const edge = extractClosestEdge(cardTarget);\n\n destination = {\n columnId: destColumnId,\n index: edge === 'bottom' ? destIndex + 1 : destIndex,\n };\n } else {\n // Dropping in empty column\n destination = {\n columnId: destColumnId,\n index: 0,\n };\n }\n }\n } else if (sourceType === KANBAN_COLUMN) {\n // Column drop\n const columnTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_COLUMN && target.data.id !== sourceId\n );\n\n if (columnTarget) {\n const destIndex = columnTarget.data.index as number;\n const edge = extractClosestEdge(columnTarget);\n\n destination = {\n index: edge === 'bottom' || edge === 'right' ? destIndex + 1 : destIndex,\n };\n }\n }\n\n const result: DropResult = {\n type: sourceType === KANBAN_CARD ? 'CARD' : 'COLUMN',\n source: {\n columnId: sourceColumnId,\n index: sourceIndex,\n },\n destination,\n draggableId: sourceId,\n };\n\n setDragState({\n draggingId: null,\n draggingType: null,\n source: null,\n destination: null,\n });\n\n onDragEnd(result, state);\n },\n });\n\n return cleanup;\n }, [disabled, onDragStart, onDragEnd, state]);\n\n return dragState;\n}\n","/**\n * Autoscroll Hook\n *\n * Automatically scrolls containers when dragging near edges.\n */\n\nimport { useEffect, useRef, useCallback } from 'react';\nimport type { AutoscrollConfig } from '../types';\nimport { isNearEdge, calculateScrollSpeed } from '../utils/dndMath';\nimport { getScrollParent, scrollBy, isScrollable } from '../utils/dom';\n\nconst DEFAULT_CONFIG: AutoscrollConfig = {\n threshold: 50, // px from edge\n maxSpeed: 20, // px per frame\n enabled: true,\n};\n\n/**\n * Hook for autoscrolling containers during drag\n */\nexport function useAutoscroll(\n containerRef: React.RefObject<HTMLElement>,\n isDragging: boolean,\n config: Partial<AutoscrollConfig> = {}\n) {\n const { threshold, maxSpeed, enabled } = { ...DEFAULT_CONFIG, ...config };\n const rafRef = useRef<number>();\n const lastMousePosRef = useRef<{ x: number; y: number } | null>(null);\n\n const handleMouseMove = useCallback(\n (event: MouseEvent) => {\n lastMousePosRef.current = { x: event.clientX, y: event.clientY };\n },\n []\n );\n\n const performScroll = useCallback(() => {\n if (!enabled || !isDragging || !containerRef.current || !lastMousePosRef.current) {\n return;\n }\n\n const container = containerRef.current;\n const scrollParent = getScrollParent(container);\n if (!scrollParent) return;\n\n const rect = scrollParent.getBoundingClientRect();\n const mousePos = lastMousePosRef.current;\n const scrollability = isScrollable(scrollParent);\n\n const nearEdge = isNearEdge(mousePos, rect, threshold);\n\n if (nearEdge.edge) {\n const speed = calculateScrollSpeed(nearEdge.distance, threshold, maxSpeed);\n\n const delta = { x: 0, y: 0 };\n\n if (scrollability.vertical) {\n if (nearEdge.edge === 'top') {\n delta.y = -speed;\n } else if (nearEdge.edge === 'bottom') {\n delta.y = speed;\n }\n }\n\n if (scrollability.horizontal) {\n if (nearEdge.edge === 'left') {\n delta.x = -speed;\n } else if (nearEdge.edge === 'right') {\n delta.x = speed;\n }\n }\n\n if (delta.x !== 0 || delta.y !== 0) {\n scrollBy(scrollParent, delta);\n }\n }\n\n rafRef.current = requestAnimationFrame(performScroll);\n }, [enabled, isDragging, containerRef, threshold, maxSpeed]);\n\n useEffect(() => {\n if (!enabled || !isDragging) {\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = undefined;\n }\n lastMousePosRef.current = null;\n return;\n }\n\n window.addEventListener('mousemove', handleMouseMove);\n rafRef.current = requestAnimationFrame(performScroll);\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [enabled, isDragging, handleMouseMove, performScroll]);\n}\n","/**\n * Announcer Component\n *\n * Provides screen reader announcements for drag-and-drop operations.\n */\n\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\n\ninterface AnnouncerContextValue {\n announce: (message: string, politeness?: 'polite' | 'assertive') => void;\n}\n\nconst AnnouncerContext = createContext<AnnouncerContextValue | null>(null);\n\n/**\n * Hook to access the announcer context\n */\nexport function useAnnouncer(): AnnouncerContextValue {\n const context = useContext(AnnouncerContext);\n if (!context) {\n throw new Error('useAnnouncer must be used within AnnouncerProvider');\n }\n return context;\n}\n\n/**\n * Props for AnnouncerProvider\n */\nexport interface AnnouncerProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Default politeness level */\n politeness?: 'polite' | 'assertive';\n}\n\n/**\n * Provider component that creates a live region for screen reader announcements\n */\nexport function AnnouncerProvider({\n children,\n politeness = 'polite',\n}: AnnouncerProviderProps) {\n const politeRef = useRef<HTMLDivElement>(null);\n const assertiveRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n const announce = (message: string, announcePoliteness: 'polite' | 'assertive' = politeness) => {\n const regionRef = announcePoliteness === 'assertive' ? assertiveRef : politeRef;\n\n if (!regionRef.current) return;\n\n // Clear existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n // Clear the region first\n regionRef.current.textContent = '';\n\n // Set the new message after a brief delay to ensure screen readers pick it up\n timeoutRef.current = setTimeout(() => {\n if (regionRef.current) {\n regionRef.current.textContent = message;\n }\n }, 100);\n };\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n const value: AnnouncerContextValue = {\n announce,\n };\n\n return (\n <AnnouncerContext.Provider value={value}>\n {children}\n {/* Polite live region */}\n <div\n ref={politeRef}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n }}\n />\n {/* Assertive live region */}\n <div\n ref={assertiveRef}\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n }}\n />\n </AnnouncerContext.Provider>\n );\n}\n\n/**\n * Generate announcement messages for different drag events\n */\nexport const announcements = {\n onDragStart: (itemName: string, position: number, totalItems: number): string =>\n `Picked up ${itemName}. Position ${position + 1} of ${totalItems}.`,\n\n onDragMove: (itemName: string, newPosition: number, totalItems: number): string =>\n `${itemName} moved to position ${newPosition + 1} of ${totalItems}.`,\n\n onDragEnd: (itemName: string, from: string, to: string, position: number): string =>\n from === to\n ? `${itemName} dropped. Position ${position + 1} in ${to}.`\n : `${itemName} moved from ${from} to ${to}. Position ${position + 1}.`,\n\n onDragCancel: (itemName: string, column: string): string =>\n `Drag cancelled. ${itemName} returned to ${column}.`,\n\n onColumnMove: (columnName: string, position: number, totalColumns: number): string =>\n `${columnName} moved to position ${position + 1} of ${totalColumns}.`,\n};\n","/**\n * Kanban Reorder Utilities\n *\n * Functions for reordering cards and columns in a Kanban board.\n */\n\nimport type { KanbanBoardState, KanbanColumn, DragLocation } from '../types';\n\n/**\n * Reorder an array by moving an item from one index to another\n */\nexport function reorderArray<T>(list: T[], startIndex: number, endIndex: number): T[] {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n}\n\n/**\n * Move a card within the same column\n */\nexport function reorderCardInColumn(\n state: KanbanBoardState,\n columnId: string,\n startIndex: number,\n endIndex: number\n): KanbanBoardState {\n const column = state.columns.find((col) => col.id === columnId);\n if (!column) return state;\n\n const newCardIds = reorderArray(column.cardIds, startIndex, endIndex);\n\n return {\n ...state,\n columns: state.columns.map((col) =>\n col.id === columnId ? { ...col, cardIds: newCardIds } : col\n ),\n };\n}\n\n/**\n * Move a card from one column to another\n */\nexport function moveCardBetweenColumns(\n state: KanbanBoardState,\n source: DragLocation,\n destination: DragLocation,\n cardId: string\n): KanbanBoardState {\n const sourceColumn = state.columns.find((col) => col.id === source.columnId);\n const destColumn = state.columns.find((col) => col.id === destination.columnId);\n\n if (!sourceColumn || !destColumn) return state;\n\n // Remove from source\n const newSourceCardIds = [...sourceColumn.cardIds];\n newSourceCardIds.splice(source.index, 1);\n\n // Add to destination\n const newDestCardIds = [...destColumn.cardIds];\n newDestCardIds.splice(destination.index, 0, cardId);\n\n return {\n ...state,\n columns: state.columns.map((col) => {\n if (col.id === source.columnId) {\n return { ...col, cardIds: newSourceCardIds };\n }\n if (col.id === destination.columnId) {\n return { ...col, cardIds: newDestCardIds };\n }\n return col;\n }),\n };\n}\n\n/**\n * Reorder columns\n */\nexport function reorderColumns(\n state: KanbanBoardState,\n startIndex: number,\n endIndex: number\n): KanbanBoardState {\n return {\n ...state,\n columns: reorderArray(state.columns, startIndex, endIndex),\n };\n}\n\n/**\n * Apply a drag result to the board state\n * This is a convenience function that handles all reorder cases\n */\nexport function applyDragResult(\n state: KanbanBoardState,\n result: {\n type: 'CARD' | 'COLUMN';\n source: DragLocation;\n destination?: DragLocation;\n draggableId: string;\n }\n): KanbanBoardState {\n // No destination = drag canceled\n if (!result.destination) {\n return state;\n }\n\n const { source, destination, type } = result;\n\n // Column reorder\n if (type === 'COLUMN') {\n if (source.index === destination.index) {\n return state; // No change\n }\n return reorderColumns(state, source.index, destination.index);\n }\n\n // Card reorder\n if (type === 'CARD') {\n // Same column\n if (source.columnId === destination.columnId) {\n if (source.index === destination.index) {\n return state; // No change\n }\n return reorderCardInColumn(\n state,\n source.columnId!,\n source.index,\n destination.index\n );\n }\n\n // Different columns\n return moveCardBetweenColumns(state, source, destination, result.draggableId);\n }\n\n return state;\n}\n","/**\n * Kanban Board Component\n *\n * High-level component that composes the Kanban board with all features.\n */\n\nimport React, { useMemo } from 'react';\nimport type { KanbanBoardProps } from '../types';\nimport { KanbanContext } from '../context';\nimport { KanbanColumnView } from './KanbanColumnView';\nimport { KanbanCardView } from './KanbanCardView';\nimport { useKanbanDnd } from '../hooks/useKanbanDnd';\n\nexport function KanbanBoard({\n state,\n onDragEnd,\n onDragStart,\n renderColumn,\n renderCard,\n getCardKey,\n getColumnKey,\n isDragDisabled,\n className,\n style,\n}: KanbanBoardProps) {\n const dragState = useKanbanDnd({\n state,\n onDragEnd,\n onDragStart,\n disabled: false,\n });\n\n const contextValue = useMemo(\n () => ({\n state,\n dragState,\n isDragDisabled,\n }),\n [state, dragState, isDragDisabled]\n );\n\n const defaultGetCardKey = (card: any) => card.id;\n const defaultGetColumnKey = (column: any) => column.id;\n\n const cardKeyExtractor = getCardKey || defaultGetCardKey;\n const columnKeyExtractor = getColumnKey || defaultGetColumnKey;\n\n return (\n <KanbanContext.Provider value={contextValue}>\n <div\n className={className}\n style={{\n display: 'flex',\n gap: '16px',\n ...style,\n }}\n >\n {state.columns.map((column, columnIndex) => (\n <KanbanColumnView\n key={columnKeyExtractor(column)}\n column={column}\n cardIds={column.cardIds}\n index={columnIndex}\n isDragDisabled={isDragDisabled?.(column.id, 'COLUMN')}\n >\n {(columnProvided, columnSnapshot) => (\n <div\n ref={columnProvided.innerRef as any}\n {...columnProvided.draggableProps}\n style={{\n minWidth: '250px',\n display: 'flex',\n flexDirection: 'column',\n ...columnProvided.draggableProps.style,\n }}\n >\n {/* Column header (draggable) */}\n <div {...columnProvided.dragHandleProps}>\n {renderColumn(column, columnProvided, columnSnapshot)}\n </div>\n\n {/* Card drop zone */}\n <div\n ref={(columnProvided as any).dropZoneRef}\n style={{\n flex: 1,\n minHeight: '100px',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n }}\n >\n {column.cardIds.map((cardId, cardIndex) => {\n const card = state.cards[cardId];\n if (!card) return null;\n\n return (\n <KanbanCardView\n key={cardKeyExtractor(card)}\n card={card}\n index={cardIndex}\n columnId={column.id}\n isDragDisabled={isDragDisabled?.(card.id, 'CARD')}\n >\n {(cardProvided, cardSnapshot) => (\n <div\n ref={cardProvided.innerRef as any}\n {...cardProvided.draggableProps}\n {...cardProvided.dragHandleProps}\n >\n {renderCard(card, cardProvided, cardSnapshot)}\n </div>\n )}\n </KanbanCardView>\n );\n })}\n </div>\n </div>\n )}\n </KanbanColumnView>\n ))}\n </div>\n </KanbanContext.Provider>\n );\n}\n","/**\n * DOM Utilities\n *\n * Helper functions for DOM measurements and manipulation.\n */\n\n/**\n * Safely get bounding client rect for an element\n */\nexport function getBoundingRect(element: HTMLElement | null): DOMRect | null {\n if (!element) return null;\n return element.getBoundingClientRect();\n}\n\n/**\n * Get scrollable parent of an element\n */\nexport function getScrollParent(element: HTMLElement | null): HTMLElement | null {\n if (!element) return null;\n\n let parent = element.parentElement;\n\n while (parent) {\n const { overflow, overflowY } = window.getComputedStyle(parent);\n if (/(auto|scroll)/.test(overflow + overflowY)) {\n return parent;\n }\n parent = parent.parentElement;\n }\n\n return document.documentElement as HTMLElement;\n}\n\n/**\n * Scroll an element by a delta\n */\nexport function scrollBy(\n element: HTMLElement,\n delta: { x?: number; y?: number }\n): void {\n if (delta.x) {\n element.scrollLeft += delta.x;\n }\n if (delta.y) {\n element.scrollTop += delta.y;\n }\n}\n\n/**\n * Check if an element is scrollable\n */\nexport function isScrollable(element: HTMLElement): {\n vertical: boolean;\n horizontal: boolean;\n} {\n const { overflow, overflowY, overflowX } = window.getComputedStyle(element);\n\n const hasVerticalScroll = /(auto|scroll)/.test(overflow + overflowY);\n const hasHorizontalScroll = /(auto|scroll)/.test(overflow + overflowX);\n\n return {\n vertical: hasVerticalScroll && element.scrollHeight > element.clientHeight,\n horizontal: hasHorizontalScroll && element.scrollWidth > element.clientWidth,\n };\n}\n\n/**\n * Get element's scroll position\n */\nexport function getScrollPosition(element: HTMLElement): { x: number; y: number } {\n if (element === document.documentElement) {\n return {\n x: window.pageXOffset || document.documentElement.scrollLeft,\n y: window.pageYOffset || document.documentElement.scrollTop,\n };\n }\n\n return {\n x: element.scrollLeft,\n y: element.scrollTop,\n };\n}\n\n/**\n * Get maximum scroll for an element\n */\nexport function getMaxScroll(element: HTMLElement): { x: number; y: number } {\n return {\n x: element.scrollWidth - element.clientWidth,\n y: element.scrollHeight - element.clientHeight,\n };\n}\n\n/**\n * Clamp scroll position to valid range\n */\nexport function clampScroll(\n scroll: { x: number; y: number },\n maxScroll: { x: number; y: number }\n): { x: number; y: number } {\n return {\n x: Math.max(0, Math.min(scroll.x, maxScroll.x)),\n y: Math.max(0, Math.min(scroll.y, maxScroll.y)),\n };\n}\n\n/**\n * Get all data attributes from an element as an object\n */\nexport function getDataAttributes(element: HTMLElement): Record<string, string> {\n const data: Record<string, string> = {};\n for (const key in element.dataset) {\n data[key] = element.dataset[key] || '';\n }\n return data;\n}\n\n/**\n * Find closest ancestor with a data attribute\n */\nexport function findClosestWithData(\n element: HTMLElement | null,\n dataKey: string\n): HTMLElement | null {\n let current = element;\n while (current) {\n if (current.dataset[dataKey]) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n}\n","/**\n * DnD Math Utilities\n *\n * Helper functions for collision detection and positioning calculations.\n */\n\n/**\n * Calculate the distance from a point to a rectangle's edges\n */\nexport function distanceToEdge(\n point: { x: number; y: number },\n rect: DOMRect\n): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n return {\n top: point.y - rect.top,\n right: rect.right - point.x,\n bottom: rect.bottom - point.y,\n left: point.x - rect.left,\n };\n}\n\n/**\n * Get the closest edge of a rectangle to a point\n */\nexport function getClosestEdge(\n point: { x: number; y: number },\n rect: DOMRect\n): 'top' | 'right' | 'bottom' | 'left' {\n const distances = distanceToEdge(point, rect);\n const entries = Object.entries(distances) as Array<[keyof typeof distances, number]>;\n const sorted = entries.sort((a, b) => a[1] - b[1]);\n return sorted[0][0];\n}\n\n/**\n * Check if a point is within a threshold distance from an edge\n */\nexport function isNearEdge(\n point: { x: number; y: number },\n rect: DOMRect,\n threshold: number\n): { edge: 'top' | 'right' | 'bottom' | 'left' | null; distance: number } {\n const distances = distanceToEdge(point, rect);\n\n for (const [edge, distance] of Object.entries(distances)) {\n if (distance < threshold) {\n return {\n edge: edge as 'top' | 'right' | 'bottom' | 'left',\n distance,\n };\n }\n }\n\n return { edge: null, distance: Infinity };\n}\n\n/**\n * Calculate scroll speed based on distance from edge\n * Closer to edge = faster scroll\n */\nexport function calculateScrollSpeed(\n distance: number,\n threshold: number,\n maxSpeed: number\n): number {\n if (distance >= threshold) return 0;\n const ratio = (threshold - distance) / threshold;\n return ratio * maxSpeed;\n}\n\n/**\n * Check if a point is inside a rectangle\n */\nexport function isPointInRect(point: { x: number; y: number }, rect: DOMRect): boolean {\n return (\n point.x >= rect.left &&\n point.x <= rect.right &&\n point.y >= rect.top &&\n point.y <= rect.bottom\n );\n}\n\n/**\n * Calculate the center point of a rectangle\n */\nexport function getRectCenter(rect: DOMRect): { x: number; y: number } {\n return {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n}\n\n/**\n * Calculate vertical drop position based on mouse Y relative to element center\n */\nexport function getVerticalDropPosition(\n mouseY: number,\n elementRect: DOMRect\n): 'top' | 'bottom' {\n const center = getRectCenter(elementRect);\n return mouseY < center.y ? 'top' : 'bottom';\n}\n\n/**\n * Calculate horizontal drop position based on mouse X relative to element center\n */\nexport function getHorizontalDropPosition(\n mouseX: number,\n elementRect: DOMRect\n): 'left' | 'right' {\n const center = getRectCenter(elementRect);\n return mouseX < center.x ? 'left' : 'right';\n}\n"],"names":["KanbanContext","createContext","KANBAN_COLUMN","KanbanColumnView","column","cardIds","children","isDragDisabled","index","columnRef","useRef","dropZoneRef","isDragging","setIsDragging","useState","isDraggingOver","setIsDraggingOver","createDraggableColumn","useCallback","element","draggable","getInitialData","type","id","onDragStart","onDrop","createColumnDropTarget","dropTargetForElements","getData","input","data","attachClosestEdge","allowedEdges","canDrop","source","createCardDropZone","columnId","onDragEnter","onDragLeave","useEffect","columnElement","current","dropZoneElement","cleanups","forEach","cleanup","provided","draggableProps","style","opacity","undefined","dragHandleProps","tabIndex","role","title","innerRef","snapshot","providedWithDropZone","Object","assign","React","createElement","Fragment","KANBAN_CARD","KanbanCardView","card","cardRef","createDraggable","createDropTarget","combine","useKanbanDnd","onDragEnd","state","disabled","dragState","setDragState","draggingId","draggingType","destination","monitorForElements","typeRaw","sourceLocation","location","sourceType","sourceId","sourceIndex","sourceColumnId","dropTargets","columnTarget","find","target","destColumnId","cardTarget","destIndex","extractClosestEdge","edge","result","draggableId","DEFAULT_CONFIG","threshold","maxSpeed","enabled","AnnouncerContext","reorderArray","list","startIndex","endIndex","Array","from","removed","splice","politeness","politeRef","assertiveRef","timeoutRef","clearTimeout","value","announce","message","announcePoliteness","regionRef","textContent","setTimeout","Provider","ref","position","width","height","padding","margin","overflow","clip","whiteSpace","border","renderColumn","renderCard","getCardKey","getColumnKey","className","contextValue","useMemo","cardKeyExtractor","columnKeyExtractor","display","gap","columns","map","columnIndex","key","columnProvided","columnSnapshot","minWidth","flexDirection","flex","minHeight","cardId","cardIndex","cards","cardProvided","cardSnapshot","itemName","totalItems","onDragMove","newPosition","to","onDragCancel","onColumnMove","columnName","totalColumns","reorderColumns","col","newCardIds","reorderCardInColumn","sourceColumn","destColumn","newSourceCardIds","newDestCardIds","moveCardBetweenColumns","context","useContext","Error","containerRef","config","rafRef","lastMousePosRef","handleMouseMove","event","x","clientX","y","clientY","performScroll","scrollParent","parent","parentElement","overflowY","window","getComputedStyle","test","document","documentElement","getScrollParent","rect","getBoundingClientRect","mousePos","scrollability","overflowX","hasVerticalScroll","hasHorizontalScroll","vertical","scrollHeight","clientHeight","horizontal","scrollWidth","clientWidth","isScrollable","nearEdge","point","distances","top","right","bottom","left","distanceToEdge","distance","entries","Infinity","isNearEdge","speed","calculateScrollSpeed","delta","scrollLeft","scrollTop","scrollBy","requestAnimationFrame","addEventListener","removeEventListener","cancelAnimationFrame"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kanban.js","sources":["../src/kanban/context.ts","../src/kanban/components/KanbanColumnView.tsx","../src/kanban/components/KanbanCardView.tsx","../src/kanban/utils/reorder.ts","../src/kanban/hooks/useKanbanDnd.ts","../src/kanban/hooks/useAutoscroll.ts","../src/kanban/a11y/Announcer.tsx","../src/kanban/components/KanbanBoard.tsx","../src/kanban/utils/dom.ts","../src/kanban/utils/dndMath.ts"],"sourcesContent":["/**\r\n * Kanban Board Context\r\n *\r\n * Internal context for sharing board state between components.\r\n */\r\n\r\nimport { createContext, useContext } from 'react';\r\nimport type { KanbanBoardState, KanbanDragState } from './types';\r\n\r\nexport interface KanbanContextValue {\r\n state: KanbanBoardState;\r\n dragState: KanbanDragState;\r\n isDragDisabled?: (id: string, type: 'CARD' | 'COLUMN') => boolean;\r\n}\r\n\r\nexport const KanbanContext = createContext<KanbanContextValue | null>(null);\r\n\r\nexport function useKanbanContext(): KanbanContextValue {\r\n const context = useContext(KanbanContext);\r\n if (!context) {\r\n throw new Error('Kanban components must be used within KanbanBoard');\r\n }\r\n return context;\r\n}\r\n","/**\r\n * Kanban Column View (Headless)\r\n *\r\n * Headless component for rendering draggable columns with drop zones.\r\n */\r\n\r\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\r\nimport type { KanbanColumnViewProps, DragProvided, DragSnapshot } from '../types';\r\n\r\nconst KANBAN_COLUMN = 'kanban-column';\r\nconst KANBAN_COLUMN_DROP_ZONE = 'kanban-column-drop-zone';\r\n\r\nexport function KanbanColumnView({\n column,\n cardIds,\n children,\n isDragDisabled = false,\n index,\r\n}: KanbanColumnViewProps) {\r\n const columnRef = useRef<HTMLDivElement>(null);\r\n const dropZoneRef = useRef<HTMLDivElement>(null);\r\n const [isDragging, setIsDragging] = useState(false);\r\n const [isDraggingOver, setIsDraggingOver] = useState(false);\r\n\r\n // Make column header draggable\r\n const createDraggableColumn = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return draggable({\r\n element,\r\n getInitialData: () => ({\r\n type: KANBAN_COLUMN,\r\n id: column.id,\r\n index,\r\n }),\r\n onDragStart: () => setIsDragging(true),\r\n onDrop: () => setIsDragging(false),\r\n });\r\n },\r\n [column.id, index, isDragDisabled]\r\n );\r\n\r\n // Make column header a drop target for column reordering\r\n const createColumnDropTarget = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return dropTargetForElements({\r\n element,\r\n getData: ({ input, element }) => {\r\n const data = { type: KANBAN_COLUMN, id: column.id, index };\r\n return attachClosestEdge(data, { input, element, allowedEdges: ['left', 'right'] });\r\n },\r\n canDrop: ({ source }) => source.data.type === KANBAN_COLUMN && source.data.id !== column.id,\r\n });\r\n },\r\n [column.id, index, isDragDisabled]\r\n );\r\n\r\n // Make card list area a drop zone for cards\r\n const createCardDropZone = useCallback(\r\n (element: HTMLElement) => {\r\n return dropTargetForElements({\r\n element,\r\n getData: () => ({\r\n type: KANBAN_COLUMN_DROP_ZONE,\r\n columnId: column.id,\r\n }),\r\n canDrop: ({ source }) => source.data.type === 'kanban-card',\r\n onDragEnter: () => setIsDraggingOver(true),\r\n onDragLeave: () => setIsDraggingOver(false),\r\n onDrop: () => setIsDraggingOver(false),\r\n });\r\n },\r\n [column.id]\r\n );\r\n\r\n useEffect(() => {\r\n const columnElement = columnRef.current;\r\n const dropZoneElement = dropZoneRef.current;\r\n if (!columnElement || !dropZoneElement) return;\r\n\r\n const cleanups = [\r\n createDraggableColumn(columnElement),\r\n createColumnDropTarget(columnElement),\r\n createCardDropZone(dropZoneElement),\r\n ];\r\n\r\n return () => {\r\n cleanups.forEach((cleanup) => cleanup());\r\n };\r\n }, [createDraggableColumn, createColumnDropTarget, createCardDropZone]);\r\n\r\n const provided: DragProvided = {\r\n draggableProps: {\r\n 'data-draggable-id': column.id,\r\n 'data-draggable-type': 'COLUMN',\r\n style: isDragging ? { opacity: 0.5 } : undefined,\r\n },\r\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable column',\n 'aria-label': `${column.title}, ${cardIds.length} cards, press space to pick up`,\n },\n innerRef: columnRef,\n dropZoneRef,\n };\n\r\n const snapshot: DragSnapshot = {\r\n isDragging,\r\n isDraggingOver,\r\n };\r\n\r\n // Pass both refs through provided\r\n return <>{children(provided, snapshot)}</>;\n}\n","/**\r\n * Kanban Card View (Headless)\r\n *\r\n * Headless component for rendering draggable cards.\r\n */\r\n\r\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\r\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\r\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\r\nimport { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\r\nimport type { KanbanCardViewProps, DragProvided, DragSnapshot } from '../types';\r\n\r\nconst KANBAN_CARD = 'kanban-card';\r\n\r\nexport function KanbanCardView({\r\n card,\r\n children,\r\n isDragDisabled = false,\r\n index,\r\n columnId,\r\n}: KanbanCardViewProps) {\r\n const cardRef = useRef<HTMLDivElement>(null);\r\n const [isDragging, setIsDragging] = useState(false);\r\n const [isDraggingOver, setIsDraggingOver] = useState(false);\r\n\r\n const createDraggable = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return draggable({\r\n element,\r\n getInitialData: () => ({\r\n type: KANBAN_CARD,\r\n id: card.id,\r\n index,\r\n columnId,\r\n }),\r\n onDragStart: () => setIsDragging(true),\r\n onDrop: () => setIsDragging(false),\r\n });\r\n },\r\n [card.id, index, columnId, isDragDisabled]\r\n );\r\n\r\n const createDropTarget = useCallback(\r\n (element: HTMLElement) => {\r\n if (isDragDisabled) return () => {};\r\n\r\n return dropTargetForElements({\r\n element,\r\n getData: ({ input, element }) => {\r\n const data = { type: KANBAN_CARD, id: card.id, index, columnId };\r\n return attachClosestEdge(data, { input, element, allowedEdges: ['top', 'bottom'] });\r\n },\r\n canDrop: ({ source }) => source.data.type === KANBAN_CARD && source.data.id !== card.id,\r\n onDragEnter: () => setIsDraggingOver(true),\r\n onDragLeave: () => setIsDraggingOver(false),\r\n onDrop: () => setIsDraggingOver(false),\r\n });\r\n },\r\n [card.id, index, columnId, isDragDisabled]\r\n );\r\n\r\n useEffect(() => {\r\n const element = cardRef.current;\r\n if (!element || isDragDisabled) return;\r\n\r\n return combine(createDraggable(element), createDropTarget(element));\r\n }, [createDraggable, createDropTarget, isDragDisabled]);\r\n\r\n const provided: DragProvided = {\r\n draggableProps: {\r\n 'data-draggable-id': card.id,\r\n 'data-draggable-type': 'CARD',\r\n style: isDragging ? { opacity: 0.5 } : undefined,\r\n },\r\n dragHandleProps: {\n tabIndex: 0,\n role: 'button',\n 'aria-roledescription': 'draggable card',\n 'aria-label': `${card.title}, press space to pick up`,\n },\n innerRef: cardRef,\n };\n\r\n const snapshot: DragSnapshot = {\r\n isDragging,\r\n isDraggingOver,\r\n };\r\n\r\n return <>{children(provided, snapshot)}</>;\r\n}\r\n","/**\r\n * Kanban Reorder Utilities\r\n *\r\n * Functions for reordering cards and columns in a Kanban board.\r\n */\r\n\r\nimport type { KanbanBoardState, DragLocation } from '../types';\n\r\n/**\r\n * Reorder an array by moving an item from one index to another\r\n */\r\nexport function reorderArray<T>(list: T[], startIndex: number, endIndex: number): T[] {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n}\n\nexport function normalizeReorderDestinationIndex(params: {\n itemCount: number;\n sourceIndex: number;\n rawDestinationIndex: number;\n isSameList: boolean;\n}): number {\n const { itemCount, sourceIndex, rawDestinationIndex, isSameList } = params;\n\n if (itemCount <= 0) return 0;\n\n const maxRaw = itemCount;\n const clampedRaw = Math.max(0, Math.min(rawDestinationIndex, maxRaw));\n const adjusted = isSameList && sourceIndex < clampedRaw ? clampedRaw - 1 : clampedRaw;\n const maxFinal = isSameList ? itemCount - 1 : itemCount;\n\n return Math.max(0, Math.min(adjusted, maxFinal));\n}\n\r\n/**\r\n * Move a card within the same column\r\n */\r\nexport function reorderCardInColumn(\r\n state: KanbanBoardState,\r\n columnId: string,\r\n startIndex: number,\r\n endIndex: number\r\n): KanbanBoardState {\r\n const column = state.columns.find((col) => col.id === columnId);\r\n if (!column) return state;\r\n\r\n const newCardIds = reorderArray(column.cardIds, startIndex, endIndex);\r\n\r\n return {\r\n ...state,\r\n columns: state.columns.map((col) =>\r\n col.id === columnId ? { ...col, cardIds: newCardIds } : col\r\n ),\r\n };\r\n}\r\n\r\n/**\r\n * Move a card from one column to another\r\n */\r\nexport function moveCardBetweenColumns(\r\n state: KanbanBoardState,\r\n source: DragLocation,\r\n destination: DragLocation,\r\n cardId: string\r\n): KanbanBoardState {\r\n const sourceColumn = state.columns.find((col) => col.id === source.columnId);\r\n const destColumn = state.columns.find((col) => col.id === destination.columnId);\r\n\r\n if (!sourceColumn || !destColumn) return state;\r\n\r\n // Remove from source\r\n const newSourceCardIds = [...sourceColumn.cardIds];\r\n newSourceCardIds.splice(source.index, 1);\r\n\r\n // Add to destination\r\n const newDestCardIds = [...destColumn.cardIds];\r\n newDestCardIds.splice(destination.index, 0, cardId);\r\n\r\n return {\r\n ...state,\r\n columns: state.columns.map((col) => {\r\n if (col.id === source.columnId) {\r\n return { ...col, cardIds: newSourceCardIds };\r\n }\r\n if (col.id === destination.columnId) {\r\n return { ...col, cardIds: newDestCardIds };\r\n }\r\n return col;\r\n }),\r\n };\r\n}\r\n\r\n/**\r\n * Reorder columns\r\n */\r\nexport function reorderColumns(\r\n state: KanbanBoardState,\r\n startIndex: number,\r\n endIndex: number\r\n): KanbanBoardState {\r\n return {\r\n ...state,\r\n columns: reorderArray(state.columns, startIndex, endIndex),\r\n };\r\n}\r\n\r\n/**\r\n * Apply a drag result to the board state\r\n * This is a convenience function that handles all reorder cases\r\n */\r\nexport function applyDragResult(\r\n state: KanbanBoardState,\r\n result: {\r\n type: 'CARD' | 'COLUMN';\r\n source: DragLocation;\r\n destination?: DragLocation;\r\n draggableId: string;\r\n }\r\n): KanbanBoardState {\r\n // No destination = drag canceled\r\n if (!result.destination) {\r\n return state;\r\n }\r\n\r\n const { source, destination, type } = result;\r\n\r\n // Column reorder\r\n if (type === 'COLUMN') {\r\n if (source.index === destination.index) {\r\n return state; // No change\r\n }\r\n return reorderColumns(state, source.index, destination.index);\r\n }\r\n\r\n // Card reorder\r\n if (type === 'CARD') {\r\n // Same column\r\n if (source.columnId === destination.columnId) {\r\n if (source.index === destination.index) {\r\n return state; // No change\r\n }\r\n return reorderCardInColumn(\r\n state,\r\n source.columnId!,\r\n source.index,\r\n destination.index\r\n );\r\n }\r\n\r\n // Different columns\r\n return moveCardBetweenColumns(state, source, destination, result.draggableId);\r\n }\r\n\r\n return state;\r\n}\r\n","/**\r\n * Core Kanban DnD Hook\r\n *\r\n * Main hook that manages drag-and-drop state for the Kanban board.\r\n */\r\n\r\nimport { useState, useEffect } from 'react';\nimport { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport type { KanbanDragState, DropResult, DragLocation, KanbanBoardState } from '../types';\nimport { normalizeReorderDestinationIndex } from '../utils/reorder';\n\r\nconst KANBAN_CARD = 'kanban-card';\r\nconst KANBAN_COLUMN = 'kanban-column';\r\n\r\nexport interface UseKanbanDndOptions {\r\n onDragStart?: (draggable: { id: string; type: 'CARD' | 'COLUMN' }) => void;\r\n onDragEnd: (result: DropResult, stateBefore: KanbanBoardState) => void;\r\n state: KanbanBoardState;\r\n disabled?: boolean;\r\n}\r\n\r\nexport function useKanbanDnd({ onDragStart, onDragEnd, state, disabled }: UseKanbanDndOptions) {\r\n const [dragState, setDragState] = useState<KanbanDragState>({\r\n draggingId: null,\r\n draggingType: null,\r\n source: null,\r\n destination: null,\r\n });\r\n\r\n useEffect(() => {\r\n if (disabled) return;\r\n\r\n const cleanup = monitorForElements({\r\n onDragStart({ source }) {\r\n const typeRaw = source.data.type as string;\r\n const id = source.data.id as string;\r\n const columnId = source.data.columnId as string | undefined;\r\n const index = source.data.index as number;\r\n\r\n const type: 'CARD' | 'COLUMN' = typeRaw === KANBAN_CARD ? 'CARD' : 'COLUMN';\r\n\r\n const sourceLocation: DragLocation = {\r\n columnId: type === 'CARD' ? columnId : undefined,\r\n index,\r\n };\r\n\r\n setDragState({\r\n draggingId: id,\r\n draggingType: type,\r\n source: sourceLocation,\r\n destination: sourceLocation,\r\n });\r\n\r\n onDragStart?.({ id, type });\r\n },\r\n\r\n onDrop({ source, location }) {\n const sourceType = source.data.type as string;\n const sourceId = source.data.id as string;\n const sourceIndex = source.data.index as number;\n const sourceColumnId = source.data.columnId as string | undefined;\n\r\n // Find the drop target\r\n const dropTargets = location.current.dropTargets;\r\n\r\n let destination: DragLocation | undefined;\r\n\r\n if (sourceType === KANBAN_CARD) {\n // Card drop - find column drop target\n const columnTarget = dropTargets.find((target) =>\n target.data.type === 'kanban-column-drop-zone'\n );\n\n if (columnTarget) {\n const destColumnId = columnTarget.data.columnId as string;\n const sourceColumn = state.columns.find((column) => column.id === sourceColumnId);\n const destColumn = state.columns.find((column) => column.id === destColumnId);\n if (sourceColumn && destColumn) {\n const cardTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_CARD && target.data.id !== sourceId\n );\n\n let rawDestinationIndex = destColumn.cardIds.length;\n if (cardTarget) {\n // Dropping on another card\n const destIndex = cardTarget.data.index as number;\n const edge = extractClosestEdge(cardTarget.data);\n rawDestinationIndex = edge === 'bottom' ? destIndex + 1 : destIndex;\n }\n\n const isSameColumn = sourceColumnId === destColumnId;\n const normalizedIndex = normalizeReorderDestinationIndex({\n itemCount: isSameColumn ? sourceColumn.cardIds.length : destColumn.cardIds.length,\n sourceIndex,\n rawDestinationIndex,\n isSameList: isSameColumn,\n });\n\n destination = {\n columnId: destColumnId,\n index: normalizedIndex,\n };\n }\n }\n } else if (sourceType === KANBAN_COLUMN) {\n // Column drop\n const columnTarget = dropTargets.find((target) =>\n target.data.type === KANBAN_COLUMN && target.data.id !== sourceId\n );\n\n if (columnTarget) {\n const destIndex = columnTarget.data.index as number;\n const edge = extractClosestEdge(columnTarget.data);\n const rawDestinationIndex =\n edge === 'bottom' || edge === 'right' ? destIndex + 1 : destIndex;\n\n destination = {\n index: normalizeReorderDestinationIndex({\n itemCount: state.columns.length,\n sourceIndex,\n rawDestinationIndex,\n isSameList: true,\n }),\n };\n }\n }\n\r\n const result: DropResult = {\r\n type: sourceType === KANBAN_CARD ? 'CARD' : 'COLUMN',\r\n source: {\r\n columnId: sourceColumnId,\r\n index: sourceIndex,\r\n },\r\n destination,\r\n draggableId: sourceId,\r\n };\r\n\r\n setDragState({\r\n draggingId: null,\r\n draggingType: null,\r\n source: null,\r\n destination: null,\r\n });\r\n\r\n onDragEnd(result, state);\r\n },\r\n });\r\n\r\n return cleanup;\r\n }, [disabled, onDragStart, onDragEnd, state]);\r\n\r\n return dragState;\r\n}\r\n","/**\r\n * Autoscroll Hook\r\n *\r\n * Automatically scrolls containers when dragging near edges.\r\n */\r\n\r\nimport { useEffect, useRef, useCallback } from 'react';\r\nimport type { AutoscrollConfig } from '../types';\r\nimport { isNearEdge, calculateScrollSpeed } from '../utils/dndMath';\r\nimport { getScrollParent, scrollBy, isScrollable } from '../utils/dom';\r\n\r\nconst DEFAULT_CONFIG: AutoscrollConfig = {\r\n threshold: 50, // px from edge\r\n maxSpeed: 20, // px per frame\r\n enabled: true,\r\n};\r\n\r\n/**\r\n * Hook for autoscrolling containers during drag\r\n */\r\nexport function useAutoscroll(\r\n containerRef: React.RefObject<HTMLElement>,\r\n isDragging: boolean,\r\n config: Partial<AutoscrollConfig> = {}\r\n) {\r\n const { threshold, maxSpeed, enabled } = { ...DEFAULT_CONFIG, ...config };\r\n const rafRef = useRef<number>();\r\n const lastMousePosRef = useRef<{ x: number; y: number } | null>(null);\r\n\r\n const handleMouseMove = useCallback(\r\n (event: MouseEvent) => {\r\n lastMousePosRef.current = { x: event.clientX, y: event.clientY };\r\n },\r\n []\r\n );\r\n\r\n const performScroll = useCallback(() => {\r\n if (!enabled || !isDragging || !containerRef.current || !lastMousePosRef.current) {\r\n return;\r\n }\r\n\r\n const container = containerRef.current;\r\n const scrollParent = getScrollParent(container);\r\n if (!scrollParent) return;\r\n\r\n const rect = scrollParent.getBoundingClientRect();\r\n const mousePos = lastMousePosRef.current;\r\n const scrollability = isScrollable(scrollParent);\r\n\r\n const nearEdge = isNearEdge(mousePos, rect, threshold);\r\n\r\n if (nearEdge.edge) {\r\n const speed = calculateScrollSpeed(nearEdge.distance, threshold, maxSpeed);\r\n\r\n const delta = { x: 0, y: 0 };\r\n\r\n if (scrollability.vertical) {\r\n if (nearEdge.edge === 'top') {\r\n delta.y = -speed;\r\n } else if (nearEdge.edge === 'bottom') {\r\n delta.y = speed;\r\n }\r\n }\r\n\r\n if (scrollability.horizontal) {\r\n if (nearEdge.edge === 'left') {\r\n delta.x = -speed;\r\n } else if (nearEdge.edge === 'right') {\r\n delta.x = speed;\r\n }\r\n }\r\n\r\n if (delta.x !== 0 || delta.y !== 0) {\r\n scrollBy(scrollParent, delta);\r\n }\r\n }\r\n\r\n rafRef.current = requestAnimationFrame(performScroll);\r\n }, [enabled, isDragging, containerRef, threshold, maxSpeed]);\r\n\r\n useEffect(() => {\r\n if (!enabled || !isDragging) {\r\n if (rafRef.current) {\r\n cancelAnimationFrame(rafRef.current);\r\n rafRef.current = undefined;\r\n }\r\n lastMousePosRef.current = null;\r\n return;\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove);\r\n rafRef.current = requestAnimationFrame(performScroll);\r\n\r\n return () => {\r\n window.removeEventListener('mousemove', handleMouseMove);\r\n if (rafRef.current) {\r\n cancelAnimationFrame(rafRef.current);\r\n }\r\n };\r\n }, [enabled, isDragging, handleMouseMove, performScroll]);\r\n}\r\n","/**\r\n * Announcer Component\r\n *\r\n * Provides screen reader announcements for drag-and-drop operations.\r\n */\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\n\r\ninterface AnnouncerContextValue {\r\n announce: (message: string, politeness?: 'polite' | 'assertive') => void;\r\n}\r\n\r\nconst AnnouncerContext = createContext<AnnouncerContextValue | null>(null);\r\n\r\n/**\r\n * Hook to access the announcer context\r\n */\r\nexport function useAnnouncer(): AnnouncerContextValue {\r\n const context = useContext(AnnouncerContext);\r\n if (!context) {\r\n throw new Error('useAnnouncer must be used within AnnouncerProvider');\r\n }\r\n return context;\r\n}\r\n\r\n/**\r\n * Props for AnnouncerProvider\r\n */\r\nexport interface AnnouncerProviderProps {\r\n /** Child components */\r\n children: React.ReactNode;\r\n /** Default politeness level */\r\n politeness?: 'polite' | 'assertive';\r\n}\r\n\r\n/**\r\n * Provider component that creates a live region for screen reader announcements\r\n */\r\nexport function AnnouncerProvider({\r\n children,\r\n politeness = 'polite',\r\n}: AnnouncerProviderProps) {\r\n const politeRef = useRef<HTMLDivElement>(null);\r\n const assertiveRef = useRef<HTMLDivElement>(null);\r\n const timeoutRef = useRef<NodeJS.Timeout>();\r\n\r\n const announce = (message: string, announcePoliteness: 'polite' | 'assertive' = politeness) => {\r\n const regionRef = announcePoliteness === 'assertive' ? assertiveRef : politeRef;\r\n\r\n if (!regionRef.current) return;\r\n\r\n // Clear existing timeout\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n\r\n // Clear the region first\r\n regionRef.current.textContent = '';\r\n\r\n // Set the new message after a brief delay to ensure screen readers pick it up\r\n timeoutRef.current = setTimeout(() => {\r\n if (regionRef.current) {\r\n regionRef.current.textContent = message;\r\n }\r\n }, 100);\r\n };\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (timeoutRef.current) {\r\n clearTimeout(timeoutRef.current);\r\n }\r\n };\r\n }, []);\r\n\r\n const value: AnnouncerContextValue = {\r\n announce,\r\n };\r\n\r\n return (\r\n <AnnouncerContext.Provider value={value}>\r\n {children}\r\n {/* Polite live region */}\r\n <div\r\n ref={politeRef}\r\n role=\"status\"\r\n aria-live=\"polite\"\r\n aria-atomic=\"true\"\r\n style={{\r\n position: 'absolute',\r\n width: '1px',\r\n height: '1px',\r\n padding: '0',\r\n margin: '-1px',\r\n overflow: 'hidden',\r\n clip: 'rect(0, 0, 0, 0)',\r\n whiteSpace: 'nowrap',\r\n border: '0',\r\n }}\r\n />\r\n {/* Assertive live region */}\r\n <div\r\n ref={assertiveRef}\r\n role=\"alert\"\r\n aria-live=\"assertive\"\r\n aria-atomic=\"true\"\r\n style={{\r\n position: 'absolute',\r\n width: '1px',\r\n height: '1px',\r\n padding: '0',\r\n margin: '-1px',\r\n overflow: 'hidden',\r\n clip: 'rect(0, 0, 0, 0)',\r\n whiteSpace: 'nowrap',\r\n border: '0',\r\n }}\r\n />\r\n </AnnouncerContext.Provider>\r\n );\r\n}\r\n\r\n/**\r\n * Generate announcement messages for different drag events\r\n */\r\nexport const announcements = {\r\n onDragStart: (itemName: string, position: number, totalItems: number): string =>\r\n `Picked up ${itemName}. Position ${position + 1} of ${totalItems}.`,\r\n\r\n onDragMove: (itemName: string, newPosition: number, totalItems: number): string =>\r\n `${itemName} moved to position ${newPosition + 1} of ${totalItems}.`,\r\n\r\n onDragEnd: (itemName: string, from: string, to: string, position: number): string =>\r\n from === to\r\n ? `${itemName} dropped. Position ${position + 1} in ${to}.`\r\n : `${itemName} moved from ${from} to ${to}. Position ${position + 1}.`,\r\n\r\n onDragCancel: (itemName: string, column: string): string =>\r\n `Drag cancelled. ${itemName} returned to ${column}.`,\r\n\r\n onColumnMove: (columnName: string, position: number, totalColumns: number): string =>\r\n `${columnName} moved to position ${position + 1} of ${totalColumns}.`,\r\n};\r\n","/**\r\n * Kanban Board Component\r\n *\r\n * High-level component that composes the Kanban board with all features.\r\n */\r\n\r\nimport React, { useMemo } from 'react';\nimport type { KanbanBoardProps, KanbanCard, KanbanColumn } from '../types';\nimport { KanbanContext } from '../context';\r\nimport { KanbanColumnView } from './KanbanColumnView';\r\nimport { KanbanCardView } from './KanbanCardView';\r\nimport { useKanbanDnd } from '../hooks/useKanbanDnd';\r\n\r\nexport function KanbanBoard({\r\n state,\r\n onDragEnd,\r\n onDragStart,\r\n renderColumn,\r\n renderCard,\r\n getCardKey,\r\n getColumnKey,\r\n isDragDisabled,\r\n className,\r\n style,\r\n}: KanbanBoardProps) {\r\n const dragState = useKanbanDnd({\r\n state,\r\n onDragEnd,\r\n onDragStart,\r\n disabled: false,\r\n });\r\n\r\n const contextValue = useMemo(\r\n () => ({\r\n state,\r\n dragState,\r\n isDragDisabled,\r\n }),\r\n [state, dragState, isDragDisabled]\r\n );\r\n\r\n const defaultGetCardKey = (card: KanbanCard) => card.id;\n const defaultGetColumnKey = (column: KanbanColumn) => column.id;\n\r\n const cardKeyExtractor = getCardKey || defaultGetCardKey;\r\n const columnKeyExtractor = getColumnKey || defaultGetColumnKey;\r\n\r\n return (\r\n <KanbanContext.Provider value={contextValue}>\r\n <div\r\n className={className}\r\n style={{\r\n display: 'flex',\r\n gap: '16px',\r\n ...style,\r\n }}\r\n >\r\n {state.columns.map((column, columnIndex) => (\r\n <KanbanColumnView\r\n key={columnKeyExtractor(column)}\r\n column={column}\r\n cardIds={column.cardIds}\r\n index={columnIndex}\r\n isDragDisabled={isDragDisabled?.(column.id, 'COLUMN')}\r\n >\r\n {(columnProvided, columnSnapshot) => (\r\n <div\n ref={columnProvided.innerRef}\n {...columnProvided.draggableProps}\n style={{\n minWidth: '250px',\n display: 'flex',\r\n flexDirection: 'column',\r\n ...columnProvided.draggableProps.style,\r\n }}\r\n >\r\n {/* Column header (draggable) */}\r\n <div {...columnProvided.dragHandleProps}>\r\n {renderColumn(column, columnProvided, columnSnapshot)}\r\n </div>\r\n\r\n {/* Card drop zone */}\r\n <div\n ref={columnProvided.dropZoneRef}\n style={{\n flex: 1,\n minHeight: '100px',\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: '8px',\r\n }}\r\n >\r\n {column.cardIds.map((cardId, cardIndex) => {\r\n const card = state.cards[cardId];\r\n if (!card) return null;\r\n\r\n return (\r\n <KanbanCardView\r\n key={cardKeyExtractor(card)}\r\n card={card}\r\n index={cardIndex}\r\n columnId={column.id}\r\n isDragDisabled={isDragDisabled?.(card.id, 'CARD')}\r\n >\r\n {(cardProvided, cardSnapshot) => (\n <div\n ref={cardProvided.innerRef}\n {...cardProvided.draggableProps}\n {...cardProvided.dragHandleProps}\n >\n {renderCard(card, cardProvided, cardSnapshot)}\r\n </div>\r\n )}\r\n </KanbanCardView>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n )}\r\n </KanbanColumnView>\r\n ))}\r\n </div>\r\n </KanbanContext.Provider>\r\n );\r\n}\r\n","/**\r\n * DOM Utilities\r\n *\r\n * Helper functions for DOM measurements and manipulation.\r\n */\r\n\r\n/**\r\n * Safely get bounding client rect for an element\r\n */\r\nexport function getBoundingRect(element: HTMLElement | null): DOMRect | null {\r\n if (!element) return null;\r\n return element.getBoundingClientRect();\r\n}\r\n\r\n/**\r\n * Get scrollable parent of an element\r\n */\r\nexport function getScrollParent(element: HTMLElement | null): HTMLElement | null {\r\n if (!element) return null;\r\n\r\n let parent = element.parentElement;\r\n\r\n while (parent) {\r\n const { overflow, overflowY } = window.getComputedStyle(parent);\r\n if (/(auto|scroll)/.test(overflow + overflowY)) {\r\n return parent;\r\n }\r\n parent = parent.parentElement;\r\n }\r\n\r\n return document.documentElement as HTMLElement;\r\n}\r\n\r\n/**\r\n * Scroll an element by a delta\r\n */\r\nexport function scrollBy(\r\n element: HTMLElement,\r\n delta: { x?: number; y?: number }\r\n): void {\r\n if (delta.x) {\r\n element.scrollLeft += delta.x;\r\n }\r\n if (delta.y) {\r\n element.scrollTop += delta.y;\r\n }\r\n}\r\n\r\n/**\r\n * Check if an element is scrollable\r\n */\r\nexport function isScrollable(element: HTMLElement): {\r\n vertical: boolean;\r\n horizontal: boolean;\r\n} {\r\n const { overflow, overflowY, overflowX } = window.getComputedStyle(element);\r\n\r\n const hasVerticalScroll = /(auto|scroll)/.test(overflow + overflowY);\r\n const hasHorizontalScroll = /(auto|scroll)/.test(overflow + overflowX);\r\n\r\n return {\r\n vertical: hasVerticalScroll && element.scrollHeight > element.clientHeight,\r\n horizontal: hasHorizontalScroll && element.scrollWidth > element.clientWidth,\r\n };\r\n}\r\n\r\n/**\r\n * Get element's scroll position\r\n */\r\nexport function getScrollPosition(element: HTMLElement): { x: number; y: number } {\r\n if (element === document.documentElement) {\r\n return {\r\n x: window.pageXOffset || document.documentElement.scrollLeft,\r\n y: window.pageYOffset || document.documentElement.scrollTop,\r\n };\r\n }\r\n\r\n return {\r\n x: element.scrollLeft,\r\n y: element.scrollTop,\r\n };\r\n}\r\n\r\n/**\r\n * Get maximum scroll for an element\r\n */\r\nexport function getMaxScroll(element: HTMLElement): { x: number; y: number } {\r\n return {\r\n x: element.scrollWidth - element.clientWidth,\r\n y: element.scrollHeight - element.clientHeight,\r\n };\r\n}\r\n\r\n/**\r\n * Clamp scroll position to valid range\r\n */\r\nexport function clampScroll(\r\n scroll: { x: number; y: number },\r\n maxScroll: { x: number; y: number }\r\n): { x: number; y: number } {\r\n return {\r\n x: Math.max(0, Math.min(scroll.x, maxScroll.x)),\r\n y: Math.max(0, Math.min(scroll.y, maxScroll.y)),\r\n };\r\n}\r\n\r\n/**\r\n * Get all data attributes from an element as an object\r\n */\r\nexport function getDataAttributes(element: HTMLElement): Record<string, string> {\r\n const data: Record<string, string> = {};\r\n for (const key in element.dataset) {\r\n data[key] = element.dataset[key] || '';\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * Find closest ancestor with a data attribute\r\n */\r\nexport function findClosestWithData(\r\n element: HTMLElement | null,\r\n dataKey: string\r\n): HTMLElement | null {\r\n let current = element;\r\n while (current) {\r\n if (current.dataset[dataKey]) {\r\n return current;\r\n }\r\n current = current.parentElement;\r\n }\r\n return null;\r\n}\r\n","/**\r\n * DnD Math Utilities\r\n *\r\n * Helper functions for collision detection and positioning calculations.\r\n */\r\n\r\n/**\r\n * Calculate the distance from a point to a rectangle's edges\r\n */\r\nexport function distanceToEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect\r\n): {\r\n top: number;\r\n right: number;\r\n bottom: number;\r\n left: number;\r\n} {\r\n return {\r\n top: point.y - rect.top,\r\n right: rect.right - point.x,\r\n bottom: rect.bottom - point.y,\r\n left: point.x - rect.left,\r\n };\r\n}\r\n\r\n/**\r\n * Get the closest edge of a rectangle to a point\r\n */\r\nexport function getClosestEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect\r\n): 'top' | 'right' | 'bottom' | 'left' {\r\n const distances = distanceToEdge(point, rect);\r\n const entries = Object.entries(distances) as Array<[keyof typeof distances, number]>;\r\n const sorted = entries.sort((a, b) => a[1] - b[1]);\r\n return sorted[0][0];\r\n}\r\n\r\n/**\r\n * Check if a point is within a threshold distance from an edge\r\n */\r\nexport function isNearEdge(\r\n point: { x: number; y: number },\r\n rect: DOMRect,\r\n threshold: number\r\n): { edge: 'top' | 'right' | 'bottom' | 'left' | null; distance: number } {\r\n const distances = distanceToEdge(point, rect);\r\n\r\n for (const [edge, distance] of Object.entries(distances)) {\r\n if (distance < threshold) {\r\n return {\r\n edge: edge as 'top' | 'right' | 'bottom' | 'left',\r\n distance,\r\n };\r\n }\r\n }\r\n\r\n return { edge: null, distance: Infinity };\r\n}\r\n\r\n/**\r\n * Calculate scroll speed based on distance from edge\r\n * Closer to edge = faster scroll\r\n */\r\nexport function calculateScrollSpeed(\r\n distance: number,\r\n threshold: number,\r\n maxSpeed: number\r\n): number {\r\n if (distance >= threshold) return 0;\r\n const ratio = (threshold - distance) / threshold;\r\n return ratio * maxSpeed;\r\n}\r\n\r\n/**\r\n * Check if a point is inside a rectangle\r\n */\r\nexport function isPointInRect(point: { x: number; y: number }, rect: DOMRect): boolean {\r\n return (\r\n point.x >= rect.left &&\r\n point.x <= rect.right &&\r\n point.y >= rect.top &&\r\n point.y <= rect.bottom\r\n );\r\n}\r\n\r\n/**\r\n * Calculate the center point of a rectangle\r\n */\r\nexport function getRectCenter(rect: DOMRect): { x: number; y: number } {\r\n return {\r\n x: rect.left + rect.width / 2,\r\n y: rect.top + rect.height / 2,\r\n };\r\n}\r\n\r\n/**\r\n * Calculate vertical drop position based on mouse Y relative to element center\r\n */\r\nexport function getVerticalDropPosition(\r\n mouseY: number,\r\n elementRect: DOMRect\r\n): 'top' | 'bottom' {\r\n const center = getRectCenter(elementRect);\r\n return mouseY < center.y ? 'top' : 'bottom';\r\n}\r\n\r\n/**\r\n * Calculate horizontal drop position based on mouse X relative to element center\r\n */\r\nexport function getHorizontalDropPosition(\r\n mouseX: number,\r\n elementRect: DOMRect\r\n): 'left' | 'right' {\r\n const center = getRectCenter(elementRect);\r\n return mouseX < center.x ? 'left' : 'right';\r\n}\r\n"],"names":["KanbanContext","createContext","KANBAN_COLUMN","KanbanColumnView","column","cardIds","children","isDragDisabled","index","columnRef","useRef","dropZoneRef","isDragging","setIsDragging","useState","isDraggingOver","setIsDraggingOver","createDraggableColumn","useCallback","element","draggable","getInitialData","type","id","onDragStart","onDrop","createColumnDropTarget","dropTargetForElements","getData","input","data","attachClosestEdge","allowedEdges","canDrop","source","createCardDropZone","columnId","onDragEnter","onDragLeave","useEffect","columnElement","current","dropZoneElement","cleanups","forEach","cleanup","provided","draggableProps","style","opacity","undefined","dragHandleProps","tabIndex","role","title","length","innerRef","snapshot","React","createElement","Fragment","KANBAN_CARD","KanbanCardView","card","cardRef","createDraggable","createDropTarget","combine","reorderArray","list","startIndex","endIndex","result","Array","from","removed","splice","normalizeReorderDestinationIndex","params","itemCount","sourceIndex","rawDestinationIndex","isSameList","maxRaw","clampedRaw","Math","max","min","adjusted","maxFinal","useKanbanDnd","onDragEnd","state","disabled","dragState","setDragState","draggingId","draggingType","destination","monitorForElements","typeRaw","sourceLocation","location","sourceType","sourceId","sourceColumnId","dropTargets","columnTarget","find","target","destColumnId","sourceColumn","columns","destColumn","cardTarget","destIndex","extractClosestEdge","isSameColumn","normalizedIndex","edge","draggableId","DEFAULT_CONFIG","threshold","maxSpeed","enabled","AnnouncerContext","politeness","politeRef","assertiveRef","timeoutRef","clearTimeout","value","announce","message","announcePoliteness","regionRef","textContent","setTimeout","Provider","ref","position","width","height","padding","margin","overflow","clip","whiteSpace","border","renderColumn","renderCard","getCardKey","getColumnKey","className","contextValue","useMemo","cardKeyExtractor","columnKeyExtractor","Object","assign","display","gap","map","columnIndex","key","columnProvided","columnSnapshot","minWidth","flexDirection","flex","minHeight","cardId","cardIndex","cards","cardProvided","cardSnapshot","itemName","totalItems","onDragMove","newPosition","to","onDragCancel","onColumnMove","columnName","totalColumns","reorderColumns","col","newCardIds","reorderCardInColumn","newSourceCardIds","newDestCardIds","moveCardBetweenColumns","context","useContext","Error","containerRef","config","rafRef","lastMousePosRef","handleMouseMove","event","x","clientX","y","clientY","performScroll","scrollParent","parent","parentElement","overflowY","window","getComputedStyle","test","document","documentElement","getScrollParent","rect","getBoundingClientRect","mousePos","scrollability","overflowX","hasVerticalScroll","hasHorizontalScroll","vertical","scrollHeight","clientHeight","horizontal","scrollWidth","clientWidth","isScrollable","nearEdge","point","distances","top","right","bottom","left","distanceToEdge","distance","entries","Infinity","isNearEdge","speed","calculateScrollSpeed","delta","scrollLeft","scrollTop","scrollBy","requestAnimationFrame","addEventListener","removeEventListener","cancelAnimationFrame"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { DragDropListProps, DraggableItem } from "../types";
|
|
3
|
-
export declare function DragDropList<T extends DraggableItem>({ items, onReorder, renderItem, containerClassName, containerStyle, itemClassName, itemStyle, dragPreviewClassName, dragPreviewStyle, onDragStart, onDragEnd, disabled, gap, direction, showDropIndicator, dropIndicatorClassName, dropIndicatorStyle, dropIndicatorPosition, }: DragDropListProps<T>): React.JSX.Element;
|
|
3
|
+
export declare function DragDropList<T extends DraggableItem>({ items, onReorder, renderItem, containerClassName, containerStyle, itemClassName, itemStyle, dragPreviewClassName, dragPreviewStyle, onDragStart, onDragEnd, disabled, gap, direction, showDropIndicator, dropIndicatorClassName, dropIndicatorStyle, dropIndicatorPosition, dragHandle, selectedIds, multiDragEnabled, }: DragDropListProps<T>): React.JSX.Element;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { DraggableItemWrapperProps, DraggableItem } from "../types";
|
|
3
|
-
export declare function DraggableItemWrapper<T extends DraggableItem>({ item, index, children, className, style, dragPreviewClassName, dragPreviewStyle, onDragStart, onDragEnd, disabled, showDropIndicator, dropIndicatorClassName, dropIndicatorStyle, dropIndicatorPosition, }: DraggableItemWrapperProps<T>): React.JSX.Element;
|
|
3
|
+
export declare function DraggableItemWrapper<T extends DraggableItem>({ item, index, children, className, style, dragPreviewClassName, dragPreviewStyle, onDragStart, onDragEnd, disabled, showDropIndicator, dropIndicatorClassName, dropIndicatorStyle, dropIndicatorPosition, direction, dragHandle, }: DraggableItemWrapperProps<T>): React.JSX.Element;
|