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

Light block: introduce useBlockWrapperProps #23034

Merged
merged 7 commits into from
Sep 21, 2020
Merged

Light block: introduce useBlockWrapperProps #23034

merged 7 commits into from
Sep 21, 2020

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Jun 9, 2020

Description

This PR introduces useBlockWrapperProps, a hook used to lightly mark any element as a block.

To use, just pass the returned props to the element:

<p attribute="value" { ...useBlockWrapperProps() } />

If the component defines a ref for the element, it must be passed through useBlockWrapperProps. If no ref is defined, useBlockWrapperProps will create one and pass it to the element.

<p attribute="value" { ...useBlockWrapperProps( { ref } ) } />

You can pass any props to useBlockWrapperProps and they will be returned, but you don't have to. In case of style and className props, useBlockWrapperProps will automatically merge them. If you don't pass them through useBlockWrapperProps, you have to merge them yourself.

Both are equally ok:

<p { ...useBlockWrapperProps( { ref, className: 'something', attribute: value } ) } />
const blockProps = useBlockWrapperProps( { ref } );
<p attribute="value" { ... blockProps } className={ classnames( blockProps.className, 'something' ) } />

A hook means that it can work for any component. No need to have a <Block as /> component and block() HoC so that it works in different scenarios. Just one API. We don't need access to the element/component at all, we only need to define some props and have access to the ref.

I think it's really nice that this leaves the original element structure intact, since it doesn't need to be wrapped in another component.

I could imagine a similar API for InnerBlocks, which would avoid having things like the ugly passedProps etc.

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 Jun 9, 2020

Size Change: +563 B (0%)

Total Size: 1.2 MB

Filename Size Change
build/block-editor/index.js 128 kB +420 B (0%)
build/block-library/index.js 135 kB +143 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.52 kB 0 B
build/api-fetch/index.js 3.34 kB 0 B
build/autop/index.js 2.72 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 8.41 kB 0 B
build/block-directory/style-rtl.css 943 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/style-rtl.css 11.1 kB 0 B
build/block-editor/style.css 11.1 kB 0 B
build/block-library/editor-rtl.css 8.59 kB 0 B
build/block-library/editor.css 8.59 kB 0 B
build/block-library/style-rtl.css 7.6 kB 0 B
build/block-library/style.css 7.59 kB 0 B
build/block-library/theme-rtl.css 741 B 0 B
build/block-library/theme.css 741 B 0 B
build/block-serialization-default-parser/index.js 1.77 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 47.5 kB 0 B
build/components/index.js 202 kB 0 B
build/components/style-rtl.css 15.5 kB 0 B
build/components/style.css 15.4 kB 0 B
build/compose/index.js 9.42 kB 0 B
build/core-data/index.js 12 kB 0 B
build/data-controls/index.js 1.27 kB 0 B
build/data/index.js 8.43 kB 0 B
build/date/index.js 31.9 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 4.42 kB 0 B
build/edit-navigation/index.js 10.4 kB 0 B
build/edit-navigation/style-rtl.css 868 B 0 B
build/edit-navigation/style.css 871 B 0 B
build/edit-post/index.js 306 kB 0 B
build/edit-post/style-rtl.css 6.24 kB 0 B
build/edit-post/style.css 6.22 kB 0 B
build/edit-site/index.js 19.6 kB 0 B
build/edit-site/style-rtl.css 3.3 kB 0 B
build/edit-site/style.css 3.3 kB 0 B
build/edit-widgets/index.js 17.6 kB 0 B
build/edit-widgets/style-rtl.css 2.79 kB 0 B
build/edit-widgets/style.css 2.79 kB 0 B
build/editor/editor-styles-rtl.css 492 B 0 B
build/editor/editor-styles.css 493 B 0 B
build/editor/index.js 45.3 kB 0 B
build/editor/style-rtl.css 3.8 kB 0 B
build/editor/style.css 3.8 kB 0 B
build/element/index.js 4.45 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.49 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 1.74 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.54 kB 0 B
build/is-shallow-equal/index.js 711 B 0 B
build/keyboard-shortcuts/index.js 2.39 kB 0 B
build/keycodes/index.js 1.85 kB 0 B
build/list-reusable-blocks/index.js 3.02 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.12 kB 0 B
build/notices/index.js 1.69 kB 0 B
build/nux/index.js 3.27 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.44 kB 0 B
build/primitives/index.js 1.34 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 13.7 kB 0 B
build/server-side-render/index.js 2.6 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.24 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.74 kB 0 B
build/warning/index.js 1.13 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@ZebulanStanphill ZebulanStanphill added [Feature] Blocks Overall functionality of blocks [Package] Block library /packages/block-library [Package] Block editor /packages/block-editor [Type] Experimental Experimental feature or API. labels Jun 9, 2020
@ZebulanStanphill
Copy link
Member

Wow, this looks really neat! I definitely prefer this to the previous approaches.

One question: should we call it useBlockProps or useBlockWrapperProps?

@ellatrix ellatrix requested a review from mkaz as a code owner June 9, 2020 17:30
@ellatrix
Copy link
Member Author

ellatrix commented Jun 9, 2020

I don't mind either way... I slightly prefer something shorter, but at the end of the day it doesn't matter much.

};
}

const BlockComponent = forwardRef(
Copy link
Contributor

Choose a reason for hiding this comment

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

This is cool, when do you think we should remove this? should we add a deprecated call with a version?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since it's experimental, maybe we can just remove it. Depending on what we do, we might have to leave it since some block components are still classes. Maybe the ref idea could replace it though.

Copy link
Contributor

Choose a reason for hiding this comment

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

We could yes, I saw some third-party usage already. So let's be nice to them and deprecate for a release or two.

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 was wondering if there's a way to make this even simpler for block authors. Instead of telling them to apply a hook, we could pass the "ref" as a prop and all they'll have to do would be to apply the ref? how possible is that?

@ellatrix
Copy link
Member Author

@youknowriad That's an excellent idea! I'll explore it quick.

@ellatrix
Copy link
Member Author

@youknowriad Oh, actually, I don't think it would be that easy because we still have to deal with the other props that need to be passed down to the block. :/

@youknowriad
Copy link
Contributor

@youknowriad Oh, actually, I don't think it would be that easy because we still have to deal with the other props that need to be passed down to the block. :/

One possibility would be to apply the style and classname using DOM apis and not React props but not sure how good is that

@ellatrix
Copy link
Member Author

@youknowriad I was thinking about that, and it would work fine if there were a limited amount of props controlled by us, but we have a filter on the block edit component where plugins are able to add additional props, so I think it's better to pass them straight to the react element.

@youknowriad
Copy link
Contributor

Starting to wonder whether the hook is the best API. I mean it is but with third-party random props we can already have issues as blocks using the hook won't "merge" all props (imagine blocks having attached event handlers).

I'd love if we can officially restrict that hook and make it more predictable, it's harming us in a lot of ways.

@ellatrix
Copy link
Member Author

imagine blocks having attached event handlers

Event handlers are ok. We don't attach any event handlers with react.

I'd love if we can officially restrict that hook and make it more predictable, it's harming us in a lot of ways.

What do you mean?

@ellatrix
Copy link
Member Author

ellatrix commented Jun 12, 2020

Let me elaborate :)

  1. We don't need access to the rendered element at all, only to the attributes/props. There's no need to concern ourselves with what element or component the block renders.
  2. It's true that some props need to be merged. This will also be the case with a block() HoC and <Block as={ Component } />.
  3. To reduce the chance of conflicts, I've moved our event listeners to be attached in effects. React only allows one event listener, while the DOM allows many, so we can leave the React slot open for use by the block.
  4. Of course there's still a change of conflict, but that's always been the case. If both a block and a block edit filter (or multiple block edit filters by multiple plugins) add onClick props, only one will make it. This has always been a problem. The filters are responsible for merging props too.

@ellatrix ellatrix changed the title Light block: introduce useBlockProps Light block: introduce useBlockWrapperProps Sep 21, 2020
@ellatrix
Copy link
Member Author

@youknowriad Yes, I'll add a deprecation.

@ellatrix ellatrix merged commit aa0abb9 into master Sep 21, 2020
@ellatrix ellatrix deleted the try/use-block branch September 21, 2020 16:21
@github-actions github-actions bot added this to the Gutenberg 9.1 milestone Sep 21, 2020
@ZebulanStanphill
Copy link
Member

Notably, the following blocks still use the Block.TAG_NAME API:

  • Column
  • Columns
  • Group
  • Heading
  • Post Title
  • Preformatted
  • Site Tagline
  • Site Title
  • Social Icons
  • Template Part
  • Verse
  • Video

@ellatrix
Copy link
Member Author

@ZebulanStanphill Yes, remaining ones should be done in #25515.

WunderBart added a commit to Automattic/wp-calypso that referenced this pull request Oct 1, 2020
...and make it backwards-compatible. This label was updated in WordPress/gutenberg#23034.
ockham pushed a commit to Automattic/wp-calypso that referenced this pull request Oct 1, 2020
...and make it backwards-compatible. This label was updated in WordPress/gutenberg#23034.

Co-authored-by: Bart <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Blocks Overall functionality of blocks [Package] Block editor /packages/block-editor [Package] Block library /packages/block-library [Type] Experimental Experimental feature or API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants