this repo has no description
1import { append_empty_stylesheet, detach, get_root_for_style } from './dom.js';
2import { raf } from './environment.js';
3
4// we need to store the information for multiple documents because a Svelte application could also contain iframes
5// https://github.com/sveltejs/svelte/issues/3624
6/** @type {Map<Document | ShadowRoot, import('./private.d.ts').StyleInformation>} */
7const managed_styles = new Map();
8
9let active = 0;
10
11// https://github.com/darkskyapp/string-hash/blob/master/index.js
12/**
13 * @param {string} str
14 * @returns {number}
15 */
16function hash(str) {
17 let hash = 5381;
18 let i = str.length;
19 while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
20 return hash >>> 0;
21}
22
23/**
24 * @param {Document | ShadowRoot} doc
25 * @param {Element & ElementCSSInlineStyle} node
26 * @returns {{ stylesheet: any; rules: {}; }}
27 */
28function create_style_information(doc, node) {
29 const info = { stylesheet: append_empty_stylesheet(node), rules: {} };
30 managed_styles.set(doc, info);
31 return info;
32}
33
34/**
35 * @param {Element & ElementCSSInlineStyle} node
36 * @param {number} a
37 * @param {number} b
38 * @param {number} duration
39 * @param {number} delay
40 * @param {(t: number) => number} ease
41 * @param {(t: number, u: number) => string} fn
42 * @param {number} uid
43 * @returns {string}
44 */
45export function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) {
46 const step = 16.666 / duration;
47 let keyframes = '{\n';
48 for (let p = 0; p <= 1; p += step) {
49 const t = a + (b - a) * ease(p);
50 keyframes += p * 100 + `%{${fn(t, 1 - t)}}\n`;
51 }
52 const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
53 const name = `__svelte_${hash(rule)}_${uid}`;
54 const doc = get_root_for_style(node);
55 const { stylesheet, rules } = managed_styles.get(doc) || create_style_information(doc, node);
56 if (!rules[name]) {
57 rules[name] = true;
58 stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
59 }
60 const animation = node.style.animation || '';
61 node.style.animation = `${
62 animation ? `${animation}, ` : ''
63 }${name} ${duration}ms linear ${delay}ms 1 both`;
64 active += 1;
65 return name;
66}
67
68/**
69 * @param {Element & ElementCSSInlineStyle} node
70 * @param {string} [name]
71 * @returns {void}
72 */
73export function delete_rule(node, name) {
74 const previous = (node.style.animation || '').split(', ');
75 const next = previous.filter(
76 name
77 ? (anim) => anim.indexOf(name) < 0 // remove specific animation
78 : (anim) => anim.indexOf('__svelte') === -1 // remove all Svelte animations
79 );
80 const deleted = previous.length - next.length;
81 if (deleted) {
82 node.style.animation = next.join(', ');
83 active -= deleted;
84 if (!active) clear_rules();
85 }
86}
87
88/** @returns {void} */
89export function clear_rules() {
90 raf(() => {
91 if (active) return;
92 managed_styles.forEach((info) => {
93 const { ownerNode } = info.stylesheet;
94 // there is no ownerNode if it runs on jsdom.
95 if (ownerNode) detach(ownerNode);
96 });
97 managed_styles.clear();
98 });
99}