feat(bases): auto-scroll the kanban board and columns during drag

This commit is contained in:
Philipinho
2026-05-24 16:20:29 +01:00
parent dba47956b1
commit abf75ec90b
3 changed files with 36 additions and 2 deletions
@@ -1,4 +1,4 @@
import { useCallback, useMemo } from "react";
import { useCallback, useMemo, useRef } from "react";
import { Badge } from "@mantine/core";
import { IconPlus } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
@@ -9,6 +9,7 @@ import {
NO_VALUE_CHOICE_ID,
} from "@/features/base/types/base.types";
import { useKanbanGroups } from "@/features/base/hooks/use-kanban-groups";
import { useKanbanAutoScroll } from "@/features/base/hooks/use-kanban-auto-scroll";
import { useUpdateViewMutation } from "@/features/base/queries/base-view-query";
import {
useCreateRowMutation,
@@ -56,6 +57,14 @@ export function BaseKanban({
const updateRowMutation = useUpdateRowMutation();
const reorderRowMutation = useReorderRowMutation();
const sortsActive = (effectiveView?.config?.sorts?.length ?? 0) > 0;
const boardRef = useRef<HTMLDivElement>(null);
const canScrollBoard = useCallback(
({ source }: { source: { data: Record<string, unknown> } }) =>
source.data.type === "base-kanban-card" ||
source.data.type === "base-kanban-column",
[],
);
useKanbanAutoScroll(boardRef, canScrollBoard);
// Rules of Hooks: call useKanbanGroups unconditionally with `undefined`
// when not groupable; switch the render path on isGroupable below.
@@ -253,7 +262,7 @@ export function BaseKanban({
{t("Sorted — cards within a column can't be reordered.")}
</div>
)}
<div className={classes.board}>
<div ref={boardRef} className={classes.board}>
{columns.map((column) => (
<KanbanColumn
key={column.key}
@@ -1,3 +1,4 @@
import { useCallback } from "react";
import { KanbanColumnData } from "@/features/base/hooks/use-kanban-groups";
import { IBaseProperty } from "@/features/base/types/base.types";
import { KanbanCard } from "./kanban-card";
@@ -6,6 +7,7 @@ import { KanbanAddCardButton } from "./kanban-add-card-button";
import type { CardDropPayload } from "@/features/base/hooks/use-kanban-card-drag";
import type { ColumnReorderPayload } from "@/features/base/hooks/use-kanban-column-reorder";
import { useKanbanColumnDrop } from "@/features/base/hooks/use-kanban-column-drop";
import { useKanbanAutoScroll } from "@/features/base/hooks/use-kanban-auto-scroll";
import classes from "@/features/base/styles/kanban.module.css";
type KanbanColumnProps = {
@@ -33,6 +35,12 @@ export function KanbanColumn({
columnKey: column.key,
onDrop: onCardDrop,
});
const canScrollColumn = useCallback(
({ source }: { source: { data: Record<string, unknown> } }) =>
source.data.type === "base-kanban-card",
[],
);
useKanbanAutoScroll(bodyRef, canScrollColumn);
return (
<div className={classes.column} data-column-key={column.key}>
@@ -0,0 +1,17 @@
import { useEffect, RefObject } from "react";
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
export function useKanbanAutoScroll(
ref: RefObject<HTMLElement | null>,
canScroll: ({
source,
}: {
source: { data: Record<string, unknown> };
}) => boolean = () => true,
) {
useEffect(() => {
const el = ref.current;
if (!el) return;
return autoScrollForElements({ element: el, canScroll });
}, [ref, canScroll]);
}