UNPKG

@adobe/coral-spectrum

Version:

Coral Spectrum is a JavaScript library of Web Components following Spectrum design patterns.

985 lines (844 loc) 32 kB
/** * Copyright 2019 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import Vent from '@adobe/vent'; import {events, validate, transform, commons} from '../../../coral-utils'; // Attributes const DROP_ZONE_ATTRIBUTE = 'coral-dragaction-dropzone'; const HANDLE_ATTRIBUTE = 'coral-dragaction-handle'; const AXIS_ATTRIBUTE = 'coral-dragaction-axis'; const SCROLL_ATTRIBUTE = 'coral-dragaction-scroll'; const CONTAINMENT_ATTRIBUTE = 'coral-dragaction-containment'; // Classes const OPEN_HAND_CLASS = 'u-coral-openHand'; const CLOSE_HAND_CLASS = 'u-coral-closedHand'; const IS_DRAGGING_CLASS = 'is-dragging'; // Scroll offset default values const DEFAULT_SCROLL_OFFSET = 20; const DEFAULT_SCROLL_BY = 10; /** Enumeration for {@link DragAction} axis restrictions. @typedef {Object} DragActionAxisEnum @property {String} FREE Allows vertically and horizontally dragging. @property {String} VERTICAL Allows vertically dragging only. @property {String} HORIZONTAL Allows horizontally dragging only. */ const axis = { FREE: 'free', VERTICAL: 'vertical', HORIZONTAL: 'horizontal' }; /** @ignore @param {HTMLElement} element @returns {HTMLElement} First parent element with overflow [hidden|scroll|auto] */ function getViewContainer(element) { while (element) { const p = element.parentNode; if (!p) { return p; } if (p.matches('body')) { return p; } const computedStyle = window.getComputedStyle(p); const overflow = computedStyle.overflow; // IE11 can return a value for overflow even if it was not set compared to other browsers so we check for X and Y. const overflowX = computedStyle.overflowX; const overflowY = computedStyle.overflowY; if ((overflow === 'hidden' || overflow === 'auto' || overflow === 'scroll') && // @polyfill IE11 overflow === overflowX && overflow === overflowY) { return p; } element = p; } } /** @ignore @param {String|HTMLElement|NodeList} el @returns {Array.<HTMLElement>} X and y position whether event was generated by a click or a touch */ function transformToArray(el) { if (typeof el === 'string') { return Array.prototype.slice.call(document.querySelectorAll(el)); } else if (el instanceof HTMLElement) { return [el]; } else if (Object.prototype.toString.call(el) === '[object NodeList]') { return Array.prototype.slice.call(el); } } /** @ignore @param {Object} event @returns {Object} X and y position whether event was generated by a click or a touch */ function getPagePosition(event) { let touch = {}; if (event.changedTouches && event.changedTouches.length > 0) { touch = event.changedTouches[0]; } else if (event.touches && event.touches.length > 0) { touch = event.touches[0]; } return { x: touch.pageX || event.pageX, y: touch.pageY || event.pageY }; } /** @ignore @param {HTMLElement} scrollingElement element that scrolls the document @param {HTMLElement} a @param {HTMLElement} b @returns {Boolean} Whether a is within b bounds */ function within(scrollingElement, a, b) { const aBoundingClientRect = a.getBoundingClientRect(); const bBoundingClientRect = b.getBoundingClientRect(); const documentScrollTop = scrollingElement.scrollTop; const documentScrollLeft = scrollingElement.scrollLeft; const al = aBoundingClientRect.left + documentScrollLeft; const ar = al + aBoundingClientRect.width; const bl = bBoundingClientRect.left + documentScrollLeft; const br = bl + bBoundingClientRect.width; const at = aBoundingClientRect.top + documentScrollTop; const ab = at + aBoundingClientRect.height; const bt = bBoundingClientRect.top + documentScrollTop; const bb = bt + bBoundingClientRect.height; return !(bl > ar || br < al || (bt > ab || bb < at)); } /** @ignore @param {DragAction} dragAction Coral.DragAction instance @returns {HTMLElement} The dropzone that is being hovered by the dragged element or null if none */ function isOverDropZone(dragAction) { let el = null; if (dragAction._dropZones && dragAction._dropZones.length) { dragAction._dropZones.some((dropZone) => { if (within(dragAction._scrollingElement, dragAction._dragElement, dropZone)) { el = dropZone; return true; } return false; }); } return el; } function getScrollParent(node) { if (!node) { return null; } return node.scrollHeight > node.clientHeight ? node : getScrollParent(node.parentNode); } /** @class Coral.DragAction @classdesc This a decorator which adds draggable functionality to elements. To define draggable actions on specific elements, handles can be used. A handle is given a special attribute : - <code>coral-dragaction</code> attribute adds draggable functionality to the corresponding element. - <code>coral-dragaction-handle</code> attribute allows dragging only by dragging the specified handle. - <code>coral-dragaction-dropzone</code> attribute is used to indicate possible dropzones making it possible to build drag-and-drop enabled interfaces in conjunction with <code>DragAction</code> events. - <code>coral-dragaction-axis</code> and setting it to either <code>horizontal</code> or <code>vertical</code>, it is possible to restrict the drag'n'drop to a single axis. - <code>coral-dragaction-scroll</code> attribute will scroll the container when the draggable is moved beyond the viewport. - <code>coral-dragaction-containment</code>, the draggable element will be constrained to its container. @param {String|HTMLElement} dragElement The draggable element. */ class DragAction { /** Takes the {HTMLElement} to be dragged as argument. @param {HTMLElement} dragElement */ constructor(dragElement) { if (!dragElement) { throw new Error('Coral.DragAction: dragElement is missing'); } let el = null; if (dragElement instanceof HTMLElement) { el = dragElement; } else if (typeof dragElement === 'string') { el = document.querySelector(dragElement); if (!el) { throw new Error('Coral.DragAction: dragElement is null'); } } this._id = commons.getUID(); this._dragElementValue = dragElement; this._dragElement = el; // Destroy instance if existing if (this._dragElement.dragAction) { this._dragElement.dragAction.destroy(); } const computedStyle = window.getComputedStyle(this._dragElement); // Store initial position this._initialPosition = { position: computedStyle.position, left: computedStyle.left, top: computedStyle.top }; // Prepare Vent this._dragEvents = new Vent(this._dragElement); // Handle options. Binds events to dragElement if no handles defined or found this.handle = this._dragElement.getAttribute(HANDLE_ATTRIBUTE); // DropZone options this.dropZone = this._dragElement.getAttribute(DROP_ZONE_ATTRIBUTE); // Axis horizontal|vertical this.axis = this._dragElement.getAttribute(AXIS_ATTRIBUTE); // Scroll options this.scroll = this._dragElement.matches(`[${SCROLL_ATTRIBUTE}]`); // Restriction to container this.containment = this._dragElement.matches(`[${CONTAINMENT_ATTRIBUTE}]`); this._drag = this._drag.bind(this); this._dragEnd = this._dragEnd.bind(this); this._dragOnKeyEnd = this._dragOnKeyEnd.bind(this); events.on(`touchmove.DragAction${this._id}`, this._drag); events.on(`mousemove.DragAction${this._id}`, this._drag); events.on(`touchend.DragAction${this._id}`, this._dragEnd); events.on(`mouseup.DragAction${this._id}`, this._dragEnd); // Store reference on dragElement this._dragElement.dragAction = this; } /** The draggable element. @name dragElement @readonly @type {String|HTMLElement} @htmlattribute coral-dragaction */ get dragElement() { return this._dragElementValue; } /** The handle allowing to drag the element. @name handle @type {String|HTMLElement} @htmlattribute coral-dragaction-handle */ get handle() { return this._handle; } set handle(value) { // Set new value this._handle = value; // Unbind events this._dragEvents.off('.DragAction'); // Remove classes document.body.classList.remove(CLOSE_HAND_CLASS); this._dragElement.classList.remove(IS_DRAGGING_CLASS); if (this._handles && this._handles.length) { this._handles.forEach((handle) => { handle._dragEvents.off('.DragAction'); handle.classList.remove(OPEN_HAND_CLASS); }); } else { this._dragElement.classList.remove(OPEN_HAND_CLASS); } if (typeof value === 'string' || value instanceof HTMLElement || Object.prototype.toString.call(value) === '[object NodeList]') { this._handles = transformToArray(value); // Bind events if (this._handles && this._handles.length) { this._handles.forEach((handle) => { handle._dragEvents = handle._dragEvents || new Vent(handle); handle._dragEvents.on('mousedown.DragAction', this._dragStart.bind(this)); handle._dragEvents.on('touchstart.DragAction', this._dragStart.bind(this)); handle._dragEvents.on('keydown.DragAction', this._dragOnKeyDown.bind(this)); handle._dragEvents.on('keyup.DragAction', this._dragOnKeyUp.bind(this)); handle._dragEvents.on('focusout.DragAction', this._dragOnFocusOut.bind(this)); handle.classList.add(OPEN_HAND_CLASS); }); } else { this._dragEvents.on('touchstart.DragAction', this._dragStart.bind(this)); this._dragEvents.on('mousedown.DragAction', this._dragStart.bind(this)); this._dragEvents.on('keydown.DragAction', this._dragOnKeyDown.bind(this)); this._dragEvents.on('keyup.DragAction', this._dragOnKeyUp.bind(this)); this._dragEvents.on('focusout.DragAction', this._dragOnFocusOut.bind(this)); this._dragElement.classList.add(OPEN_HAND_CLASS); } } else { // Defaults to the dragElement this._handles = []; this._dragEvents.on('touchstart.DragAction', this._dragStart.bind(this)); this._dragEvents.on('mousedown.DragAction', this._dragStart.bind(this)); this._dragEvents.on('keydown.DragAction', this._dragOnKeyDown.bind(this)); this._dragEvents.on('keyup.DragAction', this._dragOnKeyUp.bind(this)); this._dragEvents.on('focusout.DragAction', this._dragOnFocusOut.bind(this)); this._dragElement.classList.add(OPEN_HAND_CLASS); } } /** The dropZone to drop the dragged element. @name dropZone @type {String|HTMLElement} @htmlattribute coral-dragaction-dropzone */ get dropZone() { return this._dropZone; } set dropZone(value) { // Set new value this._dropZone = value; this._dropZoneEntered = false; if (typeof value === 'string' || value instanceof HTMLElement || Object.prototype.toString.call(value) === '[object NodeList]') { this._dropZones = transformToArray(value); } else { this._dropZones = []; } } /** The axis to constrain drag movement. See {@link DragActionAxisEnum}. @name axis @type {String} @default DragActionAxisEnum.FREE @htmlattribute coral-dragaction-axis */ get axis() { return this._axis; } set axis(value) { value = transform.string(value); this._axis = validate.enumeration(axis)(value) && value || axis.FREE; } /** Whether to scroll the container when the draggable element is moved beyond the viewport. @name scroll @default false @type {Boolean} @htmlattribute coral-dragaction-scroll */ get scroll() { return this._scroll; } set scroll(value) { this._scroll = transform.boolean(value); } get useScrollParent() { return this._useScrollParent || false; } set useScrollParent(value) { this._useScrollParent = transform.boolean(value); } /** Whether to constrain the draggable element to its container viewport. @name containment @default false @type {Boolean} @htmlattribute coral-dragaction-containment */ get containment() { return this._containment; } set containment(value) { this._containment = transform.boolean(value); } /** @private */ _dragStart(event) { if (events.isVirtualEvent(event)) { return; } // Container const viewContainer = getViewContainer(this._dragElement) || document.body; this._container = this.useScrollParent ? getScrollParent(this._dragElement) || viewContainer : viewContainer; // Prevent dragging ghost image if (event.target.tagName === 'IMG') { event.preventDefault(); } // Prevent touchscreen windows to scroll while dragging events.on('touchmove.DragAction', (e) => { e.preventDefault(); }); document.body._overflow = window.getComputedStyle(document.body).overflow; document.body.style.overflow = 'hidden'; if (!this._container.matches('body')) { this._container._overflow = window.getComputedStyle(this._container).overflow; this._container.style.overflow = this.scroll ? 'scroll' : 'hidden'; } const pagePosition = getPagePosition(event); const dragElementBoundingClientRect = this._dragElement.getBoundingClientRect(); this._dragPosition = getPagePosition(event); this._dragPosition.y -= dragElementBoundingClientRect.top + this._scrollingElement.scrollTop; this._dragPosition.x -= dragElementBoundingClientRect.left + this._scrollingElement.scrollLeft; // Handle classes document.body.classList.add(CLOSE_HAND_CLASS); if (this._handles && this._handles.length) { this._handles.forEach((handle) => { handle.classList.remove(OPEN_HAND_CLASS); }); } else { this._dragElement.classList.remove(OPEN_HAND_CLASS); } this._dragElement.classList.add(IS_DRAGGING_CLASS); // Apply relative position by default if (window.getComputedStyle(this._dragElement).position === 'static') { this._dragElement.style.position = 'relative'; } this._dragEvents.dispatch('coral-dragaction:dragstart', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y } }); } /** @private */ _drag(event) { if (this._dragElement.classList.contains(IS_DRAGGING_CLASS)) { const pagePosition = getPagePosition(event); const documentScrollTop = this._scrollingElement.scrollTop; const documentScrollLeft = this._scrollingElement.scrollLeft; const dragElementBoundingClientRect = this._dragElement.getBoundingClientRect(); const dragElementHeight = dragElementBoundingClientRect.height; const dragElementWidth = dragElementBoundingClientRect.width; const dragElementPosition = { top: dragElementBoundingClientRect.top + documentScrollTop, left: dragElementBoundingClientRect.left + documentScrollLeft }; const dragElementComputedStyle = window.getComputedStyle(this._dragElement); const dragElementCSSPosition = { top: parseFloat(dragElementComputedStyle.top) || 0, left: parseFloat(dragElementComputedStyle.left) || 0 }; const containerBoundingClientRect = this._container.getBoundingClientRect(); const containerWidth = containerBoundingClientRect.width; const containerHeight = containerBoundingClientRect.height; const containerPosition = { top: containerBoundingClientRect.top + documentScrollTop, left: containerBoundingClientRect.left + documentScrollLeft }; this._dragEvents.dispatch('coral-dragaction:drag', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y } }); // Remove selection if (document.selection) { document.selection.empty(); } else if (window.getSelection) { // @polyfill ie if (window.getSelection().removeAllRanges) { window.getSelection().removeAllRanges(); } } // Need to scroll ? if (this.scroll) { // Scroll element is the document if (this._container === document.body) { // Scroll to the top if (dragElementBoundingClientRect.top < DEFAULT_SCROLL_OFFSET) { this._scrollingElement.scrollTop = documentScrollTop - DEFAULT_SCROLL_BY; } // Scroll to the bottom but don't go further than the maximum scroll position of the document else if (dragElementBoundingClientRect.top + dragElementBoundingClientRect.height > window.innerHeight - DEFAULT_SCROLL_OFFSET && dragElementPosition.top + dragElementBoundingClientRect.height + DEFAULT_SCROLL_OFFSET < this._scrollingElement.scrollHeight) { this._scrollingElement.scrollTop = documentScrollTop + DEFAULT_SCROLL_BY; } // Scroll to the left if (dragElementBoundingClientRect.left < DEFAULT_SCROLL_OFFSET) { this._scrollingElement.scrollLeft = documentScrollLeft - DEFAULT_SCROLL_BY; } // Scroll to the right but don't go further than the maximum scroll position of the document else if (dragElementBoundingClientRect.left + dragElementBoundingClientRect.width > window.innerWidth - DEFAULT_SCROLL_OFFSET && dragElementPosition.left + dragElementBoundingClientRect.width + DEFAULT_SCROLL_OFFSET < this._scrollingElement.scrollWidth) { this._scrollingElement.scrollLeft = documentScrollLeft + DEFAULT_SCROLL_BY; } } // Scroll element is an element other than the document else { // Scroll to the top if (dragElementBoundingClientRect.top - containerBoundingClientRect.top < DEFAULT_SCROLL_OFFSET) { this._container.scrollTop = this._container.scrollTop - DEFAULT_SCROLL_BY; } // Scroll to the bottom but don't go further than the maximum scroll position of the container else if (dragElementBoundingClientRect.top - containerBoundingClientRect.top + dragElementBoundingClientRect.height > containerBoundingClientRect.height - DEFAULT_SCROLL_OFFSET && dragElementBoundingClientRect.top - containerBoundingClientRect.top + dragElementBoundingClientRect.height < containerBoundingClientRect.height) { this._container.scrollTop = this._container.scrollTop + DEFAULT_SCROLL_BY; } // Scroll to the left if (dragElementBoundingClientRect.left - containerBoundingClientRect.left < DEFAULT_SCROLL_OFFSET) { this._container.scrollLeft = this._container.scrollLeft - DEFAULT_SCROLL_BY; } // Scroll to the bottom but don't go further than the maximum scroll position of the container else if (dragElementBoundingClientRect.left - containerBoundingClientRect.left + dragElementBoundingClientRect.width > containerBoundingClientRect.width - DEFAULT_SCROLL_OFFSET && dragElementBoundingClientRect.left - containerBoundingClientRect.left + dragElementBoundingClientRect.width < containerBoundingClientRect.width) { this._container.scrollLeft = this._container.scrollLeft + DEFAULT_SCROLL_BY; } } } // Set drag element's new position const newPosition = {}; if (this.axis !== 'horizontal') { const top = pagePosition.y - this._dragPosition.y; // Applying container containment for y movements if (this.containment) { if (top >= containerPosition.top && top + dragElementHeight <= containerPosition.top + containerHeight) { newPosition.top = top; } // put the drag element to the container's top else if (pagePosition.y <= containerPosition.top) { newPosition.top = containerPosition.top; } // put the drag element to the container's bottom else if (pagePosition.y >= containerPosition.top + containerHeight) { newPosition.top = containerPosition.top + containerHeight - dragElementHeight; } } else { newPosition.top = top; } } if (this.axis !== 'vertical') { const left = pagePosition.x - this._dragPosition.x; // Applying container containment for x movements if (this.containment) { if (left >= containerPosition.left && left + dragElementWidth <= containerPosition.left + containerWidth) { newPosition.left = left; } // put the drag element to the container's left else if (pagePosition.x <= containerPosition.left) { newPosition.left = containerPosition.left; } // put the drag element to the container's right else if (pagePosition.x >= containerPosition.left + containerWidth) { newPosition.left = containerPosition.left + containerWidth - dragElementWidth; } } else { newPosition.left = left; } } // Set the new position this._dragElement.style.top = `${newPosition.top - dragElementPosition.top + dragElementCSSPosition.top}px`; this._dragElement.style.left = `${newPosition.left - dragElementPosition.left + dragElementCSSPosition.left}px`; // Trigger dropzone related events const dropZone = isOverDropZone(this); if (dropZone) { this._dropElement = dropZone; if (!this._dropZoneEntered) { this._dropZoneEntered = true; this._dragEvents.dispatch('coral-dragaction:dragenter', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y, dropElement: this._dropElement } }); } this._dragEvents.dispatch('coral-dragaction:dragover', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y, dropElement: this._dropElement } }); } else if (this._dropZoneEntered) { this._dragEvents.dispatch('coral-dragaction:dragleave', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y, dropElement: this._dropElement } }); this._dropZoneEntered = false; } } } /** @private */ _dragEnd(event) { if (this._dragElement.classList.contains(IS_DRAGGING_CLASS)) { const pagePosition = getPagePosition(event); // Restore overflow document.body.style.overflow = document.body._overflow; document.body._overflow = undefined; if (!this._container.matches('body')) { this._container.style.overflow = this._container._overflow; this._container._overflow = undefined; } document.body.classList.remove(CLOSE_HAND_CLASS); this._dragElement.classList.remove(IS_DRAGGING_CLASS); if (this._handles && this._handles.length) { this._handles.forEach((handle) => { handle.classList.add(OPEN_HAND_CLASS); }); } else { this._dragElement.classList.add(OPEN_HAND_CLASS); } if (this._dropZoneEntered) { const dropZone = isOverDropZone(this); if (dropZone) { this._dropElement = dropZone; this._dragEvents.dispatch('coral-dragaction:drop', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y, dropElement: this._dropElement } }); } } this._dragEvents.dispatch('coral-dragaction:dragend', { detail: { dragElement: this._dragElement, pageX: pagePosition.x, pageY: pagePosition.y } }); } } /** @private */ _dragOnKeyDown(event) { switch (event.code) { case 'Space': case 'ArrowDown': case 'ArrowUp': case 'Enter': case 'Escape': event.preventDefault(); break; } } /** @private */ _dragOnKeyUp(event) { switch (event.code) { case 'Space': if (!this.isKeyboardDragging) { this._dragEvents.dispatch('coral-dragaction:dragonkeyspace', { detail: { dragElement: this._dragElement } }); this.isKeyboardDragging = true; } else { this._dragOnKeyEnd(); } break; case 'ArrowDown': this._dragEvents.dispatch('coral-dragaction:dragoveronkeyarrowdown', { detail: { dragElement: this._dragElement } }); break; case 'ArrowUp': this._dragEvents.dispatch('coral-dragaction:dragoveronkeyarrowup', { detail: { dragElement: this._dragElement } }); break; case 'Enter': case 'Escape': this._dragOnKeyEnd(); break; } } /** @private */ _dragOnFocusOut(event) { window.setTimeout(() => { if (document.activeElement === event.target) { return; } this._dragOnKeyEnd(); }, 0); } /** @private */ _dragOnKeyEnd() { this._dragEvents.dispatch('coral-dragaction:dragendonkey', { detail: { dragElement: this._dragElement } }); this.isKeyboardDragging = false; } /** Remove draggable actions @function destroy @param {Boolean} restorePosition Whether to restore the draggable element to its initial position */ destroy(restorePosition) { // Unbind events and remove classes document.body.classList.remove(CLOSE_HAND_CLASS); this._dragElement.classList.remove(IS_DRAGGING_CLASS); if (this._handles && this._handles.length) { this._handles.forEach((handle) => { handle._dragEvents.off('.DragAction'); handle.classList.remove(OPEN_HAND_CLASS); }); } else { this._dragEvents.off('.DragAction'); this._dragElement.classList.remove(OPEN_HAND_CLASS); } events.off(`.DragAction${this._id}`); // Restore overflow if (document.body._overflow) { document.body.style.overflow = document.body._overflow; document.body._overflow = undefined; } // Container might not have been initialized if (this._container) { if (!this._container.matches('body') && this._container._overflow) { this._container.style.overflow = this._container._overflow; this._container._overflow = undefined; } } // Set to initial position if (restorePosition) { this._dragElement.style.position = this._initialPosition.position; this._dragElement.style.top = this._initialPosition.top; this._dragElement.style.left = this._initialPosition.left; } // Remove reference this._dragElement.dragAction = undefined; } /** Returns {@link DragAction} axis restrictions. @return {DragActionAxisEnum} */ static get axis() { return axis; } /** @private */ get _scrollingElement() { // @polyfill ie11 // Element that scrolls the document. return document.scrollingElement || document.documentElement; } /** Triggered when the {@link DragAction#dragElement} starts to be dragged. @typedef {CustomEvent} coral-dragaction:dragstart @property {HTMLElement} dragElement The dragged element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} is being dragged. @typedef {CustomEvent} coral-dragaction:drag @property {HTMLElement} dragElement The dragged element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} stops to be dragged. @typedef {CustomEvent} coral-dragaction:dragend @property {HTMLElement} dragElement The dragged element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} enters a drop element. @typedef {CustomEvent} coral-dragaction:dragenter @property {HTMLElement} dragElement The dragged element @property {HTMLElement} dropElement The drop element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} is over a drop element. @typedef {CustomEvent} coral-dragaction:dragover @property {HTMLElement} dragElement The dragged element @property {HTMLElement} dropElement The drop element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} leaves a drop element. @typedef {CustomEvent} coral-dragaction:dragleave @property {HTMLElement} dragElement The dragged element @property {HTMLElement} dropElement The drop element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} is dropped on a drop element. @typedef {CustomEvent} coral-dragaction:drop @property {HTMLElement} dragElement The dragged element @property {HTMLElement} dropElement The drop element @property {Number} pageX The mouse position relative to the left edge of the document. @property {Number} pageY The mouse position relative to the top edge of the document. */ /** Triggered when the {@link DragAction#dragElement} is selected to be dragged. @typedef {CustomEvent} coral-dragaction:dragonkeyspace @property {HTMLElement} dragElement The dragged element */ /** Triggered when the {@link DragAction#dragElement} is moved on arrow down pressed. @typedef {CustomEvent} coral-dragaction:dragoveronkeyarrowdown @property {HTMLElement} dragElement The dragged element */ /** Triggered when the {@link DragAction#dragElement} is moved on arrow up pressed. @typedef {CustomEvent} coral-dragaction:dragoveronkeyarrowup @property {HTMLElement} dragElement The dragged element */ /** Triggered when the {@link DragAction#dragElement} is losing focus. @typedef {CustomEvent} coral-dragaction:dragonkeyfocusout @property {HTMLElement} dragElement The dragged element */ /** Triggered when the {@link DragAction#dragElement} is dropped on key. @typedef {CustomEvent} coral-dragaction:dragendonkey @property {HTMLElement} dragElement The dragged element */ } export default DragAction;