UNPKG

@geneui/components

Version:

The Gene UI components library designed for BI tools

1,403 lines (1,367 loc) 243 kB
import { _ as _extends } from './_rollupPluginBabelHelpers-e8fb2e5c.js'; import React__default, { createContext, memo, useEffect, useLayoutEffect, useState, useCallback, useMemo, isValidElement, cloneElement, useContext, useRef, forwardRef } from 'react'; import PropTypes from 'prop-types'; import { D as Dropdown, I as InfiniteLoader, W as WindowScroller, A as AutoSizer, L as List, C as CellMeasurer } from './index-9d8d0112.js'; import { C as CellMeasurerCache } from './CellMeasurerCache-661c24a8.js'; import { c as classnames } from './index-031ff73c.js'; import { s as stopEvent, o as oneIsRequired, n as noop } from './index-a0e4e333.js'; import useMount from './hooks/useMount.js'; import useUpdate from './hooks/useUpdate.js'; import './configs-00612ce0.js'; import useThrottle from './hooks/useThrottle.js'; import Empty from './Empty/index.js'; import CustomScrollbar from './Scrollbar/index.js'; import BusyLoader from './BusyLoader/index.js'; import useMutationObserver from './hooks/useMutationObserver.js'; import Icon from './Icon/index.js'; import { r as reactIsExports } from './index-6d7e99cd.js'; import Button from './Button/index.js'; import { s as styleInject } from './style-inject.es-746bb8ed.js'; import './dateValidation-67caec66.js'; import { g as guid } from './guid-8ddf77b3.js'; import ReactDOM__default from 'react-dom'; import SkeletonLoader from './SkeletonLoader/index.js'; import Copy from './Copy/index.js'; import { c as callAfterDelay } from './callAfterDelay-7272faca.js'; import Popover from './Popover/index.js'; import ExtendedInput from './ExtendedInput/index.js'; import Menu from './Menu/index.js'; import { d as debounce } from './debounce-4419bc2f.js'; import { j as jsxRuntimeExports } from './index-08898b29.js'; import { a as createStore } from './redux-b3e598ca.js'; /** * Create the React Context */ const DndContext = createContext({ dragDropManager: undefined }); /** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf-style format (only %s is supported) and arguments * to provide information about what broke and what you were * expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ function invariant(condition, format, ...args) { if (isProduction()) { if (format === undefined) { throw new Error('invariant requires an error message argument'); } } if (!condition) { let error; if (format === undefined) { error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); } else { let argIndex = 0; error = new Error(format.replace(/%s/g, function() { return args[argIndex++]; })); error.name = 'Invariant Violation'; } error.framesToPop = 1 // we don't care about invariant's own frame ; throw error; } } function isProduction() { return typeof process !== 'undefined' && process.env['NODE_ENV'] === 'production'; } // cheap lodash replacements /** * drop-in replacement for _.get * @param obj * @param path * @param defaultValue */ function get(obj, path, defaultValue) { return path.split('.').reduce((a, c)=>a && a[c] ? a[c] : defaultValue || null , obj); } /** * drop-in replacement for _.without */ function without$1(items, item) { return items.filter((i)=>i !== item ); } /** * drop-in replacement for _.isString * @param input */ function isObject(input) { return typeof input === 'object'; } /** * replacement for _.xor * @param itemsA * @param itemsB */ function xor(itemsA, itemsB) { const map = new Map(); const insertItem = (item)=>{ map.set(item, map.has(item) ? map.get(item) + 1 : 1); }; itemsA.forEach(insertItem); itemsB.forEach(insertItem); const result = []; map.forEach((count, key)=>{ if (count === 1) { result.push(key); } }); return result; } /** * replacement for _.intersection * @param itemsA * @param itemsB */ function intersection(itemsA, itemsB) { return itemsA.filter((t)=>itemsB.indexOf(t) > -1 ); } const INIT_COORDS = 'dnd-core/INIT_COORDS'; const BEGIN_DRAG = 'dnd-core/BEGIN_DRAG'; const PUBLISH_DRAG_SOURCE = 'dnd-core/PUBLISH_DRAG_SOURCE'; const HOVER = 'dnd-core/HOVER'; const DROP = 'dnd-core/DROP'; const END_DRAG = 'dnd-core/END_DRAG'; function setClientOffset(clientOffset, sourceClientOffset) { return { type: INIT_COORDS, payload: { sourceClientOffset: sourceClientOffset || null, clientOffset: clientOffset || null } }; } const ResetCoordinatesAction = { type: INIT_COORDS, payload: { clientOffset: null, sourceClientOffset: null } }; function createBeginDrag(manager) { return function beginDrag(sourceIds = [], options = { publishSource: true }) { const { publishSource =true , clientOffset , getSourceClientOffset , } = options; const monitor = manager.getMonitor(); const registry = manager.getRegistry(); // Initialize the coordinates using the client offset manager.dispatch(setClientOffset(clientOffset)); verifyInvariants$1(sourceIds, monitor, registry); // Get the draggable source const sourceId = getDraggableSource(sourceIds, monitor); if (sourceId == null) { manager.dispatch(ResetCoordinatesAction); return; } // Get the source client offset let sourceClientOffset = null; if (clientOffset) { if (!getSourceClientOffset) { throw new Error('getSourceClientOffset must be defined'); } verifyGetSourceClientOffsetIsFunction(getSourceClientOffset); sourceClientOffset = getSourceClientOffset(sourceId); } // Initialize the full coordinates manager.dispatch(setClientOffset(clientOffset, sourceClientOffset)); const source = registry.getSource(sourceId); const item = source.beginDrag(monitor, sourceId); // If source.beginDrag returns null, this is an indicator to cancel the drag if (item == null) { return undefined; } verifyItemIsObject(item); registry.pinSource(sourceId); const itemType = registry.getSourceType(sourceId); return { type: BEGIN_DRAG, payload: { itemType, item, sourceId, clientOffset: clientOffset || null, sourceClientOffset: sourceClientOffset || null, isSourcePublic: !!publishSource } }; }; } function verifyInvariants$1(sourceIds, monitor, registry) { invariant(!monitor.isDragging(), 'Cannot call beginDrag while dragging.'); sourceIds.forEach(function(sourceId) { invariant(registry.getSource(sourceId), 'Expected sourceIds to be registered.'); }); } function verifyGetSourceClientOffsetIsFunction(getSourceClientOffset) { invariant(typeof getSourceClientOffset === 'function', 'When clientOffset is provided, getSourceClientOffset must be a function.'); } function verifyItemIsObject(item) { invariant(isObject(item), 'Item must be an object.'); } function getDraggableSource(sourceIds, monitor) { let sourceId = null; for(let i = sourceIds.length - 1; i >= 0; i--){ if (monitor.canDragSource(sourceIds[i])) { sourceId = sourceIds[i]; break; } } return sourceId; } function _defineProperty$4(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread$4(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _defineProperty$4(target, key, source[key]); }); } return target; } function createDrop(manager) { return function drop(options = {}) { const monitor = manager.getMonitor(); const registry = manager.getRegistry(); verifyInvariants(monitor); const targetIds = getDroppableTargets(monitor); // Multiple actions are dispatched here, which is why this doesn't return an action targetIds.forEach((targetId, index)=>{ const dropResult = determineDropResult(targetId, index, registry, monitor); const action = { type: DROP, payload: { dropResult: _objectSpread$4({}, options, dropResult) } }; manager.dispatch(action); }); }; } function verifyInvariants(monitor) { invariant(monitor.isDragging(), 'Cannot call drop while not dragging.'); invariant(!monitor.didDrop(), 'Cannot call drop twice during one drag operation.'); } function determineDropResult(targetId, index, registry, monitor) { const target = registry.getTarget(targetId); let dropResult = target ? target.drop(monitor, targetId) : undefined; verifyDropResultType(dropResult); if (typeof dropResult === 'undefined') { dropResult = index === 0 ? {} : monitor.getDropResult(); } return dropResult; } function verifyDropResultType(dropResult) { invariant(typeof dropResult === 'undefined' || isObject(dropResult), 'Drop result must either be an object or undefined.'); } function getDroppableTargets(monitor) { const targetIds = monitor.getTargetIds().filter(monitor.canDropOnTarget, monitor); targetIds.reverse(); return targetIds; } function createEndDrag(manager) { return function endDrag() { const monitor = manager.getMonitor(); const registry = manager.getRegistry(); verifyIsDragging(monitor); const sourceId = monitor.getSourceId(); if (sourceId != null) { const source = registry.getSource(sourceId, true); source.endDrag(monitor, sourceId); registry.unpinSource(); } return { type: END_DRAG }; }; } function verifyIsDragging(monitor) { invariant(monitor.isDragging(), 'Cannot call endDrag while not dragging.'); } function matchesType(targetType, draggedItemType) { if (draggedItemType === null) { return targetType === null; } return Array.isArray(targetType) ? targetType.some((t)=>t === draggedItemType ) : targetType === draggedItemType; } function createHover(manager) { return function hover(targetIdsArg, { clientOffset } = {}) { verifyTargetIdsIsArray(targetIdsArg); const targetIds = targetIdsArg.slice(0); const monitor = manager.getMonitor(); const registry = manager.getRegistry(); const draggedItemType = monitor.getItemType(); removeNonMatchingTargetIds(targetIds, registry, draggedItemType); checkInvariants(targetIds, monitor, registry); hoverAllTargets(targetIds, monitor, registry); return { type: HOVER, payload: { targetIds, clientOffset: clientOffset || null } }; }; } function verifyTargetIdsIsArray(targetIdsArg) { invariant(Array.isArray(targetIdsArg), 'Expected targetIds to be an array.'); } function checkInvariants(targetIds, monitor, registry) { invariant(monitor.isDragging(), 'Cannot call hover while not dragging.'); invariant(!monitor.didDrop(), 'Cannot call hover after drop.'); for(let i = 0; i < targetIds.length; i++){ const targetId = targetIds[i]; invariant(targetIds.lastIndexOf(targetId) === i, 'Expected targetIds to be unique in the passed array.'); const target = registry.getTarget(targetId); invariant(target, 'Expected targetIds to be registered.'); } } function removeNonMatchingTargetIds(targetIds, registry, draggedItemType) { // Remove those targetIds that don't match the targetType. This // fixes shallow isOver which would only be non-shallow because of // non-matching targets. for(let i = targetIds.length - 1; i >= 0; i--){ const targetId = targetIds[i]; const targetType = registry.getTargetType(targetId); if (!matchesType(targetType, draggedItemType)) { targetIds.splice(i, 1); } } } function hoverAllTargets(targetIds, monitor, registry) { // Finally call hover on all matching targets. targetIds.forEach(function(targetId) { const target = registry.getTarget(targetId); target.hover(monitor, targetId); }); } function createPublishDragSource(manager) { return function publishDragSource() { const monitor = manager.getMonitor(); if (monitor.isDragging()) { return { type: PUBLISH_DRAG_SOURCE }; } return; }; } function createDragDropActions(manager) { return { beginDrag: createBeginDrag(manager), publishDragSource: createPublishDragSource(manager), hover: createHover(manager), drop: createDrop(manager), endDrag: createEndDrag(manager) }; } class DragDropManagerImpl { receiveBackend(backend) { this.backend = backend; } getMonitor() { return this.monitor; } getBackend() { return this.backend; } getRegistry() { return this.monitor.registry; } getActions() { /* eslint-disable-next-line @typescript-eslint/no-this-alias */ const manager = this; const { dispatch } = this.store; function bindActionCreator(actionCreator) { return (...args)=>{ const action = actionCreator.apply(manager, args); if (typeof action !== 'undefined') { dispatch(action); } }; } const actions = createDragDropActions(this); return Object.keys(actions).reduce((boundActions, key)=>{ const action = actions[key]; boundActions[key] = bindActionCreator(action); return boundActions; }, {}); } dispatch(action) { this.store.dispatch(action); } constructor(store, monitor){ this.isSetUp = false; this.handleRefCountChange = ()=>{ const shouldSetUp = this.store.getState().refCount > 0; if (this.backend) { if (shouldSetUp && !this.isSetUp) { this.backend.setup(); this.isSetUp = true; } else if (!shouldSetUp && this.isSetUp) { this.backend.teardown(); this.isSetUp = false; } } }; this.store = store; this.monitor = monitor; store.subscribe(this.handleRefCountChange); } } /** * Coordinate addition * @param a The first coordinate * @param b The second coordinate */ function add(a, b) { return { x: a.x + b.x, y: a.y + b.y }; } /** * Coordinate subtraction * @param a The first coordinate * @param b The second coordinate */ function subtract(a, b) { return { x: a.x - b.x, y: a.y - b.y }; } /** * Returns the cartesian distance of the drag source component's position, based on its position * at the time when the current drag operation has started, and the movement difference. * * Returns null if no item is being dragged. * * @param state The offset state to compute from */ function getSourceClientOffset(state) { const { clientOffset , initialClientOffset , initialSourceClientOffset } = state; if (!clientOffset || !initialClientOffset || !initialSourceClientOffset) { return null; } return subtract(add(clientOffset, initialSourceClientOffset), initialClientOffset); } /** * Determines the x,y offset between the client offset and the initial client offset * * @param state The offset state to compute from */ function getDifferenceFromInitialOffset(state) { const { clientOffset , initialClientOffset } = state; if (!clientOffset || !initialClientOffset) { return null; } return subtract(clientOffset, initialClientOffset); } const NONE = []; const ALL = []; NONE.__IS_NONE__ = true; ALL.__IS_ALL__ = true; /** * Determines if the given handler IDs are dirty or not. * * @param dirtyIds The set of dirty handler ids * @param handlerIds The set of handler ids to check */ function areDirty(dirtyIds, handlerIds) { if (dirtyIds === NONE) { return false; } if (dirtyIds === ALL || typeof handlerIds === 'undefined') { return true; } const commonIds = intersection(handlerIds, dirtyIds); return commonIds.length > 0; } class DragDropMonitorImpl { subscribeToStateChange(listener, options = {}) { const { handlerIds } = options; invariant(typeof listener === 'function', 'listener must be a function.'); invariant(typeof handlerIds === 'undefined' || Array.isArray(handlerIds), 'handlerIds, when specified, must be an array of strings.'); let prevStateId = this.store.getState().stateId; const handleChange = ()=>{ const state = this.store.getState(); const currentStateId = state.stateId; try { const canSkipListener = currentStateId === prevStateId || currentStateId === prevStateId + 1 && !areDirty(state.dirtyHandlerIds, handlerIds); if (!canSkipListener) { listener(); } } finally{ prevStateId = currentStateId; } }; return this.store.subscribe(handleChange); } subscribeToOffsetChange(listener) { invariant(typeof listener === 'function', 'listener must be a function.'); let previousState = this.store.getState().dragOffset; const handleChange = ()=>{ const nextState = this.store.getState().dragOffset; if (nextState === previousState) { return; } previousState = nextState; listener(); }; return this.store.subscribe(handleChange); } canDragSource(sourceId) { if (!sourceId) { return false; } const source = this.registry.getSource(sourceId); invariant(source, `Expected to find a valid source. sourceId=${sourceId}`); if (this.isDragging()) { return false; } return source.canDrag(this, sourceId); } canDropOnTarget(targetId) { // undefined on initial render if (!targetId) { return false; } const target = this.registry.getTarget(targetId); invariant(target, `Expected to find a valid target. targetId=${targetId}`); if (!this.isDragging() || this.didDrop()) { return false; } const targetType = this.registry.getTargetType(targetId); const draggedItemType = this.getItemType(); return matchesType(targetType, draggedItemType) && target.canDrop(this, targetId); } isDragging() { return Boolean(this.getItemType()); } isDraggingSource(sourceId) { // undefined on initial render if (!sourceId) { return false; } const source = this.registry.getSource(sourceId, true); invariant(source, `Expected to find a valid source. sourceId=${sourceId}`); if (!this.isDragging() || !this.isSourcePublic()) { return false; } const sourceType = this.registry.getSourceType(sourceId); const draggedItemType = this.getItemType(); if (sourceType !== draggedItemType) { return false; } return source.isDragging(this, sourceId); } isOverTarget(targetId, options = { shallow: false }) { // undefined on initial render if (!targetId) { return false; } const { shallow } = options; if (!this.isDragging()) { return false; } const targetType = this.registry.getTargetType(targetId); const draggedItemType = this.getItemType(); if (draggedItemType && !matchesType(targetType, draggedItemType)) { return false; } const targetIds = this.getTargetIds(); if (!targetIds.length) { return false; } const index = targetIds.indexOf(targetId); if (shallow) { return index === targetIds.length - 1; } else { return index > -1; } } getItemType() { return this.store.getState().dragOperation.itemType; } getItem() { return this.store.getState().dragOperation.item; } getSourceId() { return this.store.getState().dragOperation.sourceId; } getTargetIds() { return this.store.getState().dragOperation.targetIds; } getDropResult() { return this.store.getState().dragOperation.dropResult; } didDrop() { return this.store.getState().dragOperation.didDrop; } isSourcePublic() { return Boolean(this.store.getState().dragOperation.isSourcePublic); } getInitialClientOffset() { return this.store.getState().dragOffset.initialClientOffset; } getInitialSourceClientOffset() { return this.store.getState().dragOffset.initialSourceClientOffset; } getClientOffset() { return this.store.getState().dragOffset.clientOffset; } getSourceClientOffset() { return getSourceClientOffset(this.store.getState().dragOffset); } getDifferenceFromInitialOffset() { return getDifferenceFromInitialOffset(this.store.getState().dragOffset); } constructor(store, registry){ this.store = store; this.registry = registry; } } // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that // have WebKitMutationObserver but not un-prefixed MutationObserver. // Must use `global` or `self` instead of `window` to work in both frames and web // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. /* globals self */ const scope = typeof global !== 'undefined' ? global : self; const BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; function makeRequestCallFromTimer(callback) { return function requestCall() { // We dispatch a timeout with a specified delay of 0 for engines that // can reliably accommodate that request. This will usually be snapped // to a 4 milisecond delay, but once we're flushing, there's no delay // between events. const timeoutHandle = setTimeout(handleTimer, 0); // However, since this timer gets frequently dropped in Firefox // workers, we enlist an interval handle that will try to fire // an event 20 times per second until it succeeds. const intervalHandle = setInterval(handleTimer, 50); function handleTimer() { // Whichever timer succeeds will cancel both timers and // execute the callback. clearTimeout(timeoutHandle); clearInterval(intervalHandle); callback(); } }; } // To request a high priority event, we induce a mutation observer by toggling // the text of a text node between "1" and "-1". function makeRequestCallFromMutationObserver(callback) { let toggle = 1; const observer = new BrowserMutationObserver(callback); const node = document.createTextNode(''); observer.observe(node, { characterData: true }); return function requestCall() { toggle = -toggle; node.data = toggle; }; } const makeRequestCall = typeof BrowserMutationObserver === 'function' ? // reliably everywhere they are implemented. // They are implemented in all modern browsers. // // - Android 4-4.3 // - Chrome 26-34 // - Firefox 14-29 // - Internet Explorer 11 // - iPad Safari 6-7.1 // - iPhone Safari 7-7.1 // - Safari 6-7 makeRequestCallFromMutationObserver : // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera // 11-12, and in web workers in many engines. // Although message channels yield to any queued rendering and IO tasks, they // would be better than imposing the 4ms delay of timers. // However, they do not work reliably in Internet Explorer or Safari. // Internet Explorer 10 is the only browser that has setImmediate but does // not have MutationObservers. // Although setImmediate yields to the browser's renderer, it would be // preferrable to falling back to setTimeout since it does not have // the minimum 4ms penalty. // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and // Desktop to a lesser extent) that renders both setImmediate and // MessageChannel useless for the purposes of ASAP. // https://github.com/kriskowal/q/issues/396 // Timers are implemented universally. // We fall back to timers in workers in most engines, and in foreground // contexts in the following browsers. // However, note that even this simple case requires nuances to operate in a // broad spectrum of browsers. // // - Firefox 3-13 // - Internet Explorer 6-9 // - iPad Safari 4.3 // - Lynx 2.8.7 makeRequestCallFromTimer; class AsapQueue { // Use the fastest means possible to execute a task in its own turn, with // priority over other events including IO, animation, reflow, and redraw // events in browsers. // // An exception thrown by a task will permanently interrupt the processing of // subsequent tasks. The higher level `asap` function ensures that if an // exception is thrown by a task, that the task queue will continue flushing as // soon as possible, but if you use `rawAsap` directly, you are responsible to // either ensure that no exceptions are thrown from your task, or to manually // call `rawAsap.requestFlush` if an exception is thrown. enqueueTask(task) { const { queue: q , requestFlush } = this; if (!q.length) { requestFlush(); this.flushing = true; } // Equivalent to push, but avoids a function call. q[q.length] = task; } constructor(){ this.queue = []; // We queue errors to ensure they are thrown in right order (FIFO). // Array-as-queue is good enough here, since we are just dealing with exceptions. this.pendingErrors = []; // Once a flush has been requested, no further calls to `requestFlush` are // necessary until the next `flush` completes. // @ts-ignore this.flushing = false; // The position of the next task to execute in the task queue. This is // preserved between calls to `flush` so that it can be resumed if // a task throws an exception. this.index = 0; // If a task schedules additional tasks recursively, the task queue can grow // unbounded. To prevent memory exhaustion, the task queue will periodically // truncate already-completed tasks. this.capacity = 1024; // The flush function processes all tasks that have been scheduled with // `rawAsap` unless and until one of those tasks throws an exception. // If a task throws an exception, `flush` ensures that its state will remain // consistent and will resume where it left off when called again. // However, `flush` does not make any arrangements to be called again if an // exception is thrown. this.flush = ()=>{ const { queue: q } = this; while(this.index < q.length){ const currentIndex = this.index; // Advance the index before calling the task. This ensures that we will // begin flushing on the next task the task throws an error. this.index++; q[currentIndex].call(); // Prevent leaking memory for long chains of recursive calls to `asap`. // If we call `asap` within tasks scheduled by `asap`, the queue will // grow, but to avoid an O(n) walk for every task we execute, we don't // shift tasks off the queue after they have been executed. // Instead, we periodically shift 1024 tasks off the queue. if (this.index > this.capacity) { // Manually shift all values starting at the index back to the // beginning of the queue. for(let scan = 0, newLength = q.length - this.index; scan < newLength; scan++){ q[scan] = q[scan + this.index]; } q.length -= this.index; this.index = 0; } } q.length = 0; this.index = 0; this.flushing = false; }; // In a web browser, exceptions are not fatal. However, to avoid // slowing down the queue of pending tasks, we rethrow the error in a // lower priority turn. this.registerPendingError = (err)=>{ this.pendingErrors.push(err); this.requestErrorThrow(); }; // `requestFlush` requests that the high priority event queue be flushed as // soon as possible. // This is useful to prevent an error thrown in a task from stalling the event // queue if the exception handled by Node.js’s // `process.on("uncaughtException")` or by a domain. // `requestFlush` is implemented using a strategy based on data collected from // every available SauceLabs Selenium web driver worker at time of writing. // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 this.requestFlush = makeRequestCall(this.flush); this.requestErrorThrow = makeRequestCallFromTimer(()=>{ // Throw first error if (this.pendingErrors.length) { throw this.pendingErrors.shift(); } }); } } // The message channel technique was discovered by Malte Ubl and was the // original foundation for this library. // http://www.nonblocking.io/2011/06/windownexttick.html // Safari 6.0.5 (at least) intermittently fails to create message ports on a // page's first load. Thankfully, this version of Safari supports // MutationObservers, so we don't need to fall back in that case. // function makeRequestCallFromMessageChannel(callback) { // var channel = new MessageChannel(); // channel.port1.onmessage = callback; // return function requestCall() { // channel.port2.postMessage(0); // }; // } // For reasons explained above, we are also unable to use `setImmediate` // under any circumstances. // Even if we were, there is another bug in Internet Explorer 10. // It is not sufficient to assign `setImmediate` to `requestFlush` because // `setImmediate` must be called *by name* and therefore must be wrapped in a // closure. // Never forget. // function makeRequestCallFromSetImmediate(callback) { // return function requestCall() { // setImmediate(callback); // }; // } // Safari 6.0 has a problem where timers will get lost while the user is // scrolling. This problem does not impact ASAP because Safari 6.0 supports // mutation observers, so that implementation is used instead. // However, if we ever elect to use timers in Safari, the prevalent work-around // is to add a scroll event listener that calls for a flush. // `setTimeout` does not call the passed callback if the delay is less than // approximately 7 in web workers in Firefox 8 through 18, and sometimes not // even then. // This is for `asap.js` only. // Its name will be periodically randomized to break any code that depends on // // its existence. // rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer // ASAP was originally a nextTick shim included in Q. This was factored out // into this ASAP package. It was later adapted to RSVP which made further // amendments. These decisions, particularly to marginalize MessageChannel and // to capture the MutationObserver implementation in a closure, were integrated // back into ASAP proper. // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js // `call`, just like a function. class RawTask { call() { try { this.task && this.task(); } catch (error) { this.onError(error); } finally{ this.task = null; this.release(this); } } constructor(onError, release){ this.onError = onError; this.release = release; this.task = null; } } class TaskFactory { create(task) { const tasks = this.freeTasks; const t1 = tasks.length ? tasks.pop() : new RawTask(this.onError, (t)=>tasks[tasks.length] = t ); t1.task = task; return t1; } constructor(onError){ this.onError = onError; this.freeTasks = []; } } const asapQueue = new AsapQueue(); const taskFactory = new TaskFactory(asapQueue.registerPendingError); /** * Calls a task as soon as possible after returning, in its own event, with priority * over other events like animation, reflow, and repaint. An error thrown from an * event will not interrupt, nor even substantially slow down the processing of * other events, but will be rather postponed to a lower priority event. * @param {{call}} task A callable object, typically a function that takes no * arguments. */ function asap(task) { asapQueue.enqueueTask(taskFactory.create(task)); } const ADD_SOURCE = 'dnd-core/ADD_SOURCE'; const ADD_TARGET = 'dnd-core/ADD_TARGET'; const REMOVE_SOURCE = 'dnd-core/REMOVE_SOURCE'; const REMOVE_TARGET = 'dnd-core/REMOVE_TARGET'; function addSource(sourceId) { return { type: ADD_SOURCE, payload: { sourceId } }; } function addTarget(targetId) { return { type: ADD_TARGET, payload: { targetId } }; } function removeSource(sourceId) { return { type: REMOVE_SOURCE, payload: { sourceId } }; } function removeTarget(targetId) { return { type: REMOVE_TARGET, payload: { targetId } }; } function validateSourceContract(source) { invariant(typeof source.canDrag === 'function', 'Expected canDrag to be a function.'); invariant(typeof source.beginDrag === 'function', 'Expected beginDrag to be a function.'); invariant(typeof source.endDrag === 'function', 'Expected endDrag to be a function.'); } function validateTargetContract(target) { invariant(typeof target.canDrop === 'function', 'Expected canDrop to be a function.'); invariant(typeof target.hover === 'function', 'Expected hover to be a function.'); invariant(typeof target.drop === 'function', 'Expected beginDrag to be a function.'); } function validateType(type, allowArray) { if (allowArray && Array.isArray(type)) { type.forEach((t)=>validateType(t, false) ); return; } invariant(typeof type === 'string' || typeof type === 'symbol', allowArray ? 'Type can only be a string, a symbol, or an array of either.' : 'Type can only be a string or a symbol.'); } var HandlerRole; (function(HandlerRole) { HandlerRole["SOURCE"] = "SOURCE"; HandlerRole["TARGET"] = "TARGET"; })(HandlerRole || (HandlerRole = {})); let nextUniqueId = 0; function getNextUniqueId() { return nextUniqueId++; } function getNextHandlerId(role) { const id = getNextUniqueId().toString(); switch(role){ case HandlerRole.SOURCE: return `S${id}`; case HandlerRole.TARGET: return `T${id}`; default: throw new Error(`Unknown Handler Role: ${role}`); } } function parseRoleFromHandlerId(handlerId) { switch(handlerId[0]){ case 'S': return HandlerRole.SOURCE; case 'T': return HandlerRole.TARGET; default: throw new Error(`Cannot parse handler ID: ${handlerId}`); } } function mapContainsValue(map, searchValue) { const entries = map.entries(); let isDone = false; do { const { done , value: [, value] , } = entries.next(); if (value === searchValue) { return true; } isDone = !!done; }while (!isDone) return false; } class HandlerRegistryImpl { addSource(type, source) { validateType(type); validateSourceContract(source); const sourceId = this.addHandler(HandlerRole.SOURCE, type, source); this.store.dispatch(addSource(sourceId)); return sourceId; } addTarget(type, target) { validateType(type, true); validateTargetContract(target); const targetId = this.addHandler(HandlerRole.TARGET, type, target); this.store.dispatch(addTarget(targetId)); return targetId; } containsHandler(handler) { return mapContainsValue(this.dragSources, handler) || mapContainsValue(this.dropTargets, handler); } getSource(sourceId, includePinned = false) { invariant(this.isSourceId(sourceId), 'Expected a valid source ID.'); const isPinned = includePinned && sourceId === this.pinnedSourceId; const source = isPinned ? this.pinnedSource : this.dragSources.get(sourceId); return source; } getTarget(targetId) { invariant(this.isTargetId(targetId), 'Expected a valid target ID.'); return this.dropTargets.get(targetId); } getSourceType(sourceId) { invariant(this.isSourceId(sourceId), 'Expected a valid source ID.'); return this.types.get(sourceId); } getTargetType(targetId) { invariant(this.isTargetId(targetId), 'Expected a valid target ID.'); return this.types.get(targetId); } isSourceId(handlerId) { const role = parseRoleFromHandlerId(handlerId); return role === HandlerRole.SOURCE; } isTargetId(handlerId) { const role = parseRoleFromHandlerId(handlerId); return role === HandlerRole.TARGET; } removeSource(sourceId) { invariant(this.getSource(sourceId), 'Expected an existing source.'); this.store.dispatch(removeSource(sourceId)); asap(()=>{ this.dragSources.delete(sourceId); this.types.delete(sourceId); }); } removeTarget(targetId) { invariant(this.getTarget(targetId), 'Expected an existing target.'); this.store.dispatch(removeTarget(targetId)); this.dropTargets.delete(targetId); this.types.delete(targetId); } pinSource(sourceId) { const source = this.getSource(sourceId); invariant(source, 'Expected an existing source.'); this.pinnedSourceId = sourceId; this.pinnedSource = source; } unpinSource() { invariant(this.pinnedSource, 'No source is pinned at the time.'); this.pinnedSourceId = null; this.pinnedSource = null; } addHandler(role, type, handler) { const id = getNextHandlerId(role); this.types.set(id, type); if (role === HandlerRole.SOURCE) { this.dragSources.set(id, handler); } else if (role === HandlerRole.TARGET) { this.dropTargets.set(id, handler); } return id; } constructor(store){ this.types = new Map(); this.dragSources = new Map(); this.dropTargets = new Map(); this.pinnedSourceId = null; this.pinnedSource = null; this.store = store; } } const strictEquality = (a, b)=>a === b ; /** * Determine if two cartesian coordinate offsets are equal * @param offsetA * @param offsetB */ function areCoordsEqual(offsetA, offsetB) { if (!offsetA && !offsetB) { return true; } else if (!offsetA || !offsetB) { return false; } else { return offsetA.x === offsetB.x && offsetA.y === offsetB.y; } } /** * Determines if two arrays of items are equal * @param a The first array of items * @param b The second array of items */ function areArraysEqual(a, b, isEqual = strictEquality) { if (a.length !== b.length) { return false; } for(let i = 0; i < a.length; ++i){ if (!isEqual(a[i], b[i])) { return false; } } return true; } function reduce$5(// eslint-disable-next-line @typescript-eslint/no-unused-vars _state = NONE, action) { switch(action.type){ case HOVER: break; case ADD_SOURCE: case ADD_TARGET: case REMOVE_TARGET: case REMOVE_SOURCE: return NONE; case BEGIN_DRAG: case PUBLISH_DRAG_SOURCE: case END_DRAG: case DROP: default: return ALL; } const { targetIds =[] , prevTargetIds =[] } = action.payload; const result = xor(targetIds, prevTargetIds); const didChange = result.length > 0 || !areArraysEqual(targetIds, prevTargetIds); if (!didChange) { return NONE; } // Check the target ids at the innermost position. If they are valid, add them // to the result const prevInnermostTargetId = prevTargetIds[prevTargetIds.length - 1]; const innermostTargetId = targetIds[targetIds.length - 1]; if (prevInnermostTargetId !== innermostTargetId) { if (prevInnermostTargetId) { result.push(prevInnermostTargetId); } if (innermostTargetId) { result.push(innermostTargetId); } } return result; } function _defineProperty$3(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread$3(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _defineProperty$3(target, key, source[key]); }); } return target; } const initialState$1 = { initialSourceClientOffset: null, initialClientOffset: null, clientOffset: null }; function reduce$4(state = initialState$1, action) { const { payload } = action; switch(action.type){ case INIT_COORDS: case BEGIN_DRAG: return { initialSourceClientOffset: payload.sourceClientOffset, initialClientOffset: payload.clientOffset, clientOffset: payload.clientOffset }; case HOVER: if (areCoordsEqual(state.clientOffset, payload.clientOffset)) { return state; } return _objectSpread$3({}, state, { clientOffset: payload.clientOffset }); case END_DRAG: case DROP: return initialState$1; default: return state; } } function _defineProperty$2(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread$2(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _defineProperty$2(target, key, source[key]); }); } return target; } const initialState = { itemType: null, item: null, sourceId: null, targetIds: [], dropResult: null, didDrop: false, isSourcePublic: null }; function reduce$3(state = initialState, action) { const { payload } = action; switch(action.type){ case BEGIN_DRAG: return _objectSpread$2({}, state, { itemType: payload.itemType, item: payload.item, sourceId: payload.sourceId, isSourcePublic: payload.isSourcePublic, dropResult: null, didDrop: false }); case PUBLISH_DRAG_SOURCE: return _objectSpread$2({}, state, { isSourcePublic: true }); case HOVER: return _objectSpread$2({}, state, { targetIds: payload.targetIds }); case REMOVE_TARGET: if (state.targetIds.indexOf(payload.targetId) === -1) { return state; } return _objectSpread$2({}, state, { targetIds: without$1(state.targetIds, payload.targetId) }); case DROP: return _objectSpread$2({}, state, { dropResult: payload.dropResult, didDrop: true, targetIds: [] }); case END_DRAG: return _objectSpread$2({}, state, { itemType: null, item: null, sourceId: null, dropResult: null, didDrop: false, isSourcePublic: null, targetIds: [] }); default: return state; } } function reduce$2(state = 0, action) { switch(action.type){ case ADD_SOURCE: case ADD_TARGET: return state + 1; case REMOVE_SOURCE: case REMOVE_TARGET: return state - 1; default: return state; } } function reduce$1(state = 0) { return state + 1; } function _defineProperty$1(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread$1(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _defineProperty$1(target, key, source[key]); }); } return target; } function reduce(state = {}, action) { return { dirtyHandlerIds: reduce$5(state.dirtyHandlerIds, { type: action.type, payload: _objectSpread$1({}, action.payload, { prevTargetIds: get(state, 'dragOperation.targetIds', []) }) }), dragOffset: reduce$4(state.dragOffset, action), refCount: reduce$2(state.refCount, action), dragOperation: reduce$3(state.dragOperation, action), stateId: reduce$1(state.stateId) }; } function createDragDropManager(backendFactory, globalContext = undefined, backendOptions = {}, debugMode = false) { const store = makeStoreInstance(debugMode); const monitor = new DragDropMonitorImpl(store, new HandlerRegistryImpl(store)); const manager = new DragDropManagerImpl(store, monitor); const backend = backendFactory(manager, globalContext, backendOptions); manager.receiveBackend(backend); return manager; } function makeStoreInstance(debugMode) { // TODO: if we ever make a react-native version of this, // we'll need to consider how to pull off dev-tooling const reduxDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__; return createStore(reduce, debugMode && reduxDevTools && reduxDevTools({ name: 'dnd-core', instanceId: 'dnd-core' })); } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for(i = 0; i < sourceSymbolKeys.length; i++){