CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-rnd

React component for creating draggable and resizable UI elements with comprehensive interaction controls

Pending
Overview
Eval results
Files

event-handling.mddocs/

Event Handling

Callback props for all drag and resize interaction phases with detailed event data. React RnD provides comprehensive event handling for all user interactions.

Capabilities

Drag Event Callbacks

Handle all phases of drag interactions with detailed position and delta information.

/**
 * Called when drag operation starts
 * Can return false to cancel the drag operation
 */
onDragStart?: RndDragCallback;

/**
 * Called continuously during drag operation
 * Can return false to cancel the drag operation
 */
onDrag?: RndDragCallback;

/**
 * Called when drag operation completes
 */
onDragStop?: RndDragCallback;

// RndDragCallback is imported from react-draggable as DraggableEventHandler
type RndDragCallback = import("react-draggable").DraggableEventHandler;

type RndDragEvent =
  | React.MouseEvent<HTMLElement | SVGElement>
  | React.TouchEvent<HTMLElement | SVGElement>
  | MouseEvent
  | TouchEvent;

interface DraggableData extends Position {
  /** DOM element being dragged */
  node: HTMLElement;
  /** X coordinate in pixels */
  x: number;
  /** Y coordinate in pixels */
  y: number;
  /** Change in X since last event */
  deltaX: number;
  /** Change in Y since last event */
  deltaY: number;
  /** Previous X coordinate */
  lastX: number;
  /** Previous Y coordinate */
  lastY: number;
}

Usage Examples:

function DragTrackingExample() {
  const [dragInfo, setDragInfo] = React.useState<string>('');

  return (
    <div>
      <div>Drag Status: {dragInfo}</div>
      <Rnd
        default={{ x: 0, y: 0, width: 200, height: 150 }}
        onDragStart={(e, d) => {
          setDragInfo(`Drag started at (${d.x}, ${d.y})`);
          console.log('Drag started:', d);
        }}
        onDrag={(e, d) => {
          setDragInfo(`Dragging to (${d.x}, ${d.y}), delta: (${d.deltaX}, ${d.deltaY})`);
        }}
        onDragStop={(e, d) => {
          setDragInfo(`Drag ended at (${d.x}, ${d.y})`);
          console.log('Final position:', d.x, d.y);
        }}
      >
        Drag me and watch the console
      </Rnd>
    </div>
  );
}

// Conditional drag prevention
<Rnd
  default={{ x: 0, y: 0, width: 200, height: 150 }}
  onDragStart={(e, d) => {
    // Prevent drag if certain condition is met
    if (someCondition) {
      console.log('Drag prevented');
      return false; // Cancel drag
    }
  }}
>
  Conditionally draggable
</Rnd>

Resize Event Callbacks

Handle all phases of resize interactions with size delta and position information.

/**
 * Called when resize operation starts
 * Can return false to cancel the resize operation
 */
onResizeStart?: RndResizeStartCallback;

/**
 * Called continuously during resize operation
 */
onResize?: RndResizeCallback;

/**
 * Called when resize operation completes
 */
onResizeStop?: RndResizeCallback;

type RndResizeStartCallback = (
  e: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>,
  dir: ResizeDirection,
  elementRef: HTMLElement
) => void | boolean;

type RndResizeCallback = (
  e: MouseEvent | TouchEvent,
  dir: ResizeDirection,
  elementRef: HTMLElement,
  delta: ResizableDelta,
  position: Position
) => void;

interface ResizableDelta {
  /** Change in width since resize started */
  width: number;
  /** Change in height since resize started */
  height: number;
}

type ResizeDirection = 
  | "top" | "right" | "bottom" | "left"
  | "topRight" | "bottomRight" | "bottomLeft" | "topLeft";

Usage Examples:

function ResizeTrackingExample() {
  const [resizeInfo, setResizeInfo] = React.useState<string>('');

  return (
    <div>
      <div>Resize Status: {resizeInfo}</div>
      <Rnd
        default={{ x: 0, y: 0, width: 200, height: 150 }}
        onResizeStart={(e, dir, ref) => {
          setResizeInfo(`Resize started from ${dir} handle`);
          console.log('Resize started:', dir, ref.getBoundingClientRect());
        }}
        onResize={(e, dir, ref, delta, position) => {
          setResizeInfo(
            `Resizing ${dir}: ${ref.style.width} x ${ref.style.height}, ` +
            `delta: (${delta.width}, ${delta.height}), pos: (${position.x}, ${position.y})`
          );
        }}
        onResizeStop={(e, dir, ref, delta, position) => {
          setResizeInfo(`Resize ended: ${ref.style.width} x ${ref.style.height}`);
          console.log('Final size:', ref.style.width, ref.style.height);
          console.log('Final position:', position);
        }}
      >
        Resize me and watch the console
      </Rnd>
    </div>
  );
}

// Conditional resize prevention
<Rnd
  default={{ x: 0, y: 0, width: 200, height: 150 }}
  onResizeStart={(e, dir, ref) => {
    // Prevent resize from certain handles
    if (dir === 'top' || dir === 'topLeft' || dir === 'topRight') {
      console.log('Top resize prevented');
      return false; // Cancel resize
    }
  }}
>
  Only bottom/side resize allowed
</Rnd>

State Management Integration

Integrate with React state management for controlled components.

function ControlledRndExample() {
  const [state, setState] = React.useState({
    x: 0,
    y: 0,
    width: 200,
    height: 150,
  });

  return (
    <Rnd
      size={{ width: state.width, height: state.height }}
      position={{ x: state.x, y: state.y }}
      onDragStop={(e, d) => {
        setState(prev => ({
          ...prev,
          x: d.x,
          y: d.y,
        }));
      }}
      onResizeStop={(e, direction, ref, delta, position) => {
        setState({
          width: ref.style.width,
          height: ref.style.height,
          ...position,
        });
      }}
    >
      Controlled component with state
    </Rnd>
  );
}

Mouse Event Callbacks

Handle general mouse events on the component.

/**
 * Called on mouse down events
 * Note: This is a native MouseEvent, not React SyntheticEvent
 */
onMouseDown?: (e: MouseEvent) => void;

/**
 * Called on mouse up events
 * Note: This is a native MouseEvent, not React SyntheticEvent
 */
onMouseUp?: (e: MouseEvent) => void;

Usage Examples:

<Rnd
  default={{ x: 0, y: 0, width: 200, height: 150 }}
  onMouseDown={(e) => {
    console.log('Mouse down at:', e.clientX, e.clientY);
  }}
  onMouseUp={(e) => {
    console.log('Mouse up at:', e.clientX, e.clientY);
  }}
>
  General mouse event handling
</Rnd>

Advanced Event Patterns

Event Coordination

Coordinate between drag and resize events for complex interactions.

function CoordinatedEventsExample() {
  const [isDragging, setIsDragging] = React.useState(false);
  const [isResizing, setIsResizing] = React.useState(false);

  return (
    <Rnd
      default={{ x: 0, y: 0, width: 200, height: 150 }}
      onDragStart={() => {
        setIsDragging(true);
        console.log('Started dragging');
      }}
      onDragStop={() => {
        setIsDragging(false);
        console.log('Stopped dragging');
      }}
      onResizeStart={() => {
        setIsResizing(true);
        console.log('Started resizing');
      }}
      onResizeStop={() => {
        setIsResizing(false);
        console.log('Stopped resizing');
      }}
      style={{
        border: isDragging ? '2px solid blue' : isResizing ? '2px solid red' : '1px solid gray',
      }}
    >
      Visual feedback during interactions
    </Rnd>
  );
}

Validation and Constraints

Use event callbacks to implement custom validation and constraints.

function ValidationExample() {
  const [errors, setErrors] = React.useState<string[]>([]);

  return (
    <div>
      {errors.map((error, i) => (
        <div key={i} style={{ color: 'red' }}>{error}</div>
      ))}
      <Rnd
        default={{ x: 0, y: 0, width: 200, height: 150 }}
        onDrag={(e, d) => {
          const newErrors: string[] = [];
          if (d.x < 0) newErrors.push('Cannot move to negative X');
          if (d.y < 0) newErrors.push('Cannot move to negative Y');
          setErrors(newErrors);
        }}
        onResize={(e, dir, ref, delta, position) => {
          const newErrors: string[] = [];
          const width = parseInt(ref.style.width);
          const height = parseInt(ref.style.height);
          if (width > 500) newErrors.push('Width cannot exceed 500px');
          if (height > 400) newErrors.push('Height cannot exceed 400px');
          setErrors(newErrors);
        }}
      >
        Validation feedback during interaction
      </Rnd>
    </div>
  );
}

Performance Optimization

Optimize event handling for performance-critical applications.

function OptimizedEventsExample() {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });
  const [size, setSize] = React.useState({ width: 200, height: 150 });
  
  // Debounced state updates
  const debouncedUpdatePosition = React.useMemo(
    () => debounce((x: number, y: number) => setPosition({ x, y }), 100),
    []
  );

  return (
    <Rnd
      default={{ x: 0, y: 0, width: 200, height: 150 }}
      onDrag={(e, d) => {
        // Update immediately for smooth interaction
        // Debounced state update for expensive operations
        debouncedUpdatePosition(d.x, d.y);
      }}
      onResizeStop={(e, dir, ref, delta, pos) => {
        // Only update state on stop for better performance
        setSize({ 
          width: parseInt(ref.style.width), 
          height: parseInt(ref.style.height) 
        });
        setPosition(pos);
      }}
    >
      Performance optimized events
    </Rnd>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-rnd

docs

component-api.md

drag-config.md

event-handling.md

index.md

resize-config.md

size-position.md

tile.json