-
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
feature: Add ability for themes to configure font sizes; Extract fontSize logic from paragraph #6628
feature: Add ability for themes to configure font sizes; Extract fontSize logic from paragraph #6628
Conversation
e849f06
to
0b7ad83
Compare
cfda02b
to
57a5512
Compare
3660c0e
to
44fa0c4
Compare
44fa0c4
to
d188bd6
Compare
d188bd6
to
d50f581
Compare
de53519
to
4a4dddb
Compare
This has merge conflicts which need to be resolved. I'll review what's here in the meantime. |
core-blocks/paragraph/index.js
Outdated
@@ -251,7 +197,7 @@ class ParagraphBlock extends Component { | |||
fallbackBackgroundColor, | |||
fallbackTextColor, | |||
} } | |||
isLargeText={ fontSize >= 18 } | |||
isLargeText={ fontSize.size >= 18 } |
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.
Should this be built-in to the abstraction if "large" text (for accessibility compliancy) is a standard condition?
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.
Yes maybe we can add a property of fontSize to contrast checker where we only pass the fontSize and it decides if it is large or not, but as it is not directly related to changes here I will do that in a different PR.
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.
but as it is not directly related to changes here I will do that in a different PR.
Can you create a (ideally self-assigned) issue tracking this?
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.
For this cases where I feel a PR would be very small, I prefer to create a PR directly instead of writing an issue. The PR is available at #8059.
It ended up being a little bigger than what I was expecting initally because I needed to add additional test cases.
@@ -261,11 +207,12 @@ class ParagraphBlock extends Component { | |||
'has-drop-cap': dropCap, | |||
[ backgroundColor.class ]: backgroundColor.class, | |||
[ textColor.class ]: textColor.class, | |||
[ fontSize.class ]: fontSize.class, |
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.
My initial reaction without looking through to see the implementation: Why do we have both fontSize.class
and getFontSizeClass
?
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.
We use fontSize.class on the edit method because there it was already computed by the HOC. On the save function we don't use the HOC so we use the getFontSizeClass.
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.
Seems unnecessarily disjointed.
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 alternatives are:
- not passing class in the HOC and use getFontSizeClass in the edit method (when editing we know class is going to be required so not passing it already is just adding more work to the developers).
- -try to use the HOC in the save (it seems unnecessary as most of its functionality is not used).- Edited: I think this is not an option because the HOC requires context and setAttributes which we don't have on save.
It seems the current version is better than the alternative we have it is also the same that we are doing in the colors logic so a change in this mechanism will require an update to the existing color mechanism so we keep the consistency.
core-blocks/paragraph/index.js
Outdated
@@ -501,7 +449,7 @@ export const settings = { | |||
|
|||
const textClass = getColorClass( 'color', textColor ); | |||
const backgroundClass = getColorClass( 'background-color', backgroundColor ); | |||
const fontSizeClass = fontSize && `is-${ fontSize }-text`; | |||
const fontSizeClass = getFontSizeClass( 'font-size', fontSize ); |
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.
For what reason are we changing the class syntax now?
- Do we need to update
deprecated
reference to the old syntax? - There are still references to
is-small-text
, etc. incore-blocks/paragraph/style.scss
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 feel using has-large-font-size is more inline with the classes we use for colors, and I would like to change theme.
Block with the old syntax are automatically migrated as classes differences are ignored during validation.
We are keeping the old classes, to not break the existing paragraphs on the front end. I think the solution here is adding a global deprecation notice and keep the classes for two versions and I updated the code to include the notice.
* Returns a class based on fontSizeName. | ||
* | ||
* @param {string} fontSizeContext Context/place where the font size is being used, is used during class generation. | ||
* Normally the value is "font-size". |
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.
When would it ever not be font-size
? Does this even need to be an option?
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 would like to keep doors open, and maybe in the future we have a different kind of classes that need a different context e.g: relative-font-size. But its a fact that right now we don't use context at all so I will remove it for now in the future we can add it if needed.
* @return {Function} Higher-order component. | ||
*/ | ||
export default ( ...args ) => { | ||
const fontSizeMap = reduce( args, ( fontSizeAccumulator, arg ) => { |
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.
What are we assigning here? I've no idea on a glance of the code.
|
9f3dc30
to
661c5bd
Compare
Hi @aduth thank you a lot for your review. I think I addressed most points. The remaining is the usage of getFontSizeClass in save vs fontSize.class in edit. The only solution I see is removing the class from fontSize and using getFontSizeClass in edit too. As it takes more effort from the developer I personally prefer the current approach, but the difference is not huge and if you prefer to use getFontSizeClass in both places I will gladly change the code. Hi @chrisvanpatten the code and its documentation already used an array for fontSizes I missed the update on the PR description it is now corrected. |
@jorgefilipecosta Awesome, looks great :) Excited for this! |
661c5bd
to
6da7fe0
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.
I left a few comments. I have some concerns regarding the current implementation of withFontSizes
HOC. At first glance it seems like we are introducig additional logic which needs happen on everyt attribute change.
docs/extensibility/theme-support.md
Outdated
The font sizes are rendered on the font size picker in the order themes provide them. | ||
|
||
Themes are responsible for creating the classes that apply the correct font size styles. | ||
The class name is built appending 'has-', followed by the font size name *using* kebab case and ending in -font-size. |
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.
Nit: It should be reworderd to
ending with
-font-size
.
edit-post/index.js
Outdated
@@ -55,6 +55,13 @@ export function initializeEditor( id, postType, postId, settings, overridePost ) | |||
const reboot = reinitializeEditor.bind( null, postType, postId, target, settings, overridePost ); | |||
|
|||
// Global deprecations which cannot otherwise be injected into known usage. | |||
deprecated( 'class set is-small-text, ..., is-large-text', { | |||
version: '3.5', |
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.
It's 3.6 now.
editor/store/defaults.js
Outdated
name: __( 'larger' ), | ||
shortName: __( 'XL' ), | ||
size: 48, | ||
slug: 'larger', |
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.
Why not extra-large
? Similar to the example where we have extra-small
.
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 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't do much about it 🤷♂️
withSelect( ( select ) => { | ||
const settings = select( 'core/editor' ).getEditorSettings(); | ||
return { | ||
fontSizes: get( settings, [ 'fontSizes' ], DEFAULT_FONT_SIZES ), |
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.
We have fontSizes
provided in settings. Do we really need this default value?
https://github.com/WordPress/gutenberg/pull/6628/files#diff-6e3d39c654369a46e3c418427b3dbddbR9 - here we don't provide the default value. We should pick one approach.
} | ||
|
||
static getDerivedStateFromProps( { attributes, fontSizes }, previousState ) { | ||
return reduce( fontSizeNames, ( newState, fontSizeAttributeName ) => { |
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 method will be called every time any prop changes which means every time any attribute will change. Is there any way to opimize it to avoid doing all those computations where values change for attributes that have nothing to do with fonts?
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 @gziolo, I optimized the performance of this function. And now in the most common case where props unrelated to font size change we just compare the font size props with the previous version. Of course, the code is now a little bit more complex because of this optimization.
a5fd9f5
to
d0a4747
Compare
}; | ||
|
||
if ( ! some( fontSizeAttributeNames, didAttributesChange ) ) { | ||
return previousState; |
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.
It should return null
when no changes happened. See: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#new-lifecycle-getderivedstatefromprops.
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 new static
getDerivedStateFromProps
lifecycle is invoked after a component is instantiated as well as before it is re-rendered. It can return an object to update state, ornull
to indicate that the new props do not require any state updates.
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.
Corrected, I'm still mind programmed to return the same value when changes did not happen.
if ( ! some( fontSizeAttributeNames, didAttributesChange ) ) { | ||
return previousState; | ||
} | ||
|
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.
It seems like you could further simplify this code using filter
method;
const changedAttributes = filter( fontSizeAttributeNames, didAttributesChange );
if ( changedAttributes.length === 0 ) {
return null;
}
const newState = reduce( fontSizeAttributeNames, ( newStateAccumulator, customFontSizeAttributeName, fontSizeAttributeName ) => {
// the same logic but without if statement
}, {} );
return {
...previousState,
...newState,
};
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 did some code improvements following the logic you proposed. I was not able to use filter because filters always return an array but I used pickBy (is equivalent for the object case).
I kept the "some" verification, because creating a new object is still a non-trivial operation and doing the check allows us to on the most common case (font attributes did not change) do only comparisons.
6a35a9f
to
28b0e29
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.
I tested it locally and everything works great. I ensured that there are no unnecessary rerenders when changing non-font attributes. Awesome job with this one.
Feel free to merge as soon as you address my last comment.
/** | ||
* WordPress dependencies | ||
*/ | ||
import { createHigherOrderComponent, Component, compose } from '@wordpress/element'; |
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.
compose
and createHigherOrderComponent
should be imported from @wordpress/compose
- I see deprecation warning on the JS console.
63c2bf6
to
bd46fcd
Compare
…Size logic from paragraph
bd46fcd
to
42f25af
Compare
This PR depends on #6618.
It extracts the logic to manage font sizes in a similar way to what we used to abstract the color logic.
We refactored the styles, so they are not specific to paragraphs. Now, other blocks can make use of the same classes.
The class names were renamed from the format is-large-text to has-large-font-size, this makes the names consistent with the names used in color classes. The new name makes clear that the primary style set is the font-size.
Color sizes are now read from editor settings instead of being a constant in the paragraph block.
Themes can now configure the font sizes show in the editor.
Fixes: #5714
How has this been tested?
Verify changing font sizes in the paragraph still works as before, no noticeable changes are expected.
Verify we are back compatible with blocks using the old class names by pasting the following text in the code view:
Add the follwing code to a theme functions.php and verify that the size picker correctly reflects it:
Use Highlight Updates dev tools feature to verify no unnecessary re-renders happen when comparing to master.