Skip to content

Commit

Permalink
feat(framework): Make addCustomCSS dynamic (#2083)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladitasev committed Aug 13, 2020
1 parent 974401b commit 7b54b9b
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 34 deletions.
5 changes: 4 additions & 1 deletion packages/base/src/RenderScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
Expand Down
23 changes: 12 additions & 11 deletions packages/base/src/UI5Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 });
}

Expand Down
35 changes: 28 additions & 7 deletions packages/base/src/theming/CustomStyle.js
Original file line number Diff line number Diff line change
@@ -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,
};
5 changes: 5 additions & 0 deletions packages/base/src/theming/createComponentStyleTag.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
22 changes: 13 additions & 9 deletions packages/base/src/theming/getConstructableStyle.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
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
* @param ElementClass
* @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;
19 changes: 15 additions & 4 deletions packages/base/src/theming/getEffectiveStyle.js
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 3 additions & 1 deletion packages/main/bundle.es5.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -25,7 +27,7 @@ const configuration = {
};
export {
configuration,
getIconNames,
applyDirection,
ResizeHandler,
addCustomCSS,
};
3 changes: 2 additions & 1 deletion packages/main/bundle.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -109,8 +110,8 @@ window["sap-ui-webcomponents-bundle"] = {
getRTL,
getFirstDayOfWeek,
},
getIconNames,
getLocaleData,
applyDirection,
ResizeHandler,
addCustomCSS,
};
53 changes: 53 additions & 0 deletions packages/main/test/pages/CustomCSS.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta charset="utf-8">

<title>Button</title>

<script data-ui5-config type="application/json">
{
"language": "EN",
"noConflict": {
"events": ["click"]
},
"calendarType": "Islamic"
}
</script>

<script src="../../webcomponentsjs/webcomponents-loader.js"></script>
<script src="../../resources/bundle.esm.js" type="module"></script>
<script nomodule src="../../resources/bundle.es5.js"></script>

</head>

<body style="background-color: var(--sapBackgroundColor);">

<ui5-select id="select">
<ui5-option>1</ui5-option>
<ui5-option>2</ui5-option>
</ui5-select>

<br />
<br />

<ui5-button id="btn">Apply custom css and rerender</ui5-button>

<br />
<br />

<script>
const applyCustomCSSAndRerender = function() {
window["sap-ui-webcomponents-bundle"].addCustomCSS("ui5-select", ".ui5-select-root { background-color: red; } ");
};

document
.getElementById("btn")
.addEventListener("click", applyCustomCSSAndRerender);

</script>

</body>
</html>

0 comments on commit 7b54b9b

Please sign in to comment.