@wordpress/block-library
Version:
Block library for the WordPress editor.
116 lines (101 loc) • 3.66 kB
JavaScript
/**
* WordPress dependencies
*/
import { store as blockEditorStore } from '@wordpress/block-editor';
import { useDispatch } from '@wordpress/data';
/**
* Internal dependencies
*/
import {
LinkUI,
updateAttributes,
useEntityBinding,
} from '../../navigation-link/shared';
const BLOCKS_WITH_LINK_UI_SUPPORT = [
'core/navigation-link',
'core/navigation-submenu',
];
export function NavigationLinkUI( { block, insertedBlock, setInsertedBlock } ) {
const { updateBlockAttributes, removeBlock } =
useDispatch( blockEditorStore );
const supportsLinkControls = BLOCKS_WITH_LINK_UI_SUPPORT?.includes(
insertedBlock?.name
);
const blockWasJustInserted = insertedBlock?.clientId === block.clientId;
const showLinkControls = supportsLinkControls && blockWasJustInserted;
// Get binding utilities for the inserted block
const { createBinding, clearBinding } = useEntityBinding( {
clientId: insertedBlock?.clientId,
attributes: insertedBlock?.attributes || {},
} );
if ( ! showLinkControls ) {
return null;
}
/**
* Cleanup function for auto-inserted Navigation Link blocks.
*
* Removes the block if it has no URL and clears the inserted block state.
* This ensures consistent cleanup behavior across different contexts.
*/
const cleanupInsertedBlock = () => {
// Prevent automatic block selection when removing blocks in list view context
// This avoids focus stealing that would close the list view and switch to canvas
const shouldAutoSelectBlock = false;
// Follows the exact same pattern as Navigation Link block's onClose handler
// If there is no URL then remove the auto-inserted block to avoid empty blocks
if ( ! insertedBlock?.attributes?.url && insertedBlock?.clientId ) {
// Remove the block entirely to avoid poor UX
// This matches the Navigation Link block's behavior
removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
}
setInsertedBlock( null );
};
const setInsertedBlockAttributes =
( _insertedBlockClientId ) => ( _updatedAttributes ) => {
if ( ! _insertedBlockClientId ) {
return;
}
updateBlockAttributes( _insertedBlockClientId, _updatedAttributes );
};
// Wrapper function to clean up original block when a new block is selected
const handleSetInsertedBlock = ( newBlock ) => {
// Prevent automatic block selection when removing blocks in list view context
// This avoids focus stealing that would close the list view and switch to canvas
const shouldAutoSelectBlock = false;
// If we have an existing inserted block and a new block is being set,
// remove the original block to avoid duplicates
if ( insertedBlock?.clientId && newBlock ) {
removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
}
setInsertedBlock( newBlock );
};
return (
<LinkUI
clientId={ insertedBlock?.clientId }
link={ insertedBlock?.attributes }
onBlockInsert={ handleSetInsertedBlock }
onClose={ () => {
// Use cleanup function
cleanupInsertedBlock();
} }
onChange={ ( updatedValue ) => {
// updateAttributes determines the final state and returns metadata
const { isEntityLink, attributes: updatedAttributes } =
updateAttributes(
updatedValue,
setInsertedBlockAttributes( insertedBlock?.clientId ),
insertedBlock?.attributes
);
// Handle URL binding based on the final computed state
// Only create bindings for entity links (posts, pages, taxonomies)
// Never create bindings for custom links (manual URLs)
if ( isEntityLink ) {
createBinding( updatedAttributes );
} else {
clearBinding();
}
setInsertedBlock( null );
} }
/>
);
}