diff --git a/dspublisher/theme/global.css b/dspublisher/theme/global.css index b413c75765..bad5995139 100644 --- a/dspublisher/theme/global.css +++ b/dspublisher/theme/global.css @@ -90,6 +90,13 @@ html { --docs-before-background-color: var(--red-50); --docs-after-background-color: var(--green-100); --docs-before-after-border-color: var(--gray-300); + + /* Example frame styles currently use hardcoded values from the Lumo theme */ + --docs-example-render-font-family: + -apple-system, BlinkMacSystemFont, 'Roboto', 'Segoe UI', Helvetica, Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --docs-example-render-color: light-dark(hsla(214, 40%, 16%, 0.94), hsla(214, 96%, 96%, 0.9)); + --docs-example-render-background-color: light-dark(#fff, hsl(214, 35%, 21%)); } ::-moz-selection { diff --git a/frontend/demo/foundation/lumo-tokens.ts b/frontend/demo/foundation/lumo-tokens.ts index 946e96d2b9..faf08cb4e2 100644 --- a/frontend/demo/foundation/lumo-tokens.ts +++ b/frontend/demo/foundation/lumo-tokens.ts @@ -1,5 +1,5 @@ -import propsStyles from '@vaadin/vaadin-lumo-styles/src/props/index.css?inline'; import colorScheme from '@vaadin/vaadin-lumo-styles/src/global/color-scheme.css?inline'; +import propsStyles from '@vaadin/vaadin-lumo-styles/src/props/index.css?inline'; import utilityStyles from '@vaadin/vaadin-lumo-styles/utility.css?inline'; import { addStylesheet } from 'Frontend/demo/theme'; diff --git a/frontend/demo/init.ts b/frontend/demo/init.ts index dd05111e0d..7a53673e99 100644 --- a/frontend/demo/init.ts +++ b/frontend/demo/init.ts @@ -6,17 +6,18 @@ import '../generated/vaadin-featureflags'; import { applyTheme } from 'Frontend/demo/theme'; import client from 'Frontend/generated/connect-client.default'; -// Apply the theme to the document, so that notification styles work as expected, -// as the notification container is added to the document body. -applyTheme(document); +// Some Vaadin components add elements to document.body that require theme styles +// (e.g. Notification). Such components are embedded via iframes, but the same examples +// can also be opened as standalone pages. To support both cases, apply the theme +// to the document when the example runs in an iframe or standalone. This is safe +// because in those modes the styles are isolated from the rest of the site. +if (window.location.pathname.endsWith('/example')) { + applyTheme(document); +} // @ts-expect-error Inserted by DS Publisher client.prefix = __VAADIN_CONNECT_PREFIX__; // eslint-disable-line no-undef -document.body.style.setProperty('--docs-example-render-font-family', 'var(--lumo-font-family)'); -document.body.style.setProperty('--docs-example-render-color', 'var(--lumo-body-text-color)'); -document.body.style.setProperty('--docs-example-render-background-color', 'var(--lumo-base-color)'); - // Ensures standalone UI sample pags have a lang attribute document.documentElement.setAttribute('lang', 'en'); diff --git a/frontend/demo/theme.ts b/frontend/demo/theme.ts index a9ae5a5223..475a6cb171 100644 --- a/frontend/demo/theme.ts +++ b/frontend/demo/theme.ts @@ -1,4 +1,7 @@ +import '@vaadin/vaadin-lumo-styles/src/props/icons.css'; import type { CSSResultGroup } from 'lit'; +import auraCss from '@vaadin/aura/aura.css?inline'; +import lumoCss from '@vaadin/vaadin-lumo-styles/lumo.css?inline'; import docsCss from 'Frontend/themes/docs/styles.css?inline'; function createStylesheet(css: CSSResultGroup | string): CSSStyleSheet { @@ -11,14 +14,44 @@ function createStylesheet(css: CSSResultGroup | string): CSSStyleSheet { return stylesheet; } -const docsStylesheet = createStylesheet(docsCss); +const lumoStyleSheet = createStylesheet(lumoCss); +const auraStyleSheet = createStylesheet(auraCss); +const docsStyleSheet = createStylesheet(docsCss); + +function getRootHost(root: DocumentOrShadowRoot) { + let host: Element; + if (root instanceof ShadowRoot) { + host = root.host; + } else { + host = (root as Document).documentElement; + } + return host; +} export function applyTheme(root: DocumentFragment | DocumentOrShadowRoot | HTMLElement) { - // The root parameter type is very broad to handle the default return type of - // LitElement.createRenderRoot. In general, we expect this to either be a document or a shadow - // root. The adoptedStyleSheets check below makes Typescript accept the parameter type. - if ('adoptedStyleSheets' in root && !root.adoptedStyleSheets.includes(docsStylesheet)) { - root.adoptedStyleSheets = [...root.adoptedStyleSheets, docsStylesheet]; + if (root instanceof ShadowRoot || root instanceof Document) { + const host = getRootHost(root); + + const updateTheme = () => { + const adoptedStyleSheets = root.adoptedStyleSheets.filter( + (styleSheet) => ![lumoStyleSheet, auraStyleSheet, docsStyleSheet].includes(styleSheet) + ); + + if (host.matches('[theme~="aura"]')) { + adoptedStyleSheets.push(auraStyleSheet); + } else { + adoptedStyleSheets.push(lumoStyleSheet); + } + + root.adoptedStyleSheets = [...adoptedStyleSheets, docsStyleSheet]; + }; + + new MutationObserver(updateTheme).observe(host, { + attributes: true, + attributeFilter: ['theme'], + }); + + updateTheme(); } } diff --git a/frontend/themes/docs/styles.css b/frontend/themes/docs/styles.css index f0ba261f5d..1e3b5829e1 100644 --- a/frontend/themes/docs/styles.css +++ b/frontend/themes/docs/styles.css @@ -1,7 +1,3 @@ -/* Import Lumo theme and utility classes */ -@import '@vaadin/vaadin-lumo-styles/lumo.css'; -@import '@vaadin/vaadin-lumo-styles/utility.css'; - /* Import custom styles used in examples */ @import './app-layout.css'; @import './basic-layouts.css'; diff --git a/vite.config.ts b/vite.config.ts index f0d6566c7c..174139711c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -26,7 +26,7 @@ const customConfig: UserConfigFn = (env) => ({ }, { name: 'apply-docs-theme', - transform(_code, id) { + transform(code, id) { // This module is imported by web components exported from Flow to inject styles into their // shadow root. Instead of importing the docs styles from the Flow bundle again, for example // by adding @CssImport to DemoExporter, we provide a global from the docs @@ -36,6 +36,12 @@ const customConfig: UserConfigFn = (env) => ({ if (id.endsWith('generated/css.generated.js')) { return 'export const applyCss = window.__applyTheme.applyTheme;'; } + + // Remove applyCss(document) from `generated/vaadin-web-component.ts` because the global theme + // styles injection is handled by `init.ts` in the docs project. + if (id.endsWith('generated/vaadin-web-component.ts')) { + return code.replace('applyCss(document);', ''); + } }, }, ],