/
query.ts
72 lines (68 loc) · 2.01 KB
/
query.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
72
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* IMPORTANT: For compatibility with tsickle and the Closure JS compiler, all
* property decorators (but not class decorators) in this file that have
* an @ExportDecoratedItems annotation must be defined as a regular function,
* not an arrow function.
*/
import {ReactiveElement} from '../reactive-element.js';
import {decorateProperty} from './base.js';
const DEV_MODE = true;
/**
* A property decorator that converts a class property into a getter that
* executes a querySelector on the element's renderRoot.
*
* @param selector A DOMString containing one or more selectors to match.
* @param cache An optional boolean which when true performs the DOM query only
* once and caches the result.
*
* See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
*
* ```ts
* class MyElement {
* @query('#first')
* first: HTMLDivElement;
*
* render() {
* return html`
* <div id="first"></div>
* <div id="second"></div>
* `;
* }
* }
* ```
* @category Decorator
*/
export function query(selector: string, cache?: boolean) {
return decorateProperty({
descriptor: (name: PropertyKey) => {
const descriptor = {
get(this: ReactiveElement) {
return this.renderRoot?.querySelector(selector) ?? null;
},
enumerable: true,
configurable: true,
};
if (cache) {
const key = DEV_MODE
? Symbol(`${String(name)} (@query() cache)`)
: Symbol();
descriptor.get = function (this: ReactiveElement) {
if (
(this as unknown as {[key: symbol]: Element | null})[key] ===
undefined
) {
(this as unknown as {[key: symbol]: Element | null})[key] =
this.renderRoot?.querySelector(selector) ?? null;
}
return (this as unknown as {[key: symbol]: Element | null})[key];
};
}
return descriptor;
},
});
}