UNPKG

@1771technologies/lytenyte-pro

Version:

Blazingly fast headless React data grid with 100s of features.

93 lines (92 loc) 3.9 kB
import { isInView } from "@1771technologies/lytenyte-shared"; import { getFirstNode } from "../navigation/get-first-node.js"; import { getLastNode } from "../navigation/get-last-node.js"; import { getNextNode } from "../navigation/get-next-node.js"; import { getPrevNode } from "../navigation/get-prev-node.js"; import { getFocusableNodes } from "../utils/get-focusable-nodes.js"; import { getFocusedNode } from "../utils/get-focused-node.js"; import { getIdsBetweenNodes } from "../utils/get-ids-between-nodes.js"; import { getTreeNodeId } from "../utils/get-tree-node-id.js"; import { selectNode } from "../utils/select-node.js"; import { toggleAllSelections } from "../utils/toggle-all-selections.js"; import { toggleSelection } from "../utils/toggle-selection.js"; export function makeHandleSelection(ctx) { const acceptedKeys = ["Enter", "Home", "End", "ArrowDown", "ArrowUp", "Space", " ", "a"]; const make = (ev) => { if (ctx.selectionMode === "none") return; if (!acceptedKeys.includes(ev.key)) return; ev.preventDefault(); const pivot = ctx.selectionPivotRef.current; if (ev.key === " " && (ctx.selectionMode === "single" || !ev.shiftKey || !pivot)) { const node = getFocusedNode(); toggleSelection(node, ctx); return; } if (ctx.selectionMode !== "multiple") return; const focusables = getFocusableNodes(ctx.panel); const focused = getFocusedNode(); const focusedIndex = focusables.indexOf(focused); if (focusedIndex === -1) return; if (ev.ctrlKey || ev.metaKey) { if (ev.key === "a") { ev.preventDefault(); toggleAllSelections(ctx); return; } } if (!ev.shiftKey) return; if (ev.key === "ArrowUp" && focusedIndex !== 0) { const node = getPrevNode(focused); if (!isInView(node, ctx.panel)) node?.scrollIntoView({ behavior: "instant", block: "start" }); selectNode(node, ctx, true); return; } if (ev.key === "ArrowDown" && focusedIndex !== focusables.length) { const node = getNextNode(focused); if (!isInView(node, ctx.panel)) node?.scrollIntoView({ behavior: "instant", block: "end" }); selectNode(node, ctx, true); return; } if (ev.key === " ") { const pivotNode = focusables.find((c) => getTreeNodeId(c) === pivot); if (!pivotNode) return; const ids = ctx.getIdsBetweenNodes(pivotNode, focused, ctx.panel); const next = new Set(ctx.selection); ids.forEach((c) => next.add(c)); ctx.onSelectionChange(next); ctx.selectionPivotRef.current = getTreeNodeId(focused); return; } if (!ev.ctrlKey && !ev.metaKey) return; if (ev.key === "Home") { const firstNode = getFirstNode(ctx.panel); const ids = getIdsBetweenNodes(firstNode, focused, ctx.panel); const next = new Set(ctx.selection); ids.forEach((c) => next.add(c)); ctx.onSelectionChange(next); firstNode?.focus(); ctx.selectionPivotRef.current = getTreeNodeId(firstNode); return; } if (ev.key === "End") { const lastNode = getLastNode(ctx.panel); const ids = ctx.getIdsBetweenNodes(focused, lastNode, ctx.panel); const next = new Set(ctx.selection); ids.forEach((c) => next.add(c)); ctx.onSelectionChange(next); lastNode?.focus(); ctx.selectionPivotRef.current = getTreeNodeId(lastNode); return; } }; return make; }