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

Add rudimentary theme support for Emotion components #36042

Closed
wants to merge 6 commits into from

Conversation

sarayourfriend
Copy link
Contributor

Description

Adds rudimantary theme support for Emotion components.

I've added two basic utilities for accessing the theme in Emotion styles:

  1. useTheme: this is a simple wrapper around Emotion's own useTheme function but will return the default theme if no theme has been provided. Emotion's ThemeContext is configured to return an empty object if no theme has been provided, so we can just check for the existence of the WordPressTheme specific properties (config and colors) to see if we have a custom theme or an Emotion theme. This is safe because createTheme is type safe and the @emotion/react Theme type has been extended using TypeScript's interface merging to require the config and colors values, so you cannot pass anything that doesn't match the WordPressTheme type to ThemeProvider's theme prop. For example <ThemeProvider theme={{ foo: 'bar' }}> would raise a type error. Unfortunately there is one flaw in this approach in that ThemeProvider's props type applies Partial to the Theme type meaning you could pass an empty object to the ThemeProvider. Luckily that would be safe as long as useTheme and safeTheme are used consistently.
  2. safeTheme: This is a guard function to run the conditional described above used by useTheme. The context for this function is inside of styled components interpolated functions. For example styled.span`color: ${props => safeTheme(props.theme).colors.black};` safeTheme ensures that you always have a WordPressTheme object, either the one provided to a ThemeProvider parent component or the default theme.

There are some trade offs to this approach, in particular with safeTheme. For one, we're running property checks every render on the object. For some styled components I suppose this could add a certain amount of runtime overhead. It would also be easy to accidentally forget to use safeTheme and access props.theme directly. I toyed with some ideas of how to prevent this but all of them ultimately ended in having to roll-our-own styled object so they're not really viable solutions. There's no way to monkey patch or hook into how styled provides the theme prop that I could tell, nor would I consider such a solution exactly "maintainable". safeTheme is probably the most future proof approach to this becuase it is, after all, just a function. Whatever method Emotion has in the future for providing the theme to a styled component for function interpolation, you'll always be able to pass it through safeTheme.

useTheme seems perfectly safe to me, the only risk being if someone accidentally used the original useTheme exported from @emotion/react. Unfortunately I don't think we can add an ESLint rule to restrict the import because we can't restrict specific imports, just broad imports from entire modules.

Hopefully we can catch those two things (accessing props.theme directly instead of through safeTheme and importing the wrong useTheme) in code reviews 🙂

Oh, I also added some stories to demonstrate the two ways of using the Emotion theme.

How has this been tested?

Run npm run storybook:dev and visit http://localhost:50240/?path=/story/components-experimental-theme--default.

Inspect the source code for the story and ensure that it makes sense and covers all the use cases. I'll also be adding unit tests shortly.

Types of changes

New feature

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • [N/A] My code follows the accessibility standards.
  • [N/A] I've tested my changes with keyboard and screen readers.
  • 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 (please manually search all *.native.js files for terms that need renaming or removal).

@github-actions
Copy link

github-actions bot commented Oct 28, 2021

Size Change: -2 B (0%)

Total Size: 1.08 MB

Filename Size Change
build/components/index.min.js 212 kB -2 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/index.min.js 6.2 kB
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-editor/index.min.js 135 kB
build/block-editor/style-rtl.css 14 kB
build/block-editor/style.css 14 kB
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 470 B
build/block-library/blocks/button/editor.css 470 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 B
build/block-library/blocks/buttons/editor-rtl.css 309 B
build/block-library/blocks/buttons/editor.css 309 B
build/block-library/blocks/buttons/style-rtl.css 317 B
build/block-library/blocks/buttons/style.css 317 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 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/cover/style-rtl.css 1.17 kB
build/block-library/blocks/cover/style.css 1.17 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/editor-rtl.css 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 502 B
build/block-library/blocks/image/style.css 505 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/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 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 642 B
build/block-library/blocks/navigation-link/editor.css 642 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 299 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.81 kB
build/block-library/blocks/navigation/editor.css 1.81 kB
build/block-library/blocks/navigation/style-rtl.css 1.71 kB
build/block-library/blocks/navigation/style.css 1.7 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/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/style-rtl.css 347 B
build/block-library/blocks/post-comments-form/style.css 347 B
build/block-library/blocks/post-comments/style-rtl.css 492 B
build/block-library/blocks/post-comments/style.css 493 B
build/block-library/blocks/post-content/style-rtl.css 56 B
build/block-library/blocks/post-content/style.css 56 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 396 B
build/block-library/blocks/post-featured-image/editor.css 397 B
build/block-library/blocks/post-featured-image/style-rtl.css 156 B
build/block-library/blocks/post-featured-image/style.css 156 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/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 223 B
build/block-library/blocks/quote/theme.css 226 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 397 B
build/block-library/blocks/search/style.css 398 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/editor-rtl.css 770 B
build/block-library/blocks/site-logo/editor.css 770 B
build/block-library/blocks/site-logo/style-rtl.css 165 B
build/block-library/blocks/site-logo/style.css 165 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 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 824 B
build/block-library/blocks/social-links/editor.css 823 B
build/block-library/blocks/social-links/style-rtl.css 1.32 kB
build/block-library/blocks/social-links/style.css 1.32 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 560 B
build/block-library/blocks/template-part/editor.css 559 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/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 815 B
build/block-library/common.css 812 B
build/block-library/editor-rtl.css 9.78 kB
build/block-library/editor.css 9.78 kB
build/block-library/index.min.js 154 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 10.5 kB
build/block-library/style.css 10.6 kB
build/block-library/theme-rtl.css 668 B
build/block-library/theme.css 673 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 46 kB
build/components/style-rtl.css 15.4 kB
build/components/style.css 15.4 kB
build/compose/index.min.js 10.9 kB
build/core-data/index.min.js 12.6 kB
build/customize-widgets/index.min.js 11.2 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.44 kB
build/edit-navigation/index.min.js 15.8 kB
build/edit-navigation/style-rtl.css 3.76 kB
build/edit-navigation/style.css 3.76 kB
build/edit-post/classic-rtl.css 492 B
build/edit-post/classic.css 494 B
build/edit-post/index.min.js 29.4 kB
build/edit-post/style-rtl.css 7.12 kB
build/edit-post/style.css 7.12 kB
build/edit-site/index.min.js 30.7 kB
build/edit-site/style-rtl.css 5.79 kB
build/edit-site/style.css 5.79 kB
build/edit-widgets/index.min.js 16.3 kB
build/edit-widgets/style-rtl.css 4.17 kB
build/edit-widgets/style.css 4.18 kB
build/editor/index.min.js 37.7 kB
build/editor/style-rtl.css 3.78 kB
build/editor/style.css 3.77 kB
build/element/index.min.js 3.21 kB
build/escape-html/index.min.js 517 B
build/format-library/index.min.js 6.34 kB
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.19 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.7 kB
build/server-side-render/index.min.js 1.52 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

@youknowriad
Copy link
Contributor

I think my main issue with this is that "theming" shouldn't be a "@wordpress/components" thing as we already have a more generic theming in WP (user profiles) that can apply cross packages.

@sarayourfriend
Copy link
Contributor Author

@youknowriad that's a good point... I wonder if there's a way to merge those approaches? One way or another @wordpress/components's Emotion components need to be able to access those user profile themes so they'd have to be exposed to the JavaScript in some way. Whatever mechanism that ends up being I guess you'd just want to replace the DEFAULT_THEME constant with a reference to that (or maybe a non-constant value that resolves to either some injected global user profile theme or the DEFAULT_THEME, or some combination of them, or more likely something that merges the user profile theme with the DEFAULT_THEME object).

The context for this is that someone is trying to use the SearchInput component in the big W menu, where it needs to be contextually in a "dark mode". Without hand overridding every single style (and having to maintain that every time a change to SearchInput is made) Emotion's theme support is the answer for this. It's even better than the situation with regular Sass where you'd have to maintain specific overrides for every single color based style on the SearchInput (which should be able to freely introduce or change where and how it applies colors without having to worry about how consumers are styling it).

@youknowriad
Copy link
Contributor

@sarayourfriend It makes sense to me to merge these two (a theme package or something like that that generates both CSS variables and potentially a react context if the variables are not enough for the components)

That said, I'm still not sure whether "Dark Mode" is a "theme" or an option of any theme. In other words whether components should support both dark and light mode for all themes.

@sarayourfriend
Copy link
Contributor Author

If there are user profile themes, then "dark mode" doesn't really correspond to anything specific. But there are contexts in the Gutenberg UI where a "dark mode" needs to be applied to components (like the big W navigation menu). That's where cascading ThemeProviders would come into effect. We'd essentially have a root theme provider that injects the user profile theme into the context that would be used in all use cases where there wasn't a contextually specific theme applied.

const baseTheme = createTheme( userProfileTheme );
const navigationTheme = createTheme( { colors: { black: 'white', white: 'black' } }, { isStatic: false } )
const App = () => (
  <>
    <ThemeProvider theme={ baseTheme }>
      <Header>
        <BigWMenu>
          <Button pressed={ true } onClick={ setMenuOpen }>W</Button>
          { menuOpen && (
            <ThemeProvider theme={ navigationTheme }>
              <Navigation />
            </ThemeProvider>
          ) }
        </BigWMenu>
      </Header>
      <RestOfTheApp />
    </ThemeProvider>
  </>
);

That would have to live somewhere like the edit-post package or something like that... which means exposing createTheme (at the very least) as a public API (or else preventing it from exporting to the global wp object 😕)

@sarayourfriend
Copy link
Contributor Author

sarayourfriend commented Oct 28, 2021

a theme package or something like that that generates both CSS variables and potentially a react context if the variables are not enough for the components

This seems like a good idea. As I recall we were ready to dive head first into use purely CSS variables but then realized that every CSS variable is technically a public API, which gave us pause. That's why we ended up opting for the singleton JS objects of CONFIG and COLORS. Switching to using all CSS variables seems like it would be great. A hybrid of the two, with some things being in the singleton objects and some being CSS variables seems worse from a dev ex perspective. It would be confusing to know when and where to look for certain variables, but is still technically workable.

The benefits of CSS variables over React context (which is all the Emotion theme stuff really is, for those following along who aren't in the loop) is that we get native browser performance and zero additional processing time for styles (aside from what the browser will do to resolve variables, but we can trust that will be fast).

Centralizing all theme variables, whether CSS or in-JS into a single package seems like a great idea. I know we were hesitant to introduce new packages in the past though, so not sure where we stand on that right now.

@mirka
Copy link
Member

mirka commented Oct 29, 2021

I don't feel fully equipped to assess this yet, so definitely waiting for @ciampo's input!

Switching to using all CSS variables seems like it would be great.

I'm leaning toward all underlying values being CSS variables, too. var(--unstable--wp-*) if we must. And these CSS variables would simply be aliased in the JS singletons so the type safety is there for consumers that want it.

Our underlying color system is not ready for a "public API" set of themable variables in a light/dark mode context though, with a bunch of shades of gray being used in an unsemantic way (gray[700] vs. ui.border). Out of all the things that are unstable in the current component system, consolidating/stabilizing the grays is maybe one of the most low risk, high impact things we can do for devex. It is pretty confusing to me now.

@ciampo
Copy link
Contributor

ciampo commented Nov 22, 2021

Thank you @sarayourfriend for experimenting with this approach!

I would also personally prefer using CSS variables for theming:

  • I like that it's an approach based 100% on web platform standards, which would satisfy the requirement expressed earlier in this conversation about cascading, overriding theme configs
  • as you said, it would definitely offer better rendering performance compared to a React Context-based approach
  • as @mirka mentioned, it would require us to first tidy up the configuration and the variables in the @wordpress/components package

As you also mentioned, though, we would need to come with a good strategy for which and how many variables to expose, how to name them, etc...

Finally, it's still not 100% clear to me how we should tie @wordpress/components theming with the overall WordPress/Gutengerg theming. In my mind:

  • the @wordpress/components package would be defining a library-specific theme, assuming that the package can be used also of this repo.
  • the block editor would then be responsible of setting the correct values for the package's theme when importing it.

@sarayourfriend
Copy link
Contributor Author

Closing this PR for lack of activity and because it seems like (I'm hoping) we'll take the CSS variable approach instead of using Emotion's theme context (which would be restrictive and silo theme styles into a specific, non-general, non-standard system). CSS Variables can also be used to easily theme "areas" of the app. It might be nice to create some kind of component that makes this easier through props and that can be type-checked, instead of relying on ad-hoc style objects. The component could have discrete props that would map directly to the variable name eventually passed to a style object.

@ciampo
Copy link
Contributor

ciampo commented Jan 31, 2022

it seems like (I'm hoping) we'll take the CSS variable approach

This is indeed the plan, and you already summed up the whys behind the decision very well (although we haven't started active work on it yet, mostly for lack of time/resources as we focused on Global Styles and the WordPress 5.9 release).

It might be nice to create some kind of component that makes this easier through props and that can be type-checked, instead of relying on ad-hoc style objects. The component could have discrete props that would map directly to the variable name eventually passed to a style object.

This is something that I didn't personally think of before, thank you for sharing it! We'll definitely consider this option too when working on this feature.

Finally, I just wanted to thank you for taking the initiative of exploring using Emotion's theme context for styling components — even if it's not the path that we'll end up taking, I believe it was still a very valuable exploration!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Component System WordPress component system [Package] Components /packages/components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants