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

feat(web-components): enabling setting theme on an individual element and unsetting themes #31973

Merged
merged 67 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
e5d7891
refactor setTheme() for setting theme on elements
marchbox Jul 8, 2024
3bff695
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 8, 2024
7ecf93d
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 9, 2024
1bcd739
reorg the code
marchbox Jul 9, 2024
964b29d
set local themes
marchbox Jul 9, 2024
41ca177
fix firefox bug
marchbox Jul 9, 2024
c20be72
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 10, 2024
cbc6471
improve set theme story
marchbox Jul 10, 2024
694d794
fix story
marchbox Jul 10, 2024
1af991d
fix safari scope bug
marchbox Jul 10, 2024
1f3afa9
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 10, 2024
66a3a60
update api report
marchbox Jul 10, 2024
d22c5b4
check themeable element
marchbox Jul 11, 2024
24a1a6a
add change file
marchbox Jul 11, 2024
4b6b1a6
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 11, 2024
b9f3770
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 11, 2024
42a880b
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 15, 2024
3b2f458
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 16, 2024
8761294
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 18, 2024
ded57a8
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 19, 2024
092400c
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 20, 2024
54d056f
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 23, 2024
2aa86bd
Merge branch 'master' of github.com:marchbox/fluentui into users/mach…
marchbox Jul 24, 2024
0cc1a90
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 24, 2024
c25f436
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 26, 2024
651b7e7
update Theme type in story
marchbox Jul 26, 2024
110e03e
wip: add test
marchbox Jul 28, 2024
bdbb26e
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 29, 2024
a37ed82
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 29, 2024
cd2e084
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 30, 2024
c0f0348
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 30, 2024
8e064b3
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Jul 31, 2024
35e358f
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Aug 1, 2024
318eb26
fix formatting
marchbox Aug 1, 2024
3cc0a90
Merge branch 'users/machi/setthemefor' of github.com:marchbox/fluentu…
marchbox Aug 1, 2024
f3fa397
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Aug 2, 2024
9284219
Merge branch 'master' of github.com:marchbox/fluentui into users/mach…
marchbox Aug 5, 2024
3933664
clean up set theme in storybook and playwright
marchbox Aug 5, 2024
2f090a2
fix formatting
marchbox Aug 5, 2024
c915770
unset theme when css scope is not supported
marchbox Aug 6, 2024
97cb258
Merge branch 'microsoft:master' into users/machi/setthemefor
marchbox Aug 6, 2024
64ff7ba
use removeProperty instead
marchbox Aug 6, 2024
f0b2565
Merge branch 'master' of github.com:marchbox/fluentui into users/mach…
marchbox Aug 13, 2024
1b9c5d0
revert unwanted change
marchbox Aug 13, 2024
be32c93
improve the stories
marchbox Aug 13, 2024
2ec4205
add tests
marchbox Aug 13, 2024
8a6eb15
fix formatting
marchbox Aug 13, 2024
5cd9fa2
enable tests in other engines and fix issues
marchbox Aug 14, 2024
587923b
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 14, 2024
dac52c8
fix formatting
marchbox Aug 14, 2024
f1802ac
remove use of CSS.registerProperty()
marchbox Aug 14, 2024
d461235
allow unset global theme in story
marchbox Aug 14, 2024
28b6bed
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 14, 2024
d9b6f83
trim margins
marchbox Aug 14, 2024
b133052
fix formatting
marchbox Aug 14, 2024
84fe643
add argument doc
marchbox Aug 14, 2024
2a92a62
add more test
marchbox Aug 15, 2024
d82f6a9
update api report
marchbox Aug 15, 2024
c679aa5
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 15, 2024
aeb64b4
add perf tests for setting themes on light and shadow DOM
marchbox Aug 15, 2024
963ad6c
fix formatting
marchbox Aug 15, 2024
b1fefdd
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 15, 2024
a6848cb
update change file as per feedback
marchbox Aug 16, 2024
5d6e374
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 16, 2024
f148920
revert accidental changes
marchbox Aug 16, 2024
f4e65e8
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 16, 2024
94fc7b4
Merge branch 'master' into users/machi/setthemefor
marchbox Aug 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
marchbox marked this conversation as resolved.
Show resolved Hide resolved
marchbox marked this conversation as resolved.
Show resolved Hide resolved
"type": "prerelease",
"comment": "feat(web-components): enabling setting theme on an individual element and unsetting themes",
marchbox marked this conversation as resolved.
Show resolved Hide resolved
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
17 changes: 14 additions & 3 deletions packages/web-components/.storybook/preview.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import { switchTheme } from '../public/theme-switch.js';
import { teamsDarkTheme, teamsLightTheme, webDarkTheme, webLightTheme } from '@fluentui/tokens';
import webcomponentsTheme from './theme.mjs';
import { setTheme } from '../src/theme/set-theme.js';

import '../src/index-rollup.js';
import './docs-root.css';

const themes = {
'web-light': webLightTheme,
'web-dark': webDarkTheme,
'teams-light': teamsLightTheme,
'teams-dark': teamsDarkTheme,
};

function changeTheme(/** @type {Event} */ e) {
switchTheme(/** @type {Parameters<typeof switchTheme>[number]} */ (/** @type {HTMLInputElement}*/ (e.target).value));
setTheme(themes[/** @type {keyof themes} */ (/** @type {HTMLInputElement}*/ (e.target).value)]);
}

// This is needed in Playwright.
Object.defineProperty(window, 'setTheme', { value: setTheme });

document.getElementById('theme-switch')?.addEventListener('change', changeTheme, false);
switchTheme('web-light');
setTheme(themes['web-light']);

export const parameters = {
layout: 'fullscreen',
Expand Down
31 changes: 27 additions & 4 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export const accordionStyles: ElementStyles;
export const accordionTemplate: ElementViewTemplate<Accordion>;

// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag
// Warning: (ae-forgotten-export) The symbol "BaseAnchor" needs to be exported by the entry point index.d.ts
// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "AnchorButton" because one of its declarations is marked as @internal
//
// @public
Expand Down Expand Up @@ -451,6 +450,30 @@ export class BaseAccordionItem extends FASTElement {
id: string;
}

// @public
export class BaseAnchor extends FASTElement {
constructor();
// @internal
clickHandler(e: PointerEvent): boolean;
// (undocumented)
connectedCallback(): void;
// (undocumented)
disconnectedCallback(): void;
download?: string;
// @internal
elementInternals: ElementInternals;
// @internal
handleChange(source: any, propertyName: string): void;
href?: string;
hreflang?: string;
keydownHandler(e: KeyboardEvent): boolean | void;
ping?: string;
referrerpolicy?: string;
rel: string;
target?: AnchorTarget;
type?: string;
}

// @public
export class BaseAvatar extends FASTElement {
constructor();
Expand Down Expand Up @@ -3033,12 +3056,12 @@ export const roleForMenuItem: {
// Warning: (ae-internal-missing-underscore) The name "setTheme" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export const setTheme: (theme: Theme) => void;
export function setTheme(theme: Theme | null, node?: Document | HTMLElement): void;

// Warning: (ae-internal-missing-underscore) The name "setThemeFor" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal (undocumented)
export const setThemeFor: (element: HTMLElement, theme: Theme) => void;
// @internal @deprecated (undocumented)
export function setThemeFor(element: HTMLElement, theme: Theme | null): void;

// @public
export const shadow16 = "var(--shadow16)";
Expand Down
13 changes: 0 additions & 13 deletions packages/web-components/public/theme-switch.ts

This file was deleted.

42 changes: 42 additions & 0 deletions packages/web-components/src/theme/set-theme.spec.ts
davatron5000 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { expect, test } from '@playwright/test';
import { fixtureURL } from '../helpers.tests.js';

import type { setTheme as _setTheme, Theme } from './set-theme.js';

const theme1: Theme = {
foo: 'foo1',
bar: 'bar1',
};

const theme2: Theme = {
foo: 'foo2',
bar: 'bar2',
};

declare global {
interface Window {
setTheme: typeof _setTheme;
}
}

test.describe('setTheme()', () => {
test.beforeEach(async ({ page }) => {
await page.goto(fixtureURL('theme-settheme--set-theme'));
await page.setContent(`<div></div>`);
});

test('should set tokens with the correct custom property values', async ({ page }) => {
await page.evaluate(theme => {
window.setTheme(theme);
}, theme1);
const body = page.locator('body');

await expect(body).toHaveCSS('--foo', 'foo1');

await page.evaluate(theme => {
window.setTheme(theme);
}, theme2);

await expect(body).toHaveCSS('--foo', 'foo2');
});
});
186 changes: 143 additions & 43 deletions packages/web-components/src/theme/set-theme.stories.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import { html } from '@microsoft/fast-element';
import { html, repeat, when } from '@microsoft/fast-element';
import { teamsDarkTheme, teamsLightTheme, webDarkTheme, webLightTheme } from '@fluentui/tokens';

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

const fluentTheme: Record<string, Theme> = {
webLightTheme,
webDarkTheme,
teamsLightTheme,
teamsDarkTheme,
};
const themes: Map<string, Theme | null> = new Map([
['web-light', webLightTheme],
['web-dark', webDarkTheme],
['team-light', teamsLightTheme],
['team-dark', teamsDarkTheme],
['unset', null],
]);

function updateTheme(evt: Event, type = 'global') {
const { value } = evt.target as HTMLSelectElement;

if (themes.has(value) !== undefined) {
switch (type) {
case 'global':
setTheme(themes.get(value)!);
break;
case 'local':
setTheme(themes.get(value)!, document.querySelector('.local') as HTMLElement);
break;
case 'shadow':
setTheme(themes.get(value)!, document.querySelector('.shadow') as HTMLElement);
break;
}
}
}

const themeDescription = `
Flat object of theme tokens. Each object entry must follow these rules:
Expand All @@ -26,29 +44,13 @@ you can pass in an arbitrary theme object as long as each entry’s value is eit

export default {
title: 'Theme/SetTheme',
argTypes: {
theme: {
type: 'string',
control: 'select',
options: Object.keys(fluentTheme),
description: themeDescription,
},
},
args: {
theme: 'webLightTheme',
},
};
} as Meta;

const ComponentCloudTemplate = html`
<p><fluent-button>A button</fluent-button></p>
<p><fluent-spinner></fluent-spinner></p>
<p>
<fluent-text-input>
<fluent-label>Text input</fluent-label>
</fluent-text-input>
</p>
<fluent-divider></fluent-divider>
<p>
<fluent-button>A button</fluent-button>
<fluent-spinner></fluent-spinner>
<fluent-slider step="10" min="0" max="100"></fluent-slider>
<fluent-menu>
<fluent-menu-button appearance="primary" slot="trigger">Toggle Menu</fluent-menu-button>
<fluent-menu-list>
Expand All @@ -59,11 +61,15 @@ const ComponentCloudTemplate = html`
</fluent-menu-list>
</fluent-menu>
</p>
<fluent-divider></fluent-divider>
<p>
<fluent-text-input>
<fluent-label>Text input</fluent-label>
</fluent-text-input>
</p>
<p>
<fluent-field>
<label slot="label" for="radiogroup">Radio group</label>
<fluent-radio-group slot="input" id="radiogroup" orientation="vertical">
<fluent-radio-group slot="input" id="radiogroup">
<fluent-field label-position="after">
<fluent-radio slot="input" id="radiogroup-radio-1"></fluent-radio>
<label slot="label" for="radiogroup-radio-1">Option 1</label>
Expand All @@ -79,23 +85,117 @@ const ComponentCloudTemplate = html`
</fluent-radio-group>
</fluent-field>
</p>
<fluent-divider></fluent-divider>
<p>
<fluent-field label-position="after">
<label slot="label" for="checkbox">I would like this option</label>
<fluent-checkbox slot="input" id="checkbox"></fluent-checkbox>
</fluent-field>
</p>
<fluent-divider></fluent-divider>
<p>
<fluent-slider step="10" min="0" max="100"></fluent-slider>
</p>
<p></p>
`;

const ThemeOptionsTemplate = (selected: string = '', hasUnset = false) => html`
${when(hasUnset, html`<option value="unset">unset</option>`)}
${repeat(
Array.from(themes.keys()),
html`
${when(k => k !== 'unset', html` <option ?selected=${k => selected === k} value="${k => k}">${k => k}</option> `)}
`,
)}
`;

export const SetTheme: Story = renderComponent(ComponentCloudTemplate);
SetTheme.decorators = [
(Story, { args: { theme } }) => {
theme && setTheme(fluentTheme[theme]);
return Story();
},
];
export const SetTheme = renderComponent(html`
<style>
.toolbar {
align-items: end;
display: flex;
gap: 1rem;
border-block-end: 1px solid #ccc;
padding-block-end: 2rem;

label,
select {
display: flow-root;
inline-size: fit-content;
}

label {
flex: 1 0 0;
}

select {
inline-size: 100%;
margin-block-start: 0.5rem;
padding: 0.5rem;
}
}

.global {
margin-block: 2rem;
}

.local {
background: var(--colorNeutralBackground2);
border: 1px solid #ccc;
color: var(--colorNeutralForeground2);
padding: 1rem;
margin-trim: block;

& > :first-child {
margin-block-start: 0;
}

& > :last-child {
margin-block-end: 0;
}

.shadow {
background: var(--colorNeutralBackground2);
color: var(--colorNeutralForeground2);
}
}

fluent-spinner {
vertical-align: middle;
}
</style>
<div class="toolbar">
<label>
Global theme
<select @change="${(_, c) => updateTheme(c.event)}">
${ThemeOptionsTemplate('web-light')}
</select>
</label>

<label>
Local theme (element without shadow root)
<select @change="${(_, c) => updateTheme(c.event, 'local')}">
${ThemeOptionsTemplate('', true)}
</select>
</label>

<label>
Local theme (element with shadow root)
<select @change="${(_, c) => updateTheme(c.event, 'shadow')}">
${ThemeOptionsTemplate('', true)}
</select>
</label>
</div>

<div class="global">
<p>These elements follow the global theme</p>
${ComponentCloudTemplate}
</div>

<div class="local">
<p>These elements follow the container element’s theme</p>
${ComponentCloudTemplate}

<fluent-divider></fluent-divider>

<p>This element (which has shadow root) follows its own theme when set</p>
<fluent-text-input class="shadow">
<fluent-label>Text input</fluent-label>
</fluent-text-input>
</div>
`);
Loading
Loading