UNPKG

@wordpress/block-editor

Version:
8 lines (7 loc) 27 kB
{ "version": 3, "sources": ["../../../src/components/list-view/use-list-view-drop-zone.js"], "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useSelect } from '@wordpress/data';\nimport { useState, useCallback, useEffect } from '@wordpress/element';\nimport {\n\tuseThrottle,\n\t__experimentalUseDropZone as useDropZone,\n\tusePrevious,\n} from '@wordpress/compose';\nimport { isRTL } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport {\n\tgetDistanceToNearestEdge,\n\tisPointContainedByRect,\n} from '../../utils/math';\nimport useOnBlockDrop from '../use-on-block-drop';\nimport { store as blockEditorStore } from '../../store';\n\n/** @typedef {import('../../utils/math').WPPoint} WPPoint */\n\n/**\n * The type of a drag event.\n *\n * @typedef {'default'|'file'|'html'} WPDragEventType\n */\n\n/**\n * An object representing data for blocks in the DOM used by drag and drop.\n *\n * @typedef {Object} WPListViewDropZoneBlock\n * @property {string} clientId The client id for the block.\n * @property {string} rootClientId The root client id for the block.\n * @property {number} blockIndex The block's index.\n * @property {Element} element The DOM element representing the block.\n * @property {number} innerBlockCount The number of inner blocks the block has.\n * @property {boolean} isDraggedBlock Whether the block is currently being dragged.\n * @property {boolean} isExpanded Whether the block is expanded in the UI.\n * @property {boolean} canInsertDraggedBlocksAsSibling Whether the dragged block can be a sibling of this block.\n * @property {boolean} canInsertDraggedBlocksAsChild Whether the dragged block can be a child of this block.\n */\n\n/**\n * An array representing data for blocks in the DOM used by drag and drop.\n *\n * @typedef {WPListViewDropZoneBlock[]} WPListViewDropZoneBlocks\n */\n\n/**\n * An object containing details of a drop target.\n *\n * @typedef {Object} WPListViewDropZoneTarget\n * @property {string} blockIndex The insertion index.\n * @property {string} rootClientId The root client id for the block.\n * @property {string|undefined} clientId The client id for the block.\n * @property {'top'|'bottom'|'inside'} dropPosition The position relative to the block that the user is dropping to.\n * 'inside' refers to nesting as an inner block.\n */\n\n// When the indentation level, the corresponding left margin in `style.scss`\n// must be updated as well to ensure the drop zone is aligned with the indentation.\nexport const NESTING_LEVEL_INDENTATION = 24;\n\n/**\n * Determines whether the user is positioning the dragged block to be\n * moved up to a parent level.\n *\n * Determined based on nesting level indentation of the current block.\n *\n * @param {WPPoint} point The point representing the cursor position when dragging.\n * @param {DOMRect} rect The rectangle.\n * @param {number} nestingLevel The nesting level of the block.\n * @param {boolean} rtl Whether the editor is in RTL mode.\n * @return {boolean} Whether the gesture is an upward gesture.\n */\nfunction isUpGesture( point, rect, nestingLevel = 1, rtl = false ) {\n\t// If the block is nested, and the user is dragging to the bottom\n\t// left of the block (or bottom right in RTL languages), then it is an upward gesture.\n\tconst blockIndentPosition = rtl\n\t\t? rect.right - nestingLevel * NESTING_LEVEL_INDENTATION\n\t\t: rect.left + nestingLevel * NESTING_LEVEL_INDENTATION;\n\treturn rtl ? point.x > blockIndentPosition : point.x < blockIndentPosition;\n}\n\n/**\n * Returns how many nesting levels up the user is attempting to drag to.\n *\n * The relative parent level is calculated based on how far\n * the cursor is from the provided nesting level (e.g. of a candidate block\n * that the user is hovering over). The nesting level is considered \"desired\"\n * because it is not guaranteed that the user will be able to drag to the desired level.\n *\n * The returned integer can be used to access an ascending array\n * of parent blocks, where the first item is the block the user\n * is hovering over, and the last item is the root block.\n *\n * @param {WPPoint} point The point representing the cursor position when dragging.\n * @param {DOMRect} rect The rectangle.\n * @param {number} nestingLevel The nesting level of the block.\n * @param {boolean} rtl Whether the editor is in RTL mode.\n * @return {number} The desired relative parent level.\n */\nfunction getDesiredRelativeParentLevel(\n\tpoint,\n\trect,\n\tnestingLevel = 1,\n\trtl = false\n) {\n\t// In RTL languages, the block indent position is from the right edge of the block.\n\t// In LTR languages, the block indent position is from the left edge of the block.\n\tconst blockIndentPosition = rtl\n\t\t? rect.right - nestingLevel * NESTING_LEVEL_INDENTATION\n\t\t: rect.left + nestingLevel * NESTING_LEVEL_INDENTATION;\n\n\tconst distanceBetweenPointAndBlockIndentPosition = rtl\n\t\t? blockIndentPosition - point.x\n\t\t: point.x - blockIndentPosition;\n\n\tconst desiredParentLevel = Math.round(\n\t\tdistanceBetweenPointAndBlockIndentPosition / NESTING_LEVEL_INDENTATION\n\t);\n\n\treturn Math.abs( desiredParentLevel );\n}\n\n/**\n * Returns an array of the parent blocks of the block the user is dropping to.\n *\n * @param {WPListViewDropZoneBlock} candidateBlockData The block the user is dropping to.\n * @param {WPListViewDropZoneBlocks} blocksData Data about the blocks in list view.\n * @return {WPListViewDropZoneBlocks} An array of block parents, including the block the user is dropping to.\n */\nfunction getCandidateBlockParents( candidateBlockData, blocksData ) {\n\tconst candidateBlockParents = [];\n\tlet currentBlockData = candidateBlockData;\n\n\twhile ( currentBlockData ) {\n\t\tcandidateBlockParents.push( { ...currentBlockData } );\n\t\tcurrentBlockData = blocksData.find(\n\t\t\t( blockData ) =>\n\t\t\t\tblockData.clientId === currentBlockData.rootClientId\n\t\t);\n\t}\n\n\treturn candidateBlockParents;\n}\n\n/**\n * Given a list of blocks data and a block index, return the next non-dragged\n * block. This is used to determine the block that the user is dropping to,\n * while ignoring the dragged block.\n *\n * @param {WPListViewDropZoneBlocks} blocksData Data about the blocks in list view.\n * @param {number} index The index to begin searching from.\n * @return {WPListViewDropZoneBlock | undefined} The next non-dragged block.\n */\nfunction getNextNonDraggedBlock( blocksData, index ) {\n\tconst nextBlockData = blocksData[ index + 1 ];\n\tif ( nextBlockData && nextBlockData.isDraggedBlock ) {\n\t\treturn getNextNonDraggedBlock( blocksData, index + 1 );\n\t}\n\n\treturn nextBlockData;\n}\n\n/**\n * Determines whether the user positioning the dragged block to nest as an\n * inner block.\n *\n * Determined based on nesting level indentation of the current block, plus\n * the indentation of the next level of nesting. The vertical position of the\n * cursor must also be within the block.\n *\n * @param {WPPoint} point The point representing the cursor position when dragging.\n * @param {DOMRect} rect The rectangle.\n * @param {number} nestingLevel The nesting level of the block.\n * @param {boolean} rtl Whether the editor is in RTL mode.\n */\nfunction isNestingGesture( point, rect, nestingLevel = 1, rtl = false ) {\n\tconst blockIndentPosition = rtl\n\t\t? rect.right - nestingLevel * NESTING_LEVEL_INDENTATION\n\t\t: rect.left + nestingLevel * NESTING_LEVEL_INDENTATION;\n\n\tconst isNestingHorizontalGesture = rtl\n\t\t? point.x < blockIndentPosition - NESTING_LEVEL_INDENTATION\n\t\t: point.x > blockIndentPosition + NESTING_LEVEL_INDENTATION;\n\n\treturn isNestingHorizontalGesture && point.y < rect.bottom;\n}\n\n// Block navigation is always a vertical list, so only allow dropping\n// to the above or below a block.\nconst ALLOWED_DROP_EDGES = [ 'top', 'bottom' ];\n\n/**\n * Given blocks data and the cursor position, compute the drop target.\n *\n * @param {WPListViewDropZoneBlocks} blocksData Data about the blocks in list view.\n * @param {WPPoint} position The point representing the cursor position when dragging.\n * @param {boolean} rtl Whether the editor is in RTL mode.\n *\n * @return {WPListViewDropZoneTarget | undefined} An object containing data about the drop target.\n */\nexport function getListViewDropTarget( blocksData, position, rtl = false ) {\n\tlet candidateEdge;\n\tlet candidateBlockData;\n\tlet candidateDistance;\n\tlet candidateRect;\n\tlet candidateBlockIndex;\n\n\tfor ( let i = 0; i < blocksData.length; i++ ) {\n\t\tconst blockData = blocksData[ i ];\n\t\tif ( blockData.isDraggedBlock ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst rect = blockData.element.getBoundingClientRect();\n\t\tconst [ distance, edge ] = getDistanceToNearestEdge(\n\t\t\tposition,\n\t\t\trect,\n\t\t\tALLOWED_DROP_EDGES\n\t\t);\n\n\t\tconst isCursorWithinBlock = isPointContainedByRect( position, rect );\n\t\tif (\n\t\t\tcandidateDistance === undefined ||\n\t\t\tdistance < candidateDistance ||\n\t\t\tisCursorWithinBlock\n\t\t) {\n\t\t\tcandidateDistance = distance;\n\n\t\t\tconst index = blocksData.indexOf( blockData );\n\t\t\tconst previousBlockData = blocksData[ index - 1 ];\n\n\t\t\t// If dragging near the top of a block and the preceding block\n\t\t\t// is at the same level, use the preceding block as the candidate\n\t\t\t// instead, as later it makes determining a nesting drop easier.\n\t\t\tif (\n\t\t\t\tedge === 'top' &&\n\t\t\t\tpreviousBlockData &&\n\t\t\t\tpreviousBlockData.rootClientId === blockData.rootClientId &&\n\t\t\t\t! previousBlockData.isDraggedBlock\n\t\t\t) {\n\t\t\t\tcandidateBlockData = previousBlockData;\n\t\t\t\tcandidateEdge = 'bottom';\n\t\t\t\tcandidateRect =\n\t\t\t\t\tpreviousBlockData.element.getBoundingClientRect();\n\t\t\t\tcandidateBlockIndex = index - 1;\n\t\t\t} else {\n\t\t\t\tcandidateBlockData = blockData;\n\t\t\t\tcandidateEdge = edge;\n\t\t\t\tcandidateRect = rect;\n\t\t\t\tcandidateBlockIndex = index;\n\t\t\t}\n\n\t\t\t// If the mouse position is within the block, break early\n\t\t\t// as the user would intend to drop either before or after\n\t\t\t// this block.\n\t\t\t//\n\t\t\t// This solves an issue where some rows in the list view\n\t\t\t// tree overlap slightly due to sub-pixel rendering.\n\t\t\tif ( isCursorWithinBlock ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( ! candidateBlockData ) {\n\t\treturn;\n\t}\n\n\tconst candidateBlockParents = getCandidateBlockParents(\n\t\tcandidateBlockData,\n\t\tblocksData\n\t);\n\n\tconst isDraggingBelow = candidateEdge === 'bottom';\n\n\t// If the user is dragging towards the bottom of the block check whether\n\t// they might be trying to nest the block as a child.\n\t// If the block already has inner blocks, and is expanded, this should be treated\n\t// as nesting since the next block in the tree will be the first child.\n\t// However, if the block is collapsed, dragging beneath the block should\n\t// still be allowed, as the next visible block in the tree will be a sibling.\n\tif (\n\t\tisDraggingBelow &&\n\t\tcandidateBlockData.canInsertDraggedBlocksAsChild &&\n\t\t( ( candidateBlockData.innerBlockCount > 0 &&\n\t\t\tcandidateBlockData.isExpanded ) ||\n\t\t\tisNestingGesture(\n\t\t\t\tposition,\n\t\t\t\tcandidateRect,\n\t\t\t\tcandidateBlockParents.length,\n\t\t\t\trtl\n\t\t\t) )\n\t) {\n\t\t// If the block is expanded, insert the block as the first child.\n\t\t// Otherwise, for collapsed blocks, insert the block as the last child.\n\t\tconst newBlockIndex = candidateBlockData.isExpanded\n\t\t\t? 0\n\t\t\t: candidateBlockData.innerBlockCount || 0;\n\n\t\treturn {\n\t\t\trootClientId: candidateBlockData.clientId,\n\t\t\tclientId: candidateBlockData.clientId,\n\t\t\tblockIndex: newBlockIndex,\n\t\t\tdropPosition: 'inside',\n\t\t};\n\t}\n\n\t// If the user is dragging towards the bottom of the block check whether\n\t// they might be trying to move the block to be at a parent level.\n\tif (\n\t\tisDraggingBelow &&\n\t\tcandidateBlockData.rootClientId &&\n\t\tisUpGesture(\n\t\t\tposition,\n\t\t\tcandidateRect,\n\t\t\tcandidateBlockParents.length,\n\t\t\trtl\n\t\t)\n\t) {\n\t\tconst nextBlock = getNextNonDraggedBlock(\n\t\t\tblocksData,\n\t\t\tcandidateBlockIndex\n\t\t);\n\t\tconst currentLevel = candidateBlockData.nestingLevel;\n\t\tconst nextLevel = nextBlock ? nextBlock.nestingLevel : 1;\n\n\t\tif ( currentLevel && nextLevel ) {\n\t\t\t// Determine the desired relative level of the block to be dropped.\n\t\t\tconst desiredRelativeLevel = getDesiredRelativeParentLevel(\n\t\t\t\tposition,\n\t\t\t\tcandidateRect,\n\t\t\t\tcandidateBlockParents.length,\n\t\t\t\trtl\n\t\t\t);\n\n\t\t\tconst targetParentIndex = Math.max(\n\t\t\t\tMath.min( desiredRelativeLevel, currentLevel - nextLevel ),\n\t\t\t\t0\n\t\t\t);\n\n\t\t\tif ( candidateBlockParents[ targetParentIndex ] ) {\n\t\t\t\t// Default to the block index of the candidate block.\n\t\t\t\tlet newBlockIndex = candidateBlockData.blockIndex;\n\n\t\t\t\t// If the next block is at the same level, use that as the default\n\t\t\t\t// block index. This ensures that the block is dropped in the correct\n\t\t\t\t// position when dragging to the bottom of a block.\n\t\t\t\tif (\n\t\t\t\t\tcandidateBlockParents[ targetParentIndex ].nestingLevel ===\n\t\t\t\t\tnextBlock?.nestingLevel\n\t\t\t\t) {\n\t\t\t\t\tnewBlockIndex = nextBlock?.blockIndex;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, search from the current block index back\n\t\t\t\t\t// to find the last block index within the same target parent.\n\t\t\t\t\tfor ( let i = candidateBlockIndex; i >= 0; i-- ) {\n\t\t\t\t\t\tconst blockData = blocksData[ i ];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tblockData.rootClientId ===\n\t\t\t\t\t\t\tcandidateBlockParents[ targetParentIndex ]\n\t\t\t\t\t\t\t\t.rootClientId\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tnewBlockIndex = blockData.blockIndex + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\trootClientId:\n\t\t\t\t\t\tcandidateBlockParents[ targetParentIndex ].rootClientId,\n\t\t\t\t\tclientId: candidateBlockData.clientId,\n\t\t\t\t\tblockIndex: newBlockIndex,\n\t\t\t\t\tdropPosition: candidateEdge,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\t// If dropping as a sibling, but block cannot be inserted in\n\t// this context, return early.\n\tif ( ! candidateBlockData.canInsertDraggedBlocksAsSibling ) {\n\t\treturn;\n\t}\n\n\tconst offset = isDraggingBelow ? 1 : 0;\n\treturn {\n\t\trootClientId: candidateBlockData.rootClientId,\n\t\tclientId: candidateBlockData.clientId,\n\t\tblockIndex: candidateBlockData.blockIndex + offset,\n\t\tdropPosition: candidateEdge,\n\t};\n}\n\n// Throttle options need to be defined outside of the hook to avoid\n// re-creating the object on every render. This is due to a limitation\n// of the `useThrottle` hook, where the options object is included\n// in the dependency array for memoization.\nconst EXPAND_THROTTLE_OPTIONS = {\n\tleading: false, // Don't call the function immediately on the first call.\n\ttrailing: true, // Do call the function on the last call.\n};\n\n/**\n * A react hook for implementing a drop zone in list view.\n *\n * @param {Object} props Named parameters.\n * @param {?HTMLElement} [props.dropZoneElement] Optional element to be used as the drop zone.\n * @param {Object} [props.expandedState] The expanded state of the blocks in the list view.\n * @param {Function} [props.setExpandedState] Function to set the expanded state of a list of block clientIds.\n *\n * @return {WPListViewDropZoneTarget} The drop target.\n */\nexport default function useListViewDropZone( {\n\tdropZoneElement,\n\texpandedState,\n\tsetExpandedState,\n} ) {\n\tconst {\n\t\tgetBlockRootClientId,\n\t\tgetBlockIndex,\n\t\tgetBlockCount,\n\t\tgetDraggedBlockClientIds,\n\t\tcanInsertBlocks,\n\t} = useSelect( blockEditorStore );\n\tconst [ target, setTarget ] = useState();\n\tconst { rootClientId: targetRootClientId, blockIndex: targetBlockIndex } =\n\t\ttarget || {};\n\n\tconst onBlockDrop = useOnBlockDrop( targetRootClientId, targetBlockIndex );\n\n\tconst rtl = isRTL();\n\n\tconst previousRootClientId = usePrevious( targetRootClientId );\n\n\tconst maybeExpandBlock = useCallback(\n\t\t( _expandedState, _target ) => {\n\t\t\t// If the user is attempting to drop a block inside a collapsed block,\n\t\t\t// that is, using a nesting gesture flagged by 'inside' dropPosition,\n\t\t\t// expand the block within the list view, if it isn't already.\n\t\t\tconst { rootClientId } = _target || {};\n\t\t\tif ( ! rootClientId ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t_target?.dropPosition === 'inside' &&\n\t\t\t\t! _expandedState[ rootClientId ]\n\t\t\t) {\n\t\t\t\tsetExpandedState( {\n\t\t\t\t\ttype: 'expand',\n\t\t\t\t\tclientIds: [ rootClientId ],\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ setExpandedState ]\n\t);\n\n\t// Throttle the maybeExpandBlock function to avoid expanding the block\n\t// too quickly when the user is dragging over the block. This is to\n\t// avoid expanding the block when the user is just passing over it.\n\tconst throttledMaybeExpandBlock = useThrottle(\n\t\tmaybeExpandBlock,\n\t\t500,\n\t\tEXPAND_THROTTLE_OPTIONS\n\t);\n\n\tuseEffect( () => {\n\t\tif (\n\t\t\ttarget?.dropPosition !== 'inside' ||\n\t\t\tpreviousRootClientId !== target?.rootClientId\n\t\t) {\n\t\t\tthrottledMaybeExpandBlock.cancel();\n\t\t\treturn;\n\t\t}\n\t\tthrottledMaybeExpandBlock( expandedState, target );\n\t}, [\n\t\texpandedState,\n\t\tpreviousRootClientId,\n\t\ttarget,\n\t\tthrottledMaybeExpandBlock,\n\t] );\n\n\tconst draggedBlockClientIds = getDraggedBlockClientIds();\n\tconst throttled = useThrottle(\n\t\tuseCallback(\n\t\t\t( event, currentTarget ) => {\n\t\t\t\tconst position = { x: event.clientX, y: event.clientY };\n\t\t\t\tconst isBlockDrag = !! draggedBlockClientIds?.length;\n\n\t\t\t\tconst blockElements = Array.from(\n\t\t\t\t\tcurrentTarget.querySelectorAll( '[data-block]' )\n\t\t\t\t);\n\n\t\t\t\tconst blocksData = blockElements.map( ( blockElement ) => {\n\t\t\t\t\tconst clientId = blockElement.dataset.block;\n\t\t\t\t\tconst isExpanded = blockElement.dataset.expanded === 'true';\n\t\t\t\t\tconst isDraggedBlock =\n\t\t\t\t\t\tblockElement.classList.contains( 'is-dragging' );\n\n\t\t\t\t\t// Get nesting level from `aria-level` attribute because Firefox does not support `element.ariaLevel`.\n\t\t\t\t\tconst nestingLevel = parseInt(\n\t\t\t\t\t\tblockElement.getAttribute( 'aria-level' ),\n\t\t\t\t\t\t10\n\t\t\t\t\t);\n\t\t\t\t\tconst rootClientId = getBlockRootClientId( clientId );\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\tisExpanded,\n\t\t\t\t\t\trootClientId,\n\t\t\t\t\t\tblockIndex: getBlockIndex( clientId ),\n\t\t\t\t\t\telement: blockElement,\n\t\t\t\t\t\tnestingLevel: nestingLevel || undefined,\n\t\t\t\t\t\tisDraggedBlock: isBlockDrag ? isDraggedBlock : false,\n\t\t\t\t\t\tinnerBlockCount: getBlockCount( clientId ),\n\t\t\t\t\t\tcanInsertDraggedBlocksAsSibling: isBlockDrag\n\t\t\t\t\t\t\t? canInsertBlocks(\n\t\t\t\t\t\t\t\t\tdraggedBlockClientIds,\n\t\t\t\t\t\t\t\t\trootClientId\n\t\t\t\t\t\t\t )\n\t\t\t\t\t\t\t: true,\n\t\t\t\t\t\tcanInsertDraggedBlocksAsChild: isBlockDrag\n\t\t\t\t\t\t\t? canInsertBlocks( draggedBlockClientIds, clientId )\n\t\t\t\t\t\t\t: true,\n\t\t\t\t\t};\n\t\t\t\t} );\n\n\t\t\t\tconst newTarget = getListViewDropTarget(\n\t\t\t\t\tblocksData,\n\t\t\t\t\tposition,\n\t\t\t\t\trtl\n\t\t\t\t);\n\n\t\t\t\tif ( newTarget ) {\n\t\t\t\t\tsetTarget( newTarget );\n\t\t\t\t}\n\t\t\t},\n\t\t\t[\n\t\t\t\tcanInsertBlocks,\n\t\t\t\tdraggedBlockClientIds,\n\t\t\t\tgetBlockCount,\n\t\t\t\tgetBlockIndex,\n\t\t\t\tgetBlockRootClientId,\n\t\t\t\trtl,\n\t\t\t]\n\t\t),\n\t\t50\n\t);\n\n\tconst ref = useDropZone( {\n\t\tdropZoneElement,\n\t\tonDrop( event ) {\n\t\t\tthrottled.cancel();\n\t\t\tif ( target ) {\n\t\t\t\tonBlockDrop( event );\n\t\t\t}\n\t\t\t// Use `undefined` value to indicate that the drag has concluded.\n\t\t\t// This allows styling rules that are active only when a user is\n\t\t\t// dragging to be removed.\n\t\t\tsetTarget( undefined );\n\t\t},\n\t\tonDragLeave() {\n\t\t\tthrottled.cancel();\n\t\t\t// Use `null` value to indicate that the drop target is not valid,\n\t\t\t// but that the drag is still active. This allows for styling rules\n\t\t\t// that are active only when a user drags outside of the list view.\n\t\t\tsetTarget( null );\n\t\t},\n\t\tonDragOver( event ) {\n\t\t\t// `currentTarget` is only available while the event is being\n\t\t\t// handled, so get it now and pass it to the thottled function.\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget\n\t\t\tthrottled( event, event.currentTarget );\n\t\t},\n\t\tonDragEnd() {\n\t\t\tthrottled.cancel();\n\t\t\t// Use `undefined` value to indicate that the drag has concluded.\n\t\t\t// This allows styling rules that are active only when a user is\n\t\t\t// dragging to be removed.\n\t\t\tsetTarget( undefined );\n\t\t},\n\t} );\n\n\treturn { ref, target };\n}\n"], "mappings": "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", "names": [] }