Skip to content

Commit

Permalink
refactor(web-components): use adopted style sheets to set theme tokens (
Browse files Browse the repository at this point in the history
#31713)

Co-authored-by: Chris Holt <[email protected]>
  • Loading branch information
marchbox and chrisdholt authored Jun 27, 2024
1 parent 272dafa commit 896c9d3
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "refactor setTheme() to use adoptedStyleSheets",
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
6 changes: 6 additions & 0 deletions packages/web-components/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
}
},
"rules": {
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"no-extra-boolean-cast": "off",
"no-prototype-builtins": "off",
"no-fallthrough": "off",
Expand Down
4 changes: 4 additions & 0 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

```ts

/// <reference types="web" />

import type { Constructable } from '@microsoft/fast-element';
import { CSSDirective } from '@microsoft/fast-element';
import { Direction } from '@microsoft/fast-web-utilities';
Expand Down Expand Up @@ -3152,6 +3154,8 @@ class Text_2 extends FASTElement {
block: boolean;
// (undocumented)
connectedCallback(): void;
// (undocumented)
disconnectedCallback(): void;
// @internal
elementInternals: ElementInternals;
font?: TextFont;
Expand Down
2 changes: 1 addition & 1 deletion packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@
},
"devDependencies": {
"@microsoft/fast-element": "2.0.0-beta.26",
"@tensile-perf/web-components": "~0.2.0",
"@types/web": "^0.0.142",
"@storybook/html": "6.5.15",
"@tensile-perf/web-components": "~0.1.15",
"chromedriver": "^125.0.0"
},
"dependencies": {
Expand Down
30 changes: 30 additions & 0 deletions packages/web-components/src/theme/set-theme.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { measurePerformance, type TestRenderFunction } from '@tensile-perf/web-components';
import { teamsDarkTheme, teamsLightTheme, webDarkTheme, webLightTheme } from '@fluentui/tokens';

import { setTheme } from './set-theme.js';

const tests: Record<string, TestRenderFunction> = {
mount: ({ onComplete }) => {
const { startMeasure, endMeasure } = measurePerformance();

startMeasure();

// Newly set themes
setTheme(webLightTheme);
setTheme(webDarkTheme);
setTheme(teamsDarkTheme);
setTheme(teamsLightTheme);

// Cached themes
setTheme(webLightTheme);
setTheme(webDarkTheme);
setTheme(teamsDarkTheme);
setTheme(teamsLightTheme);

endMeasure();

onComplete();
},
};

export { tests };
16 changes: 16 additions & 0 deletions packages/web-components/src/theme/set-theme.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { html } from '@microsoft/fast-element';
import { teamsDarkTheme, teamsLightTheme, webDarkTheme, webLightTheme } from '@fluentui/tokens';

import { renderComponent } from '../helpers.stories.js';
import { setTheme } from './set-theme.js';

export default {
title: 'Theme/SetTheme',
};

export const SetTheme = renderComponent(html`
<fluent-button @click="${() => setTheme(webLightTheme)}">webLightTheme</fluent-button>
<fluent-button @click="${() => setTheme(webDarkTheme)}">webDarkTheme</fluent-button>
<fluent-button @click="${() => setTheme(teamsLightTheme)}">teamsLightTheme</fluent-button>
<fluent-button @click="${() => setTheme(teamsDarkTheme)}">teamsDarkTheme</fluent-button>
`);
56 changes: 37 additions & 19 deletions packages/web-components/src/theme/set-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,52 @@ import * as tokens from './design-tokens.js';

const tokenNames = Object.keys(tokens) as (keyof Theme)[];

const SUPPORTS_REGISTER_PROPERTY = 'registerProperty' in CSS;
const SUPPORTS_ADOPTED_STYLE_SHEETS = 'adoptedStyleSheets' in document;
const themeStyleSheet = new CSSStyleSheet();
const themeStyleTextMap = new Map<Theme, string>();

/**
* Sets the theme tokens on defaultNode.
* @param theme - Flat object of theme token values.
* @internal
*/
export const setTheme = (theme: Theme) => {
for (const t of tokenNames) {
let registered = false;

if ('registerProperty' in CSS) {
try {
CSS.registerProperty({
name: `--${t}`,
inherits: true,
initialValue: theme[t] as string,
});
registered = true;
} catch {
// Do nothing.
// Fallback to setting token custom properties on `<html>` element’s `style`
// attribute, only checking the support of `document.adoptedStyleSheets`
// here because it has broader support than `CSS.registerProperty()`, which
// is checked later.
if (!SUPPORTS_ADOPTED_STYLE_SHEETS) {
setThemeFor(document.documentElement, theme);
return;
}

if (!themeStyleTextMap.has(theme)) {
const tokenDeclarations: string[] = [];

for (const t of tokenNames) {
if (SUPPORTS_REGISTER_PROPERTY) {
try {
CSS.registerProperty({
name: `--${t}`,
inherits: true,
initialValue: theme[t] as string,
});
} catch {}
}
tokenDeclarations.push(`--${t}: ${theme[t] as string};`);
}

if (!registered) {
// TODO: Find a better way to update the values. Current approach adds
// lots of code to the `style` attribute on `<body>`. Maybe look into
// `document.adoptedStyleSheets`.
setThemeFor(document.body, theme);
}
themeStyleTextMap.set(theme, `html{${tokenDeclarations.join('')}}`);
}

if (!document.adoptedStyleSheets.includes(themeStyleSheet)) {
document.adoptedStyleSheets.push(themeStyleSheet);
} else {
// The very first call to `setTheme()` within a document doesn’t need to
// call `replaceSync()`, because `CSS.registerProperty()` above is
// sufficient to set the tokens.
themeStyleSheet.replaceSync(themeStyleTextMap.get(theme)!);
}
};

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4640,10 +4640,10 @@
dependencies:
"@tensile-perf/tools" "0.1.7"

"@tensile-perf/web-components@~0.1.15":
version "0.1.15"
resolved "https://registry.yarnpkg.com/@tensile-perf/web-components/-/web-components-0.1.15.tgz#95587b220d0b09b79b339da4e4f8694772fab91a"
integrity sha512-gawc20t7uvZyWUZOqBCA6/2Z7wEGECy2ytxe2/FMplDOuUj/CLXKoDY9mtS1dlo+6HjERuL8iP4IjdqURXo2UA==
"@tensile-perf/web-components@~0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@tensile-perf/web-components/-/web-components-0.2.0.tgz#355ac463a121656e68c0567f9c15accf19b61734"
integrity sha512-NEKH6d/2HrOJgW60E/oZ/O2D4vjzBv9xgSQmAz1cQnrEyQ/Odz/l3OWDwfEobcg8VHm6iODVoNAyvYAr4ESTKQ==
dependencies:
"@tensile-perf/runner" "0.4.0"
"@tensile-perf/tools" "0.1.7"
Expand Down

0 comments on commit 896c9d3

Please sign in to comment.