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.* in save component #20721

Closed
wants to merge 4 commits into from
Closed

Block.* in save component #20721

wants to merge 4 commits into from

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Mar 9, 2020

Description

This PR mirrors Block.* for light blocks in the save component, much like we do now for InnerBlocks and RichText. The benefit of this is that we could automatically add blocks classes with this component (if not opting out), making it seem less like a magical things that gets added during serialisation.

Another benefit is that a block could potentially render something around the actual block (such as an alignment wrapper), which is possible right now in the edit function, but not in the save function.

How has this been tested?

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • 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.

@github-actions
Copy link

github-actions bot commented Mar 9, 2020

Size Change: +180 B (0%)

Total Size: 859 kB

Filename Size Change
build/block-editor/index.js 101 kB +77 B (0%)
build/block-library/index.js 110 kB +33 B (0%)
build/blocks/index.js 57.6 kB +70 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 998 B 0 B
build/annotations/index.js 3.43 kB 0 B
build/api-fetch/index.js 3.39 kB 0 B
build/autop/index.js 2.58 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 6.02 kB 0 B
build/block-directory/style-rtl.css 760 B 0 B
build/block-directory/style.css 760 B 0 B
build/block-editor/style-rtl.css 11 kB 0 B
build/block-editor/style.css 11 kB 0 B
build/block-library/editor-rtl.css 7.24 kB 0 B
build/block-library/editor.css 7.24 kB 0 B
build/block-library/style-rtl.css 7.41 kB 0 B
build/block-library/style.css 7.42 kB 0 B
build/block-library/theme-rtl.css 669 B 0 B
build/block-library/theme.css 671 B 0 B
build/block-serialization-default-parser/index.js 1.65 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/components/index.js 191 kB 0 B
build/components/style-rtl.css 15.8 kB 0 B
build/components/style.css 15.7 kB 0 B
build/compose/index.js 6.21 kB 0 B
build/core-data/index.js 10.6 kB 0 B
build/data-controls/index.js 1.04 kB 0 B
build/data/index.js 8.26 kB 0 B
build/date/index.js 5.37 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.06 kB 0 B
build/edit-post/index.js 91.2 kB 0 B
build/edit-post/style-rtl.css 8.47 kB 0 B
build/edit-post/style.css 8.46 kB 0 B
build/edit-site/index.js 6.72 kB 0 B
build/edit-site/style-rtl.css 2.88 kB 0 B
build/edit-site/style.css 2.88 kB 0 B
build/edit-widgets/index.js 4.43 kB 0 B
build/edit-widgets/style-rtl.css 2.58 kB 0 B
build/edit-widgets/style.css 2.58 kB 0 B
build/editor/editor-styles-rtl.css 381 B 0 B
build/editor/editor-styles.css 382 B 0 B
build/editor/index.js 43.8 kB 0 B
build/editor/style-rtl.css 4 kB 0 B
build/editor/style.css 3.98 kB 0 B
build/element/index.js 4.44 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 6.95 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 1.93 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.49 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keyboard-shortcuts/index.js 2.3 kB 0 B
build/keycodes/index.js 1.69 kB 0 B
build/list-reusable-blocks/index.js 2.99 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 4.84 kB 0 B
build/notices/index.js 1.57 kB 0 B
build/nux/index.js 3.01 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.54 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 781 B 0 B
build/redux-routine/index.js 2.84 kB 0 B
build/rich-text/index.js 14.4 kB 0 B
build/server-side-render/index.js 2.55 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 4.01 kB 0 B
build/viewport/index.js 1.61 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.18 kB 0 B

compressed-size-action

@ellatrix ellatrix changed the title Block save component Block.* in save component Mar 9, 2020
@ellatrix
Copy link
Member Author

ellatrix commented Mar 9, 2020

@youknowriad Wondering what you think of this, or if you had something else in mind.

* @param {Object} attributes Block attributes.
*/
applyFilters(
'blocks.getSaveContent.extraProps',
Copy link
Contributor

Choose a reason for hiding this comment

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

One thing I was wondering is whether we should just apply this hook to the Edit version of Block.*

Copy link
Member Author

Choose a reason for hiding this comment

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

We could, but we'd need more context and then the hook namespace also doesn't make sense anymore.

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.

I think we should try this.

@ellatrix
Copy link
Member Author

@youknowriad I wonder if we should name it Block.Content to align with both RichText.Content and InnerBlocks.Content. I'm not sure I like the naming, but maybe it's good to keep it consistent.

@youknowriad
Copy link
Contributor

@ellatrix Yeah Block.Content seems a bit weird and potentially misleading.

return (
<BlockPropsFilterContext.Consumer>
{ ( filter ) => {
return (
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'm running into a really strange problem here. filter returns the BlockContent function from the BlockContentProvider (for InnerBlocks)... even though I'm subscribing to BlockPropsFilterContext. If I swap the two provider components, then it works, but then InnerBlocks.Content stops working. @youknowriad Any idea why context is behaving strangely during serialisation? Been staring at this for a while. 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

I know that we have a custom serializer implementation and we don't rely on React. That might be the reason. cc @aduth

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, it could very well be an issue in the implementation of the custom serializer.

In particular, looking at this code, I can see how it might be problematic for two separate context values to coexist in the same render tree, since the second argument would replace the current context:

case Provider.$$typeof:
return renderChildren( props.children, props.value, legacyContext );

It's likely not been discovered since our use of context in serialization is pretty minimal to date.

The solution may be a bit tricky, since we context still needs to be associated 1:1 for a given provider/context pair, and we can't assume anything about the shape of that value (i.e. can't be doing any Object.assign).

I'd guess we might want to implement context here as some [Weak]Map which can be looked up by Provider class at the time if/when the Consumer is rendered.

Failing test case:

it( 'renders provided value through multiple context providers', () => {
	const {
		Consumer: FirstConsumer,
		Provider: FirstProvider,
	} = createContext();
	const { Provider: SecondProvider } = createContext();

	const result = renderElement(
		<FirstProvider value="first">
			<SecondProvider value="second">
				<FirstConsumer>
					{ ( context ) => context.value }
				</FirstConsumer>
			</SecondProvider>
		</FirstProvider>
	);

	expect( result ).toBe( 'first' );
} );

On the general point of the custom serializer, there's other issues here as well (notably, hooks, see #15873). Even if we fixed the above implementation of serializer provider rendering, I'd guess useContext likely still wouldn't work? I'm open to reevaluating this implementation, depending how much a burden it continues to be. For context on why it exists in the first place, see #5897 (#3353).

Copy link
Member

Choose a reason for hiding this comment

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

See: #21156

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

I do like the idea of reducing the magic we currently have, since this sort of thing will be really hard to decipher in future maintenance as to if and why that wrapper exists.

Coming from a position of relative ignorance, I'm still not sure I "get it"... as in, why can't I just use a div in my edit function if I want to render a div ? It's more of a rhetorical question, since I'm sure there are reasons, but I don't know that we can expect these to be immediately obvious (or when it is or isn't needed).

@@ -38,8 +42,11 @@ export default function save( { attributes } ) {
};

return (
<div className={ className ? className : undefined } style={ style }>
<Block.Save.div
Copy link
Member

Choose a reason for hiding this comment

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

Reiterating a concern I raised in previous pull requests: I can't help but foresee this becoming a never-ending maintenance burden. For what reason do we need to whitelist these tag names?

Could it be something where we use instead some prop, like...

Copy link
Contributor

Choose a reason for hiding this comment

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

Could it be something where we use instead some prop, like...

The main idea of Block.* is that you can pass it, itself as a tagName of another component (RichText, InnerBlocks)

That said, I think it has limits, for example, it's impossible to support custom tags (which I think we should support).

So we might have to find a new approach to solve both problems.

@ellatrix
Copy link
Member Author

why can't I just use a div in my edit function if I want to render a div ?

The idea is to require it if you're using the light block wrapper.

Of course, we can choose not to go for this Block.* component in the save function and just rely on the block author to add the class to the div. That would be the clearest, but you risk that the block author would not do it.

@ellatrix
Copy link
Member Author

Replaced by #25644.

@ellatrix ellatrix closed this Sep 25, 2020
@ellatrix ellatrix deleted the try/block-save-component branch September 25, 2020 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants