-
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
Display heading levels dynamically in Heading Options when Heading block is selected #14689
Conversation
@WordPress/gutenberg-core that's a very interesting proposal. On one side, I like how it automates the handling of the heading levels. On the other hand, I don't think that updating the list of selectors is a good idea as it might invalidate Heading block in the previously stored blocks if they used removed However, this PR gave me an idea that in addition to values of level: {
type: 'number',
default: 2,
+ enum: [ 2, 3, 4 ],
}, And use |
@gziolo Thanks for your response. Whether updating the list of headings is a good idea or not, it's more up to a project specs. In our case, we need to prevent editors to use H1, H5 and H6 in their posts for consistency and SEO matters. I know that this change could invalidate the content of the block but that's something we're having in mind. On the other hand, changing attributes by using That said, I've updated the PR with your recommendation about the |
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 like the implementation here in rendering based on the component's own enum
value. The filter mechanic is maybe not the nicest experience for extending, but it seems like the best option currently available. It could probably do with some complementing documentation / tutorial for customizing the block options.
However, as I consider it more, it's worth highlighting that enum
validation is not currently implemented in the browser (it is for server block registration). I fear that if this were to become implemented and values outside the limited enum
range were to become rejected, we'd face the same issue of previous block content being marked as invalidated.
} ) { | ||
const { align, content, level, placeholder } = attributes; | ||
const tagName = 'h' + level; | ||
|
||
const BlockControlsLevelsRange = ( levelChoices.length <= 3 ) ? |
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 should be camel-cased with an initial lower-case letter.
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.
Fixed
|
||
const BlockControlsLevelsRange = ( levelChoices.length <= 3 ) ? | ||
levelChoices : | ||
levelChoices.slice( 1, 4 ); // |
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'm not sure I'm following what the logic is here as far as the second, third, fourth, and fifth level choice options being significant. I sense you'd considered to add an inline comment but forgot to complete it?
Taking a guess with the default options, is it mostly about limiting to a select few common options, and omitting H1
specifically? In that case it seems more accurate to express as something like take( without( levelChoices, [ 1 ] ), 3 )
(Array#slice
can work just as well)
https://lodash.com/docs/4.17.11#take
https://lodash.com/docs/4.17.11#without
This also seems like it would help avoid having to test length <= 3
and just have a single consistent expression for computing the level choices.
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.
@aduth What I'm trying to do here is to replicate the previous behavior in the BlockControls options (not the sidebar). Right now, it displays only 3 headings: H2, H3 and H4. So if the levels list contains 3 or less options, it will display all of them, otherwise, slice the array and display 3 elements starting by the second one. I think using Lodash for that would be an overkill for such a simple operation.
</BlockControls> | ||
<InspectorControls> | ||
<PanelBody title={ __( 'Heading Settings' ) }> | ||
<p>{ __( 'Level' ) }</p> | ||
<HeadingToolbar minLevel={ 1 } maxLevel={ 7 } selectedLevel={ level } onChange={ ( newLevel ) => setAttributes( { level: newLevel } ) } /> |
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.
Did the default max level change from 7 to 6? And if so, why?
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.
See my comment here: https://github.com/WordPress/gutenberg/pull/14689/files#r271809189
); | ||
|
||
return { | ||
levelChoices, |
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 implementation will result in poor performance, at least when using the fallback empty array value, due to a combination of factors that (a) withSelect
is called for any change in application state, (b) you are producing a new array reference value ([] !== []
), and (c) a render is forced for any new prop value reference.
As long as a block types attributes.level.enum
remains a consistent reference (I think it's safe to assume), then a simple adjustment here may be to move the array default to the top of the file as a shared constant:
const DEFAULT_LEVEL_CHOICES = [ 1, 2, 3, 4, 5, 6, 7 ];
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.
Thanks! Great point. It's fixed now.
Just a side comment: The previous maxLevel
was set to 7 but that's confusing, HeadingToolbar
component makes use of Lodash range
https://lodash.com/docs/4.17.11#range and when it generates the range, the second argument passed to the function (7) is not included in the range. That's why we only need 1-6 as default values.
Thanks @aduth, I've pushed some changes.
I don't know if I'm following you 100% but I'll use an example:
Depending on how |
Yeah, that's the crux of it. We don't have the validation today for blocks registered in the browser. The default behavior for server-registered blocks using It's also increasingly seeming like something which should be aligned with the server validation sooner than later, given the potential for unintended block invalidations (though |
@aduth This can wait a bit more if you need so and test with that |
I think a fallback to a default value would be expected, if one is specified (this occurs server-side). I sense it's still an issue however in how the block validation works: Following the same example, if the default was |
@aduth That's correct. I don't really know how you handle these cases in Gutenberg, do you think that this case would be more of a developer responsibility or should we use another approach? |
To give some update so this doesn't stagnate: I don't think we can realistically leverage extending a block's |
I opened #15450 and linked this PR to ensure it is included in the discussion about |
@jorgefilipecosta and @nosolosw – any thoughts on how this sort of block specific attributes could be controlled with Global Styles or block editor features mechanics? |
If we see heading levels as block specific attribute, I don't think it should be a setting present in global styles/ block editor features. But if we see heading levels as a global setting that may be used by multiple blocks (heading block, site title block, post title, a custom heading implementation, etc), I think it may make sense to add the setting to Global Styles, similarly to how we have a drop cap setting. |
Description
public_html/wp-content/plugins/gutenberg/packages/block-library/src/heading/edit.js
now parses the heading selector choices into numbers and dynamically display them as selector options in sidebar and toolbar.public_html/wp-content/plugins/gutenberg/packages/block-library/src/heading/heading-toolbar.js
(HeadingToolbar
component) now accepts another parameter,levelsRange
, that allows passing a list of levels instead of min/max values. This would allow passing heading lists like H1, H3, H5... instead of the common H1, H2, H3, H4, H5.levelsRange
prop is preset, theminLevel
and themaxLevel
props will be ignored. I couldn't come up with another solution to keep backward compatibility for other developers that could be using this component in their own JS.How has this been tested?
And you should see just a subset of headings to choose:
Types of changes
New feature (non-breaking change which adds functionality)
Checklist: