-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Try multi-select inspector for same blocks #3535
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,28 +2,76 @@ | |
* External dependencies | ||
*/ | ||
import { connect } from 'react-redux'; | ||
import { uniq, keys, flatten } from 'lodash'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { Slot } from '@wordpress/components'; | ||
import { getBlockType } from '@wordpress/blocks'; | ||
|
||
/** | ||
* Internal Dependencies | ||
*/ | ||
import './style.scss'; | ||
import { getSelectedBlock, getSelectedBlockCount } from '../../selectors'; | ||
import { getSelectedBlock, getSelectedBlockCount, getMultiSelectedBlocks } from '../../selectors'; | ||
|
||
const BlockInspector = ( { selectedBlock, count } ) => { | ||
const BlockInspector = ( { selectedBlock, count, multiSelectedBlocks, onChange } ) => { | ||
if ( count > 1 ) { | ||
return <span className="editor-block-inspector__multi-blocks">{ __( 'Coming Soon' ) }</span>; | ||
const names = uniq( multiSelectedBlocks.map( ( { name } ) => name ) ); | ||
|
||
if ( names.length === 1 ) { | ||
const Inspector = getBlockType( names[ 0 ] ).inspector; | ||
|
||
if ( ! Inspector ) { | ||
return null; | ||
} | ||
|
||
const attributeArray = multiSelectedBlocks.map( ( block ) => block.attributes ); | ||
const attributeKeys = uniq( flatten( attributeArray.map( keys ) ) ); | ||
const attributes = attributeKeys.reduce( ( acc, key ) => { | ||
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. Attempted to use lodash's |
||
acc[ key ] = attributeArray.reduce( ( accu, attrs ) => { | ||
return accu === attrs[ key ] ? accu : undefined; | ||
}, attributeArray[ 0 ][ key ] ); | ||
return acc; | ||
}, {} ); | ||
|
||
const setAttributes = ( attrs ) => { | ||
multiSelectedBlocks.forEach( ( block ) => { | ||
onChange( block.uid, { | ||
...block.attributes, | ||
...attrs, | ||
} ); | ||
} ); | ||
}; | ||
|
||
return ( | ||
<Inspector | ||
attributes={ attributes } | ||
setAttributes={ setAttributes } | ||
/> | ||
); | ||
} | ||
|
||
return <span className="editor-block-inspector__multi-blocks">{ __( 'Various blocks' ) }</span>; | ||
} | ||
|
||
if ( ! selectedBlock ) { | ||
return <span className="editor-block-inspector__no-blocks">{ __( 'No block selected.' ) }</span>; | ||
} | ||
|
||
const Inspector = getBlockType( selectedBlock.name ).inspector; | ||
|
||
if ( Inspector ) { | ||
return ( | ||
<Inspector | ||
attributes={ selectedBlock.attributes } | ||
setAttributes={ ( attrs ) => onChange( selectedBlock.uid, attrs ) } | ||
/> | ||
); | ||
} | ||
|
||
return ( | ||
<Slot name="Inspector.Controls" /> | ||
); | ||
|
@@ -34,6 +82,16 @@ export default connect( | |
return { | ||
selectedBlock: getSelectedBlock( state ), | ||
count: getSelectedBlockCount( state ), | ||
multiSelectedBlocks: getMultiSelectedBlocks( state ), | ||
}; | ||
} | ||
}, | ||
( dispatch ) => ( { | ||
onChange( uid, attributes ) { | ||
dispatch( { | ||
type: 'UPDATE_BLOCK_ATTRIBUTES', | ||
uid, | ||
attributes, | ||
} ); | ||
}, | ||
} ), | ||
)( BlockInspector ); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
A little bit concerned about this. Some times we need local state to be shared beween the inspector, toolbar and the
edit
. If we separate this, it's not possible anymore.Do you think it's possible to add some magic to
InspectorControls
to detect if it's a multiselection and only render for one block only or something?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.
I tried it before, but can't remember it well, so I'll try it again. Could you give an example of local state, just for me to think about solutions for it? :)
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.
We don't have an exemple with shared local state between the
edit
andBlockInspector
but we do have betweenedit
andBlockControls
(in theaudio
orblock
blocks) and I believe these two are similar because in the exact same way we can display the same block toolbar in we multi-select similar blocks.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.
Exactly, what is done here for the inspector should then also be done for the toolbar. The problem with the edit function is that it makes use for
focus
. We'd need to remove that and figure out how to do that differently. I'll find the example with shared state and think about it.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.
@youknowriad Which block are you referring to with the local state? Is there anything that wouldn't be solvable with block attributes? Ideally, we should stick with those for state.
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.
@iseulde block attributes are "state" but they are "state" persisted in post_content or comments or meta. I don't know if it's a good idea to use them for "local state", we may end up serializing useless local state attributes in comments.
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.
For example, the
audio
block triggers anediting
local state using a button toolbar. And this local state changes the UI of the block.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.
I'm looking at this for the block toolbar (so if the selected blocks are of the same type, they get the toolbar and the controls apply changes to all selected blocks.)
It seems to me that having an
inspector
andtoolbar
function like this is very close to what we need, but as we need to share state between edit and BlockInspector/Toolbar, we need to reuse those functions to fill the appropriate slots.The render in edit would look like this:
The slots would get filled as normal, single block selection behaviour in unchanged.
Then, for example, in the block inspector where we currently have "Coming Soon", we'd get the block settings for the type of blocks we have selected, and call
settings.inspector
passing an appropriate state, attributes, and a setAttributes function that would set attributes across all selected blocks. The state and attributes could be reduced from the selected blocks, so that if all blocks had the same value for a control, it would get that value (for example, if all paragraphs were the same color, that color would be selected).