1 | /**
|
2 | * @license
|
3 | * Copyright 2020 Google LLC
|
4 | * SPDX-License-Identifier: BSD-3-Clause
|
5 | */
|
6 | import { _$LH, } from './lit-html.js';
|
7 | const { _ChildPart: ChildPart } = _$LH;
|
8 | const ENABLE_SHADYDOM_NOPATCH = true;
|
9 | const wrap = ENABLE_SHADYDOM_NOPATCH &&
|
10 | window.ShadyDOM?.inUse &&
|
11 | window.ShadyDOM?.noPatch === true
|
12 | ? window.ShadyDOM.wrap
|
13 | : (node) => node;
|
14 | /**
|
15 | * Tests if a value is a primitive value.
|
16 | *
|
17 | * See https://tc39.github.io/ecma262/#sec-typeof-operator
|
18 | */
|
19 | export const isPrimitive = (value) => value === null || (typeof value != 'object' && typeof value != 'function');
|
20 | export const TemplateResultType = {
|
21 | HTML: 1,
|
22 | SVG: 2,
|
23 | };
|
24 | /**
|
25 | * Tests if a value is a TemplateResult or a CompiledTemplateResult.
|
26 | */
|
27 | export const isTemplateResult = (value, type) => type === undefined
|
28 | ? // This property needs to remain unminified.
|
29 | value?.['_$litType$'] !== undefined
|
30 | : value?.['_$litType$'] === type;
|
31 | /**
|
32 | * Tests if a value is a CompiledTemplateResult.
|
33 | */
|
34 | export const isCompiledTemplateResult = (value) => {
|
35 | return value?.['_$litType$']?.h != null;
|
36 | };
|
37 | /**
|
38 | * Tests if a value is a DirectiveResult.
|
39 | */
|
40 | export const isDirectiveResult = (value) =>
|
41 | // This property needs to remain unminified.
|
42 | value?.['_$litDirective$'] !== undefined;
|
43 | /**
|
44 | * Retrieves the Directive class for a DirectiveResult
|
45 | */
|
46 | export const getDirectiveClass = (value) =>
|
47 | // This property needs to remain unminified.
|
48 | value?.['_$litDirective$'];
|
49 | /**
|
50 | * Tests whether a part has only a single-expression with no strings to
|
51 | * interpolate between.
|
52 | *
|
53 | * Only AttributePart and PropertyPart can have multiple expressions.
|
54 | * Multi-expression parts have a `strings` property and single-expression
|
55 | * parts do not.
|
56 | */
|
57 | export const isSingleExpression = (part) => part.strings === undefined;
|
58 | const createMarker = () => document.createComment('');
|
59 | /**
|
60 | * Inserts a ChildPart into the given container ChildPart's DOM, either at the
|
61 | * end of the container ChildPart, or before the optional `refPart`.
|
62 | *
|
63 | * This does not add the part to the containerPart's committed value. That must
|
64 | * be done by callers.
|
65 | *
|
66 | * @param containerPart Part within which to add the new ChildPart
|
67 | * @param refPart Part before which to add the new ChildPart; when omitted the
|
68 | * part added to the end of the `containerPart`
|
69 | * @param part Part to insert, or undefined to create a new part
|
70 | */
|
71 | export const insertPart = (containerPart, refPart, part) => {
|
72 | const container = wrap(containerPart._$startNode).parentNode;
|
73 | const refNode = refPart === undefined ? containerPart._$endNode : refPart._$startNode;
|
74 | if (part === undefined) {
|
75 | const startNode = wrap(container).insertBefore(createMarker(), refNode);
|
76 | const endNode = wrap(container).insertBefore(createMarker(), refNode);
|
77 | part = new ChildPart(startNode, endNode, containerPart, containerPart.options);
|
78 | }
|
79 | else {
|
80 | const endNode = wrap(part._$endNode).nextSibling;
|
81 | const oldParent = part._$parent;
|
82 | const parentChanged = oldParent !== containerPart;
|
83 | if (parentChanged) {
|
84 | part._$reparentDisconnectables?.(containerPart);
|
85 | // Note that although `_$reparentDisconnectables` updates the part's
|
86 | // `_$parent` reference after unlinking from its current parent, that
|
87 | // method only exists if Disconnectables are present, so we need to
|
88 | // unconditionally set it here
|
89 | part._$parent = containerPart;
|
90 | // Since the _$isConnected getter is somewhat costly, only
|
91 | // read it once we know the subtree has directives that need
|
92 | // to be notified
|
93 | let newConnectionState;
|
94 | if (part._$notifyConnectionChanged !== undefined &&
|
95 | (newConnectionState = containerPart._$isConnected) !==
|
96 | oldParent._$isConnected) {
|
97 | part._$notifyConnectionChanged(newConnectionState);
|
98 | }
|
99 | }
|
100 | if (endNode !== refNode || parentChanged) {
|
101 | let start = part._$startNode;
|
102 | while (start !== endNode) {
|
103 | const n = wrap(start).nextSibling;
|
104 | wrap(container).insertBefore(start, refNode);
|
105 | start = n;
|
106 | }
|
107 | }
|
108 | }
|
109 | return part;
|
110 | };
|
111 | /**
|
112 | * Sets the value of a Part.
|
113 | *
|
114 | * Note that this should only be used to set/update the value of user-created
|
115 | * parts (i.e. those created using `insertPart`); it should not be used
|
116 | * by directives to set the value of the directive's container part. Directives
|
117 | * should return a value from `update`/`render` to update their part state.
|
118 | *
|
119 | * For directives that require setting their part value asynchronously, they
|
120 | * should extend `AsyncDirective` and call `this.setValue()`.
|
121 | *
|
122 | * @param part Part to set
|
123 | * @param value Value to set
|
124 | * @param index For `AttributePart`s, the index to set
|
125 | * @param directiveParent Used internally; should not be set by user
|
126 | */
|
127 | export const setChildPartValue = (part, value, directiveParent = part) => {
|
128 | part._$setValue(value, directiveParent);
|
129 | return part;
|
130 | };
|
131 | // A sentinel value that can never appear as a part value except when set by
|
132 | // live(). Used to force a dirty-check to fail and cause a re-render.
|
133 | const RESET_VALUE = {};
|
134 | /**
|
135 | * Sets the committed value of a ChildPart directly without triggering the
|
136 | * commit stage of the part.
|
137 | *
|
138 | * This is useful in cases where a directive needs to update the part such
|
139 | * that the next update detects a value change or not. When value is omitted,
|
140 | * the next update will be guaranteed to be detected as a change.
|
141 | *
|
142 | * @param part
|
143 | * @param value
|
144 | */
|
145 | export const setCommittedValue = (part, value = RESET_VALUE) => (part._$committedValue = value);
|
146 | /**
|
147 | * Returns the committed value of a ChildPart.
|
148 | *
|
149 | * The committed value is used for change detection and efficient updates of
|
150 | * the part. It can differ from the value set by the template or directive in
|
151 | * cases where the template value is transformed before being committed.
|
152 | *
|
153 | * - `TemplateResult`s are committed as a `TemplateInstance`
|
154 | * - Iterables are committed as `Array<ChildPart>`
|
155 | * - All other types are committed as the template value or value returned or
|
156 | * set by a directive.
|
157 | *
|
158 | * @param part
|
159 | */
|
160 | export const getCommittedValue = (part) => part._$committedValue;
|
161 | /**
|
162 | * Removes a ChildPart from the DOM, including any of its content.
|
163 | *
|
164 | * @param part The Part to remove
|
165 | */
|
166 | export const removePart = (part) => {
|
167 | part._$notifyConnectionChanged?.(false, true);
|
168 | let start = part._$startNode;
|
169 | const end = wrap(part._$endNode).nextSibling;
|
170 | while (start !== end) {
|
171 | const n = wrap(start).nextSibling;
|
172 | wrap(start).remove();
|
173 | start = n;
|
174 | }
|
175 | };
|
176 | export const clearPart = (part) => {
|
177 | part._$clear();
|
178 | };
|
179 | //# sourceMappingURL=directive-helpers.js.map |
\ | No newline at end of file |