@gripflow/core
v0.1.1
Published
Gripflow core: framework-independent, headless drag and drop engine with pointer, touch and keyboard sensors, collision detection, modifiers, sortable model and auto-scroll.
Maintainers
Readme
@gripflow/core
The framework-independent drag-and-drop engine behind Gripflow. Pointer, touch and keyboard sensors, collision detection, modifiers, sortable math, auto-scroll and accessibility announcements, in plain TypeScript.
Building a React or Next.js app? You don't need to install this directly. Start with
@gripflow/presets(sortable list, grid, table),@gripflow/kanbanor@gripflow/tree.@gripflow/coreis installed for you.
Install @gripflow/core when you want to:
- use the pure helpers (
arrayMove,applySortableMove, collision functions) on the server or in tests, - write custom sensors, modifiers or collision detection,
- or build an adapter for another UI framework (Vue, Svelte, Solid, vanilla DOM).
It has no React dependency, no network access and no telemetry.
Install
npm install @gripflow/corePure helpers
Reordering without mutating your data:
import { arrayMove, applySortableMove } from "@gripflow/core";
arrayMove(["a", "b", "c"], 0, 2); // ["b", "c", "a"]
// Apply the move reported by a drag-end event, by id, across containers:
const next = applySortableMove({ todo: todoCards, done: doneCards }, event.move, (card) => card.id);Also exported: arrayInsert, arrayRemove, moveById, moveBetweenContainers, findContainerOf.
The engine
DragEngine is the headless state machine. It owns sensors, the active drag, drop validation and events;
you register elements and render the result however your framework does.
import { DragEngine, pointerSensor, keyboardSensor } from "@gripflow/core";
const engine = new DragEngine({
sensors: [pointerSensor(), keyboardSensor()],
onDragEnd(event) {
console.log("dropped", event.active.id, "over", event.over?.id, "move:", event.move);
},
});
const unmount = engine.mount(); // starts listening; call the returned function to stop
const card = document.querySelector<HTMLElement>("#card-1")!;
const registration = engine.registerDraggable({ id: "card-1", element: card });
// later:
registration.unregister();
unmount();The React packages (@gripflow/react and friends) are thin bindings around exactly this API.
Building blocks
| Area | Exports |
| --- | --- |
| Engine | DragEngine, createStore, SortableCoordinator, GeometryCache |
| Sensors | pointerSensor, keyboardSensor, isInteractiveTarget |
| Collision detection | closestCenter, closestCorners, pointerWithin, rectIntersection, containerAware, composeDetectors, defaultCollisionDetector |
| Modifiers | restrictToVerticalAxis, restrictToHorizontalAxis, restrictToWindowEdges, restrictToParentElement, restrictToBounds, snapToGrid |
| Sorting strategies | verticalListStrategy, horizontalListStrategy, rectSortingStrategy, noSortingStrategy |
| Sortable data | arrayMove, applySortableMove, moveBetweenContainers, arrayInsert, arrayRemove |
| Scrolling and motion | AutoScroller, resolveAnimation, prefersReducedMotion |
| Accessibility | createDefaultAnnouncements, DEFAULT_INSTRUCTIONS |
| Helpers | createHistory (undo/redo), createOptimisticController (optimistic updates with rollback), loggerPlugin |
Example: constrain dragging to a vertical axis (works through @gripflow/react's modifiers prop too):
import { restrictToVerticalAxis, restrictToWindowEdges } from "@gripflow/core";
new DragEngine({ modifiers: [restrictToVerticalAxis, restrictToWindowEdges()] });Every export is fully typed, so your editor shows documentation as you type.
Events
dragStart, dragMove, dragOver, dropTargetEnter, dropTargetLeave, dropRequested,
dropAccepted, dropRejected, dragEnd, dragCancel, error. Subscribe with engine.on(name, handler) or
pass onDragEnd-style handlers in the options.
Related packages
@gripflow/react ·
@gripflow/presets ·
@gripflow/kanban ·
@gripflow/tree ·
@gripflow/nestjs-adapter
Author
Created and maintained by salmannizam. Issues and ideas are welcome on GitHub. MIT licensed.
