[fix] ensure style manager instances don't conflict with each other (#7114)

pull/7127/head
Hofer Ivan 3 years ago committed by GitHub
parent 1143b5615a
commit 806cba2b75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -157,7 +157,7 @@ export function get_root_for_style(node: Node): ShadowRoot | Document {
export function append_empty_stylesheet(node: Node) { export function append_empty_stylesheet(node: Node) {
const style_element = element('style') as HTMLStyleElement; const style_element = element('style') as HTMLStyleElement;
append_stylesheet(get_root_for_style(node), style_element); append_stylesheet(get_root_for_style(node), style_element);
return style_element; return style_element.sheet as CSSStyleSheet;
} }
function append_stylesheet(node: ShadowRoot | Document, style: HTMLStyleElement) { function append_stylesheet(node: ShadowRoot | Document, style: HTMLStyleElement) {

@ -1,12 +1,14 @@
import { append_empty_stylesheet, get_root_for_style } from './dom'; import { append_empty_stylesheet, get_root_for_style } from './dom';
import { raf } from './environment'; import { raf } from './environment';
interface ExtendedDoc extends Document { interface StyleInformation {
__svelte_stylesheet: CSSStyleSheet; stylesheet: CSSStyleSheet;
__svelte_rules: Record<string, true>; rules: Record<string, true>;
} }
const active_docs = new Set<ExtendedDoc>(); // we need to store the information for multiple documents because a Svelte application could also contain iframes
// https://github.com/sveltejs/svelte/issues/3624
const managed_styles = new Map<Document | ShadowRoot, StyleInformation>();
let active = 0; let active = 0;
// https://github.com/darkskyapp/string-hash/blob/master/index.js // https://github.com/darkskyapp/string-hash/blob/master/index.js
@ -18,6 +20,12 @@ function hash(str: string) {
return hash >>> 0; return hash >>> 0;
} }
function create_style_information(doc: Document | ShadowRoot, node: Element & ElementCSSInlineStyle) {
const info = { stylesheet: append_empty_stylesheet(node), rules: {} };
managed_styles.set(doc, info);
return info;
}
export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b: number, duration: number, delay: number, ease: (t: number) => number, fn: (t: number, u: number) => string, uid: number = 0) { export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b: number, duration: number, delay: number, ease: (t: number) => number, fn: (t: number, u: number) => string, uid: number = 0) {
const step = 16.666 / duration; const step = 16.666 / duration;
let keyframes = '{\n'; let keyframes = '{\n';
@ -29,13 +37,12 @@ export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b:
const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`; const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
const name = `__svelte_${hash(rule)}_${uid}`; const name = `__svelte_${hash(rule)}_${uid}`;
const doc = get_root_for_style(node) as ExtendedDoc; const doc = get_root_for_style(node);
active_docs.add(doc);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = append_empty_stylesheet(node).sheet as CSSStyleSheet); const { stylesheet, rules } = managed_styles.get(doc) || create_style_information(doc, node);
const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});
if (!current_rules[name]) { if (!rules[name]) {
current_rules[name] = true; rules[name] = true;
stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length); stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
} }
@ -63,12 +70,12 @@ export function delete_rule(node: Element & ElementCSSInlineStyle, name?: string
export function clear_rules() { export function clear_rules() {
raf(() => { raf(() => {
if (active) return; if (active) return;
active_docs.forEach(doc => { managed_styles.forEach(info => {
const stylesheet = doc.__svelte_stylesheet; const { stylesheet } = info;
let i = stylesheet.cssRules.length; let i = stylesheet.cssRules.length;
while (i--) stylesheet.deleteRule(i); while (i--) stylesheet.deleteRule(i);
doc.__svelte_rules = {}; info.rules = {};
}); });
active_docs.clear(); managed_styles.clear();
}); });
} }

Loading…
Cancel
Save