-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Add Columns template options, support InnerBlock templateOptions #16129
Conversation
@@ -90,6 +90,69 @@ const TEMPLATE = [ [ 'core/columns', {}, [ | |||
|
|||
The previous example creates an InnerBlocks area containing two columns one with an image and the other with a paragraph. | |||
|
|||
### `templateOptions` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I'm still uncertain about this prop. It seems like that something that could have easily been built in the columns block itself (not render InnerBlocks
until a template is chosen).
Is the idea here to "generalize" this behavior? Is this part of the goal of the original issue?
I can see value just trying to see if we really want to introduce it now, or maybe try to see if we need it in at least two blocks to introduce something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I'm still uncertain about this prop. It seems like that something that could have easily been built in the columns block itself (not render
InnerBlocks
until a template is chosen).Is the idea here to "generalize" this behavior? Is this part of the goal of the original issue?
From the original comment:
I'd appreciate feedback about whether this is a reasonable enhancement for InnerBlocks, or if we should consider shifting this responsibility back to the block component to handle (optionally enhancing Placeholder instead, or creating new components to render a set of Button choices).
From the related issue (and as evidenced by prior art in a number of plugins), there's a desire for a common behavior here in template selection. I worry about inconsistency if we start proposing that it be implemented ad hoc by each block.
As in the text above, I think there might be some way we can still put it on the block to implement, with sufficient component coverage (Placeholder
) to at least strongly encourage conforming to a consistent UI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I worry more about the growing number of props the InnerBlocks
could and will have in the future. Maybe a first step here could be to make the TemplatePicker
component, the sharable API, the same way we have MediaPlaceholder
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @aduth, sorry, I arrived late to the party (did not checked this PR sooner). I like the idea of providing a consistent UI for this scenario that we predict may become very common. I share the concern of increasing the number of props/responsibilities of InnerBlocks with @youknowriad.
What if we only add a new prop called placeholder to InnerBlocks (it just renders a placeholder when the template is null and no child blocks exist). Then we can expose a TemplatePlaceholder component that handles all the UI? (I think this version was exactly what @youknowriad suggested). It seems InnerBlocks should not receive a prop that is called when a template is selected and it may be good to extract that behavior. Even having a placeholder prop that receives an element rendered when the placeholder should be shown is an unnecessary prop but it is useful otherwise blocks would need to check the number of child blocks they have and conditionally render the placeholder.
🎉 This is an excellent start, @aduth!
Cool. We can leave as is for now. 👍
Ah yes — this should've been underlined in my comp. Good call. Lots of good discussion in that ticket. This is essentially a "Cancel" action, which WordPress typically handles visually as a link button. Depending on the outcome of #7532, if we decide to style it differently, we should also apply a similar style to the "Cancel" link in the image replacement flow.
For consistency, I do think it's important to have the Columns icon and label in there. The instructions are probably okay to be generic though.
Yep, definitely. This feels sort of like a new component to me, but it may be possible to just build upon what we use for the block styles (and for the block inserter buttons). We're thinking through adding a better "active" state to these in #15906 (comment), which would also come in handy here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, I feel we're almost there. Let's try to get this into the next release.
@aduth is AFK this week and in an attempt to land this, I'll be making some small tweaks here. |
|
||
class InnerBlocks extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
this.state = { | ||
templateInProcess: !! this.props.template, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The e2e tests show a failure because of this. I think it ensures the InnerBlocks don't focus the placeholder to avoid creating any extra block while the template is being processed (or something like that).
@jorgefilipecosta might now more, I think it would be good to document.
Right now, I'm going to restore it.
a1320df
to
0eced9d
Compare
@@ -124,15 +202,13 @@ export default withDispatch( ( dispatch, ownProps, registry ) => ( { | |||
setAttributes( { columns } ); | |||
|
|||
let innerBlocks = getBlocks( clientId ); | |||
if ( ! hasExplicitColumnWidths( innerBlocks ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a bug here in master if you try to change the number of columns from 2
to 4
(more than 1). This function only accounted for a single addition/removal.
icon: <SVG width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><Path fillRule="evenodd" clipRule="evenodd" d="M39 12C40.1046 12 41 12.8954 41 14V34C41 35.1046 40.1046 36 39 36H9C7.89543 36 7 35.1046 7 34V14C7 12.8954 7.89543 12 9 12H39ZM39 34V14H25V34H39ZM23 34H9V14H23V34Z" /></SVG>, | ||
template: [ | ||
[ 'core/column' ], | ||
[ 'core/column' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the explicit widths from the evenly distributed templates.
0eced9d
to
1a85e20
Compare
Love to see this! |
}, | ||
{ | ||
title: __( 'Two columns; one-third, two-thirds split' ), | ||
icon: <SVG width="48" height="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><Path fillRule="evenodd" clipRule="evenodd" d="M39 12C40.1046 12 41 12.8954 41 14V34C41 35.1046 40.1046 36 39 36H9C7.89543 36 7 35.1046 7 34V14C7 12.8954 7.89543 12 9 12H39ZM39 34V14H20V34H39ZM18 34H9V14H18V34Z" /></SVG>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we imagine a few more cases that go beyond layout columns here to ensure this can scale well? One that comes to mind is for #15623 — imagine adding the "Post" block and choosing from "title only", "title and date", "title and excerpt", "full post" shapes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, it also goes beyond the innerBlocks and could potentially be used to apply all kind of attributes.
I'm thinking we should create an issue about that describing the problem (block attributes sets) and maybe include one example in addition to the setup state of the columns block in order to come up with the best API for both use-cases. Do you have an example on mind with the current set of blocks?
Also, I can go ahead and create an issue unless you want to create it yourself to detail your thoughs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, these are other reasons to mark the APIs used as experimental for now until we cover the whole feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, these are other reasons to mark the APIs used as experimental for now until we cover the whole feature.
I think this is fair. Considering from the how this scales to other templates, and @mtias comment below at #16129 (comment), it occurs to me that this might not make sense as a prop of InnerBlocks
, but rather more similar to the block's registration of styles (both as a setting of the block, and with its own API registerBlockStyle
). That being said, doing so leaves open the question of how to configure options like skip links, callback function. Experimental props might be the best compromise for now (maybe in the future we still support it as a prop, but automatically provide it via context using the block's settings).
migrate( attributes, innerBlocks ) { | ||
attributes = { | ||
...attributes, | ||
columns: innerBlocks.length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we've dropped the columns
attribute, this should no longer apply?
Aside my latest comment, and with future consideration of Dev Note, I think this looks good to land for an initial iteration. Thanks for taking it over in my absence. Given the discussion, I think there's lots of directions we may take with how "selection" applies (both as inner blocks and as a block's own attributes) or is reused (post layouts, etc). Implementing the props as experimental for this iteration should allow us some flexibility for how those iterations are explored. |
While the implementation here has since changed, the general problem is pretty well-summarized/tracked at #8119 (or, at least, a solution there should provide the necessary tools to avoid these situations for synchronous block updates as well). |
7d8ccc7
to
02c6c04
Compare
02c6c04
to
409e48c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -26,7 +26,7 @@ function gutenberg_test_templates_register_book_type() { | |||
array( 'core/quote' ), | |||
array( | |||
'core/columns', | |||
array(), | |||
array( 'columns' => 2 ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be here, should it?
(I don't think it's too problematic for merge, if at least the tests still pass)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, it's probably ignored.
Thank you!:) |
Closes #15662
Partially addresses #15663
This pull request seeks to enhance the
InnerBlocks
component to allow developers to specify a set of template options to allow the user to select from upon inserting the block. As demonstration, this is implemented into the Columns block, allowing the user to select from a number of predefined columns layouts.Work In Progress:
InnerBlocks
templateInProcess
state, removed hereImplementation Notes:
There's a question here about if or how we preserve the current default columns count (2 columns). The absence of a columns serves as a useful indicator for considering the block in a placeholder state, similar to the Image block using the absence of its
url
attribute to determine whether it is in a placeholder state. This has obvious complications for existing content which assumes the default of 2 columns. Included here is a deprecation which is intended to transition a block which assumes the default to one which defines it explicitly. There is some awkwardness here in the fact that if a user chooses to skip template selection (the "Skip" button), we still "default" to 2 columns.Note below in "Design Notes" the consideration about customizing labels. I'd appreciate feedback about whether this is a reasonable enhancement for
InnerBlocks
, or if we should consider shifting this responsibility back to the block component to handle (optionally enhancing Placeholder instead, or creating new components to render a set of Button choices).Design Notes:
There are a few notable differences from the concepts as presented by @kjellr at #15663 (comment). For the most part, these differences come down to consequences of consistency and in considering the technical requirements of these interfaces (e.g. labels specific to "Columns" block vs. generic labels).
Placeholder
styling. If we want more padding, we should consider if it should be applied to all instances ofPlaceholder
.<Button isLink />
styling. If we want no underline, we should again consider if it should apply to all link-styled buttons.templateSelectionPlaceholderProps
object prop). At that point, it begs the question whether this ought to be a common feature ofInnerBlocks
vs. custom implemented in each block vs. enhancing thePlaceholder
component to better support a set of buttons.IconButton
component, at least as sharing the same semantic purpose. The ones in the concept appear quite similar to those found in the inserter menu and in the block transforms menu, and subsequent screenshots of the concept display similar buttons in the sidebar.IconButton
to reuse across these multitude of use-cases.