diff --git a/packages/base/src/RenderScheduler.js b/packages/base/src/RenderScheduler.js index 964d32af4cdf..65b0ad02298c 100644 --- a/packages/base/src/RenderScheduler.js +++ b/packages/base/src/RenderScheduler.js @@ -142,18 +142,21 @@ class RenderScheduler { * * Usage: * reRenderAllUI5Elements() -> rerenders all components + * reRenderAllUI5Elements({tag: "ui5-button"}) -> re-renders only instances of ui5-button * reRenderAllUI5Elements({rtlAware: true}) -> re-renders only rtlAware components * reRenderAllUI5Elements({languageAware: true}) -> re-renders only languageAware components * reRenderAllUI5Elements({rtlAware: true, languageAware: true}) -> re-renders components that are rtlAware or languageAware + * etc... * * @public * @param {Object|undefined} filters - Object with keys that can be "rtlAware" or "languageAware" */ static reRenderAllUI5Elements(filters) { registeredElements.forEach(element => { + const tag = element.constructor.getMetadata().getTag(); const rtlAware = isRtlAware(element.constructor); const languageAware = element.constructor.getMetadata().isLanguageAware(); - if (!filters || (filters.rtlAware && rtlAware) || (filters.languageAware && languageAware)) { + if (!filters || (filters.tag === tag) || (filters.rtlAware && rtlAware) || (filters.languageAware && languageAware)) { RenderScheduler.renderDeferred(element); } }); diff --git a/packages/base/src/UI5Element.js b/packages/base/src/UI5Element.js index 0fba1339763e..855800463b54 100644 --- a/packages/base/src/UI5Element.js +++ b/packages/base/src/UI5Element.js @@ -85,17 +85,6 @@ class UI5Element extends HTMLElement { // Init Shadow Root if (needsShadowDOM) { this.attachShadow({ mode: "open" }); - - // IE11, Edge - if (window.ShadyDOM) { - createComponentStyleTag(this.constructor); - } - - // Chrome - if (document.adoptedStyleSheets) { - const style = getConstructableStyle(this.constructor); - this.shadowRoot.adoptedStyleSheets = [style]; - } } // Init StaticAreaItem only if needed @@ -562,9 +551,21 @@ class UI5Element extends HTMLElement { let styleToPrepend; const renderResult = this.constructor.template(this); + // IE11, Edge + if (window.ShadyDOM) { + createComponentStyleTag(this.constructor); + } + + // Chrome + if (document.adoptedStyleSheets) { + this.shadowRoot.adoptedStyleSheets = getConstructableStyle(this.constructor); + } + + // FF, Safari if (!document.adoptedStyleSheets && !window.ShadyDOM) { styleToPrepend = getEffectiveStyle(this.constructor); } + this.constructor.render(renderResult, this.shadowRoot, styleToPrepend, { eventContext: this }); } diff --git a/packages/base/src/theming/CustomStyle.js b/packages/base/src/theming/CustomStyle.js index 2632f5592b45..f3bec1874743 100644 --- a/packages/base/src/theming/CustomStyle.js +++ b/packages/base/src/theming/CustomStyle.js @@ -1,19 +1,40 @@ -const customCSSFor = {}; +import RenderScheduler from "../RenderScheduler.js"; +import EventProvider from "../EventProvider.js"; -const addCustomCSS = (tag, css, ...rest) => { - if (rest.length) { - throw new Error("addCustomCSS no longer accepts theme specific CSS. new signature is `addCustomCSS(tag, css)`"); - } +const eventProvider = new EventProvider(); +const CUSTOM_CSS_CHANGE = "CustomCSSChange"; + +const attachCustomCSSChange = listener => { + eventProvider.attachEvent(CUSTOM_CSS_CHANGE, listener); +}; +const detachCustomCSSChange = listener => { + eventProvider.detachEvent(CUSTOM_CSS_CHANGE, listener); +}; + +const fireCustomCSSChange = tag => { + return eventProvider.fireEvent(CUSTOM_CSS_CHANGE, tag); +}; + +const customCSSFor = {}; + +const addCustomCSS = (tag, css) => { if (!customCSSFor[tag]) { customCSSFor[tag] = []; } - customCSSFor[tag].push(css); + fireCustomCSSChange(tag); + + RenderScheduler.reRenderAllUI5Elements({ tag }); }; const getCustomCSS = tag => { return customCSSFor[tag] ? customCSSFor[tag].join("") : ""; }; -export { addCustomCSS, getCustomCSS }; +export { + addCustomCSS, + getCustomCSS, + attachCustomCSSChange, + detachCustomCSSChange, +}; diff --git a/packages/base/src/theming/createComponentStyleTag.js b/packages/base/src/theming/createComponentStyleTag.js index 30d1eb400bb9..3267d871d70d 100644 --- a/packages/base/src/theming/createComponentStyleTag.js +++ b/packages/base/src/theming/createComponentStyleTag.js @@ -2,9 +2,14 @@ import createStyleInHead from "../util/createStyleInHead.js"; import getEffectiveStyle from "./getEffectiveStyle.js"; import adaptCSSForIE from "./adaptCSSForIE.js"; import { ponyfillNeeded, schedulePonyfill } from "./CSSVarsPonyfill.js"; +import { attachCustomCSSChange } from "./CustomStyle.js"; const IEStyleSet = new Set(); +attachCustomCSSChange(tag => { + IEStyleSet.delete(tag); +}); + const getStaticStyle = ElementClass => { let componentStaticStyles = ElementClass.staticAreaStyles; if (Array.isArray(componentStaticStyles)) { diff --git a/packages/base/src/theming/getConstructableStyle.js b/packages/base/src/theming/getConstructableStyle.js index 8e65ce67e83f..ce86eedeb033 100644 --- a/packages/base/src/theming/getConstructableStyle.js +++ b/packages/base/src/theming/getConstructableStyle.js @@ -1,7 +1,12 @@ import getEffectiveStyle from "./getEffectiveStyle.js"; +import { attachCustomCSSChange } from "./CustomStyle.js"; const constructableStyleMap = new Map(); +attachCustomCSSChange(tag => { + constructableStyleMap.delete(tag); +}); + /** * Returns (and caches) a constructable style sheet for a web component class * Note: Chrome @@ -9,17 +14,16 @@ const constructableStyleMap = new Map(); * @returns {*} */ const getConstructableStyle = ElementClass => { - const tagName = ElementClass.getMetadata().getTag(); - const styleContent = getEffectiveStyle(ElementClass); - if (constructableStyleMap.has(tagName)) { - return constructableStyleMap.get(tagName); - } + const tag = ElementClass.getMetadata().getTag(); - const style = new CSSStyleSheet(); - style.replaceSync(styleContent); + if (!constructableStyleMap.has(tag)) { + const styleContent = getEffectiveStyle(ElementClass); + const style = new CSSStyleSheet(); + style.replaceSync(styleContent); + constructableStyleMap.set(tag, [style]); + } - constructableStyleMap.set(tagName, style); - return style; + return constructableStyleMap.get(tag); }; export default getConstructableStyle; diff --git a/packages/base/src/theming/getEffectiveStyle.js b/packages/base/src/theming/getEffectiveStyle.js index 69a3a2d34eb1..9f40f329451f 100644 --- a/packages/base/src/theming/getEffectiveStyle.js +++ b/packages/base/src/theming/getEffectiveStyle.js @@ -1,12 +1,23 @@ -import { getCustomCSS } from "./CustomStyle.js"; +import { getCustomCSS, attachCustomCSSChange } from "./CustomStyle.js"; import getStylesString from "./getStylesString.js"; +const effectiveStyleMap = new Map(); + +attachCustomCSSChange(tag => { + effectiveStyleMap.delete(tag); +}); + const getEffectiveStyle = ElementClass => { const tag = ElementClass.getMetadata().getTag(); - const customStyle = getCustomCSS(tag) || ""; - const builtInStyles = getStylesString(ElementClass.styles); - return `${builtInStyles} ${customStyle}`; + if (!effectiveStyleMap.has(tag)) { + const customStyle = getCustomCSS(tag) || ""; + const builtInStyles = getStylesString(ElementClass.styles); + const effectiveStyle = `${builtInStyles} ${customStyle}`; + effectiveStyleMap.set(tag, effectiveStyle); + } + + return effectiveStyleMap.get(tag); }; export default getEffectiveStyle; diff --git a/packages/main/bundle.es5.js b/packages/main/bundle.es5.js index 21cf02da3990..2d783f0a8303 100644 --- a/packages/main/bundle.es5.js +++ b/packages/main/bundle.es5.js @@ -12,6 +12,8 @@ import { getFirstDayOfWeek } from "@ui5/webcomponents-base/dist/config/FormatSet import { getRegisteredNames as getIconNames } from "@ui5/webcomponents-base/dist/SVGIconRegistry.js"; import applyDirection from "@ui5/webcomponents-base/dist/locale/applyDirection.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import { addCustomCSS } from "@ui5/webcomponents-base/dist/Theming.js"; + const configuration = { getAnimationMode, setAnimationMode, @@ -25,7 +27,7 @@ const configuration = { }; export { configuration, - getIconNames, applyDirection, ResizeHandler, + addCustomCSS, }; diff --git a/packages/main/bundle.esm.js b/packages/main/bundle.esm.js index 22382ba85607..3d7789c2f187 100644 --- a/packages/main/bundle.esm.js +++ b/packages/main/bundle.esm.js @@ -97,6 +97,7 @@ import { getFirstDayOfWeek } from "@ui5/webcomponents-base/dist/config/FormatSet import { getRegisteredNames as getIconNames } from "@ui5/webcomponents-base/dist/SVGIconRegistry.js"; import applyDirection from "@ui5/webcomponents-base/dist/locale/applyDirection.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import { addCustomCSS } from "@ui5/webcomponents-base/dist/Theming"; window["sap-ui-webcomponents-bundle"] = { configuration : { getAnimationMode, @@ -109,8 +110,8 @@ window["sap-ui-webcomponents-bundle"] = { getRTL, getFirstDayOfWeek, }, - getIconNames, getLocaleData, applyDirection, ResizeHandler, + addCustomCSS, }; diff --git a/packages/main/test/pages/CustomCSS.html b/packages/main/test/pages/CustomCSS.html new file mode 100644 index 000000000000..da5010dda427 --- /dev/null +++ b/packages/main/test/pages/CustomCSS.html @@ -0,0 +1,53 @@ + + +
+ + + + +