Socket
Socket
Sign inDemoInstall

@vaadin/vaadin-themable-mixin

Package Overview
Dependencies
Maintainers
12
Versions
445
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/vaadin-themable-mixin - npm Package Compare versions

Comparing version 24.4.0-dev.b3e1d14600 to 24.4.0-rc1

4

package.json
{
"name": "@vaadin/vaadin-themable-mixin",
"version": "24.4.0-dev.b3e1d14600",
"version": "24.4.0-rc1",
"publishConfig": {

@@ -43,3 +43,3 @@ "access": "public"

},
"gitHead": "502d4f5b03f770a83d270d98078cde230254dd0e"
"gitHead": "a81e3b927d44c56613fa4e1307494a2acc81005f"
}

@@ -8,3 +8,2 @@ # vaadin-themable-mixin

[![npm version](https://badgen.net/npm/v/@vaadin/vaadin-themable-mixin)](https://www.npmjs.com/package/@vaadin/vaadin-themable-mixin)
[![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)

@@ -11,0 +10,0 @@ ## License

@@ -5,3 +5,3 @@ import type { CSSResultGroup } from 'lit';

* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -8,0 +8,0 @@ */

/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { css, CSSResult, unsafeCSS } from 'lit';
import { adoptStyles, css, CSSResult, LitElement, unsafeCSS } from 'lit';
import { ThemePropertyMixin } from './vaadin-theme-property-mixin.js';

@@ -27,2 +27,12 @@

/**
* @type {WeakRef<HTMLElement>[]}
*/
const themableInstances = new Set();
/**
* @type {string[]}
*/
const themableTagNames = new Set();
/**
* Check if the custom element type has themes applied.

@@ -62,2 +72,125 @@ * @param {Function} elementClass

/**
* Returns true if the themeFor string matches the tag name
* @param {string} themeFor
* @param {string} tagName
* @returns {boolean}
*/
function matchesThemeFor(themeFor, tagName) {
return (themeFor || '').split(' ').some((themeForToken) => {
return new RegExp(`^${themeForToken.split('*').join('.*')}$`, 'u').test(tagName);
});
}
/**
* Returns the CSS text content from an array of CSSResults
* @param {CSSResult[]} styles
* @returns {string}
*/
function getCssText(styles) {
return styles.map((style) => style.cssText).join('\n');
}
const STYLE_ID = 'vaadin-themable-mixin-style';
/**
* Includes the styles to the template.
* @param {CSSResult[]} styles
* @param {HTMLTemplateElement} template
*/
function addStylesToTemplate(styles, template) {
const styleEl = document.createElement('style');
styleEl.id = STYLE_ID;
styleEl.textContent = getCssText(styles);
template.content.appendChild(styleEl);
}
/**
* Dynamically updates the styles of the given component instance.
* @param {HTMLElement} instance
*/
function updateInstanceStyles(instance) {
if (!instance.shadowRoot) {
return;
}
const componentClass = instance.constructor;
if (instance instanceof LitElement) {
// LitElement
// The adoptStyles function may fall back to appending style elements to shadow root.
// Remove them first to avoid duplicates.
[...instance.shadowRoot.querySelectorAll('style')].forEach((style) => style.remove());
// Adopt the updated styles
adoptStyles(instance.shadowRoot, componentClass.elementStyles);
} else {
// PolymerElement
// Update style element content in the shadow root
const style = instance.shadowRoot.getElementById(STYLE_ID);
const template = componentClass.prototype._template;
style.textContent = template.content.getElementById(STYLE_ID).textContent;
}
}
/**
* Dynamically updates the styles of the instances matching the given component type.
* @param {Function} componentClass
*/
function updateInstanceStylesOfType(componentClass) {
// Iterate over component instances and update their styles if needed
themableInstances.forEach((ref) => {
const instance = ref.deref();
if (instance instanceof componentClass) {
updateInstanceStyles(instance);
} else if (!instance) {
// Clean up the weak reference to a GC'd instance
themableInstances.delete(ref);
}
});
}
/**
* Dynamically updates the styles of the given component type.
* @param {Function} componentClass
*/
function updateComponentStyles(componentClass) {
if (componentClass.prototype instanceof LitElement) {
// Update LitElement-based component's elementStyles
componentClass.elementStyles = componentClass.finalizeStyles(componentClass.styles);
} else {
// Update Polymer-based component's template
const template = componentClass.prototype._template;
template.content.getElementById(STYLE_ID).textContent = getCssText(componentClass.getStylesForThis());
}
// Update the styles of inheriting types
themableTagNames.forEach((inheritingTagName) => {
const inheritingClass = customElements.get(inheritingTagName);
if (inheritingClass !== componentClass && inheritingClass.prototype instanceof componentClass) {
updateComponentStyles(inheritingClass);
}
});
}
/**
* Check if the component type already has a style matching the given styles.
*
* @param {Function} componentClass
* @param {CSSResultGroup} styles
* @returns {boolean}
*/
function hasMatchingStyle(componentClass, styles) {
const themes = componentClass.__themes;
if (!themes || !styles) {
return false;
}
return themes.some((theme) =>
theme.styles.some((themeStyle) => styles.some((style) => style.cssText === themeStyle.cssText)),
);
}
/**
* Registers CSS styles for a component type. Make sure to register the styles before

@@ -73,11 +206,2 @@ * the first instance of a component of the type is attached to DOM.

export function registerStyles(themeFor, styles, options = {}) {
if (themeFor) {
if (hasThemes(themeFor)) {
console.warn(`The custom element definition for "${themeFor}"
was finalized before a style module was registered.
Make sure to add component specific style modules before
importing the corresponding custom element.`);
}
}
styles = flattenStyles(styles);

@@ -95,2 +219,30 @@

}
if (themeFor) {
// Update styles of the component types that match themeFor and have already been finalized
themableTagNames.forEach((tagName) => {
if (matchesThemeFor(themeFor, tagName) && hasThemes(tagName)) {
const componentClass = customElements.get(tagName);
if (hasMatchingStyle(componentClass, styles)) {
// Show a warning if the component type already has some of the given styles
console.warn(`Registering styles that already exist for ${tagName}`);
} else if (!window.Vaadin || !window.Vaadin.suppressPostFinalizeStylesWarning) {
// Show a warning if the component type has already been finalized
console.warn(
`The custom element definition for "${tagName}" ` +
`was finalized before a style module was registered. ` +
`Ideally, import component specific style modules before ` +
`importing the corresponding custom element. ` +
`This warning can be suppressed by setting "window.Vaadin.suppressPostFinalizeStylesWarning = true".`,
);
}
// Update the styles of the component type
updateComponentStyles(componentClass);
// Update the styles of the component instances matching the component type
updateInstanceStylesOfType(componentClass);
}
});
}
}

@@ -111,14 +263,2 @@

/**
* Returns true if the themeFor string matches the tag name
* @param {string} themeFor
* @param {string} tagName
* @returns {boolean}
*/
function matchesThemeFor(themeFor, tagName) {
return (themeFor || '').split(' ').some((themeForToken) => {
return new RegExp(`^${themeForToken.split('*').join('.*')}$`, 'u').test(tagName);
});
}
/**
* Maps the moduleName to an include priority number which is used for

@@ -160,13 +300,2 @@ * determining the order in which styles are applied.

/**
* Includes the styles to the template.
* @param {CSSResult[]} styles
* @param {HTMLTemplateElement} template
*/
function addStylesToTemplate(styles, template) {
const styleEl = document.createElement('style');
styleEl.innerHTML = styles.map((style) => style.cssText).join('\n');
template.content.appendChild(styleEl);
}
/**
* Returns an array of themes that should be used for styling a component matching

@@ -206,2 +335,8 @@ * the tag name. The array is sorted by the include order.

class VaadinThemableMixin extends ThemePropertyMixin(superClass) {
constructor() {
super();
// Store a weak reference to the instance
themableInstances.add(new WeakRef(this));
}
/**

@@ -214,2 +349,6 @@ * Covers PolymerElement based component styling

if (this.is) {
themableTagNames.add(this.is);
}
// Make sure not to run the logic intended for PolymerElement when LitElement is used.

@@ -238,3 +377,3 @@ if (this.elementStyles) {

const themeStyles = this.getStylesForThis();
return styles ? [...super.finalizeStyles(styles), ...themeStyles] : themeStyles;
return styles ? [...[styles].flat(Infinity), ...themeStyles] : themeStyles;
}

@@ -248,5 +387,6 @@

static getStylesForThis() {
const superClassThemes = superClass.__themes || [];
const parent = Object.getPrototypeOf(this.prototype);
const inheritedThemes = (parent ? parent.constructor.__themes : []) || [];
this.__themes = [...inheritedThemes, ...getThemes(this.is)];
this.__themes = [...superClassThemes, ...inheritedThemes, ...getThemes(this.is)];
const themeStyles = this.__themes.flatMap((theme) => theme.styles);

@@ -253,0 +393,0 @@ // Remove duplicates

/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2017 - 2023 Vaadin Ltd.
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc