-
Notifications
You must be signed in to change notification settings - Fork 439
Expand file tree
/
Copy pathrenderer-hooks.ts
More file actions
104 lines (98 loc) · 3.64 KB
/
renderer-hooks.ts
File metadata and controls
104 lines (98 loc) · 3.64 KB
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* 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 { ElementDirectiveName } from './types';
import type State from '../state';
import type { BaseElement } from './types';
/**
* Config representing criteria for an element match.
* All conditions specified must be satisfied to be considered a match.
*/
export interface CustomRendererElementConfig {
/**
* Tag name to use to match an element.
*/
tagName: string;
/**
* Optional namespace to match an element.
*/
namespace?: string;
/**
* Specify attributes that need to be matched.
* This field is optional.
* If undefined or empty, attribute matching is skipped.
*/
attributes?: string[];
}
/**
* Config to specify which elements and directives require a customizable renderer.
* An element is qualified if it matches the CustomRendererElementConfig OR the directives.
*/
export interface CustomRendererConfig {
/**
* Element matching criteria. Element much satisfy all conditions of the CustomRendererElementConfig
*/
elements: CustomRendererElementConfig[];
/**
* List of lwc directives that qualify an element. An element must use at least 1
* directive to be considered a match.
* If empty, elements matching is not done based on directives.
*/
directives: string[];
}
function shouldAddCustomRenderer(element: BaseElement, state: State): boolean {
// Elements of type `ExternalComponent` (e.g., elements with the lwc:external directive)
if (state.crDirectives.has('lwc:external') && element.type === 'ExternalComponent') {
return true;
}
// Elements of type `Component` are not allowed to have custom renderer hooks.
// The renderer is cascaded down from the owner(custom element) to all its child nodes who
// do not have a renderer specified.
// lwc:component will resolve to a custom element at runtime.
if (element.type === 'Component' || element.name === 'lwc:component') {
return false;
}
const { attributes, directives } = element;
if (directives.length) {
// If any directives require custom renderer
const directiveMatched = directives.some((dir) => {
return state.crDirectives.has(ElementDirectiveName[dir.name]);
});
if (directiveMatched) {
return true;
}
}
const elementConfig = state.crElmToConfigMap[element.name];
// If element requires custom renderer
if (elementConfig) {
const { namespace, attributes: attrConfig } = elementConfig;
// if element config has namespace, then namespace has to be a match
if (namespace && element.namespace !== namespace) {
return false;
}
// If no attributes are specified, then consider the element requires custom renderer
if (
attrConfig.size === 0 ||
attributes.some((attribute) => attrConfig.has(attribute.name))
) {
return true;
}
}
return false;
}
export function isCustomRendererHookRequired(element: BaseElement, state: State): boolean {
let addCustomRenderer = false;
if (state.config.customRendererConfig) {
const cachedResult = state.crCheckedElements.get(element);
if (cachedResult !== undefined) {
return cachedResult;
} else {
addCustomRenderer = shouldAddCustomRenderer(element, state);
state.crCheckedElements.set(element, addCustomRenderer);
}
}
return addCustomRenderer;
}