|
1 |
| -import { copyCSSStyleSheetsIfNeed, isFunction, isSupportCSSStyleSheet, toArrayIfNotNil } from '@lun/utils'; |
| 1 | +import { copyCSSStyleSheetsIfNeed, runIfFn, isSupportCSSStyleSheet, toArrayIfNotNil } from '@lun/utils'; |
2 | 2 | import type { OpenShadowComponentKey } from 'config';
|
3 | 3 | import { GlobalStaticConfig, componentsWithTeleport, useContextConfig } from 'config';
|
4 | 4 | import { computed, getCurrentInstance, h, watchEffect } from 'vue';
|
5 | 5 | import { onCEMount } from './shadowDom';
|
6 | 6 | import { error } from '../utils/console';
|
| 7 | +import { processStringStyle } from 'utils'; |
7 | 8 |
|
8 | 9 | export function useContextStyles(name: OpenShadowComponentKey) {
|
9 | 10 | const vm = getCurrentInstance()!;
|
10 | 11 | if (__DEV__ && !vm) {
|
11 | 12 | error('useContextStyles must be called inside setup()');
|
12 | 13 | return;
|
13 | 14 | }
|
14 |
| - const dynamicStyles = useContextConfig('dynamicStyles'); |
15 |
| - const styles = toArrayIfNotNil(dynamicStyles[name]).concat(() => (vm.props.innerStyle as string) || ''); |
| 15 | + const context = useContextConfig(); |
| 16 | + const { dynamicStyles } = context; |
| 17 | + const styles = toArrayIfNotNil(dynamicStyles[name]).concat( |
| 18 | + () => (vm.props.innerStyle as string) || '', |
| 19 | + ); |
16 | 20 | if (name === 'teleport-holder') {
|
17 | 21 | styles.push(...componentsWithTeleport.flatMap((name) => dynamicStyles[name]));
|
18 | 22 | }
|
19 |
| - let sheets: CSSStyleSheet[] = []; |
| 23 | + const sheets: (CSSStyleSheet & { _clone?: CSSStyleSheet; _css: () => string })[] = []; |
20 | 24 | const textStyles: (() => string)[] = [];
|
21 | 25 | const adopt = isSupportCSSStyleSheet() && GlobalStaticConfig.preferCSSStyleSheet;
|
22 | 26 | styles.forEach((s) => {
|
23 | 27 | if (!s) return;
|
24 |
| - const css = !isFunction(s) ? () => String(s) : s; |
| 28 | + const css = () => processStringStyle(runIfFn(s, vm, name, context), true); |
25 | 29 | if (adopt) {
|
26 |
| - const sheet = new CSSStyleSheet(); |
27 |
| - watchEffect(() => { |
28 |
| - const result = css(vm); |
29 |
| - result && sheet.replaceSync(String(result)); |
30 |
| - }); |
| 30 | + const sheet = new CSSStyleSheet() as CSSStyleSheet & { _clone?: CSSStyleSheet; _css: () => string }; |
| 31 | + sheet._css = css; |
31 | 32 | sheets.push(sheet);
|
32 | 33 | } else {
|
33 |
| - textStyles.push(() => css(vm)); |
| 34 | + textStyles.push(css); |
34 | 35 | }
|
35 | 36 | });
|
| 37 | + watchEffect(() => { |
| 38 | + sheets.forEach((s) => { |
| 39 | + s.replaceSync(s._css()); |
| 40 | + if (s._clone) { |
| 41 | + s._clone.replaceSync(s._css()); |
| 42 | + } |
| 43 | + }); |
| 44 | + }); |
36 | 45 | onCEMount(({ shadowRoot }) => {
|
37 | 46 | if (sheets.length) {
|
| 47 | + // TODO 或许不用管clone,或许可以通过vm.CE去获取window的CSSStyleSheet,这样就不用克隆了 |
38 | 48 | // copyCSSStyleSheetsIfNeed is for doc-pip component. when custom-element is moved to another document, it will throw an error: Sharing constructed stylesheets in multiple documents is not allowed
|
39 | 49 | // so we must check if the stylesheets are shared between documents, if so, we must clone them
|
40 |
| - shadowRoot.adoptedStyleSheets.push(...copyCSSStyleSheetsIfNeed(sheets, shadowRoot)); |
| 50 | + const cloned = copyCSSStyleSheetsIfNeed(sheets, shadowRoot); |
| 51 | + // attach cloned sheet to original sheet, so that it can be updated in watchEffect |
| 52 | + cloned.forEach((s, i) => { |
| 53 | + if (s !== sheets[i]) { |
| 54 | + sheets[i]._clone = s; |
| 55 | + } |
| 56 | + }); |
| 57 | + shadowRoot.adoptedStyleSheets.push(...cloned); |
41 | 58 | }
|
42 | 59 | });
|
43 | 60 | return computed(() => textStyles.map((i) => h('style', { type: 'text/css' }, i())));
|
|
0 commit comments