Skip to content

Commit 39b57ac

Browse files
committed
feat: Optimize theme color settings
1 parent 2b7a17b commit 39b57ac

File tree

5 files changed

+109
-117
lines changed

5 files changed

+109
-117
lines changed

src/Theme/StyleManagerSheet.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class StyleManagerSheet extends React.Component<StyleManagerSheetState, S
1111

1212
render() {
1313
return (
14-
<style>{this.state.CSSText}</style>
14+
<style scoped>{this.state.CSSText}</style>
1515
);
1616
}
1717
}

src/Theme/index.tsx

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -75,34 +75,55 @@ export class Theme extends React.Component<ThemeProps, ThemeState> {
7575
}
7676

7777
componentDidMount() {
78+
this.setThemeHelper(this.state.currTheme);
7879
window.addEventListener("scroll", this.handleScrollReveal);
7980
}
8081

8182
componentWillUnmount() {
83+
window.removeEventListener("scroll", this.handleScrollReveal);
84+
this.state.currTheme.styleManager.cleanAllStyles();
85+
this.removeTheme(this.state.currTheme);
86+
8287
const {
83-
currTheme: {
84-
acrylicTexture40,
85-
acrylicTexture60,
86-
acrylicTexture80,
87-
styleManager
88-
}
89-
} = this.state;
88+
acrylicTexture40,
89+
acrylicTexture60,
90+
acrylicTexture80
91+
} = this.state.currTheme;
9092
URL.revokeObjectURL(acrylicTexture40.background);
9193
URL.revokeObjectURL(acrylicTexture60.background);
9294
URL.revokeObjectURL(acrylicTexture80.background);
93-
styleManager.cleanStyleSheet();
95+
}
9496

95-
window.removeEventListener("scroll", this.handleScrollReveal);
97+
removeTheme(prevTheme: ThemeType, newTheme?: ThemeType) {
98+
const {
99+
styleManager
100+
} = prevTheme;
101+
const { scrollBarStyleSelector } = this.props;
102+
103+
if (newTheme) {
104+
styleManager.onSheetsUpdate = (() => {
105+
if (this.styleManagerSheet) {
106+
this.styleManagerSheet.setState(() => ({ CSSText: styleManager.getAllCSSText() }));
107+
}
108+
});
109+
110+
styleManager.removeCSSText(getBaseCSSText(prevTheme, scrollBarStyleSelector));
111+
const CSSText = getBaseCSSText(newTheme, scrollBarStyleSelector);
112+
styleManager.addCSSText(CSSText);
113+
newTheme.styleManager.addCSSText(CSSText);
114+
} else {
115+
styleManager.removeCSSText(getBaseCSSText(prevTheme, scrollBarStyleSelector));
116+
}
96117
}
97118

98119
componentWillReceiveProps(nextProps: ThemeProps) {
99-
const { theme } = nextProps;
100-
this.setState(() => ({ currTheme: theme }));
120+
this.updateTheme(nextProps.theme);
101121
}
102122

103123
setThemeHelper(theme: ThemeType) {
104124
const { scrollBarStyleSelector } = this.props;
105125
const { styleManager } = theme;
126+
106127
styleManager.addCSSText(getBaseCSSText(theme, scrollBarStyleSelector));
107128
styleManager.onSheetsUpdate = (() => {
108129
if (this.styleManagerSheet) {
@@ -112,7 +133,7 @@ export class Theme extends React.Component<ThemeProps, ThemeState> {
112133

113134
Object.assign(theme, {
114135
onThemeUpdate: currTheme => {
115-
this.setState({ currTheme });
136+
this.updateTheme(currTheme);
116137
},
117138
onToastsUpdate: (toasts) => {
118139
const { toastWrapper } = this;
@@ -134,47 +155,13 @@ export class Theme extends React.Component<ThemeProps, ThemeState> {
134155
}
135156

136157
updateTheme(currTheme: ThemeType) {
137-
this.setState(() => ({ currTheme }));
158+
this.setState((prevState) => {
159+
this.removeTheme(prevState.currTheme, currTheme);
160+
this.setThemeHelper(currTheme);
161+
return { currTheme };
162+
});
138163
}
139164

140-
// sureNeedGenerateAcrylic(newTheme: ThemeType) {
141-
// const { currTheme } = this.state;
142-
// let needGenerateAcrylic = newTheme.desktopBackgroundImage && this.props.needGenerateAcrylic;
143-
144-
// if (needGenerateAcrylic &&
145-
// newTheme.desktopBackgroundImage === currTheme.desktopBackgroundImage
146-
// ) {
147-
// if (currTheme.useFluentDesign) {
148-
// Object.assign(currTheme.isDarkTheme ? this.cacheDarkAcrylicTextures : this.cacheLightAcrylicTextures, {
149-
// acrylicTexture40: currTheme.acrylicTexture40,
150-
// acrylicTexture60: currTheme.acrylicTexture60,
151-
// acrylicTexture80: currTheme.acrylicTexture80
152-
// } as ThemeType);
153-
// needGenerateAcrylic = false;
154-
// }
155-
// if (newTheme.useFluentDesign) {
156-
// if (newTheme.isDarkTheme && this.cacheDarkAcrylicTextures.acrylicTexture40 || (
157-
// !newTheme.isDarkTheme && this.cacheLightAcrylicTextures.acrylicTexture40
158-
// )) {
159-
// Object.assign(newTheme, newTheme.isDarkTheme ? this.cacheDarkAcrylicTextures : this.cacheLightAcrylicTextures);
160-
// needGenerateAcrylic = false;
161-
// } else {
162-
// needGenerateAcrylic = true;
163-
// }
164-
// } else {
165-
// needGenerateAcrylic = false;
166-
// Object.assign(newTheme, {
167-
// acrylicTexture40: currTheme.acrylicTexture40,
168-
// acrylicTexture60: currTheme.acrylicTexture60,
169-
// acrylicTexture80: currTheme.acrylicTexture80
170-
// } as ThemeType);
171-
// }
172-
// }
173-
// needGenerateAcrylic = needGenerateAcrylic && newTheme.useFluentDesign && this.props.needGenerateAcrylic;
174-
175-
// return needGenerateAcrylic;
176-
// }
177-
178165
handleScrollReveal = (e?: Event) => {
179166
handleScrollReveal(this.state.currTheme);
180167
}
@@ -192,7 +179,6 @@ export class Theme extends React.Component<ThemeProps, ThemeState> {
192179
...attributes
193180
} = this.props;
194181
const { currTheme } = this.state;
195-
this.setThemeHelper(currTheme);
196182

197183
const styles = getStyles(this);
198184
const classes = currTheme.prepareStyles({

src/styles/StyleManager.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,19 @@ export class StyleManager {
5555
this.prefixClassName = prefixClassName ? `${prefixClassName}-` : "";
5656
}
5757

58-
cleanStyleSheet = (): void => {
58+
cleanAllStyles() {
59+
this.cleanSheets();
60+
this.cleanCSSText();
61+
}
62+
63+
cleanSheets = (): void => {
5964
this.theme = null;
6065
this.sheets = {};
66+
}
67+
68+
cleanCSSText() {
69+
this.theme = null;
70+
this.addedCSSText = {};
6171
this.CSSText = "";
6272
}
6373

@@ -105,7 +115,7 @@ export class StyleManager {
105115
return this.sheets[id];
106116
}
107117

108-
addCSSText = (CSSText: string): void => {
118+
addCSSText = (CSSText: string) => {
109119
const hash = createHash(CSSText);
110120
const shouldUpdate = !this.addedCSSText[hash];
111121
if (shouldUpdate) {
@@ -115,6 +125,13 @@ export class StyleManager {
115125
this.onSheetsUpdate(this.sheets);
116126
}
117127

128+
removeCSSText = (CSSText: string) => {
129+
const hash = createHash(CSSText);
130+
this.addedCSSText[hash] = false;
131+
this.CSSText = this.CSSText.replace(CSSText, "");
132+
this.onSheetsUpdate(this.sheets);
133+
}
134+
118135
setStyleToManager(config?: {
119136
style?: CustomCSSProperties;
120137
className?: string;

src/styles/generateAcrylicTexture.ts

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
11
import * as stackBlurCanvas from "stackblur-canvas";
22
import * as tinycolor2 from "tinycolor2";
33

4-
export default function generateAcrylicTexture(
5-
image?: string,
6-
tintColor = "#fff",
7-
tintOpacity = 0.4,
8-
blurSize = 24,
9-
noiseSize = 1,
10-
noiseOpacity = 0.2,
11-
callback = (image?: string) => {}
12-
) {
13-
if (!image) return "none";
14-
const id = `react-uwp-AcrylicTexture-${tintColor}-${tintOpacity}`;
15-
let canvas: HTMLCanvasElement = document.getElementById(id) as any;
16-
if (!canvas) {
17-
canvas = document.createElement("canvas");
18-
canvas.id = id;
19-
document.body.appendChild(canvas);
4+
export interface AcrylicTextureConfig {
5+
image: string;
6+
tintColor: string;
7+
tintOpacity: number;
8+
blurSize?: number;
9+
callback?: (image?: string) => void;
10+
}
11+
12+
const acrylicTextureMap = new Map<string, string>();
13+
export default function generateAcrylicTexture(config: AcrylicTextureConfig) {
14+
let { image, tintColor, tintOpacity, blurSize, callback } = config;
15+
blurSize = blurSize || 24;
16+
const configStr = JSON.stringify({ image, tintColor, tintOpacity, blurSize });
17+
let acrylicTexture = acrylicTextureMap.get(configStr);
18+
19+
if (acrylicTexture) {
20+
callback(acrylicTexture);
21+
return;
2022
}
21-
canvas.style.display = "none";
23+
24+
const canvas = document.createElement("canvas");
2225
const context = canvas.getContext("2d");
2326
const imageNode = new Image();
2427
imageNode.crossOrigin = "Anonymous";
28+
2529
imageNode.onload = () => {
2630
let { naturalWidth, naturalHeight } = imageNode;
2731
if (naturalWidth > 1000) {
@@ -33,34 +37,28 @@ export default function generateAcrylicTexture(
3337
naturalHeight = 1000;
3438
}
3539

36-
3740
canvas.width = naturalWidth;
3841
canvas.height = naturalHeight;
3942
context.drawImage(imageNode, 0, 0, naturalWidth, naturalHeight);
40-
4143
stackBlurCanvas.canvasRGBA(canvas, 0, 0, naturalWidth, naturalHeight, blurSize);
4244

4345
context.fillStyle = tinycolor2(tintColor).setAlpha(tintOpacity).toRgbString();
4446
context.fillRect(0, 0, naturalWidth, naturalHeight);
45-
46-
// const noiseWidth = 40;
47-
// const noiseHeight = 40;
48-
// const noiseImageDate = generateNoise(canvas, context, noiseWidth, noiseHeight, noiseSize, noiseOpacity);
49-
5047
if (HTMLCanvasElement.prototype.toBlob) {
5148
canvas.toBlob((blob) => {
52-
const url = URL.createObjectURL(blob);
53-
callback(url);
49+
acrylicTexture = URL.createObjectURL(blob);
5450
});
5551
} else if (HTMLCanvasElement.prototype["msToBlob"]) {
5652
const blob = canvas["msToBlob"]();
57-
const url = URL.createObjectURL(blob);
58-
callback(url);
53+
acrylicTexture = URL.createObjectURL(blob);
5954
} else {
60-
callback(canvas.toDataURL("image/jpg"));
55+
acrylicTexture = canvas.toDataURL("image/jpg");
6156
}
57+
58+
acrylicTextureMap.set(configStr, acrylicTexture);
59+
if (callback) callback(acrylicTexture);
6260
};
63-
imageNode.src = image;
61+
6462
}
6563

6664

src/styles/getTheme.ts

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { Toast } from "../Toast";
44
import { StyleManager, CustomCSSProperties, StyleClasses } from "./StyleManager";
55
import generateAcrylicTexture from "./generateAcrylicTexture";
66

7-
const styleManager = new StyleManager();
87
export function darken(color: string, coefficient: number) {
98
const hsl = tinycolor(color).toHsl();
109
hsl.l = hsl.l * (1 - coefficient);
@@ -65,7 +64,7 @@ export class Theme {
6564
segoeMDL2Assets: string;
6665
};
6766

68-
styleManager?: StyleManager = styleManager;
67+
styleManager?: StyleManager = new StyleManager();
6968
scrollReveals?: ScrollRevealType[] = [];
7069

7170
desktopBackground?: string;
@@ -386,9 +385,7 @@ export class Theme {
386385
this.generateAcrylicTextures = (themeCallback?: (theme?: Theme) => void) => {
387386
this.acrylicTextureCount = 0;
388387
const baseConfig = {
389-
blurSize: 24,
390-
noiseSize: 1,
391-
noiseOpacity: 0.2
388+
blurSize: 24
392389
};
393390

394391
const callback = (image: string, key: number) => {
@@ -427,33 +424,27 @@ export class Theme {
427424
}
428425
};
429426

430-
generateAcrylicTexture(
431-
this.desktopBackgroundImage,
432-
this.chromeMediumLow,
433-
0.4,
434-
void 0,
435-
void 0,
436-
void 0,
437-
image => callback(image, 4)
438-
);
439-
generateAcrylicTexture(
440-
this.desktopBackgroundImage,
441-
this.chromeLow,
442-
0.6,
443-
void 0,
444-
void 0,
445-
void 0,
446-
image => callback(image, 6)
447-
);
448-
generateAcrylicTexture(
449-
this.desktopBackgroundImage,
450-
this.chromeLow,
451-
0.8,
452-
void 0,
453-
void 0,
454-
void 0,
455-
image => callback(image, 8)
456-
);
427+
generateAcrylicTexture({
428+
image: this.desktopBackgroundImage,
429+
tintColor: this.chromeMediumLow,
430+
tintOpacity: 0.4,
431+
blurSize: baseConfig.blurSize,
432+
callback: image => callback(image, 4)
433+
});
434+
generateAcrylicTexture({
435+
image: this.desktopBackgroundImage,
436+
tintColor: this.chromeLow,
437+
tintOpacity: 0.6,
438+
blurSize: baseConfig.blurSize,
439+
callback: image => callback(image, 6)
440+
});
441+
generateAcrylicTexture({
442+
image: this.desktopBackgroundImage,
443+
tintColor: this.chromeLow,
444+
tintOpacity: 0.8,
445+
blurSize: baseConfig.blurSize,
446+
callback: image => callback(image, 8)
447+
});
457448
};
458449

459450
// toasts storage.

0 commit comments

Comments
 (0)