-
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
Display inserter popover in offcanvas UI #46013
Changes from all commits
0a42349
35267a3
ec85f0f
83afff5
c12cf1e
e317c95
c3345fc
61fe222
54ae328
23297bd
dc69e51
7bef737
53c2824
6c4fdce
63322ce
c66d778
450931e
0a71370
defbdba
983f4e2
383faa3
13eb8e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -260,6 +260,7 @@ export default compose( [ | |
allowedBlockType, | ||
directInsertBlock, | ||
onSelectOrClose, | ||
selectBlockOnInsert, | ||
} = ownProps; | ||
|
||
if ( ! hasSingleBlockType && ! directInsertBlock ) { | ||
|
@@ -370,10 +371,17 @@ export default compose( [ | |
blockToInsert = createBlock( allowedBlockType.name ); | ||
} | ||
|
||
insertBlock( blockToInsert, getInsertionIndex(), rootClientId ); | ||
insertBlock( | ||
blockToInsert, | ||
getInsertionIndex(), | ||
rootClientId, | ||
selectBlockOnInsert | ||
); | ||
|
||
if ( onSelectOrClose ) { | ||
onSelectOrClose(); | ||
onSelectOrClose( { | ||
insertedBlockId: blockToInsert?.clientId, | ||
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. This is what provides us with access to information about the block that was just inserted. |
||
} ); | ||
} | ||
|
||
const message = sprintf( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,19 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect } from '@wordpress/data'; | ||
import { forwardRef } from '@wordpress/element'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { forwardRef, useState } from '@wordpress/element'; | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as blockEditorStore } from '../../store'; | ||
import Inserter from '../inserter'; | ||
import { LinkUI } from './link-ui'; | ||
import { updateAttributes } from './update-attributes'; | ||
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. This holds a lot of complex logic so we must borrow it from the implementation in Navigation Link block |
||
|
||
export const Appender = forwardRef( ( props, ref ) => { | ||
const [ insertedBlock, setInsertedBlock ] = useState(); | ||
|
||
const { hideInserter, clientId } = useSelect( ( select ) => { | ||
const { | ||
getTemplateLock, | ||
|
@@ -27,18 +31,71 @@ export const Appender = forwardRef( ( props, ref ) => { | |
}; | ||
}, [] ); | ||
|
||
const { insertedBlockAttributes } = useSelect( | ||
( select ) => { | ||
const { getBlockAttributes } = select( blockEditorStore ); | ||
|
||
return { | ||
insertedBlockAttributes: getBlockAttributes( insertedBlock ), | ||
}; | ||
}, | ||
[ insertedBlock ] | ||
); | ||
Comment on lines
+34
to
+43
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. When the inserted block ID changes we need to refetch info about the block attributes so we can update the Link UI. |
||
|
||
const { updateBlockAttributes } = useDispatch( blockEditorStore ); | ||
|
||
const setAttributes = | ||
( insertedBlockClientId ) => ( _updatedAttributes ) => { | ||
updateBlockAttributes( insertedBlockClientId, _updatedAttributes ); | ||
}; | ||
Comment on lines
+47
to
+50
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. We provide a customised implementation of The function is curried in order that we can partially apply the blockID in advance. |
||
|
||
let maybeLinkUI; | ||
|
||
if ( insertedBlock ) { | ||
const link = { | ||
url: insertedBlockAttributes.url, | ||
opensInNewTab: insertedBlockAttributes.opensInNewTab, | ||
title: insertedBlockAttributes.label, | ||
}; | ||
maybeLinkUI = ( | ||
<LinkUI | ||
clientId={ insertedBlock } | ||
value={ link } | ||
linkAttributes={ { | ||
type: insertedBlockAttributes.type, | ||
url: insertedBlockAttributes.url, | ||
kind: insertedBlockAttributes.kind, | ||
} } | ||
onClose={ () => setInsertedBlock( null ) } | ||
hasCreateSuggestion={ false } | ||
onChange={ ( updatedValue ) => { | ||
updateAttributes( | ||
updatedValue, | ||
setAttributes( insertedBlock ), | ||
insertedBlockAttributes | ||
); | ||
setInsertedBlock( null ); | ||
} } | ||
/> | ||
); | ||
} | ||
|
||
if ( hideInserter ) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className="offcanvas-editor__appender"> | ||
{ maybeLinkUI } | ||
<Inserter | ||
ref={ ref } | ||
rootClientId={ clientId } | ||
position="bottom right" | ||
isAppender | ||
__experimentalIsQuick | ||
isAppender={ true } | ||
selectBlockOnInsert={ false } | ||
onSelectOrClose={ ( { insertedBlockId } ) => { | ||
setInsertedBlock( insertedBlockId ); | ||
} } | ||
{ ...props } | ||
/> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// Note: this file is copied directly from packages/block-library/src/navigation-link/link-ui.js | ||
|
||
/** | ||
scruffian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* WordPress dependencies | ||
*/ | ||
import { Popover, Button } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { switchToBlockType } from '@wordpress/blocks'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as blockEditorStore } from '../../store'; | ||
import LinkControl from '../link-control'; | ||
import BlockIcon from '../block-icon'; | ||
|
||
/** | ||
* Given the Link block's type attribute, return the query params to give to | ||
* /wp/v2/search. | ||
* | ||
* @param {string} type Link block's type attribute. | ||
* @param {string} kind Link block's entity of kind (post-type|taxonomy) | ||
* @return {{ type?: string, subtype?: string }} Search query params. | ||
*/ | ||
export function getSuggestionsQuery( type, kind ) { | ||
switch ( type ) { | ||
case 'post': | ||
case 'page': | ||
return { type: 'post', subtype: type }; | ||
case 'category': | ||
return { type: 'term', subtype: 'category' }; | ||
case 'tag': | ||
return { type: 'term', subtype: 'post_tag' }; | ||
case 'post_format': | ||
return { type: 'post-format' }; | ||
default: | ||
if ( kind === 'taxonomy' ) { | ||
return { type: 'term', subtype: type }; | ||
} | ||
if ( kind === 'post-type' ) { | ||
return { type: 'post', subtype: type }; | ||
} | ||
return {}; | ||
} | ||
} | ||
|
||
/** | ||
* Add transforms to Link Control | ||
* | ||
* @param {Object} props Component props. | ||
* @param {string} props.clientId Block client ID. | ||
*/ | ||
function LinkControlTransforms( { clientId } ) { | ||
const { getBlock, blockTransforms } = useSelect( | ||
( select ) => { | ||
const { | ||
getBlock: _getBlock, | ||
getBlockRootClientId, | ||
getBlockTransformItems, | ||
} = select( blockEditorStore ); | ||
|
||
return { | ||
getBlock: _getBlock, | ||
blockTransforms: getBlockTransformItems( | ||
_getBlock( clientId ), | ||
getBlockRootClientId( clientId ) | ||
), | ||
}; | ||
}, | ||
[ clientId ] | ||
); | ||
|
||
const { replaceBlock } = useDispatch( blockEditorStore ); | ||
|
||
const featuredBlocks = [ | ||
'core/site-logo', | ||
'core/social-links', | ||
'core/search', | ||
]; | ||
Comment on lines
+76
to
+80
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. I will track this in #46166 |
||
|
||
const transforms = blockTransforms.filter( ( item ) => { | ||
return featuredBlocks.includes( item?.name ); | ||
} ); | ||
|
||
if ( ! transforms?.length ) { | ||
return null; | ||
} | ||
|
||
if ( ! clientId ) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className="link-control-transform"> | ||
<h3 className="link-control-transform__subheading"> | ||
{ __( 'Transform' ) } | ||
</h3> | ||
<div className="link-control-transform__items"> | ||
{ transforms.map( ( item, index ) => { | ||
return ( | ||
<Button | ||
key={ `transform-${ index }` } | ||
onClick={ () => | ||
replaceBlock( | ||
clientId, | ||
switchToBlockType( | ||
getBlock( clientId ), | ||
item.name | ||
) | ||
) | ||
} | ||
className="link-control-transform__item" | ||
> | ||
<BlockIcon icon={ item.icon } /> | ||
{ item.title } | ||
</Button> | ||
); | ||
} ) } | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export function LinkUI( props ) { | ||
return ( | ||
<Popover | ||
placement="bottom" | ||
onClose={ props?.onClose } | ||
anchor={ props?.anchor } | ||
shift | ||
> | ||
<LinkControl | ||
hasTextControl | ||
hasRichPreviews | ||
className="wp-block-navigation-link__inline-link-input" | ||
value={ props?.value } | ||
showInitialSuggestions={ true } | ||
withCreateSuggestion={ props?.hasCreateSuggestion } | ||
noDirectEntry={ !! props?.linkAttributes?.type } | ||
noURLSuggestion={ !! props?.linkAttributes?.type } | ||
suggestionsQuery={ getSuggestionsQuery( | ||
props?.linkAttributes?.type, | ||
props?.linkAttributes?.kind | ||
) } | ||
onChange={ props.onChange } | ||
onRemove={ props.onRemove } | ||
renderControlBottom={ | ||
! props?.linkAttributes?.url | ||
? () => ( | ||
<LinkControlTransforms | ||
clientId={ props?.clientId } | ||
/> | ||
) | ||
: null | ||
} | ||
/> | ||
</Popover> | ||
); | ||
} |
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.
If
undefined
this will default totrue
meaning that the blocks will continue to be focused in other contexts.