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

Refactor how the Global Styles access and sets data #35264

Merged
merged 15 commits into from
Oct 7, 2021

Conversation

youknowriad
Copy link
Contributor

This PR is not working yet but the code is in a state good enough to showcase what I'm trying to achieve:

  • Centralize all Global Styles Data Access and Write in a global-styles/hooks file with no dependency to context or whatsoever. Ultimately we should be able to move the whole global-styles folder anywhere.
  • Unify the way we retrieve settings, styles and update them, all of the following are correct:
const [ color, setColor ] = useStyle( 'color.text' );
const [ color, setColor ] = useStyle( 'color.text', 'core/paragraph' );
const [ color, setColor ] = useStyle( 'color.text', 'core/paragraph', 'user' );
const [ color, setColor ] = useStyle( 'color.text', 'core/paragraph', 'base' );

const [ colorPalette, setColorPalette ] = useStyle( 'color.palette' );
const [ colorPalette, setColorPalette ] = useStyle( 'color.palette', 'core/paragraph' );
const [ colorPalette, setColorPalette ] = useStyle( 'color.palette', 'core/paragraph', 'user' );
const [ colorPalette, setColorPalette ] = useStyle( 'color.palette', 'core/paragraph', 'base' );
  • The different components to render the different panels only need to know the contextName (blockName or undefined for root)

Notes

  • Right now I think this is not working yet because useStyle need to make transformations to values (it can't return the stored value). The current methods to do that in editor/utils look a bit too complex to me. I could use some help there cc @jorgefilipecosta. Can we simplify these? should we move them to global-styles/utils

@youknowriad youknowriad added [Type] Code Quality Issues or PRs that relate to code quality Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Sep 30, 2021
@youknowriad youknowriad self-assigned this Sep 30, 2021
function useGlobalStylesUserConfig() {
const globalStylesId = useSelect( ( select ) => {
return select( editSiteStore ).getSettings()
.__experimentalGlobalStylesUserEntityId;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now this is how we retrieve the current global styles entity ID. This is not great, we shouldn't be depending on the a setting of editSite store, The proposed endpoint here would solve this #35141

'wp_global_styles',
'content',
globalStylesId
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way we retrieve user global styles (CPT endpoint) and base global styles (__experimentalGlobalStylesBaseStyles setting) is inconsistent, we should try to unify this. The proposed endpoint here would solve this #35141

} );

return supportKeys;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The new hooks useSetting and useStyle might be a bit less performant than the previous APIs in. global-styles-provider (which we should try to remove) because I'm not using "context" at all. I believe it's something we can improve later if we do notice issues, right now I wanted to focus on DevX

@github-actions
Copy link

github-actions bot commented Sep 30, 2021

Size Change: +319 B (0%)

Total Size: 1.07 MB

Filename Size Change
build/block-directory/index.min.js 6.2 kB +4 B (0%)
build/block-editor/index.min.js 134 kB +2 B (0%)
build/block-editor/style-rtl.css 13.9 kB -8 B (0%)
build/block-editor/style.css 13.9 kB -8 B (0%)
build/block-library/blocks/image/editor-rtl.css 731 B +3 B (0%)
build/block-library/blocks/image/editor.css 730 B +2 B (0%)
build/block-library/blocks/image/style-rtl.css 491 B +9 B (+2%)
build/block-library/blocks/image/style.css 494 B +7 B (+1%)
build/block-library/blocks/media-text/style-rtl.css 493 B +5 B (+1%)
build/block-library/blocks/media-text/style.css 490 B +5 B (+1%)
build/block-library/blocks/site-logo/editor-rtl.css 466 B +4 B (+1%)
build/block-library/blocks/site-logo/editor.css 467 B +3 B (+1%)
build/block-library/editor.css 9.71 kB -1 B (0%)
build/block-library/index.min.js 147 kB +138 B (0%)
build/block-library/style-rtl.css 10.4 kB -2 B (0%)
build/block-library/style.css 10.4 kB -2 B (0%)
build/components/index.min.js 214 kB +66 B (0%)
build/components/style-rtl.css 15.9 kB -3 B (0%)
build/components/style.css 15.9 kB -2 B (0%)
build/customize-widgets/index.min.js 11.2 kB +75 B (+1%)
build/edit-navigation/index.min.js 15.3 kB -3 B (0%)
build/edit-post/index.min.js 29.2 kB +15 B (0%)
build/edit-post/style-rtl.css 7.19 kB +4 B (0%)
build/edit-post/style.css 7.18 kB +3 B (0%)
build/edit-site/index.min.js 28.9 kB -75 B (0%)
build/edit-site/style-rtl.css 5.47 kB +41 B (+1%)
build/edit-site/style.css 5.47 kB +42 B (+1%)
build/editor/index.min.js 37.5 kB -4 B (0%)
build/format-library/index.min.js 5.93 kB -1 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 931 B
build/admin-manifest/index.min.js 1.09 kB
build/annotations/index.min.js 2.7 kB
build/api-fetch/index.min.js 2.21 kB
build/autop/index.min.js 2.08 kB
build/blob/index.min.js 459 B
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 58 B
build/block-library/blocks/audio/editor.css 58 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 474 B
build/block-library/blocks/button/editor.css 474 B
build/block-library/blocks/button/style-rtl.css 600 B
build/block-library/blocks/button/style.css 600 B
build/block-library/blocks/buttons/editor-rtl.css 315 B
build/block-library/blocks/buttons/editor.css 315 B
build/block-library/blocks/buttons/style-rtl.css 370 B
build/block-library/blocks/buttons/style.css 370 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 206 B
build/block-library/blocks/columns/editor.css 205 B
build/block-library/blocks/columns/style-rtl.css 497 B
build/block-library/blocks/columns/style.css 496 B
build/block-library/blocks/cover/editor-rtl.css 666 B
build/block-library/blocks/cover/editor.css 670 B
build/block-library/blocks/cover/style-rtl.css 1.23 kB
build/block-library/blocks/cover/style.css 1.23 kB
build/block-library/blocks/embed/editor-rtl.css 488 B
build/block-library/blocks/embed/editor.css 488 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 322 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 977 B
build/block-library/blocks/gallery/editor.css 982 B
build/block-library/blocks/gallery/style-rtl.css 1.6 kB
build/block-library/blocks/gallery/style.css 1.59 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/home-link/style-rtl.css 247 B
build/block-library/blocks/home-link/style.css 247 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B
build/block-library/blocks/latest-posts/editor.css 137 B
build/block-library/blocks/latest-posts/style-rtl.css 528 B
build/block-library/blocks/latest-posts/style.css 527 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 568 B
build/block-library/blocks/navigation-link/editor.css 570 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 300 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/style-rtl.css 195 B
build/block-library/blocks/navigation-submenu/style.css 195 B
build/block-library/blocks/navigation-submenu/view.min.js 343 B
build/block-library/blocks/navigation/editor-rtl.css 1.72 kB
build/block-library/blocks/navigation/editor.css 1.72 kB
build/block-library/blocks/navigation/style-rtl.css 1.62 kB
build/block-library/blocks/navigation/style.css 1.61 kB
build/block-library/blocks/navigation/view.min.js 2.74 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 198 B
build/block-library/blocks/page-list/style.css 198 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/editor-rtl.css 210 B
build/block-library/blocks/post-author/editor.css 210 B
build/block-library/blocks/post-author/style-rtl.css 182 B
build/block-library/blocks/post-author/style.css 181 B
build/block-library/blocks/post-comments-form/style-rtl.css 140 B
build/block-library/blocks/post-comments-form/style.css 140 B
build/block-library/blocks/post-comments/style-rtl.css 360 B
build/block-library/blocks/post-comments/style.css 359 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 398 B
build/block-library/blocks/post-featured-image/editor.css 398 B
build/block-library/blocks/post-featured-image/style-rtl.css 146 B
build/block-library/blocks/post-featured-image/style.css 146 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 391 B
build/block-library/blocks/post-template/style.css 392 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 60 B
build/block-library/blocks/post-title/style.css 60 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 378 B
build/block-library/blocks/pullquote/style.css 378 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 262 B
build/block-library/blocks/query-pagination/editor.css 255 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query-title/editor-rtl.css 85 B
build/block-library/blocks/query-title/editor.css 85 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 187 B
build/block-library/blocks/quote/style.css 187 B
build/block-library/blocks/quote/theme-rtl.css 220 B
build/block-library/blocks/quote/theme.css 222 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 374 B
build/block-library/blocks/search/style.css 375 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 250 B
build/block-library/blocks/separator/style.css 250 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/style-rtl.css 153 B
build/block-library/blocks/site-logo/style.css 153 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 165 B
build/block-library/blocks/social-link/editor.css 165 B
build/block-library/blocks/social-links/editor-rtl.css 812 B
build/block-library/blocks/social-links/editor.css 811 B
build/block-library/blocks/social-links/style-rtl.css 1.3 kB
build/block-library/blocks/social-links/style.css 1.3 kB
build/block-library/blocks/spacer/editor-rtl.css 307 B
build/block-library/blocks/spacer/editor.css 307 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 146 B
build/block-library/blocks/tag-cloud/style.css 146 B
build/block-library/blocks/template-part/editor-rtl.css 636 B
build/block-library/blocks/template-part/editor.css 635 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/editor-rtl.css 90 B
build/block-library/blocks/term-description/editor.css 90 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 853 B
build/block-library/common.css 849 B
build/block-library/editor-rtl.css 9.72 kB
build/block-library/reset-rtl.css 536 B
build/block-library/reset.css 536 B
build/block-library/theme-rtl.css 665 B
build/block-library/theme.css 669 B
build/block-serialization-default-parser/index.min.js 1.09 kB
build/block-serialization-spec-parser/index.min.js 2.79 kB
build/blocks/index.min.js 45.7 kB
build/compose/index.min.js 10.3 kB
build/core-data/index.min.js 12.4 kB
build/customize-widgets/style-rtl.css 1.5 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 614 B
build/data/index.min.js 7.1 kB
build/date/index.min.js 31.5 kB
build/deprecated/index.min.js 428 B
build/dom-ready/index.min.js 304 B
build/dom/index.min.js 4.45 kB
build/edit-navigation/style-rtl.css 3.74 kB
build/edit-navigation/style.css 3.74 kB
build/edit-post/classic-rtl.css 492 B
build/edit-post/classic.css 494 B
build/edit-widgets/index.min.js 15.7 kB
build/edit-widgets/style-rtl.css 4.1 kB
build/edit-widgets/style.css 4.1 kB
build/editor/style-rtl.css 3.76 kB
build/editor/style.css 3.75 kB
build/element/index.min.js 3.17 kB
build/escape-html/index.min.js 517 B
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 424 B
build/i18n/index.min.js 3.6 kB
build/is-shallow-equal/index.min.js 501 B
build/keyboard-shortcuts/index.min.js 1.72 kB
build/keycodes/index.min.js 1.3 kB
build/list-reusable-blocks/index.min.js 1.85 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.92 kB
build/notices/index.min.js 845 B
build/nux/index.min.js 2.03 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.83 kB
build/primitives/index.min.js 921 B
build/priority-queue/index.min.js 582 B
build/react-i18n/index.min.js 671 B
build/redux-routine/index.min.js 2.63 kB
build/reusable-blocks/index.min.js 2.28 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.6 kB
build/server-side-render/index.min.js 1.5 kB
build/shortcode/index.min.js 1.48 kB
build/token-list/index.min.js 562 B
build/url/index.min.js 1.74 kB
build/viewport/index.min.js 1.02 kB
build/warning/index.min.js 248 B
build/widgets/index.min.js 7.11 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

useHasBorderWidthControl( { supports, name } ),
useHasBorderColorControl( name ),
useHasBorderRadiusControl( name ),
useHasBorderStyleControl( name ),
Copy link
Member

Choose a reason for hiding this comment

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

Removing the supports property is a simple change that makes the code simpler 👍

: `styles.blocks.${ blockName }.${ path }`;

const setStyle = ( newValue ) => {
const newUserConfig = cloneDeep( userConfig );
Copy link
Member

Choose a reason for hiding this comment

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

I guess we could easily improve the performance and even code readability by using the immutableSet function that we already use on other parts of the codebase:

function immutableSet( object, path, value ) {
	return setWith( object ? clone( object ) : {}, path, value, clone );
}

return (
useSetting( 'border.customColor', name ) &&
useSetting( 'border.customColor', name )[ 0 ] &&
Copy link
Member

Choose a reason for hiding this comment

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

Having to use [ 0 ] when we just need to retrieve a value is the main downside of the new API, but I guess we will need to live with that.

Copy link
Contributor

@ciampo ciampo Oct 1, 2021

Choose a reason for hiding this comment

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

To improve readability, maybe we could switch to a slightly more verbose syntax?

// ...
const [ isEnabledInSettings ] = useSetting( 'border.customColor', name );
return isEnabledInSettings && supports.includes( 'borderColor' );

We'd then apply this syntax across all code changes in the PR

Copy link
Member

Choose a reason for hiding this comment

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

Yes although more verbose, that syntax is more clear.

@jorgefilipecosta
Copy link
Member

I wonder a bit about performance and how things will scale but the current solution is not perfect either. I think if we follow the endpoint approach and remove the need to serialize and unserialize things become a little better. If we don't use the endpoint we may use the transient mechanism on entities.

parentMenu={ '/blocks/' + name }
context={ blocks[ name ] }
/>
<ContextMenu parentMenu={ '/blocks/' + name } name={ name } />
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is ContextMenu named this way? Maybe we can find a name that explains a bit better what's in it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I struggled to find a good name for this component. (It's the global styles menu for a give context, a context can be "root" or a specific block, potentially other kind of context in the future)

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it! Maybe calling it GlobalStylesMenu would be a more clear name? Not big deal anyway.

@jorgefilipecosta
Copy link
Member

The API is nice and I think provides a better development experience. The fact that we are not using context may bring some challenges. I guess with the plans we have for themes where during theme switching we may alternate between styles of one and styles of the other we may have cases where we want to preview the styles of different themes. With context that is simple it is matter of wrapping the preview contexts with different global style providers I guess with hooks we can also wrap with different EntityProviders? I would love to leave the door open for this use cases.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

I wired the hooks to our variable mechanism, excluding backgrounds and gradients (that have a specific issue), everything seems to be working, and we use preset variables, etc.
But I think what we have now is not something we can follow. We are constantly on each hook usage serializing and unserializing the structure, doing merge operations between the base and user styles, and processing the user styles to add and remove their origin on presets.
We need to hold a structure somewhere that represents the result of the merge between base and user styles, that structure is important for the variable retrieving mechanism to work on (and that mechanism is called on every useStyle usage), and that structure can also be used to compile the styles.
Previously that structure was on the GlobalStylesProvider.
I see two possibilities.
The first is we keep a GlobalStylesProvider that contains the merge results. That provider is also responsible for using our entity mechanism to make changes. The useStyle, useSetting hooks would interact with the provider, our API would exactly be the same as on this PR, but the hooks would only work when wrapped in a provider. On that provider, we would keep a central object with the result of merging user and base styles that provider would also compile the stylesheet etc., similar to what we have now.
The other possibility is having the result of the merge between user and base as a transient object (similar to how blocks are transient) on the entity where we have the user styles. Given that the base styles are immutable, this approach may work well.

My changes are in commit 5852786 (#35264). Feel free to discard or apply any change to this commit, The objective of the commit is to show what we need to do to connect the hooks with our variable engine. The changes on file packages/edit-site/src/components/editor/utils.js are a port from PR #34178; because the functions there are better isolated, we should base future work on this version.

@youknowriad
Copy link
Contributor Author

The fact that we are not using context may bring some challenges

Using the context is not out of the question, For now, I wanted to keep this as simple as possible and avoid the "Provider" so that's what I removed the context, but it should be easy to bring back if we ever want to do it (without any change on the consumer components)

@youknowriad
Copy link
Contributor Author

But I think what we have now is not something we can follow. We are constantly on each hook usage serializing and unserializing the structure, doing merge operations between the base and user styles, and processing the user styles to add and remove their origin on presets.

Yes, I'm aware of that, but did you notice any real performance issues? My initial plan was to optimize for devx and iterate to improve performance... Can we have a metric to track maybe?

@youknowriad
Copy link
Contributor Author

I think if we noticed perf issues... the context solution is probably the simplest one to go for.

@@ -39,6 +79,16 @@ function useGlobalStylesUserConfig() {
let parsedConfig;
try {
parsedConfig = content ? JSON.parse( content ) : {};
// It is very important to verify if the flag isGlobalStylesUserThemeJSON is true.
// If it is not true the content was not escaped and is not safe.
if ( ! parsedConfig.isGlobalStylesUserThemeJSON ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand this? How can we retrieve an unsafe content at this point? Should we escape in the backend instead?

Copy link
Member

Choose a reason for hiding this comment

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

The WordPress escape filters don't provide information about which post type we are escaping etc, they just pass content to the filter, so we rely on the flag isGlobalStylesUserThemeJSON being present to know if we should escape the json or not. An attacker can easily bypass our escaping mechanism by not including the flag isGlobalStylesUserThemeJSON so we need on every usage to verify if the flag is present otherwise things may be unsafe.
If we have a specific endpoint that verification should be done there right now we don't have one so we need to keep this check on the client.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's still unclear to me, why not always escape?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we have a specific endpoint that verification should be done there right now we don't have one so we need to keep this check on the client.

I guess that's the missing piece for me, let's try to bring that endpoint after this PR. it seems it would solve a lot of complexity/issues.

Copy link
Member

@jorgefilipecosta jorgefilipecosta Oct 4, 2021

Choose a reason for hiding this comment

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

It's still unclear to me, why not always escape?

Because you just receive a string of content, you can not escape a given JSON or HTML or anything in the post content with the theme.json rules. That content may be a JSON from a plugin following totally different sets of rules for what should be escaped. The escape functions does not receive anything besides a string of content that flag indicates that content is a user theme.json.

@@ -105,10 +163,10 @@ export function useSetting( path, blockName, source = 'all' ) {
let result;
switch ( source ) {
case 'all':
result = get( userConfig, finalPath ) ?? getBaseSetting();
result = get( userConfig, finalPath, {} ).user ?? getBaseSetting();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change is confusing to me. Why do we have a .user subkey in the configs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems to be related to having .user as values for some configs, now that we can easily access all "user", "base" values directly maybe we can normalize all configs and drop this sunkey entirely.

Copy link
Member

Choose a reason for hiding this comment

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

I think we still need the subkey, base includes core and theme so we need the subkey to differentiate e.g: the UI will show both. So I guess we can normalize to always have subkeys as it is doing now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the UI will show

The UI can do

useSetting( 'something', context, 'all' ); // merged
useSetting( 'something', context, 'user' ); // user
useSetting( 'something', context, 'base' ); // base

so the object itself shouldn't have the keys. it's just adds complexity and it's not consistent across settings and styles (and even inside settings)

Copy link
Member

Choose a reason for hiding this comment

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

How would the UI differentiate between core and theme palettes? The base needs to have subjects for core and theme, the UI shows them differently.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It could be a different API call (query arg or something). Anyway, it feels like implementation detail for now but I feel it would simplify a lot of things if the "configs" had a consistent shape, regardless how they're retrieved and the arguments (merged, user, base,...).

Copy link
Member

Choose a reason for hiding this comment

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

it would simplify a lot of things if the "configs" had a consistent shape, regardless of how they're retrieved and the

I agree with that but I think we are being consistent if all the presets no matter where they come from are grouped by origin e.g: in base object we have { core: [], theme: [] }, in user we have { user: [] }, in the merged object we have { core: [], theme: [], user: [] }.

Grouping by origin we have a consistent shape where we can always work on.

This change is confusing to me. Why do we have a .user subkey in the configs?

The addition of the user subkey is done in order to improve consistency we make presets always have an origin subkey.

But I think I understand the point that in an user object having a user subkey is redundant it is also ok for me if the user object does not have the subkey as long as the base ( { core: [], theme: [] } ) and merged objects ( { core: [], theme: [], user: [] } ) have them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But I think I understand the point that in an user object having a user subkey is redundant it is also ok for me if the user object

Yes, this is the issue I have with this but it's not specific to the user object for me, it's for all objects. We should have a "core object", a "theme object", a "user object" and a "merged object" all with no subkeys.

Copy link
Member

Choose a reason for hiding this comment

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

We should have a "core object", a "theme object", a "user object" and a "merged object" all with no subkeys.

On the block editor, we are also going to show different color palettes per origin. So we thought it would be better to pass a single object to the block editor where presets are keyed by origin instead of passing multiple objects and that by origin subkey approach appeared. We can have multiple objects but in that case, we also need to make the block editor aware of the multiple objects, the block editor will never need anything from other sources besides the presets so the by origin approach seemed a better fit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it 👍 I guess there's drawbacks for each, let's keep it as is then and continue monitoring for the future.

@youknowriad
Copy link
Contributor Author

@jorgefilipecosta I think some of your changes might have broken the "blocks" panels.

@ciampo
Copy link
Contributor

ciampo commented Oct 5, 2021

I will leave the overall code review to @oandregal and @jorgefilipecosta , since I'm not very experienced in this area of the repo and its general architecture.

But I did some smoke testing and came across a few issues:

I wasn't able to add a custom color to the palette

global-styles-sidebar-custom-color.mp4

I wasn't able to change the text color of the Heading block

global-styles-heading-text-color.mp4

I haven't smoke tested every single combination of block/setting, so there may be more issue like this that I haven't found yet.

@youknowriad
Copy link
Contributor Author

@ciampo Both the issues are fixed for me, for the second one I'm not sure if it's a real issue or something about style specificity battle in your particular example.

@ciampo
Copy link
Contributor

ciampo commented Oct 6, 2021

Both the issues are fixed for me, for the second one I'm not sure if it's a real issue or something about style specificity battle in your particular example.

I confirm that the first issue is fixed.

Regarding the second issue (setting the text color of the Heading block), you were correct on it not being an issue. I believe the "conflict" comes from the fact that in my example, the headings were also links. I tried to create a separate heading without any linked text, and everything worked as expected

return [ resultWithFallback, setSetting ];
}

export function useStyle( path, blockName, source = 'all' ) {
Copy link
Member

Choose a reason for hiding this comment

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

What are your thoughts on accommodating elements in this API? I'm thinking about this use case: UI controls for elements.

It is something we'll add to the global styles sidebar soon. Potentially, we should also add it to the blocks UI panels (both in the block sidebar & the global sidebar): for example, at the moment, users can't update all the styles of link color despite the theme can. To support this, we'll need the ability to address elements individually. Elements can be at the top or within a block.

In this other conversation I was thinking along these lines:

useSetting( path, { block: 'blockName', element: 'elementName' }, source )

  • top level: useStyle( 'group.property' )
  • block level: useStyle( 'group.property', { block: 'block/name' } )
  • element at top-level: useStyle( 'group.property', { element: 'element/name' } )
  • element at block-level: useStyle( 'group.property', { block: 'block/name', element: 'element/name' } )

Whatever the choice to address this, I feel it should be the same in both the client and the server

Copy link
Member

Choose a reason for hiding this comment

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

I'd probably do the same for useSetting, although at the moment elements can't be in the settings. They may need that when/if they get added to the block UI panels. We may also have other contexts than blocks, so being an object will allow us to grow the API easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well right now you can do useStyle( 'elements.link.background' ) if you want to get/set the background of a link for instance. I agree it's not perfect yet and thinking of "elements" as "contexts" might make sense. These APIs are internal for now so there's room for iterations to see what would work well or not.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I know. This PR shouldn't be blocked by this. it's something we can iterate on. Though my concern with that approach is that it ties consumers to a specific theme.json shape, which we tried to avoid by separating "path" and "context" in the hooks/utilities.

];
};

export function useSetting( path, blockName, source = 'all' ) {
Copy link
Member

Choose a reason for hiding this comment

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

The useSetting hook on the block editor has a slightly different API the source is part of the path.
useSetting( 'color.palette' ) returns merged color palette.
useSetting( 'color.palette.user' ) returns user color palette.

We may need to consolidate these two approaches.

name
);
const [ userLinkColor ] = useStyle(
'elements.link.color.text',
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if elements should be treated as part of the path or if they should be something like a block in their own right. But I guess we can follow this approach for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, it's not clear. See #35264 (comment)

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

Hi @youknowriad,
I think the performance issue is noticeable even when no changes are applied and just by navigating around the panel.

I did this test in chrome with 6x CPU throttling ( I think many people have CPU even lower than my machine with throttling). The time it takes to open the color section is huge.

In this PR:

Oct-06-2021.16-01-29.mp4

In trunk:

Oct-06-2021.16-15-22.mp4

@jorgefilipecosta
Copy link
Member

I also notice some lag when moving the color picker around even without throttling (for example for a custom background color), the UI feels slow and takes some time to represent the choose background color. The trunk is not perfect on this either.

return (
<>
<ScreenHeader back="/" title={ __( 'Blocks' ) } />
{ visibleBlocks.map( ( block ) => (
{ getBlockTypes().map( ( block ) => (
Copy link
Member

@oandregal oandregal Oct 6, 2021

Choose a reason for hiding this comment

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

Reviewing this change, I've noticed that hasBlockMenuItem a few lines above is missing the hasBorderPanel || hasDimensionsPanel checks as well, so we won't list blocks that support only border or dimensions (or both).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's included in hasLayoutPanel so we should be fine I think.

Copy link
Member

@oandregal oandregal Oct 7, 2021

Choose a reason for hiding this comment

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

Oh, I missed that hasLayoutPanel is precisely the two I brought up. It's all good.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

When I apply a link color at the block level(paragraph link color) the color is not reflected on the editor but is reflected on the frontend. Inspecting the styles on the editor I see the style is not present. On trunk paragraph link color appears as expected.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

Thank you for all the work on this refactor 👍 I noticed an issue with the block level link color. I also think we should follow up and improve the performance with some throttling the slowness is noticeable just by moving between panels, and even without throttling, I notice some slowness while changing styles fast.
I think these are things we can work on after, provided the link color regression is solved I think we can merge this PR.

@youknowriad
Copy link
Contributor Author

@jorgefilipecosta I fixed the issue 👍 bad refactoring :)

For the performance side, is this something you want to try separately? (Maybe move the useGlobalStylesConfig call to a context provider). Also would be good if we can come up with some metric to track in the site editor perf tests.

@jorgefilipecosta
Copy link
Member

For the performance side, is this something you want to try separately?

yes it is something to look separately and not a blocker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Type] Code Quality Issues or PRs that relate to code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants