-
Notifications
You must be signed in to change notification settings - Fork 382
/
shadow-token.ts
71 lines (66 loc) · 2.45 KB
/
shadow-token.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
* Copyright (c) 2018, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import {
defineProperty,
isUndefined,
KEY__SHADOW_TOKEN,
KEY__SHADOW_TOKEN_PRIVATE,
KEY__SHADOW_STATIC,
KEY__SHADOW_STATIC_PRIVATE,
KEY__SHADOW_RESOLVER,
} from '@lwc/shared';
import { setAttribute, removeAttribute } from '../env/element';
import { childNodesGetter } from '../env/node';
export function getShadowToken(node: Node): string | undefined {
return (node as any)[KEY__SHADOW_TOKEN];
}
export function setShadowToken(node: Node, shadowToken: string | undefined) {
(node as any)[KEY__SHADOW_TOKEN] = shadowToken;
}
/**
* Patching Element.prototype.$shadowToken$ to mark elements a portal:
* - we use a property to allow engines to set a custom attribute that should be
* placed into the element to sandbox the css rules defined for the template.
* - this custom attribute must be unique.
*/
defineProperty(Element.prototype, KEY__SHADOW_TOKEN, {
set(this: Element, shadowToken: string | undefined) {
const oldShadowToken = (this as any)[KEY__SHADOW_TOKEN_PRIVATE];
if (!isUndefined(oldShadowToken) && oldShadowToken !== shadowToken) {
removeAttribute.call(this, oldShadowToken);
}
if (!isUndefined(shadowToken)) {
setAttribute.call(this, shadowToken, '');
}
(this as any)[KEY__SHADOW_TOKEN_PRIVATE] = shadowToken;
},
get(this: Element): string | undefined {
return (this as any)[KEY__SHADOW_TOKEN_PRIVATE];
},
configurable: true,
});
function recursivelySetShadowResolver(node: Node, fn: any) {
(node as any)[KEY__SHADOW_RESOLVER] = fn;
const childNodes = childNodesGetter.call(node);
for (let i = 0, n = childNodes.length; i < n; i++) {
recursivelySetShadowResolver(childNodes[i], fn);
}
}
defineProperty(Element.prototype, KEY__SHADOW_STATIC, {
set(this: Element, v: boolean) {
// Marking an element as static will propagate the shadow resolver to the children.
if (v) {
const fn = (this as any)[KEY__SHADOW_RESOLVER];
recursivelySetShadowResolver(this, fn);
}
(this as any)[KEY__SHADOW_STATIC_PRIVATE] = v;
},
get(this: Element): string | undefined {
return (this as any)[KEY__SHADOW_STATIC_PRIVATE];
},
configurable: true,
});