-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disallow drag from Nav list view into block canvas #47615
Changes from all commits
e7c0986
fdc7599
1e2b377
3c242af
959fcc0
c29ceb1
f79b308
f37c4eb
eee42f2
f5ac858
4d3c529
f4154ef
028a8b5
6e1991d
acdf784
5bc777c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Block Draggable | ||
|
||
Block Draggable is a block-specific implementation of a `<Draggable>` which defines behaviour for dragged elements in a block editor context, including (but not limited to): | ||
|
||
- determining whether the given block(s) can be moved. | ||
- setting information on the [`transferData` object](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer). | ||
- (optionally) setting the `target` dropzones with which this draggable is compatible. | ||
- displaying a suitable "chip" during the drag operation. | ||
- managing scrolling during the drag. | ||
|
||
Note that the majority of the behaviour is delegated to `Draggable` from `@wordpress/components`. | ||
|
||
## Usage | ||
|
||
```js | ||
import { BlockDraggable } from '@wordpress/block-editor'; | ||
|
||
function MyComponent() { | ||
return <BlockDraggable clientIds={ clientIds } />; | ||
} | ||
``` | ||
|
||
## Props | ||
|
||
### clientIds | ||
|
||
- Type: `Array` | ||
- Required: Yes | ||
|
||
Blocks IDs of candidates to be dragged. | ||
|
||
### targets | ||
|
||
- Type: `Array[string]` | ||
- Required: No | ||
|
||
A list of dropzone names that this draggable considers valid drop targets. If provided then it will only be possible to drop the draggable in a _named_ dropzone that is included in the list. | ||
|
||
### `children` | ||
|
||
- Type: Function | ||
- Required: No | ||
|
||
Component children as a function. The function receives the following arguments: | ||
|
||
- `draggable` - whether or not the block(s) are deemed to be draggable. | ||
- `onDragStart` (optional) - an event handler to be passed as the `onDragStart` event prop of any child node. | ||
- `onDragEnd` - an event handler to be passed as the `onDragEnd` event prop of any child node. | ||
|
||
See [`Draggable`](./packages/components/src/draggable/README.md) for more information. | ||
|
||
### cloneClassname | ||
|
||
- Type: `string` | ||
- Required: No | ||
|
||
A className to be passed to the clone of the draggable. | ||
|
||
### `onDragStart` | ||
|
||
- Type: Function | ||
- Required: No | ||
|
||
A function to be called on the `ondragstart` event. | ||
|
||
### `onDragEnd` | ||
|
||
- Type: Function | ||
- Required: No | ||
|
||
A function to be called on the `ondragend` event. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import { | |
} from '../../utils/math'; | ||
import useOnBlockDrop from '../use-on-block-drop'; | ||
import { store as blockEditorStore } from '../../store'; | ||
import { unlock } from '../../experiments'; | ||
|
||
/** @typedef {import('../../utils/math').WPPoint} WPPoint */ | ||
|
||
|
@@ -179,26 +180,39 @@ function getListViewDropTarget( blocksData, position ) { | |
/** | ||
* A react hook for implementing a drop zone in list view. | ||
* | ||
* @param {string} dropZoneName the name of the drop zone. | ||
* @return {WPListViewDropZoneTarget} The drop target. | ||
*/ | ||
export default function useListViewDropZone() { | ||
export default function useListViewDropZone( dropZoneName ) { | ||
const { | ||
getBlockRootClientId, | ||
getBlockIndex, | ||
getBlockCount, | ||
getDraggedBlockClientIds, | ||
canInsertBlocks, | ||
} = useSelect( blockEditorStore ); | ||
getDraggedBlocksTargets, | ||
} = unlock( useSelect( blockEditorStore ) ); | ||
const [ target, setTarget ] = useState(); | ||
const { rootClientId: targetRootClientId, blockIndex: targetBlockIndex } = | ||
target || {}; | ||
|
||
const onBlockDrop = useOnBlockDrop( targetRootClientId, targetBlockIndex ); | ||
const onBlockDrop = useOnBlockDrop( targetRootClientId, targetBlockIndex, { | ||
dropZoneName, | ||
} ); | ||
|
||
const draggedBlockClientIds = getDraggedBlockClientIds(); | ||
const throttled = useThrottle( | ||
useCallback( | ||
( event, currentTarget ) => { | ||
const draggedBlocksTargets = getDraggedBlocksTargets(); | ||
|
||
if ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this check be in |
||
draggedBlocksTargets?.length && | ||
! draggedBlocksTargets.includes( dropZoneName ) | ||
) { | ||
// If drag targets are defined and the drop zone doesn't match, don't allow dropping. | ||
return; | ||
} | ||
const position = { x: event.clientX, y: event.clientY }; | ||
const isBlockDrag = !! draggedBlockClientIds?.length; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,7 +92,8 @@ function OffCanvasEditor( | |
|
||
const [ expandedState, setExpandedState ] = useReducer( expanded, {} ); | ||
|
||
const { ref: dropZoneRef, target: blockDropTarget } = useListViewDropZone(); | ||
const { ref: dropZoneRef, target: blockDropTarget } = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make |
||
useListViewDropZone( 'offcanvas' ); | ||
const elementRef = useRef(); | ||
const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] ); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,12 @@ | ||
# useBlockDropZone | ||
|
||
`useBlockDropZone` is a React hook used to specify a drop zone for a block. This drop zone supports the drag and drop of media into the editor. | ||
|
||
## Props | ||
|
||
### dropZoneName | ||
|
||
- Type: `string` | ||
- Required: No | ||
|
||
An optional name for the dropzone. Note that if a name is provided then only `<BlockDraggable>`s that specify this name in their `targets` prop will be able to be dropped. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ import { | |
isPointContainedByRect, | ||
} from '../../utils/math'; | ||
import { store as blockEditorStore } from '../../store'; | ||
import { unlock } from '../../experiments'; | ||
|
||
/** @typedef {import('../../utils/math').WPPoint} WPPoint */ | ||
/** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */ | ||
|
@@ -141,6 +142,7 @@ export default function useBlockDropZone( { | |
// values returned by the `getRootBlockClientId` selector, which also uses | ||
// an empty string to represent top-level blocks. | ||
rootClientId: targetRootClientId = '', | ||
dropZoneName, | ||
} = {} ) { | ||
const [ dropTarget, setDropTarget ] = useState( { | ||
index: null, | ||
|
@@ -166,17 +168,33 @@ export default function useBlockDropZone( { | |
[ targetRootClientId ] | ||
); | ||
|
||
const { getBlockListSettings, getBlocks, getBlockIndex } = | ||
useSelect( blockEditorStore ); | ||
const { | ||
getBlockListSettings, | ||
getBlocks, | ||
getBlockIndex, | ||
getDraggedBlocksTargets, | ||
} = unlock( useSelect( blockEditorStore ) ); | ||
|
||
const { showInsertionPoint, hideInsertionPoint } = | ||
useDispatch( blockEditorStore ); | ||
|
||
const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, { | ||
operation: dropTarget.operation, | ||
dropZoneName, | ||
} ); | ||
const throttled = useThrottle( | ||
useCallback( | ||
( event, ownerDocument ) => { | ||
const draggedBlocksTargets = getDraggedBlocksTargets(); | ||
|
||
if ( | ||
draggedBlocksTargets?.length && | ||
! draggedBlocksTargets.includes( dropZoneName ) | ||
) { | ||
// If drag targets are defined and the drop zone doesn't match, don't allow dropping. | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exiting early here means that no drop zone UI affordances are displayed when dragging. For example the blue lines that appear when dragging over a drop zone will not show. |
||
} | ||
|
||
const blocks = getBlocks( targetRootClientId ); | ||
|
||
// The block list is empty, don't show the insertion point but still allow dropping. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a bit confusing the difference between the
target
variable this hook returns and the target finding done later.