/* Adapted from answers in this thread https://github.com/clauderic/dnd-kit/issues/477, particularly this answer: https://github.com/clauderic/dnd-kit/issues/477#issuecomment-1713536492 and from original sensor code. */ import type { MouseSensorOptions, TouchSensorOptions, KeyboardSensorOptions, KeyboardCodes, } from '@dnd-kit/core' import { MouseSensor as LibMouseSensor, TouchSensor as LibTouchSensor, KeyboardSensor as LibKeyboardSensor, KeyboardCode, } from '@dnd-kit/core' import type { MouseEvent, TouchEvent } from 'react' // Block DnD event propagation if input, text area, or if component has data attribute const shouldAllow = (cur: HTMLElement) => { if (cur.closest('input,textarea,[data-pvds-grid-no-drag]')) { return false } // Don't let portal content trigger drags either if (!cur.closest('[role="grid"],[role="treegrid"]')) { return false } return true } export class MouseSensor extends LibMouseSensor { static activators = [ { eventName: 'onMouseDown' as const, handler: ( { nativeEvent: event }: MouseEvent, { onActivation }: MouseSensorOptions ) => { if (event.button === 2) { return false } if (!shouldAllow(event.target as HTMLElement)) { return false } onActivation?.({ event }) return true }, }, ] as (typeof LibMouseSensor)['activators'] } export class TouchSensor extends LibTouchSensor { static activators = [ { eventName: 'onTouchStart' as const, handler: ( { nativeEvent: event }: TouchEvent, { onActivation }: TouchSensorOptions ) => { const { touches } = event if (touches.length > 1) { return false } if (!shouldAllow(event.target as HTMLElement)) { return false } onActivation?.({ event }) return true }, }, ] as (typeof LibTouchSensor)['activators'] } export const defaultKeyboardCodes: KeyboardCodes = { start: [KeyboardCode.Space, KeyboardCode.Enter], cancel: [KeyboardCode.Esc], end: [KeyboardCode.Space, KeyboardCode.Enter], } //Only allow keyboard activation on row elements const isAllowedKeyboardActivatorElement = (el: HTMLElement): boolean => el.getAttribute('role') === 'row' export class KeyboardSensor extends LibKeyboardSensor { static activators = [ { eventName: 'onKeyDown' as const, handler: ( event: React.KeyboardEvent, { onActivation, keyboardCodes = defaultKeyboardCodes, }: KeyboardSensorOptions, { active } ) => { const { code } = event.nativeEvent if (keyboardCodes.start.includes(code)) { const activator = active.activatorNode.current if ( !isAllowedKeyboardActivatorElement( event.target as HTMLElement ) ) { return false } if (activator && event.target !== activator) { return false } event.preventDefault() onActivation?.({ event: event.nativeEvent }) return true } return false }, }, ] as (typeof LibKeyboardSensor)['activators'] }