UNPKG

react-beautiful-dnd-next

Version:

Beautiful and accessible drag and drop for lists with React

73 lines (60 loc) 2.12 kB
// @flow import isElement from '../../is-type-of-element/is-element'; export type TagNameMap = { [tagName: string]: true, }; export const interactiveTagNames: TagNameMap = { input: true, button: true, textarea: true, select: true, option: true, optgroup: true, video: true, audio: true, }; const isAnInteractiveElement = ( parent: Element, current: ?Element, ): boolean => { if (current == null) { return false; } // Most interactive elements cannot have children. However, some can such as 'button'. // See 'Permitted content' on https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button // Rather than having two different functions we can consolidate our checks into this single // function to keep things simple. // There is no harm checking if the parent has an interactive tag name even if it cannot have // any children. We need to perform this loop anyway to check for the contenteditable attribute const hasAnInteractiveTag: boolean = Boolean( interactiveTagNames[current.tagName.toLowerCase()], ); if (hasAnInteractiveTag) { return true; } // contenteditable="true" or contenteditable="" are valid ways // of creating a contenteditable container // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable const attribute: ?string = current.getAttribute('contenteditable'); if (attribute === 'true' || attribute === '') { return true; } // nothing more can be done and no results found if (current === parent) { return false; } // recursion to check parent return isAnInteractiveElement(parent, current.parentElement); }; export default (event: Event, canDragInteractiveElements: boolean): boolean => { // Allowing drag with all element types if (canDragInteractiveElements) { return true; } const { target, currentTarget } = event; // Technically target and currentTarget are EventTarget's and do not have to be elements if (!isElement(target) || !isElement(currentTarget)) { return true; } return !isAnInteractiveElement(currentTarget, target); };