From 040c2a9494a439cb76b9ea95222ce353a86c6dfe Mon Sep 17 00:00:00 2001 From: myxvisual Date: Sat, 15 Jul 2017 21:40:09 +0800 Subject: [PATCH] feat: Update StyleManager working with Theme component --- .../{getBaseCSS.tsx => getBaseCSSText.tsx} | 2 +- src/Theme/index.tsx | 39 ++++++------------ src/styles/StyleManager.ts | 40 +++++++++++++++---- 3 files changed, 47 insertions(+), 34 deletions(-) rename src/Theme/{getBaseCSS.tsx => getBaseCSSText.tsx} (91%) diff --git a/src/Theme/getBaseCSS.tsx b/src/Theme/getBaseCSSText.tsx similarity index 91% rename from src/Theme/getBaseCSS.tsx rename to src/Theme/getBaseCSSText.tsx index 73dd2554..68164095 100644 --- a/src/Theme/getBaseCSS.tsx +++ b/src/Theme/getBaseCSSText.tsx @@ -1,5 +1,5 @@ -const getBaseCSS = (theme: ReactUWP.ThemeType, themeClassName: string) => `* { +const getBaseCSS = (theme: ReactUWP.ThemeType, themeClassName = "uwp-base") => `* { margin: 0; padding: 0; box-sizing: border-box; diff --git a/src/Theme/index.tsx b/src/Theme/index.tsx index 44e2f394..4af8edd4 100644 --- a/src/Theme/index.tsx +++ b/src/Theme/index.tsx @@ -6,7 +6,7 @@ import darkTheme from "../styles/darkTheme"; import getTheme from "../styles/getTheme"; import RenderToBody from "../RenderToBody"; import ToastWrapper from "../Toast/ToastWrapper"; -import getBaseCSS from "./getBaseCSS"; +import getBaseCSSText from "./getBaseCSSText"; import generateAcrylicTexture from "../styles/generateAcrylicTexture"; import { setSegoeMDL2AssetsFonts } from "../styles/fonts/segoe-mdl2-assets"; import IS_NODE_ENV from "../common/nodeJS/IS_NODE_ENV"; @@ -59,6 +59,7 @@ export class Theme extends React.Component { cacheDarkAcrylicTextures: ReactUWP.ThemeType; cacheLightAcrylicTextures: ReactUWP.ThemeType; toastWrapper: ToastWrapper; + prevStyleManager: StyleManager = null; getDefaultTheme = () => { let { theme, autoSaveTheme } = this.props; @@ -184,6 +185,8 @@ export class Theme extends React.Component { } bindNewThemeMethods = (theme: ReactUWP.ThemeType) => { + const styleManager = new StyleManager({ theme }); + styleManager.addCSSTextWithUpdate(getBaseCSSText(theme)); Object.assign(theme, { desktopBackground: `url(${theme.desktopBackgroundImage}) no-repeat fixed top left / cover`, updateTheme: this.updateTheme, @@ -192,9 +195,9 @@ export class Theme extends React.Component { updateToast: this.updateToast, deleteToast: this.deleteToast, generateAcrylicTextures: this.generateAcrylicTextures, - forceUpdateTheme: this.forceUpdateTheme + forceUpdateTheme: this.forceUpdateTheme, + styleManager } as ReactUWP.ThemeType); - theme.styleManager = new StyleManager(theme); } handleNewTheme = (theme: ReactUWP.ThemeType) => { @@ -235,8 +238,6 @@ export class Theme extends React.Component { this.generateAcrylicTextures(currTheme, currTheme => this.setState({ currTheme })); } - this.updateBaseCSS(); - window.addEventListener("scroll", this.handleScrollReveal); } @@ -265,11 +266,17 @@ export class Theme extends React.Component { } } + componentWillUpdate(nextProps: ThemeProps, nextState: ThemeState) { + this.prevStyleManager = this.state.currTheme.styleManager; + } + componentDidUpdate() { - this.updateBaseCSS(); + this.prevStyleManager.cleanStyleSheet(); + this.prevStyleManager = null; } componentWillUnmount() { + this.state.currTheme.styleManager.cleanStyleSheet(); window.removeEventListener("scroll", this.handleScrollReveal); } @@ -349,26 +356,6 @@ export class Theme extends React.Component { return needGenerateAcrylic; } - updateBaseCSS = (init = false) => { - const newWindow = window as ReactUWP.Window; - - const styleSheetClassName = `.${this.themeClassName}-style-sheet`; - let styleSheet = document.querySelector(styleSheetClassName); - const CSSString = getBaseCSS(this.state.currTheme, this.themeClassName); - if (!newWindow.__REACT_UWP__) newWindow.__REACT_UWP__ = {}; - if (styleSheet || newWindow.__REACT_UWP__.baseCSSRequired) { - if (styleSheet) { - styleSheet.innerHTML = CSSString; - } else return; - } else { - styleSheet = document.createElement("style"); - styleSheet.className = styleSheetClassName; - styleSheet.innerHTML = CSSString; - document.head.appendChild(styleSheet); - newWindow.__REACT_UWP__.baseCSSRequired = true; - } - } - addToast = (toast: React.ReactNode) => { this.toastWrapper.addToast(toast); } diff --git a/src/styles/StyleManager.ts b/src/styles/StyleManager.ts index f9efd4cf..bc5de6fc 100644 --- a/src/styles/StyleManager.ts +++ b/src/styles/StyleManager.ts @@ -24,8 +24,17 @@ export class StyleManager { themeId = 0; styleElement: HTMLStyleElement = null; sheets: any = {}; - - constructor(theme: ReactUWP.ThemeType, globalClassName?: string) { + styleNode: HTMLStyleElement; + sheetsDidUpdate: () => void; + CSSText = ""; + + constructor(config: { + theme: ReactUWP.ThemeType; + globalClassName?: string; + sheetsDidUpdate?: () => void; + }) { + const { globalClassName, theme, sheetsDidUpdate } = config; + this.sheetsDidUpdate = sheetsDidUpdate || (() => {}); this.globalClassName = globalClassName ? `${globalClassName}-` : ""; this.setupTheme(theme); } @@ -35,6 +44,14 @@ export class StyleManager { this.themeId = createHash([theme.accent, theme.themeName, theme.useFluentDesign].join(", ")); } + cleanStyleSheet = () => { + if (this.styleElement) document.head.removeChild(this.styleElement); + this.theme = null; + this.sheets = {}; + this.CSSText = ""; + this.styleElement = null; + } + style2CSSText = (style: React.CSSProperties) => style ? Object.keys(style).map(key => ( ` ${replace2Dashes(key)}: ${getStyleValue(key, style[key])};` )).join("\n") : void 0 @@ -76,17 +93,25 @@ export class StyleManager { return this.addSheet(style, className, this.updateSheetsToDOM); } - updateSheetByID = () => {}; + addCSSText = (CSSText: string) => this.CSSText += CSSText; - updateAllSheets = () => {}; + addCSSTextWithUpdate = (CSSText: string) => { + this.addCSSText(CSSText); + if (this.styleElement) { + this.updateStyleTextContent(this.styleElement.textContent += CSSText); + } + } removeSheetByID = () => {}; updateSheetsToDOM = () => { - const name = `data-uwp-jss-${this.themeId}`; - this.styleElement = document.querySelector(`[${name}]`) as HTMLStyleElement; - const textContent = this.sheetsToString(); + let textContent = this.sheetsToString(); + textContent += this.CSSText; + this.updateStyleTextContent(textContent); + } + updateStyleTextContent = (textContent: string) => { + const name = `data-uwp-jss-${this.themeId}`; if (!this.styleElement) { this.styleElement = document.createElement("style"); this.styleElement.setAttribute(name, ""); @@ -95,6 +120,7 @@ export class StyleManager { } else { this.styleElement.textContent = textContent; } + this.sheetsDidUpdate(); } }