Page MenuHomePhabricator

Enable and document use of Codex design tokens within MediaWiki
Closed, ResolvedPublic5 Estimated Story Points

Description

Now that the Codex design tokens package has been released, it can be used within MediaWiki. We need to do a few things to enable developers to start using them there, and to make sure the correct theme is used for each skin.

Use the skin variables system to distribute tokens

There's an existing system in MediaWiki core that lets skins override which file is used when 'mediawiki.skin.variables.less' is imported. Each skin provides its own file. There is a base file in core called mediawiki.skin.defaults.less that contains default values for each variable. Each skin's mediawiki.skin.variables.less file imports the defaults file and then overrides some or all of the variables with its own values. There are currently 36 skin variables defined. 26 of them have the same names as tokens in Codex, while 10 of them either have a different name in Codex or aren't in Codex at all.

We will distribute the tokens through this system, by making every Codex token a skin variable. In each skin's mediawiki.skin.variables.less, we will import the Codex tokens for the appropriate theme. In mediawiki.skin.defaults.less, we will define "neutral" values for each Codex token, and we'll add a unit test to verify that no tokens are missing.

In the future, we would like to add these "neutral" values as a theme in Codex, so that the defaults file can just import that theme, but that's out of scope for this task.

To avoid breaking anything, we need to be careful to change the value of any existing skin variables without intending to. For the purposes of this task, we should keep the values of all the existing skin variables the same, overriding Codex token values where necessary. Later, we will try to harmonize these and remove overrides where possible, but that's also out of scope for this task.

Concretely, mediawiki.skin.defaults.less will look like this:

@opacity-base: 1;
@opacity-medium: 0.67;
@opacity-low: 0.33;
@opacity-transparent: 0;
// etc etc for every Codex token

And a skin's mediawiki.skin.variables.less would look like this:

@import 'mediawiki.skin.defaults.less';

// Import Codex tokens for the appropriate theme: wikimedia-ui for 16px skins, wikimedia-ui-legacy for 14px skins
@import 'mediawiki.skin.codex-design-tokens/theme-wikimedia-ui-legacy.less';

// Override any token values where needed:
@opacity-icon-base: 1; // Codex: 0.87

Document usage

We should update the Codex page on mediawiki.org:

  • To import the Codex tokens in MW, do @import 'mediawiki.skin.variables.less';
  • Don't import from @wikimedia/codex-design-tokens
  • Add this to the "Differences between Codex documentation and MediaWiki usage" table

Acceptance criteria



Original task scope

Enable usage (✓ done)

Update: This was fixed in T326591

Currently, you should be able to import the tokens file relative to your location within MediaWiki. For example, from extensions/VueTest/resources/codex-demos/Sandbox.vue, I can do this:

<style lang="less">
@import ( reference ) '../../../../resources/lib/codex-design-tokens/theme-wikimedia-ui.less';

.cdx-sandbox {
    background-color: @background-color-progressive;
}
</style>

However, when I tried this, I got the following error in the browser console:

/w/load.php?lang=en&modules=ext.vueTest.codexdemo|jquery,oojs-ui-core,vue&skin=minerva&version=1nm17   Less_Exception_Compiler: error evaluating function `rgba` color functions take numbers as parameters index: 1350

This seems to be caused by the Less compiler not liking use of rgba() with calc inside, like this:

@background-color-quiet--hover: rgba( 0, 24, 73, calc( 7 / 255 ) );

Related Objects

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
AnneT raised the priority of this task from Medium to High.Jan 23 2023, 10:29 PM
AnneT updated the task description. (Show Details)

@Volker_E I've updated this task to cover the remaining work. Since we've already had lots of discussion on the topic in this task, I'd like to keep using it, rather than create a new one.

@Volker_E @Catrope I've triaged this as high priority, meaning we will complete it this month. Let me know if you don't think that's achievable!

Change 883975 had a related patch set uploaded (by Anne Tomasevich; author: Anne Tomasevich):

[mediawiki/extensions/VueTest@master] Use Codex design tokens on Sandbox page

https://gerrit.wikimedia.org/r/883975

Test wiki created on Patch demo by ATomasevich (WMF) using patch(es) linked to this task:
https://patchdemo.wmflabs.org/wikis/623ae5e5ff/w

Change 883975 merged by jenkins-bot:

[mediawiki/extensions/VueTest@master] Use Codex design tokens on Sandbox page

https://gerrit.wikimedia.org/r/883975

We already do this for things like the mediawiki.mixins file in Core. Users can just write @import ( reference ) 'mediawiki.mixins'; in any LESS file in any MW extension and it will work properly.

The way this is done is that the directory containing that file is added to the "import directories" when the LESS parser is first initialized. See here: https://github.com/wikimedia/less.php/blob/master/API.md#import-directories

We should do this for the design tokens in Codex; doing this would make it easier for people to use the tokens, and it would also make it easier for us to solve T328602: Enable use of Codex Less mixins inside of MediaWiki.

@Volker_E 's suggestion that we use the existing mediawiki.skin.variables.less system (which was part of my suggestion #2), led me to this idea: never mind, this is identical to my suggestion #1, but here are more details about how we'd implement it:

  • We add a file called codex-design-tokens.less (or whatever) in resources/src/mediawiki.less. This file imports the non-legacy Codex tokens, with something like @import '../../lib/codex-design-tokens/theme-wikimedia-ui.less';
  • In skins that need the legacy tokens (e.g Vector), we add a file in their skin's Less import path that overrides this file. For example, for Vector 2022 we'd add skins/Vector/resources/mediawiki.less/codex-design-tokens.less, which would contain something like @import '../../../../resources/lib/codex-design-tokens/theme-wikimedia-ui-legacy.less';
    • For old Vector, we'd also have to add skins/Vector/resources/mediawiki.less.legacy/codex-design-tokens.less with the same contents
    • This import path depends on the assumption that the skin is installed underneath the MW directory tree at skins/Vector. I think that's an OK assumption to make nowadays, but if it isn't, we could add resources/src/mediawiki.less/codex-design-tokens-legacy.less in core that imports the legacy tokens (using an internal-to-core relative path), and then Vector can import that with @import 'codex-design-tokens-legacy';
  • Developers who want to import the design tokens use @import 'codex-design-tokens';. This then imports the legacy tokens in Vector (or other skins that set up the same thing to point to the legacy tokens), and the non-legacy tokens in all other skins.

mediawiki.skin.variables is already providing us this functionality. Have updated the task description to expand Proposal 2. This way we could hop on top and import the right theme in the right skin's mediawiki.skin.variables.
For clarification, from my understanding we should

  1. import Codex tokens in Vector/Vector 2022/MinervaNeue in their skin.variables.less
  2. Add sane defaults (HTML oriented?) values for MediaWiki core in order to make skin overrides work
  3. (Also work with Timeless authors in order to improve their experience)

Developers would only have to @import 'mediawiki.skin.variables.less'; and leave it to the skin what themed tokens it provides. So leaving this extra codex-design-tokens import out.

With that we'd follow a MediaWiki way. The only minor disadvantages I'd see is, that outside MW we use a different import, and that Codex tokens would be hidden behind mediawiki.skin.variables, but I think that's acceptable and latter actually better long-term.

Why would we not provide the Codex tokens to all skins? Without that, I'm concerned that it would be difficult to rely on the tokens when writing MW/extension code. We could have MW provide default values for all the Codex tokens, but we'd have to update that file every time a new Codex token is added, which seems risky to me (if we forget, then code that uses a new token works in Vector/Minerva but not in other skins).

That comes back full circle to the story of MW branding.

In a perfect world we're having Codex themes, where one can't –or just with a warning disabled– add a token that is not in all themes.

Codex is going to be used in MW, and Codex components are going to be visible even in non-Vector/Minerva skins, for core features like the Recent Changes page. So I see Codex as the design system for MediaWiki as well, not just for Wikimedia installs of MediaWiki.

  • We add a file called codex-design-tokens.less (or whatever) in resources/src/mediawiki.less. This file imports the non-legacy Codex tokens, with something like @import '../../lib/codex-design-tokens/theme-wikimedia-ui.less';
  • In skins that need the legacy tokens (e.g Vector), we add a file in their skin's Less import path that overrides this file. For example, for Vector 2022 we'd add skins/Vector/resources/mediawiki.less/codex-design-tokens.less, which would contain something like @import '../../../../resources/lib/codex-design-tokens/theme-wikimedia-ui-legacy.less';
    • For old Vector, we'd also have to add skins/Vector/resources/mediawiki.less.legacy/codex-design-tokens.less with the same contents
    • This import path depends on the assumption that the skin is installed underneath the MW directory tree at skins/Vector. I think that's an OK assumption to make nowadays, but if it isn't, we could add resources/src/mediawiki.less/codex-design-tokens-legacy.less in core that imports the legacy tokens (using an internal-to-core relative path), and then Vector can import that with @import 'codex-design-tokens-legacy';
  • Developers who want to import the design tokens use @import 'codex-design-tokens';. This then imports the legacy tokens in Vector (or other skins that set up the same thing to point to the legacy tokens), and the non-legacy tokens in all other skins.

I like this approach, it seems pretty straight-forward to me. We could even provide two files – codex-design-tokens.less and codex-design-tokens-legacy.less, and then we could let developers choose which one to import when.

I'd love to get a patch up for this soon, so that we can close T328602: Enable use of Codex Less mixins inside of MediaWiki and improve the user-experience of working with these.

Codex is going to be used in MW, and Codex components are going to be visible even in non-Vector/Minerva skins, for core features like the Recent Changes page. So I see Codex as the design system for MediaWiki as well, not just for Wikimedia installs of MediaWiki.

I think there's a possible simple way to achieve for a default theme, a modern HTML browser stylesheet default interpretation, using most default colors, maybe with flatter button borders and some special cases like Tabs.
That would also provide the benefit of opening Codex up for non-Wikimedia usages more easily.

I think there's a possible simple way to achieve for a default theme, a modern HTML browser stylesheet default interpretation, using most default colors, maybe with flatter button borders and some special cases like Tabs.
That would also provide the benefit of opening Codex up for non-Wikimedia usages more easily.

I'm OK with us providing that, but in order for that to work for theming Codex components themselves, we also need that neutral theme in Codex itself. I suggest we defer that idea until we have a theme system in Codex (T296689), and use the current Codex theme by default in all skins until that time. I also would like the use of Codex tokens in MW not to be blocked by the creation of a neutral theme, even if it's just a series of Less variables outside of Codex.

Having looked at what is in mediawiki.skin.defaults.less, almost all of it is variables with the same names as our tokens. So I think a hybrid of #1 and #2 makes the most sense:

  • Add codex-design-tokens-wikimedia-ui.less in resources/src/mediawiki.less which imports the non-legacy Codex tokens. Also add codex-design-tokens-wikimedia-ui-legacy.less which imports the legacy tokens. Don't advertise these imports, they're only meant for internal use in MW core and skins. (I'm also proposing changing their names to include the theme names, for future proofing.)
  • In mediawiki.skin.defaults.less, add @import 'codex-design-tokens-wikimedia-ui'; . Remove the variables that are duplicates of Codex tokens (which is most of them).
  • In Vector and any other 14px-based skins that need the legacy tokens (Monobook?), add @import 'codex-design-tokens-wikimedia-ui-legacy'; to that skin's mediawiki.skin.variables.less file, and remove duplicated variables
  • In MinervaNeue and any other 16px-based skins that need the non-legacy tokens, we don't technically have to add @import 'codex-design-tokens-wikimedia-ui'; to their mediawiki.skin.variables.less because it's the default, but I suggest that we do it anyway for explicitness and future-proofing. We should also remove any duplicated variables.

In the future, when the neutral theme Volker proposes has been developed, we'd use that in mediawiki.skin.defaults.less instead, and we'd explicitly import the wikimedia-ui theme in any skins that need it (like MinervaNeue or Monobook) if we haven't already.

@Volker_E @egardner does this sound acceptable to both of you?

@Catrope I'm happy with this approach (especially because I don't foresee any blockers to doing this work now).

Also, now that we've moved to a solution where the issue of "different tokens for different skins" is pushed down into the mediawiki.skin.variables system instead of other kinds of magic, I think it might be worth returning to this thought:

I thought about how we can fix the import path (which could be part of this task, or we could spin it out separately if people want that), and I have some ideas for how we could make e.g. @import '@wikimedia/codex-design-tokens/theme-wikimedia-ui.less'; work. However, as Volker alludes to, that's not really what we want: we want to use different themes for different skins, so we don't want people to write code importing specific theme files.

We could use special handling for @import '@wikimedia/codex-design-tokens/blah.less' to make those imports work (even though they shouldn't be used outside of a few skin-specific files), or redirect them to 'mediawiki.skin.variables' instead so that doing the wrong thing magically works, or throw an error telling you not to try to import the tokens this way. We could also use special handling for imports from @wikimedia/codex-icons to make those work, which will be needed for the CSS-only icon mixin.

The way this would work is that we'd pass a function to the Less compiler's import dirs feature, which looks at whether the requested path starts with @wikimedia/codex-design-tokens (or @wikimedia/codex-icons) and if it does, looks for the requested file and returns the path to it. Something like:

$codexImportFunc = static function ( $path ) {
    $match = preg_match( '/^@wikimedia\/codex-design-tokens\/(.*)$/' ); // TODO also check for codex-icons
    if ( !$match ) {
        return;
    }
    $filePath = "$IP/resources/lib/codex-design-tokens/${match[1]}"; // TODO also try adding '.less' to this path
    if ( file_exists( $filePath ) ) {
        return [ Less_Environment::normalizePath( $filePath ), Less_Environment::normalizePath( dirname( $path ) ) ];
    }
};
$parser->SetLessImportPaths( [ $codexImportFunc ] );

I didn't realize that our Less compiler supported passing a function like this to the importPaths. But this exactly the kind of functionality I was hoping existed. This would allow us to continue writing our upstream Codex LESS files in a "standard" way (i.e., one that assumes you are using the files in a Node.js environment) while also un-breaking them inside of MW.

It sounds like we need to write patches for the following:

  • Add some property to skin.json inside Vector and maybe a one or two other skins to indicate that the legacy theme of Codex is to be used with that skin (we can set the non-legacy theme as the default for skins that don't specify)
  • Update https://gerrit.wikimedia.org/r/c/mediawiki/core/ /869852 to rely on skin.json properties instead of hard-coding various skins inside Resources.php
  • Update mediawiki.less and mediawiki.skin.defaults.less to import the appropriate Codex tokens
  • Update the mediawiki.skin.variables.less files in Vector, Minerva, and other skins to import the appropriate Codex tokens
  • Add some new configuration to our LESS parser so it can handle @wikimedia/codex-design-tokens style imports per your comment

Did I miss anything here? I guess we could probably consolidate all the changes we need in a given skin (add data to skin.json, update the skin variables LESS file, etc) into a single patch per skin.

This all sounds good to me, but I'd add the following:

  • In addition to handling imports from @wikimedia/codex-design-tokens, the function should also handle imports from @wikimedia/codex and @wikimedia/codex-icons (which we need for T328602), and/or should be set up to be extensible so new package name -> directory mappings can easily be added later
  • We need to decide how we want to handle imports from @wikimedia/codex-design-tokens: my code sketch would make them work, but these imports would almost always be the wrong thing to do. Unfortunately stylelint doesn't have a rule to prohibit imports matching a certain pattern. We have two other options for handling this in the import handler function:
    • When someone tries to import from the tokens package, give them the theme the skin wants, rather than the theme they asked for. This magically does the right thing but I think it's a bit too surprising and magical.
    • When someone tries to import from the tokens package, throw an error explaining what they should do instead (I prefer this option)
    • Don't handle imports from the tokens package at all (but still have the handler function for imports from the codex and icons packages), and let them error out naturally with a more confusing error message

Change 886929 had a related patch set uploaded (by Catrope; author: Catrope):

[mediawiki/core@master] [WIP] Import Codex tokens into mediawiki.skin.defaults.less

https://gerrit.wikimedia.org/r/886929

Change 886930 had a related patch set uploaded (by Catrope; author: Catrope):

[mediawiki/skins/Vector@master] [WIP] Import Codex legacy tokens into mediawiki.skin.variables.less

https://gerrit.wikimedia.org/r/886930

Change 886931 had a related patch set uploaded (by Catrope; author: Catrope):

[mediawiki/skins/MinervaNeue@master] [WIP] Remove unnecessary variables from mediawiki.skin.variables

https://gerrit.wikimedia.org/r/886931

egardner set the point value for this task to 5.Feb 7 2023, 9:40 PM

@Jdrewniak has brought up the [[ https://caniuse.com/css-initial-value | interesting idea of initial ]] as values for the default, unbranded theme. The issue right now is that initial false flat with IE 11 missing support. One could try if IE 11 would ignore the rules set as invalid and just falls back to the defaults when using initial.

Change 894130 had a related patch set uploaded (by Catrope; author: Catrope):

[mediawiki/core@master] mediawiki.skin.defaults.less: Provide mixin for importing Codex tokens

https://gerrit.wikimedia.org/r/894130

It's also valuable to ping @jackphoenix & @Isarra on Timeless that design tokens will come as central skinning architecture feature.

Merged T277615 in, as Codex tokens are the successor of WikimediaUI Base variables.

@Volker_E Are you happy with the neutral values in https://gerrit.wikimedia.org/r/c/mediawiki/core/ /886929/ , or does more work need to be done there?

Is there a MediaWiki page that documents the existing skin variables system (prior to the changes we are proposing for better Codex integration)?

In the future, we would like to add these "neutral" values as a theme in Codex, so that the defaults file can just import that theme, but that's out of scope for this task.

If this really is the better solution, should we consider just going ahead and doing this now?

Is there a MediaWiki page that documents the existing skin variables system (prior to the changes we are proposing for better Codex integration)?

Unfortunately this is poorly documented. Basically, the current skin variables system (prior to the proposed changes) works as follows:

  • In MW core, mediawiki.skin.defaults.less defines a small set of variables (I believe there are 38) and sets their default values.
  • These variables have token-like names, like background-color-base or color-link-external--visited. For some of these, there's a documentation comment explaining what these names mean, how they're supposed to be used, or why they have the values they do; for others, there isn't. There's no documentation for them outside of this file.
  • Each skin can provide a file called mediawiki.skin.variables.less, which imports the defaults file and overrides some of the variables with values appropriate for their skin. See legacy Vector's mediawiki.skin.variables.less for a simple example.
  • Less files in MediaWiki core or extensions can do @import 'mediawiki.skin.variables.less';. Through ResourceLoader magic(*), this imports the file provided by the current skin. The Less code can then use the skin variables to produce different values in different skins. For example content.links.less in MW core does a.new { color: @color-link-new; } which results in a.new { color: #d33; } in Vector-2022, a.new { color: #ba0000; } in legacy Vector, a.new { color: #c20; } in Monobook, etc.
    • (*) This works because the Less compiler is configured to resolve imports in the following order: first look in the current directory, then in the directory designated by the current skin (defined in skin,json, e.g. here for Vector), then in resources/src/mediawiki.less/. The skin puts its mediawiki.skin.variables.less file in its designated import directory, so that file is matched first. If the skin doesn't provide this file or doesn't set an import directory, the next place we look is resources/src/mediawiki.less/mediawiki.variables.less, and that file just imports the defaults file without overrides. The relevant code setting up these import paths is here and here.

Since skin variables are already a lot like tokens, and already behave the way we'd want tokens to behave (they can be changed by the skin), and there's a lot of overlap (many skin variables, e.g. background-color-base, have the same name as a Codex token, and they often have the same value too), this task proposes to essentially make every Codex token a skin variable.

In the future, we would like to add these "neutral" values as a theme in Codex, so that the defaults file can just import that theme, but that's out of scope for this task.

If this really is the better solution, should we consider just going ahead and doing this now?

That would be great, but unfortunately that's not that simple to do. Right now the hacky theme system in Codex can handle building the same token sets with different configurations: right now we build wikimedia-ui with basePxFontSize: 16 and wikimedia-ui-legacy with basePxFontSize: 14, but all the raw token values are the same, and the differences in the output are caused by the different configs. We don't yet have the infrastructure to build multiple themes with different token values. One of the surprising problems is that the way the .json files containing the tokens are named and structured don't lend themselves to this easily. We have theme-wikimedia-ui.json which contains the option tokens (all colors in the color palette, all pixel values you might want to use, etc; these are private and not exported, and have names like color-blue600) and then codex-base.json contains decision tokens (the ones that are actually exported) expressed in terms of option tokens (e.g. color-progressive is color-blue600). This separation of concepts makes sense, but the file names don't really correspond to that: it wouldn't necessarily make sense for a default theme just to slot in theme-default.json with different option tokens, and continue to use the same decision tokens from codex-base.json. The separation between option vs decision tokens isn't the same as the separation between shared vs theme-specific, but we currently pretend that it is. To put a second theme into Codex, we'd have to disentangle this.

Change 886929 merged by jenkins-bot:

[mediawiki/core@master] mediawiki.skin.defaults.less: Add neutral values for all Codex tokens

https://gerrit.wikimedia.org/r/886929

Change 894130 merged by jenkins-bot:

[mediawiki/core@master] mediawiki.skin: Provide wrapper files for importing Codex design tokens

https://gerrit.wikimedia.org/r/894130

Change 886930 merged by jenkins-bot:

[mediawiki/skins/Vector@master] Import Codex tokens into mediawiki.skin.variables.less

https://gerrit.wikimedia.org/r/886930

Change 886931 merged by jenkins-bot:

[mediawiki/skins/MinervaNeue@master] Import Codex tokens into mediawiki.skin.variables.less

https://gerrit.wikimedia.org/r/886931

I've updated the documentation on Codex mw.org site in order to resolve this and carved out Monobook, which already features a rudimentary skin variables file into T333888.

Test wiki on Patch demo by ATomasevich (WMF) using patch(es) linked to this task was deleted:

https://patchdemo.wmflabs.org/wikis/623ae5e5ff/w/