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

[Block Editor]: Conditionally show Styles if block is in Placeholder state #33823

Closed
wants to merge 3 commits into from

Conversation

ntsekouras
Copy link
Contributor

@ntsekouras ntsekouras commented Aug 2, 2021

Description

Partially addresses: #23122
Related: #33466

There is the need to show/hide some controls or other things like Styles based on whether the block is in Placeholder state or not. For example when we have an Image block with no image set, there is no need to show the Styles tab or the Styles in BlockSwitcher.

This PR adds to the block-editor store an inPlaceholderState which tracks which blocks are in such state. This value can be consumed to conditionally show/hide things. In order to be a complete solution for block.supports it will need one more property to the state per support.

For start I've implemented this for Image block and will wait for feedback for the approach. If there is a consensus, I'll follow up on this by writing tests and add it to more blocks that can utilize this like Cover block(issue: #23198)

Testing instructions

  1. Insert an Image block and observe that if you have not set an image, the Styles are not shown.
  2. Set an image and observe that Styles are shown.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

@ntsekouras ntsekouras added [Block] Image Affects the Image Block [Package] Block editor /packages/block-editor labels Aug 2, 2021
@ntsekouras ntsekouras requested review from mcsf, youknowriad, talldan, gziolo and a team August 2, 2021 17:07
@ntsekouras ntsekouras self-assigned this Aug 2, 2021
@github-actions
Copy link

github-actions bot commented Aug 2, 2021

Size Change: +305 B (0%)

Total Size: 1.03 MB

Filename Size Change
build/block-editor/index.min.js 119 kB +125 B (0%)
build/block-library/index.min.js 147 kB +180 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 931 B
build/admin-manifest/index.min.js 1.09 kB
build/annotations/index.min.js 2.7 kB
build/api-fetch/index.min.js 2.19 kB
build/autop/index.min.js 2.08 kB
build/blob/index.min.js 459 B
build/block-directory/index.min.js 6.21 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/style-rtl.css 13.8 kB
build/block-editor/style.css 13.8 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 58 B
build/block-library/blocks/audio/editor.css 58 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 474 B
build/block-library/blocks/button/editor.css 474 B
build/block-library/blocks/button/style-rtl.css 605 B
build/block-library/blocks/button/style.css 604 B
build/block-library/blocks/buttons/editor-rtl.css 315 B
build/block-library/blocks/buttons/editor.css 315 B
build/block-library/blocks/buttons/style-rtl.css 370 B
build/block-library/blocks/buttons/style.css 370 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 194 B
build/block-library/blocks/columns/editor.css 193 B
build/block-library/blocks/columns/style-rtl.css 474 B
build/block-library/blocks/columns/style.css 475 B
build/block-library/blocks/cover/editor-rtl.css 666 B
build/block-library/blocks/cover/editor.css 670 B
build/block-library/blocks/cover/style-rtl.css 1.23 kB
build/block-library/blocks/cover/style.css 1.23 kB
build/block-library/blocks/embed/editor-rtl.css 488 B
build/block-library/blocks/embed/editor.css 488 B
build/block-library/blocks/embed/style-rtl.css 400 B
build/block-library/blocks/embed/style.css 400 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 322 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 707 B
build/block-library/blocks/gallery/editor.css 706 B
build/block-library/blocks/gallery/style-rtl.css 1.05 kB
build/block-library/blocks/gallery/style.css 1.05 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 93 B
build/block-library/blocks/group/theme.css 93 B
build/block-library/blocks/heading/editor-rtl.css 152 B
build/block-library/blocks/heading/editor.css 152 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/home-link/style-rtl.css 247 B
build/block-library/blocks/home-link/style.css 247 B
build/block-library/blocks/html/editor-rtl.css 283 B
build/block-library/blocks/html/editor.css 284 B
build/block-library/blocks/image/editor-rtl.css 728 B
build/block-library/blocks/image/editor.css 728 B
build/block-library/blocks/image/style-rtl.css 482 B
build/block-library/blocks/image/style.css 487 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B
build/block-library/blocks/latest-posts/editor.css 137 B
build/block-library/blocks/latest-posts/style-rtl.css 528 B
build/block-library/blocks/latest-posts/style.css 527 B
build/block-library/blocks/list/style-rtl.css 63 B
build/block-library/blocks/list/style.css 63 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 488 B
build/block-library/blocks/media-text/style.css 485 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 474 B
build/block-library/blocks/navigation-link/editor.css 474 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation/editor-rtl.css 1.69 kB
build/block-library/blocks/navigation/editor.css 1.69 kB
build/block-library/blocks/navigation/style-rtl.css 1.65 kB
build/block-library/blocks/navigation/style.css 1.64 kB
build/block-library/blocks/navigation/view.min.js 2.52 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 310 B
build/block-library/blocks/page-list/editor.css 310 B
build/block-library/blocks/page-list/style-rtl.css 242 B
build/block-library/blocks/page-list/style.css 242 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 248 B
build/block-library/blocks/paragraph/style.css 248 B
build/block-library/blocks/post-author/editor-rtl.css 210 B
build/block-library/blocks/post-author/editor.css 210 B
build/block-library/blocks/post-author/style-rtl.css 182 B
build/block-library/blocks/post-author/style.css 181 B
build/block-library/blocks/post-comments-form/style-rtl.css 140 B
build/block-library/blocks/post-comments-form/style.css 140 B
build/block-library/blocks/post-comments/style-rtl.css 360 B
build/block-library/blocks/post-comments/style.css 359 B
build/block-library/blocks/post-content/editor-rtl.css 138 B
build/block-library/blocks/post-content/editor.css 138 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 398 B
build/block-library/blocks/post-featured-image/editor.css 398 B
build/block-library/blocks/post-featured-image/style-rtl.css 143 B
build/block-library/blocks/post-featured-image/style.css 143 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 378 B
build/block-library/blocks/post-template/style.css 379 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 60 B
build/block-library/blocks/post-title/style.css 60 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 361 B
build/block-library/blocks/pullquote/style.css 360 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 270 B
build/block-library/blocks/query-pagination/editor.css 262 B
build/block-library/blocks/query-pagination/style-rtl.css 168 B
build/block-library/blocks/query-pagination/style.css 168 B
build/block-library/blocks/query-title/editor-rtl.css 85 B
build/block-library/blocks/query-title/editor.css 85 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 169 B
build/block-library/blocks/quote/style.css 169 B
build/block-library/blocks/quote/theme-rtl.css 220 B
build/block-library/blocks/quote/theme.css 222 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 374 B
build/block-library/blocks/search/style.css 375 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 250 B
build/block-library/blocks/separator/style.css 250 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 462 B
build/block-library/blocks/site-logo/editor.css 464 B
build/block-library/blocks/site-logo/style-rtl.css 153 B
build/block-library/blocks/site-logo/style.css 153 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 165 B
build/block-library/blocks/social-link/editor.css 165 B
build/block-library/blocks/social-links/editor-rtl.css 812 B
build/block-library/blocks/social-links/editor.css 811 B
build/block-library/blocks/social-links/style-rtl.css 1.33 kB
build/block-library/blocks/social-links/style.css 1.33 kB
build/block-library/blocks/spacer/editor-rtl.css 307 B
build/block-library/blocks/spacer/editor.css 307 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 146 B
build/block-library/blocks/tag-cloud/style.css 146 B
build/block-library/blocks/template-part/editor-rtl.css 636 B
build/block-library/blocks/template-part/editor.css 635 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/editor-rtl.css 90 B
build/block-library/blocks/term-description/editor.css 90 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 1.29 kB
build/block-library/common.css 1.29 kB
build/block-library/editor-rtl.css 9.87 kB
build/block-library/editor.css 9.85 kB
build/block-library/reset-rtl.css 527 B
build/block-library/reset.css 527 B
build/block-library/style-rtl.css 10.2 kB
build/block-library/style.css 10.3 kB
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 692 B
build/block-serialization-default-parser/index.min.js 1.09 kB
build/block-serialization-spec-parser/index.min.js 2.79 kB
build/blocks/index.min.js 47 kB
build/components/index.min.js 209 kB
build/components/style-rtl.css 15.7 kB
build/components/style.css 15.8 kB
build/compose/index.min.js 10.2 kB
build/core-data/index.min.js 12.3 kB
build/customize-widgets/index.min.js 10.4 kB
build/customize-widgets/style-rtl.css 1.5 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 614 B
build/data/index.min.js 7.18 kB
build/date/index.min.js 31.5 kB
build/deprecated/index.min.js 428 B
build/dom-ready/index.min.js 304 B
build/dom/index.min.js 4.53 kB
build/edit-navigation/index.min.js 13.4 kB
build/edit-navigation/style-rtl.css 3.1 kB
build/edit-navigation/style.css 3.1 kB
build/edit-post/classic-rtl.css 492 B
build/edit-post/classic.css 494 B
build/edit-post/index.min.js 28.4 kB
build/edit-post/style-rtl.css 7.18 kB
build/edit-post/style.css 7.17 kB
build/edit-site/index.min.js 25.9 kB
build/edit-site/style-rtl.css 5.01 kB
build/edit-site/style.css 5.01 kB
build/edit-widgets/index.min.js 15.9 kB
build/edit-widgets/style-rtl.css 4.01 kB
build/edit-widgets/style.css 4.02 kB
build/editor/index.min.js 37.5 kB
build/editor/style-rtl.css 3.92 kB
build/editor/style.css 3.91 kB
build/element/index.min.js 3.16 kB
build/escape-html/index.min.js 517 B
build/format-library/index.min.js 5.36 kB
build/format-library/style-rtl.css 668 B
build/format-library/style.css 669 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 424 B
build/i18n/index.min.js 3.59 kB
build/is-shallow-equal/index.min.js 501 B
build/keyboard-shortcuts/index.min.js 1.49 kB
build/keycodes/index.min.js 1.25 kB
build/list-reusable-blocks/index.min.js 1.85 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.88 kB
build/notices/index.min.js 845 B
build/nux/index.min.js 2.03 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.83 kB
build/primitives/index.min.js 921 B
build/priority-queue/index.min.js 582 B
build/react-i18n/index.min.js 671 B
build/redux-routine/index.min.js 2.63 kB
build/reusable-blocks/index.min.js 2.28 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.6 kB
build/server-side-render/index.min.js 1.32 kB
build/shortcode/index.min.js 1.48 kB
build/token-list/index.min.js 562 B
build/url/index.min.js 1.72 kB
build/viewport/index.min.js 1.02 kB
build/warning/index.min.js 248 B
build/widgets/index.min.js 6.27 kB
build/widgets/style-rtl.css 1.04 kB
build/widgets/style.css 1.04 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

@youknowriad
Copy link
Contributor

youknowriad commented Aug 3, 2021

Thanks for the PR Nik. It sounds like a valid approach but I'd like to take some time to reflect on what it means more holistically.

Right now, block objects can have a isValid boolean. Which basically means a block can be in two states: "valid" or "invalid". This PR adds two new states for the block "placeholder" and "ready/customizable". We could see these as two completely different flags or states like this PR does. Alternatively we could see as "states" of a block. The question that I have:

  • Is the isPlaceholder state a formal state we want to introduce for all blocks?
  • Is there any other block state we think we'd need in the future? What other states the block can be in?
  • Should these states be part of the block object (like isValid) or not like (just in the block-editor store) the isPlaceholder of this PR? (I think I prefer the latter here)
  • Should these states and any potential new states have a generic implementation (block states) and a state machine.

Some questions raised by this PR, they don't need to be answered or solved all in this PR, just food for thoughts.

cc @mcsf @mtias

@talldan talldan requested a review from ajlende August 3, 2021 11:09
@Mamaduka
Copy link
Member

Mamaduka commented Aug 3, 2021

Thanks for the PR, @ntsekouras.

It never occurred to me that we can store placeholder state this way. 🙇

My ideas always leaned towards block.supports.

  • Blocks can define support for placeholder state and provide an array of attributes for this property.
  • The isInPlaceholderState value is derived based on these attributes.
{
	"apiVersion": 2,
	"name": "core/image",
	"attributes": {},
	"supports": {
		"anchor": true,
		"placeholder": [ "url" ]
	}
}

@oandregal
Copy link
Member

I've left a comment about this at #33466 (comment) I think something like this is our best shot, although it still has drawbacks for third-party tools.

@ajlende
Copy link
Contributor

ajlende commented Aug 3, 2021

@youknowriad I know your questions were meant to be rhetorical, but I've been thinking about this for a bit now, so I have some answers for some of them anyway.

Is the isPlaceholder state a formal state we want to introduce for all blocks?

I wasn't sure about this either, but I asked during the #core-editor chat and others seemed to think that it is. Looking around, more than a few blocks already have some from of a setup state where nothing will be displayed unless some attributes are set. In these cases, the block usually doesn't want to give a full set of controls until those required attributes are set.

Should these states and any potential new states have a generic implementation (block states) and a state machine?

One of my ideas would fit well with a state machine type implementation.

Given that setup state is a thing that a block developer wants to use for their block (probably not too uncommon based on the above), from a block developer perspective, what would the easiest way to handle a setup state be?

One of my ideas is adding a setup or placeholder function alongside edit and save. Block supports would be able to decide if they should be visible in the placeholder state or not. I haven't dug too deeply into block styles yet, but they could be marked either when registering the style or disabled altogether when in the setup state. The challenge is deciding how to transition from the setup to the edit state. Would we need to supply another function, call it isSetupComplete or something, for that transition, or would a simple check of prop !== undefined be enough?

@ntsekouras
Copy link
Contributor Author

Thanks for the feedback all!

Is the isPlaceholder state a formal state we want to introduce for all blocks?

I believe we could - there are many blocks that use Placeholders. Also, with the state approach we leave blocks (objects) intact.

Is there any other block state we think we'd need in the future? What other states the block can be in?

I'm not sure, but probably an editable/read only - locked state in the future, as is being discussed in this issue: #29864. Having this info in the state could be consumed by components to show/hide things in toolbar/list view etc..

Should these states and any potential new states have a generic implementation (block states) and a state machine.

If we don't find/agree on another possible state for now, I'd be reluctant to implement a generic solution. I think it would be better to test it out as experimental. Although probably the locked state is something we will need 😄

Blocks can define support for placeholder state and provide an array of attributes for this property.

@Mamaduka this can easily fall short for many blocks that need more complex calculation for this state. For example, lots of blocks are in Placeholder state when there are no innerBlocks.

One of my ideas is adding a setup or placeholder function alongside edit and save.

@ajlende since a Placeholder can be different in blocks and is tied to the edit function, IMO is okay to set this state in the same function.

@ajlende
Copy link
Contributor

ajlende commented Aug 3, 2021

since a Placeholder can be different in blocks and is tied to the edit function

I'm questioning if placehoders between blocks are different enough? And if it has to be tied to the edit function?

What would be easier for a block developer to understand? Having a separate function for when you have required props that need to be set or adding additional wiring and branching within the edit function and having two different returns in one function? (I don't really know for sure)

Having two different returns is what we already have—it's the more flexible solution, and it's able to do the things that we want to do. However, the additional wiring (the useEffect calls) can be hidden by having a separate block state for the common case of having some required setup. Maybe that would be easier for block developers?

And I just thought of this, but we want the edit function to be visually as close to what is saved, right? In the case of things like images where we've completely replaced the UI in this setup case, having a separate setup function could help support that goal too.

@gziolo
Copy link
Member

gziolo commented Aug 4, 2021

There are many core blocks that use the placeholder state. Let me share some examples so we have a better understanding of their complexity.

Columns block

const hasInnerBlocks = useSelect(
( select ) =>
select( blockEditorStore ).getBlocks( clientId ).length > 0,
[ clientId ]
);
const Component = hasInnerBlocks
? ColumnsEditContainerWrapper
: Placeholder;
return <Component { ...props } />;

Query Loop block

const hasInnerBlocks = useSelect(
( select ) =>
!! select( blockEditorStore ).getBlocks( clientId ).length,
[ clientId ]
);
const Component = hasInnerBlocks ? QueryContent : QueryPatternSetup;
return <Component { ...props } />;

Gallery block

const hasImages = !! images.length;

if ( ! hasImages ) {
return <View { ...blockProps }>{ mediaPlaceholder }</View>;
}

RSS block

const [ isEditing, setIsEditing ] = useState( ! attributes.feedURL );

if ( isEditing ) {
return (
<div { ...blockProps }>
<Placeholder icon={ rss } label="RSS">
<form
onSubmit={ onSubmitURL }
className="wp-block-rss__placeholder-form"
>
<TextControl
placeholder={ __( 'Enter URL here…' ) }
value={ feedURL }
onChange={ ( value ) =>
setAttributes( { feedURL: value } )
}
className="wp-block-rss__placeholder-input"
/>
<Button variant="primary" type="submit">
{ __( 'Use URL' ) }
</Button>
</form>
</Placeholder>
</div>
);
}

Table block

const sections = [ 'head', 'body', 'foot' ].filter(
( name ) => ! isEmptyTableSection( attributes[ name ] )
);

const isEmpty = ! sections.length;

{ isEmpty && (
<Placeholder
label={ __( 'Table' ) }
icon={ <BlockIcon icon={ icon } showColors /> }
instructions={ __( 'Insert a table for sharing data.' ) }
>
<form
className="blocks-table__placeholder-form"
onSubmit={ onCreateTable }
>
<TextControl
type="number"
label={ __( 'Column count' ) }
value={ initialColumnCount }
onChange={ onChangeInitialColumnCount }
min="1"
className="blocks-table__placeholder-input"
/>
<TextControl
type="number"
label={ __( 'Row count' ) }
value={ initialRowCount }
onChange={ onChangeInitialRowCount }
min="1"
className="blocks-table__placeholder-input"
/>
<Button
className="blocks-table__placeholder-button"
variant="primary"
type="submit"
>
{ __( 'Create Table' ) }
</Button>
</form>
</Placeholder>
) }

@jasmussen
Copy link
Contributor

I'm questioning if placehoders between blocks are different enough? And if it has to be tied to the edit function?

I'm speaking here from a pure design and user experience perspective, and I might be missing some nuance of the development side of things, so what I'm about to suggest might or might not be completely relevant.

Nevertheless the Placeholders as they exist today (white bordered boxes) have a number of shortcomings that we need to address in the future:

  • They look nothing like the end result. They don't pass the "squint" test.
  • Because of that, they often cause big layout shifts when going from the placeholder state to the final state.
  • For example, the Placeholder comes with a baked-in 200px min-height, which is not at all appropriate for a horizontal Navigation menu, for example, as those are usually 36px tall. Here's an older example of why that approach isn't ideal.
  • It works best when inserted in a big column; if you insert it in a very small context, although there's some limited responsive behavior built in, it's not very good in the default state. Each placeholder requires careful designs and configurations in order to behave well to the context it's inserted in.

In many blocks, the Placeholder is critical for the block to function. An Image block needs an image chosen, a particular Maps block might need an API key, an embed block needs a URL. In those cases, the component and "Windows 95 Wizard-like" behavior can be a good way to configure a complex block. But even here, the shortcomings noted above are still present.

In other cases, we use the Placeholder component even though we arguably shouldn't, for all the reasons listed above. For example the Table block allows you to configure the number of columns and rows in the Placeholder itself, but arguably we could just default to 2x2 and then let you change those from the block toolbar directly. This isn't meant as a critique of the choice, often the Placeholder was chosen because the block toolbar wasn't yet a good enough user experience. But it needs to be, and we need fewer of those Placeholders.

In short, what we've learned from the user experience side is that designing a good block setup state requires careful consideration of its responsive behavior, consideration of whether it's even necessary in the first place, and thoughts about how to best pass the "squint" test.

We might still be able to create some smart behaviors that handle these things in a mostly generic way, or at least provide props that help attune the component to its block type. I've revisited a few recently, though important to note I'm still not entirely happy with these:

Setup states   appenders

Setup states   appenders 2

Generic placeholder

But all that is to say: the Placeholder is not as simple as it might seem, and is likely going to vary a great deal from block to block.

@ajlende
Copy link
Contributor

ajlende commented Aug 4, 2021

Thanks @gziolo and @jasmussen for the examples!

There are many core blocks that use the placeholder state. Let me share some examples so we have a better understanding of their complexity.

It seems that the placeholders are simpler than I expected—driven almost entirely by attributes and things tied to the block clientId. Only RSS requires internal block state, and that could easily be avoided by entering the url in the toolbar like the image url in the replacement flow currently is done.

image replacement flow

But all that is to say: the Placeholder is not as simple as it might seem, and is likely going to vary a great deal from block to block.

Yeah, the design of the Placeholder is not simple—I don't think we could narrow down to even a few categories of placeholder to render. However, it seems that choosing if a block should be in a placeholder state is pretty simple—it's not so simple that we could encode it in JSON, but a single function seems like it could work.

@ntsekouras
Copy link
Contributor Author

I'm closing this for now, as this seems to be subjective about user's workflow. Might be better to address the shortcomings and usage of Placeholders in the first place, as explained very well by @jasmussen in the above comment:#33823 (comment)

@ntsekouras ntsekouras closed this Aug 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Image Affects the Image Block [Package] Block editor /packages/block-editor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants