Skip to content
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
wants to merge 1 commit into from

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Nov 17, 2017

Description

WIP, only works for the paragraph block.

This is an attempt to add inspector controls when there are multiple blocks selected of the same type. This requires us to move away the inspector rendering to a separate component so that it can be reused (PR does not include change for the edit component yet). I realise some quite like that everything is rendered in one big edit component, but I don't see how we could achieve this without splitting it up. @aduth @youknowriad @mtias What do you think about this?

This only adds the controls to the inspector. The same should then be done for the toolbar on the top.


const attributeArray = multiSelectedBlocks.map( ( block ) => block.attributes );
const attributeKeys = uniq( flatten( attributeArray.map( keys ) ) );
const attributes = attributeKeys.reduce( ( acc, key ) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attempted to use lodash's intersection or similar, but not quite sure how to get it to work.

@codecov
Copy link

codecov bot commented Nov 17, 2017

Codecov Report

Merging #3535 into master will increase coverage by 0.06%.
The diff coverage is 3.33%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3535      +/-   ##
==========================================
+ Coverage    34.9%   34.97%   +0.06%     
==========================================
  Files         263      263              
  Lines        6727     6771      +44     
  Branches     1227     1235       +8     
==========================================
+ Hits         2348     2368      +20     
- Misses       3694     3714      +20     
- Partials      685      689       +4
Impacted Files Coverage Δ
blocks/library/paragraph/index.js 26.92% <0%> (-2.25%) ⬇️
editor/components/block-inspector/index.js 3.57% <4.34%> (-10.72%) ⬇️
editor/store.js 81.81% <0%> (-1.52%) ⬇️
blocks/api/registration.js 100% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b87f59c...8b6d3ec. Read the comment docs.

@ellatrix
Copy link
Member Author

Any thoughts on this at all? :)

@@ -93,9 +92,55 @@ registerBlockType( 'core/paragraph', {
}
},

inspector( { attributes, setAttributes } ) {
Copy link
Contributor

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?

Copy link
Member Author

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? :)

Copy link
Contributor

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 and BlockInspector but we do have between edit and BlockControls (in the audio or block 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.

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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 an editing local state using a button toolbar. And this local state changes the UI of the block.

Copy link
Member

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 and toolbar 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:

<BlockControls>
    { this.toolbar( { state, attributes, setAttributes } ) }
</BlockControls>
<InspectorControls>
    { this.inspector( { state, attributes, setAttributes } ) }
</InspectorControls> 

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).

@aduth
Copy link
Member

aduth commented Dec 11, 2017

I think this does identify an issue with how we're treating edit rendering as a single component tree, since this only really works when inspector rendering is one-to-one, and we don't need to externally isolate just the inspector or toolbar behaviors. While that can work well for operating on single blocks, it doesn't work so well for sharing rendering controls across multiple selected blocks.

There's a few reasons I like keeping the slotted elements within edit is that:

  • It keeps the block API nicely segmented between "edit", "save", and the rest "meta". Splitting out a separate inspector property starts to muddy the distinction, since it's still properly relevant to the editing behaviors.
  • It forces the block implementer to be aware of the state of their block in the rendering behavior in deciding to render controls only when focused
    • This could be argued as a downside
  • It allows render logic / assigned variables scope to be shared between the form, inspector, and toolbar elements

It's quite late to be making these breaking changes to the API, but if we were, I'd suggest at least:

  • Be consistent across the board, not just isolating inspector controls, but also toolbar
  • Maybe doing so in a way that still preserves relationship between editing-relevant rendering, e.g. maybe defining edit as an object of form, inspector, toolbar? Optionally so?

If we were to build support for these to be separated, would we then handle the focus conditional rendering on behalf of the block implementer?

Noting that I've had similar issues with edit's slot / fill behavior in interoperability attempts.

@ellatrix
Copy link
Member Author

#3483 also adds an interesting case where the controls would need the node of the block...

@ellatrix
Copy link
Member Author

Trying the other approach again.

@ellatrix ellatrix added [Feature] Block API API that allows to express the block paradigm. Framework Issues related to broader framework topics, especially as it relates to javascript [Feature] Inspector Controls The interface showing block settings and the controls available for each block labels Dec 14, 2017
@ellatrix
Copy link
Member Author

If we want to keep all components in one edit function, it seems we'll have to do something like this to change the attributes and setAttributes function for more than one block. Based on the id, InspectorControls can also decide when to display something, the block implementor no longer needs to worry about focus there. @aduth @youknowriad How does this sound? I'm not sure what alternatives we have...

return [
	<InspectorControls key="inspector" id={ id }>
		{ ( { attributes, setAttributes } ) => [
			<BlockDescription>
				<p>{ __( 'Text. Great things start here.' ) }</p>
			</BlockDescription>,
		] }
	</InspectorControls>,
];

@aduth
Copy link
Member

aduth commented Dec 18, 2017

Would it be too much magic for the ID to be "injected" via React context so the block implementer doesn't need to concern themselves with it? Thinking each BlockEdit could provide its block ID as context which InspectorControls reads from.

The function as child makes sense to me, but I think could be disorienting for block implementers. Also suffers from variable shadowing.

@gziolo
Copy link
Member

gziolo commented Aug 10, 2018

Should we also close this one in favor of #7635?

@catehstn
Copy link

catehstn commented Nov 6, 2018

Closing in favour of #7635.

@catehstn catehstn closed this Nov 6, 2018
@youknowriad youknowriad deleted the try/multi-inspector branch November 6, 2018 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Inspector Controls The interface showing block settings and the controls available for each block Framework Issues related to broader framework topics, especially as it relates to javascript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants