diff --git a/apps/vr-tests-web-components/src/utilities/WCThemeDecorator.tsx b/apps/vr-tests-web-components/src/utilities/WCThemeDecorator.tsx index 0e0a5a739d9305..9b9733bc06d808 100644 --- a/apps/vr-tests-web-components/src/utilities/WCThemeDecorator.tsx +++ b/apps/vr-tests-web-components/src/utilities/WCThemeDecorator.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import type { Decorator, StoryFn } from '@storybook/react-webpack5'; import { FASTElement, customElement, html, attr } from '@microsoft/fast-element'; import { teamsLightTheme, teamsDarkTheme, webLightTheme, webDarkTheme } from '@fluentui/tokens'; -import { setThemeFor } from '@fluentui/web-components'; +import { setTheme } from '@fluentui/web-components'; const themes = [ { id: 'web-light', label: 'Web Light', theme: webLightTheme }, @@ -36,7 +36,7 @@ export class FASTThemeDecorator extends FASTElement { connectedCallback() { super.connectedCallback(); const theme = themes.find(value => value.id === this.fluentTheme)?.theme ?? defaultTheme.theme; - setThemeFor(this, theme); + setTheme(theme); } } diff --git a/change/@fluentui-web-components-753b509c-f103-4d8f-8b15-4a88a784dd81.json b/change/@fluentui-web-components-753b509c-f103-4d8f-8b15-4a88a784dd81.json new file mode 100644 index 00000000000000..f8b8932d773ffd --- /dev/null +++ b/change/@fluentui-web-components-753b509c-f103-4d8f-8b15-4a88a784dd81.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "fix: migrate to esbuild for CDN bundle, enable setTheme on globalThis", + "packageName": "@fluentui/web-components", + "email": "13071055+chrisdholt@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/web-components/.storybook/preview.mjs b/packages/web-components/.storybook/preview.mjs index 00c1916f0360f9..2913b43e5b12c6 100644 --- a/packages/web-components/.storybook/preview.mjs +++ b/packages/web-components/.storybook/preview.mjs @@ -1,7 +1,6 @@ import { teamsDarkTheme, teamsLightTheme, webDarkTheme, webLightTheme } from '@fluentui/tokens'; import * as prettier from 'prettier'; import prettierPluginHTML from 'prettier/parser-html.js'; -import { setTheme } from '../src/theme/set-theme.js'; import webcomponentsTheme from './theme.mjs'; import '../src/index-rollup.js'; @@ -17,9 +16,11 @@ const themes = { }; // This is needed in Playwright. -Object.defineProperty(window, 'setTheme', { value: setTheme }); +// @ts-ignore - setTheme is set on globalThis.Fluent by the index-rollup bundle +Object.defineProperty(window, 'Fluent', { value: globalThis.Fluent }); -setTheme(themes['web-light']); +// @ts-ignore - setTheme is set on globalThis.Fluent by the index-rollup bundle +Fluent.setTheme(themes['web-light']); export const globalTypes = { theme: { @@ -63,7 +64,8 @@ export const decorators = [ * @type {keyof typeof themes} */ const theme = context.globals.theme || 'web-light'; - setTheme(themes[theme]); + // @ts-ignore - setTheme is set on globalThis.Fluent by the index-rollup bundle + Fluent.setTheme(themes[theme]); // Set direction on the document body const dir = context.globals.dir || 'ltr'; diff --git a/packages/web-components/docs/web-components.api.md b/packages/web-components/docs/web-components.api.md index 7eb64f59ffdf12..45c4edfeca7653 100644 --- a/packages/web-components/docs/web-components.api.md +++ b/packages/web-components/docs/web-components.api.md @@ -3586,11 +3586,6 @@ export const roleForMenuItem: { // @public 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 @deprecated (undocumented) -export function setThemeFor(element: HTMLElement, theme: Theme | null): void; - // @public export const shadow16 = "var(--shadow16)"; diff --git a/packages/web-components/package.json b/packages/web-components/package.json index cbed415018f1e3..2619210a9e0f93 100644 --- a/packages/web-components/package.json +++ b/packages/web-components/package.json @@ -30,6 +30,16 @@ ], "exports": { ".": "./dist/esm/index.js", + "./web-components.js": "./dist/web-components.js", + "./web-components.min.js": "./dist/web-components.min.js", + "./web-components-all.js": { + "types": "./dist/web-components.d.ts", + "default": "./dist/web-components-all.js" + }, + "./web-components-all.min.js": { + "types": "./dist/web-components.d.ts", + "default": "./dist/web-components-all.min.js" + }, "./utils/behaviors/*.js": "./dist/esm/utils/behaviors/*.js", "./utils/*.js": "./dist/esm/utils/*.js", "./utilities.js": "./dist/esm/utils/index.js", @@ -47,10 +57,14 @@ }, "sideEffects": [ "define.*", + "define-all.*", "index-rollup.*", + "index-all-rollup.*", "./dist/esm/**/define.js", "./dist/web-components.js", - "./dist/web-components.min.js" + "./dist/web-components.min.js", + "./dist/web-components-all.js", + "./dist/web-components-all.min.js" ], "scripts": { "analyze": "cem analyze", @@ -85,7 +99,8 @@ "@wc-toolkit/cem-inheritance": "1.2.2", "@wc-toolkit/module-path-resolver": "1.0.0", "@wc-toolkit/type-parser": "1.0.3", - "chromedriver": "^125.0.0" + "chromedriver": "^125.0.0", + "rollup-plugin-fast-tagged-templates": "^1.0.2" }, "dependencies": { "@fluentui/tokens": "1.0.0-alpha.23", diff --git a/packages/web-components/rollup.config.js b/packages/web-components/rollup.config.js index f852d6179508a6..9445148e3b6db1 100644 --- a/packages/web-components/rollup.config.js +++ b/packages/web-components/rollup.config.js @@ -1,12 +1,16 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'; import commonJS from 'rollup-plugin-commonjs'; import esbuild, { minify } from 'rollup-plugin-esbuild'; -import transformTaggedTemplate from 'rollup-plugin-transform-tagged-template'; -import { transformCSSFragment, transformHTMLFragment } from './scripts/transform-fragments'; +import fastTaggedTemplates from 'rollup-plugin-fast-tagged-templates'; -const parserOptions = { - sourceType: 'module', -}; +const plugins = [ + nodeResolve({ browser: true }), + commonJS(), + esbuild({ + tsconfig: './tsconfig.lib.json', + }), + fastTaggedTemplates(), +]; export default [ { @@ -22,22 +26,21 @@ export default [ plugins: [minify()], }, ], - plugins: [ - nodeResolve({ browser: true }), - commonJS(), - esbuild({ - tsconfig: './tsconfig.lib.json', - }), - transformTaggedTemplate({ - tagsToProcess: ['css'], - transformer: transformCSSFragment, - parserOptions, - }), - transformTaggedTemplate({ - tagsToProcess: ['html'], - transformer: transformHTMLFragment, - parserOptions, - }), + plugins, + }, + { + input: 'src/index-all-rollup.ts', + output: [ + { + file: 'dist/web-components-all.js', + format: 'esm', + }, + { + file: 'dist/web-components-all.min.js', + format: 'esm', + plugins: [minify()], + }, ], + plugins, }, ]; diff --git a/packages/web-components/scripts/transform-fragments.js b/packages/web-components/scripts/transform-fragments.js deleted file mode 100644 index 8db1b711c98819..00000000000000 --- a/packages/web-components/scripts/transform-fragments.js +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-function-return-type, @typescript-eslint/typedef */ - -/** - * Reduces extra spaces in HTML tagged templates. - * - * @param {string} data - the fragment value - * @returns string - */ -export function transformHTMLFragment(data) { - data = data.replace(/\s*([<>])\s*/g, '$1'); // remove spaces before and after angle brackets - return data.replace(/\s{2,}/g, ' '); // Collapse all sequences to 1 space -} - -/** - * Reduces extra spaces in CSS tagged templates. - * - * Breakdown of this regex: - * (?:\s*\/\*(?:.|\s)+?\*\/\s*) Remove comments (non-capturing) - * (?:;)\s+(?=\}) Remove semicolons and spaces followed by property list end (non-capturing) - * \s+(?=\{) Remove spaces before property list start (non-capturing) - * (?<=:)\s+ Remove spaces after property declarations (non-capturing) - * \s*([{};,])\s* Remove extra spaces before and after braces, semicolons, and commas (captures) - * - * @param {string} data - the fragment value - * @returns string - */ -export function transformCSSFragment(data) { - return data.replace(/(?:\s*\/\*(?:.|\s)+?\*\/\s*)|(?:;)\s+(?=\})|\s+(?=\{)|(?<=:)\s+|\s*([{};,])\s*/g, '$1'); -} diff --git a/packages/web-components/src/_docs/developer/migration.mdx b/packages/web-components/src/_docs/developer/migration.mdx index 557135132841e6..2974f179848be2 100644 --- a/packages/web-components/src/_docs/developer/migration.mdx +++ b/packages/web-components/src/_docs/developer/migration.mdx @@ -216,11 +216,16 @@ Due to web platform labelling constraints of the ShadowDOM, the labelling API fo ``` -### setTheme +### Bundles + +The package ships two CDN-ready bundles, each available in minified and non-minified versions: -A more powerful and simpler set-theme API that allows setting themes at the element level. +- **`web-components.js`** / **`web-components.min.js`** — Registers all components and exposes `Fluent.setTheme` on `globalThis`. This is the recommended bundle for most CDN and script-tag consumers. +- **`web-components-all.js`** / **`web-components-all.min.js`** — Everything in the standard bundle, plus all named exports from the package (base classes, templates, styles, design tokens, and utilities). Use this if you need programmatic access to the full API surface from a CDN context. + +### setTheme -- `setThemeFor()` is deprecated in favor of `setTheme( theme, element )` +- `setTheme()` can set themes such as `setTheme(webLightTheme)` (defaults to document) or `setTheme(webDarkTheme, element)` to theme an element and its children - `setTheme()` can unset themes with `setTheme(null)` or `setTheme( null, element )` ### Case studies diff --git a/packages/web-components/src/define-all.ts b/packages/web-components/src/define-all.ts new file mode 100644 index 00000000000000..9835d0023159e7 --- /dev/null +++ b/packages/web-components/src/define-all.ts @@ -0,0 +1,42 @@ +import './accordion-item/define.js'; +import './accordion/define.js'; +import './anchor-button/define.js'; +import './avatar/define.js'; +import './badge/define.js'; +import './button/define.js'; +import './checkbox/define.js'; +import './compound-button/define.js'; +import './counter-badge/define.js'; +import './dialog/define.js'; +import './dialog-body/define.js'; +import './divider/define.js'; +import './drawer/define.js'; +import './drawer-body/define.js'; +import './dropdown/define.js'; +import './field/define.js'; +import './image/define.js'; +import './label/define.js'; +import './link/define.js'; +import './listbox/define.js'; +import './menu-button/define.js'; +import './menu-item/define.js'; +import './menu-list/define.js'; +import './menu/define.js'; +import './message-bar/define.js'; +import './option/define.js'; +import './progress-bar/define.js'; +import './radio-group/define.js'; +import './radio/define.js'; +import './rating-display/define.js'; +import './slider/define.js'; +import './spinner/define.js'; +import './switch/define.js'; +import './tab/define.js'; +import './tablist/define.js'; +import './textarea/define.js'; +import './text-input/define.js'; +import './text/define.js'; +import './toggle-button/define.js'; +import './tooltip/define.js'; +import './tree/define.js'; +import './tree-item/define.js'; diff --git a/packages/web-components/src/index-all-rollup.ts b/packages/web-components/src/index-all-rollup.ts new file mode 100644 index 00000000000000..0c90f4d287b8ce --- /dev/null +++ b/packages/web-components/src/index-all-rollup.ts @@ -0,0 +1,11 @@ +import './define-all.js'; + +// import setTheme for export on globalThis for CDN +import { setTheme } from './theme/index.js'; + +// Expose all exports from index.ts +export * from './index.js'; + +// Expose setTheme under Fluent namespace on globalThis for CDN/script-tag consumers +// @ts-expect-error - CDN bundle intentionally sets globals +globalThis.Fluent = { ...globalThis.Fluent, setTheme }; diff --git a/packages/web-components/src/index-rollup.ts b/packages/web-components/src/index-rollup.ts index 1c8e6dd2d1b8ea..9b35c8eb70f946 100644 --- a/packages/web-components/src/index-rollup.ts +++ b/packages/web-components/src/index-rollup.ts @@ -1,43 +1,8 @@ -import './accordion-item/define.js'; -import './accordion/define.js'; -import './anchor-button/define.js'; -import './avatar/define.js'; -import './badge/define.js'; -import './button/define.js'; -import './checkbox/define.js'; -import './compound-button/define.js'; -import './counter-badge/define.js'; -import './dialog/define.js'; -import './dialog-body/define.js'; -import './divider/define.js'; -import './drawer/define.js'; -import './drawer-body/define.js'; -import './dropdown/define.js'; -import './field/define.js'; -import './image/define.js'; -import './label/define.js'; -import './link/define.js'; -import './listbox/define.js'; -import './menu-button/define.js'; -import './menu-item/define.js'; -import './menu-list/define.js'; -import './menu/define.js'; -import './message-bar/define.js'; -import './option/define.js'; -import './progress-bar/define.js'; -import './radio-group/define.js'; -import './radio/define.js'; -import './rating-display/define.js'; -import './slider/define.js'; -import './spinner/define.js'; -import './switch/define.js'; -import './tab/define.js'; -import './tablist/define.js'; -import './textarea/define.js'; -import './text-input/define.js'; -import './text/define.js'; -import './toggle-button/define.js'; -import './tooltip/define.js'; -import './tree/define.js'; -import './tree-item/define.js'; -export { setTheme } from './theme/set-theme.js'; +import './define-all.js'; + +// import setTheme for export on globalThis for CDN +import { setTheme } from './theme/index.js'; + +// Expose setTheme under Fluent namespace on globalThis for CDN/script-tag consumers +// @ts-expect-error - CDN bundle intentionally sets globals +globalThis.Fluent = { ...globalThis.Fluent, setTheme }; diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts index 4acba253a84633..16ce22a0c07ecf 100644 --- a/packages/web-components/src/index.ts +++ b/packages/web-components/src/index.ts @@ -310,7 +310,7 @@ export { TextWeight, } from './text/index.js'; export * from './theme/design-tokens.js'; -export { setTheme, setThemeFor, type Theme } from './theme/index.js'; +export { setTheme, type Theme } from './theme/index.js'; export { ToggleButton, ToggleButtonAppearance, diff --git a/packages/web-components/src/theme/index.ts b/packages/web-components/src/theme/index.ts index 6982cbda59a2de..e23a0003232d1f 100644 --- a/packages/web-components/src/theme/index.ts +++ b/packages/web-components/src/theme/index.ts @@ -384,4 +384,4 @@ export { shadow28Brand, shadow64Brand, } from './design-tokens.js'; -export { setTheme, setThemeFor, type Theme } from './set-theme.js'; +export { setTheme, type Theme } from './set-theme.js'; diff --git a/packages/web-components/src/theme/set-theme.ts b/packages/web-components/src/theme/set-theme.ts index 91acd4743e00d4..8776132463a7c6 100644 --- a/packages/web-components/src/theme/set-theme.ts +++ b/packages/web-components/src/theme/set-theme.ts @@ -214,11 +214,3 @@ function forceRepaint(element: HTMLElement) { element.style.setProperty(name, currentValue); } - -/** - * @internal - * @deprecated Use `setTheme(theme, element)` instead. - */ -export function setThemeFor(element: HTMLElement, theme: Theme | null) { - setThemePropertiesOnElement(theme, element); -} diff --git a/packages/web-components/test/harness/src/main.ts b/packages/web-components/test/harness/src/main.ts index 2ca1a2fa2d4ebb..e351575b264998 100644 --- a/packages/web-components/test/harness/src/main.ts +++ b/packages/web-components/test/harness/src/main.ts @@ -12,6 +12,7 @@ import '../../../src/index-rollup.js'; setTheme(webLightTheme); +// Expose directly on window for Playwright test access Object.defineProperty(window, 'setTheme', { value: setTheme, }); diff --git a/yarn.lock b/yarn.lock index 6548596d4b514a..629621be4153c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7330,7 +7330,7 @@ clean-css@4.2.3: dependencies: source-map "~0.6.0" -clean-css@^5.2.2: +clean-css@^5.2.2, clean-css@~5.3.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg== @@ -9052,7 +9052,7 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== -entities@^4.2.0, entities@^4.5.0: +entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -11469,6 +11469,19 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" +html-minifier-terser@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz#18752e23a2f0ed4b0f550f217bb41693e975b942" + integrity sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA== + dependencies: + camel-case "^4.1.2" + clean-css "~5.3.2" + commander "^10.0.0" + entities "^4.4.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.15.1" + html-react-parser@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-4.0.0.tgz#a727be4539ad85b133a5071f97b8c2f835a55bdf" @@ -13991,7 +14004,7 @@ magic-string@^0.25.2: dependencies: sourcemap-codec "^1.4.4" -magic-string@^0.30.17, magic-string@^0.30.5: +magic-string@^0.30.12, magic-string@^0.30.17, magic-string@^0.30.5: version "0.30.21" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== @@ -17576,6 +17589,15 @@ rollup-plugin-esbuild@6.1.1: es-module-lexer "^1.3.1" get-tsconfig "^4.7.2" +rollup-plugin-fast-tagged-templates@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-fast-tagged-templates/-/rollup-plugin-fast-tagged-templates-1.0.2.tgz#ec4dae2819516a4e0aafa8478e85d6bc9c3a0654" + integrity sha512-faCdx89y6ggN3lcAw1YLlEszde+rcZT/EhiBQZlsqb8017jLJt4+tgZwVo0e4NF/QOa78UEeY+A2NsCj3bf2UA== + dependencies: + estree-walker "^3.0.3" + html-minifier-terser "^7.2.0" + magic-string "^0.30.12" + rollup-plugin-node-resolve@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523" @@ -19086,7 +19108,7 @@ terser-webpack-plugin@^5.3.1, terser-webpack-plugin@^5.3.11: serialize-javascript "^6.0.2" terser "^5.31.1" -terser@5.39.1, terser@^5.10.0, terser@^5.16.0, terser@^5.26.0, terser@^5.31.1: +terser@5.39.1, terser@^5.10.0, terser@^5.15.1, terser@^5.16.0, terser@^5.26.0, terser@^5.31.1: version "5.39.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.39.1.tgz#1c80e6bde2b362c6f9f3e79e295c228a3882d983" integrity sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==