UNPKG

@atlaskit/pragmatic-drag-and-drop-docs

Version:

This package holds the documentation for Pragmatic drag and drop in one place. It is not intended to be consumed directly by consumers. The package is used by other tools for sharing examples

140 lines (113 loc) 4.43 kB
--- title: Monitors description: Monitors can listen to all events for a draggable entity, such as an element or file. --- Monitors are a way of listening for drag and drop operation events anywhere. ## Basic usage ```ts // monitors are exposed through adapters import { monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter'; // listen for all drag events for files const cleanup = monitorForExternal({ onDragStart: () => console.log('I am called whenever any external enters this window'), }); ``` A _monitor_ can be located anywhere and is not tied to any element. ```tsx // basic usage with react import React, { useEffect, useRef } from 'react'; import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; function App() { // It is often convenient to tie monitors to components using effects // By doing this you can ensure you monitors are cleaned up // when a component is no longer being used. useEffect(() => { return monitorForElements({ onDragStart: () => console.log('I am called whenever any element drag starts'), }); }, []); return <div>{/*...*/}</div>; } ``` ## Conditional monitoring A _monitor_ can be conditionally activated for a drag operation by using the `canMonitor()` function. - `canMonitor?: (args: MonitorGetFeedbackArgs<DragType>) => boolean` ```ts type MonitorGetFeedbackArgs = { /** * The users initial drag location */ initial: DragLocation; /** * The data associated with the entity being dragged */ source: DragType['payload']; }; ``` ```ts monitorForElements({ canMonitor: ({ source }) => source.data.type === 'card', onDragStart: () => console.log('I will only be activated when dragging a card!'), }); ``` `canMonitor()` is only called once for a monitor during a drag operation as the drag is starting. If a _monitor_ is added during an active drag, then `canMonitor()` will be called as it is created with the _intial_ drag source value and initial drag location. All monitors are called with the same `MonitorGetFeedbackArgs` value during the same drag operation. We wanted to make this behvaiour clear as the `source` value can change for external drag types in the `"onDrop"` event (eg files). If you want to do more complicated checks, you can do those inside of your _monitor_ event listeners: ```ts monitorForElements({ // filtering will opt the monitor into the whole drag operation canMonitor: ({ source }) => source.data.type === 'card', onDrag: ({ location }) => { // Additional action filtering based on changes during the drag if (location.current.data.action === 'delete') { console.log('about to delete'); } }, }); ``` ## Event ordering All events flow through the system in the same way: 1. drag source (eg `draggable`) if relevant 2. drop targets - inner most upwards (bubble ordering) `grandChild -> child -> parent` 3. monitors (in the order that they were created) _monitors_ are called in the same order in which they are created. Over time it can be hard to reason about what this ordering is as a consumer as you might be creating / destroying monitors frequently. So it is safe to expect that "monitors are called last", but you need to be careful if you want to rely on any ordering relationships between _monitors_. ```tsx function App() { useEffect(() => { const cleanup = monitorForElements({ onDragStart: () => 'This monitor gets created on each render!', }); return cleanup; }); return null; } ``` [Learn more about event ordering](/components/pragmatic-drag-and-drop/core-package/events) ## Adding monitors during an event A _monitor_ that is added during an event (eg `onDragStart`) will not be called for the current event. This is to prevent the accidental creation of infinite loops. This behaviour matches native [`EventTargets`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) where an event listener cannot add another event listener during an active event to the same event target in the same event phase. ```ts const monitor1 = monitorForElements({ onGenerateDragPreview: () => { const monitor2 = monitorForElements({ // Setting up another monitor during `onGenerateDragPreview` onGenerateDragPreview: () => { // monitor2 will not be called for the _current_ `onGenerateDragPreview` event }, // The monitor will be called for subsequent events onDragStart: () => {}, }); }, }); ```