Internal utilities shared between @dnd-kit packages providing React hooks, coordinate manipulation, and DOM utilities.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Type guards and utilities for working with DOM events, including touch and keyboard event detection with cross-frame compatibility.
Type guard that checks if an event has viewport-relative coordinate properties (clientX and clientY).
/**
* Type guard for events with viewport-relative coordinates
* @param event - DOM event to check
* @returns True if event has clientX and clientY properties
*/
function hasViewportRelativeCoordinates(
event: Event
): event is Event & Pick<PointerEvent, 'clientX' | 'clientY'>;Usage Examples:
import { hasViewportRelativeCoordinates } from "@dnd-kit/utilities";
function handleGenericEvent(event: Event) {
if (hasViewportRelativeCoordinates(event)) {
// TypeScript now knows event has clientX and clientY
console.log(`Coordinates: ${event.clientX}, ${event.clientY}`);
// Safe to use coordinate properties
const rect = event.target?.getBoundingClientRect();
if (rect) {
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
console.log(`Relative: ${relativeX}, ${relativeY}`);
}
} else {
console.log("Event does not have coordinate information");
}
}
// Use with multiple event types
element.addEventListener("mousedown", handleGenericEvent);
element.addEventListener("touchstart", handleGenericEvent);
element.addEventListener("keydown", handleGenericEvent); // Won't have coordinatesType guard that determines if an event is a KeyboardEvent. Uses cross-frame compatible detection.
/**
* Type guard for KeyboardEvent with cross-frame compatibility
* @param event - Event to check (can be undefined or null)
* @returns True if event is a KeyboardEvent
*/
function isKeyboardEvent(event: Event | undefined | null): event is KeyboardEvent;Usage Examples:
import { isKeyboardEvent } from "@dnd-kit/utilities";
function handleInteractionEvent(event: Event | null) {
if (isKeyboardEvent(event)) {
// TypeScript knows this is a KeyboardEvent
console.log(`Key pressed: ${event.key}`);
console.log(`Ctrl key: ${event.ctrlKey}`);
console.log(`Key code: ${event.code}`);
// Handle specific keys
if (event.key === "Enter") {
console.log("Enter key pressed");
}
if (event.key === "Escape") {
console.log("Escape key pressed");
}
}
}
// React example
import React from "react";
function KeyboardAwareComponent() {
const handleKeyEvent = (event: React.KeyboardEvent | Event) => {
const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;
if (isKeyboardEvent(nativeEvent)) {
// Handle keyboard-specific logic
if (nativeEvent.key === "ArrowUp") {
// Move up
} else if (nativeEvent.key === "ArrowDown") {
// Move down
}
}
};
return (
<div tabIndex={0} onKeyDown={handleKeyEvent}>
Press arrow keys to navigate
</div>
);
}Type guard that determines if an event is a TouchEvent. Uses cross-frame compatible detection.
/**
* Type guard for TouchEvent with cross-frame compatibility
* @param event - Event to check (can be undefined or null)
* @returns True if event is a TouchEvent
*/
function isTouchEvent(event: Event | undefined | null): event is TouchEvent;Usage Examples:
import { isTouchEvent } from "@dnd-kit/utilities";
function handlePointerEvent(event: Event) {
if (isTouchEvent(event)) {
// TypeScript knows this is a TouchEvent
console.log(`Number of touches: ${event.touches.length}`);
// Access touch-specific properties
if (event.touches.length > 0) {
const firstTouch = event.touches[0];
console.log(`Touch at: ${firstTouch.clientX}, ${firstTouch.clientY}`);
}
// Handle multi-touch
if (event.touches.length > 1) {
console.log("Multi-touch detected");
const touch1 = event.touches[0];
const touch2 = event.touches[1];
const distance = Math.sqrt(
Math.pow(touch2.clientX - touch1.clientX, 2) +
Math.pow(touch2.clientY - touch1.clientY, 2)
);
console.log(`Distance between touches: ${distance}`);
}
} else {
// Likely a mouse event
console.log("Non-touch event detected");
}
}
// Unified event handling
function createUnifiedHandler(element: HTMLElement) {
const handleStart = (event: Event) => {
if (isTouchEvent(event)) {
// Touch-specific handling
event.preventDefault(); // Prevent scrolling
const touch = event.touches[0];
startDrag(touch.clientX, touch.clientY);
} else {
// Mouse event handling
const mouseEvent = event as MouseEvent;
startDrag(mouseEvent.clientX, mouseEvent.clientY);
}
};
element.addEventListener("touchstart", handleStart);
element.addEventListener("mousedown", handleStart);
}
function startDrag(x: number, y: number) {
console.log(`Starting drag at: ${x}, ${y}`);
}
// React drag and drop example
import React from "react";
function TouchAwareDraggable() {
const handleDragStart = (event: React.TouchEvent | React.MouseEvent) => {
const nativeEvent = event.nativeEvent;
if (isTouchEvent(nativeEvent)) {
// Touch drag
const touch = nativeEvent.touches[0];
console.log("Touch drag started at:", touch.clientX, touch.clientY);
} else {
// Mouse drag
const mouseEvent = nativeEvent as MouseEvent;
console.log("Mouse drag started at:", mouseEvent.clientX, mouseEvent.clientY);
}
};
return (
<div
onTouchStart={handleDragStart}
onMouseDown={handleDragStart}
style={{ touchAction: "none" }} // Prevent default touch behaviors
>
Touch or click to drag
</div>
);
}Install with Tessl CLI
npx tessl i tessl/npm-dnd-kit--utilities