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: removing the multi-block type check to make __experimentalConvert more useful #22577

Merged
merged 4 commits into from
Jun 5, 2020

Conversation

gwwar
Copy link
Contributor

@gwwar gwwar commented May 22, 2020

Problem:

During block registration if we specify the following transform for a block other than "core/group" and make a selection of mixed block types say: (one paragraph, one image, and one heading) instead of (three paragraphs), we still have the option in the inserter to transform the selection to the block, however we will run into a JS error before the __experimentalConvert fires, due to the explicit check in

if (
! isContainerGroupBlock( name ) &&
isMultiBlock &&
! isBlockSelectionOfSameType( blocksArray )

or TL;DR no other block other than group can transform mixed block selections.

transforms: {
  from: [ {
    type: 'block',
    isMultiBlock: true,
    blocks: [ '*' ],
    __experimentalConvert( blocks ) {

As for why the check is here, it looks like we explicitly guard for this, but @getdave and others don't recall why this is the case. That being the case, we'll try removing this limitation but keep an eye out for any Group block regressions during testing.

Example Block Use Case:

Automattic/wp-calypso#42548

premium content

Testing Instructions

  • Verify that npm run test-unit -- --testPathPattern packages/blocks/src/api/test/factory.js is green, and new test cases make sense
  • Manually test for potential Group block regressions

TODO

  • Code cleanup around isBlockSelectionOfSameType and any other unneeded usages
  • Any needed e2e or unit test updates

@github-actions
Copy link

github-actions bot commented May 22, 2020

Size Change: +417 B (0%)

Total Size: 1.12 MB

Filename Size Change
build/block-editor/index.js 106 kB +287 B (0%)
build/block-editor/style-rtl.css 11.4 kB +2 B (0%)
build/block-editor/style.css 11.4 kB +2 B (0%)
build/block-library/editor-rtl.css 7.87 kB -4 B (0%)
build/block-library/editor.css 7.87 kB -3 B (0%)
build/block-library/index.js 127 kB +183 B (0%)
build/block-library/style-rtl.css 7.72 kB +31 B (0%)
build/block-library/style.css 7.72 kB +31 B (0%)
build/blocks/index.js 48.1 kB -37 B (0%)
build/components/index.js 193 kB -99 B (0%)
build/components/style-rtl.css 19.5 kB +15 B (0%)
build/components/style.css 19.5 kB +10 B (0%)
build/date/index.js 5.47 kB +1 B
build/edit-site/index.js 15 kB -1 B
build/editor/index.js 44.7 kB -1 B
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.62 kB 0 B
build/api-fetch/index.js 3.4 kB 0 B
build/autop/index.js 2.83 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 6.75 kB 0 B
build/block-directory/style-rtl.css 892 B 0 B
build/block-directory/style.css 892 B 0 B
build/block-library/theme-rtl.css 684 B 0 B
build/block-library/theme.css 686 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/compose/index.js 9.31 kB 0 B
build/core-data/index.js 11.4 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.46 kB 0 B
build/deprecated/index.js 771 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 3.17 kB 0 B
build/edit-navigation/index.js 8.25 kB 0 B
build/edit-navigation/style-rtl.css 918 B 0 B
build/edit-navigation/style.css 919 B 0 B
build/edit-post/index.js 302 kB 0 B
build/edit-post/style-rtl.css 5.43 kB 0 B
build/edit-post/style.css 5.43 kB 0 B
build/edit-site/style-rtl.css 2.96 kB 0 B
build/edit-site/style.css 2.96 kB 0 B
build/edit-widgets/index.js 8.83 kB 0 B
build/edit-widgets/style-rtl.css 2.4 kB 0 B
build/edit-widgets/style.css 2.4 kB 0 B
build/editor/editor-styles-rtl.css 425 B 0 B
build/editor/editor-styles.css 428 B 0 B
build/editor/style-rtl.css 4.26 kB 0 B
build/editor/style.css 4.27 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.72 kB 0 B
build/format-library/style-rtl.css 502 B 0 B
build/format-library/style.css 502 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 711 B 0 B
build/keyboard-shortcuts/index.js 2.52 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.12 kB 0 B
build/list-reusable-blocks/style-rtl.css 226 B 0 B
build/list-reusable-blocks/style.css 226 B 0 B
build/media-utils/index.js 5.3 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 616 B 0 B
build/nux/style.css 613 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 14.8 kB 0 B
build/server-side-render/index.js 2.68 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.28 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

! isBlockSelectionOfSameType( blocksArray )
) {
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think initially, this was needed to limit the "paragraph -> list" conversion to paragraph only selections. It doesn't seem like the removal impacts this as we can't transform any multiselection to lists yet.

This is me saying, I agree with this change conceptually but how do you think we should define that a conversion is liimited to the same types or not?

Copy link
Contributor

Choose a reason for hiding this comment

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

how do you think we should define that a conversion is liimited to the same types or not?

What about adding a new property like sameBlockTypes to the transform?

transforms: {
	from: [
		{
			type: 'block',
			isMultiBlock: true,
			blocks: [ '*' ],
			sameBlockTypes: true
			__experimentalConvert( blocks ) { // ... },
		},
	},
}

switchToBlockType can then check the value of that property before applying the conversion:

diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js
index 8775b6f78e..762a5c4d15 100644
--- a/packages/blocks/src/api/factory.js
+++ b/packages/blocks/src/api/factory.js
@@ -449,6 +449,9 @@ export function switchToBlockType( blocks, name ) {
 	let transformationResults;
 
 	if ( transformation.isMultiBlock ) {
+		if ( transformation.sameBlockTypes && ! isBlockSelectionOfSameType( blocksArray ) ) {
+			return null;
+		}
 		if ( has( transformation, '__experimentalConvert' ) ) {
 			transformationResults = transformation.__experimentalConvert(
 				blocksArray

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Naming is always difficult but I like the idea @mmtr !

if (
! isContainerGroupBlock( name ) &&
isMultiBlock &&
! isBlockSelectionOfSameType( blocksArray )
Copy link
Member

Choose a reason for hiding this comment

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

Pretty sure this function isBlockSelectionOfSameType becomes unused after this change (exported, but only for purpose of unit testing).

@aduth aduth added [Feature] Block API API that allows to express the block paradigm. [Package] Blocks /packages/blocks labels May 25, 2020
@aduth
Copy link
Member

aduth commented May 25, 2020

Previously: #14908

@getdave Would you have any additional context regarding if / why the restriction here is necessary? (relevant also: #22577 (comment))

@kwight
Copy link

kwight commented May 25, 2020

One thing that might be odd to handle is ungrouping. The Group transform has its corresponding Ungroup menu, to bring those blocks back to their standalone state. With Premium Content as an example, the user can only delete the whole Premium Content block (and all the blocks within it). Would we add an "Undo Premium Content" menu item, or allow allow reuse of the "Ungroup" item?..

Without an equivalent "ungroup"-type action, the user could copy and paste each block out of the Premium Content block, but it's kinda awkward compared to the similarly-tasked Group block. One other consideration might be to have the block-moving arrows not bounded by their containing block, so that blocks could be moved in and out that way instead (but I'm assuming that's more technically complicated).

@mmtr
Copy link
Contributor

mmtr commented May 26, 2020

That's a nice thing to consider, @kwight.

I see the Ungroup button is intentionally tidied to the Group block. Opening it to any block would allow users to ungroup any block with nested blocks causing unexpected behavior on blocks that have a parent restriction (like core/column or core/button).

I guess we could disable it on blocks having that restriction, but I'm assuming users will still find the UI confusing if we stick to the "Ungroup" term since there has not been any grouping action before.

Instead, I think that any block interested in pulling its inner blocks out with a user-facing button should implement its own ungroup button to be added to its block toolbar. That's possible with the current API, so in the case of the Premium Content block it should be addressed in Automattic/wp-calypso#42548 (or as a follow up).

@mmtr
Copy link
Contributor

mmtr commented May 26, 2020

Would we add an "Undo Premium Content" menu item, or allow allow reuse of the "Ungroup" item?..

Without an equivalent "ungroup"-type action, the user could copy and paste each block out of the Premium Content block, but it's kinda awkward compared to the similarly-tasked Group block.

Just noting the "Undo" button is still available and it will revert any block transformation.

Screen Shot 2020-05-26 at 11 44 18

@gwwar
Copy link
Contributor Author

gwwar commented May 26, 2020

One thing that might be odd to handle is ungrouping.

Oh true @kwight! The current work around would likely be adding a transform from custom block to Group transform then ungroup but that's rather awkward. We can maybe defer for future updates unless there's a need for it.

Another common block case to consider for__experimentalConvert would be allowing * for all block types but the custom container block. Groups may nest each other, but it might be the case that we don't want a custom container block containing itself.

@gwwar
Copy link
Contributor Author

gwwar commented May 29, 2020

@youknowriad @aduth If we're open to the change here, is work left then:

  • Add an additional property to the __experimentalConvert transform, to note when to limit by same block type. For example only transform when selected contains all paragraphs or all headings, instead of one paragraph and one heading.
  • Additional E2E Tests / unit tests
  • Code cleanup around isBlockSelectionOfSameType and any other unneeded usages?

We'd be happy to update the PR if so.

@youknowriad
Copy link
Contributor

I think it's fine @gwwar but do you think we can do a quick summary of the pros/cons compared to the existing approach?

@gwwar
Copy link
Contributor Author

gwwar commented Jun 1, 2020

I think it's fine @gwwar but do you think we can do a quick summary of the pros/cons compared to the existing approach?

Problem:

@youknowriad During block registration if we specify the following transform for a block other than "core/group" and make a selection of mixed block types say: (one paragraph, one image, and one heading) instead of (three paragraphs), we still have the option in the inserter to transform the selection to the block, however we will run into a JS error before the __experimentalConvert fires, due to the explicit check in

if (
! isContainerGroupBlock( name ) &&
isMultiBlock &&
! isBlockSelectionOfSameType( blocksArray )

or TL;DR no other block other than group can transform mixed block selections.

transforms: {
  from: [ {
    type: 'block',
    isMultiBlock: true,
    blocks: [ '*' ],
    __experimentalConvert( blocks ) {

As for the pros, @getdave do you recall what specific case we're guarding against here for the group block? We can probably guard against that in a different way.

@getdave
Copy link
Contributor

getdave commented Jun 2, 2020

I actually cannot remember why I added that check. It was obviously a very deliberate act though as indicated by the code structure and comment. I wish past me had provided more detail on the WHY and not the WHAT!

I wish I could be of more help.

@youknowriad
Copy link
Contributor

Thanks @gwwar that's helpful.

Given the difficulty to identify the original reasons for the check, it seems like the plan here #22577 (comment) is a good one.

isBlockSelectionOfSameType

I know I suggested this but I did so because I thought that it was the reason the check existed here in the first place, if there's no use-case for this right now, it's fine to avoid it IMO. blocks: [ 'core/paragraph' ] can also have the same purpose right?

@gwwar
Copy link
Contributor Author

gwwar commented Jun 2, 2020

if there's no use-case for this right now, it's fine to avoid it IMO. blocks: [ 'core/paragraph' ] can also have the same purpose right?

Yes I believe so! Thanks, I'll update the summary for clarity on the whys and next steps.

@gwwar gwwar force-pushed the try/remove-multi-type-check branch from 9ca1f94 to 1fbbb28 Compare June 4, 2020 22:14
@gwwar
Copy link
Contributor Author

gwwar commented Jun 4, 2020

This one is ready for review @youknowriad @mmtr @kwight @getdave

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

LGTM

seems like there's a lint issue somewhere.

@gwwar
Copy link
Contributor Author

gwwar commented Jun 5, 2020

Thanks I can tidy that. I suppose prettier doesn't run as a pre-commit?

Screen Shot 2020-06-05 at 12 06 00 PM

@gwwar
Copy link
Contributor Author

gwwar commented Jun 5, 2020

We have a green build ✨ Thanks for the reviews @youknowriad @getdave @aduth @mmtr @kwight !

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. [Package] Blocks /packages/blocks
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants