/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ import { _$LH, } from './lit-html.js'; const { _ChildPart: ChildPart } = _$LH; const ENABLE_SHADYDOM_NOPATCH = true; const wrap = ENABLE_SHADYDOM_NOPATCH && window.ShadyDOM?.inUse && window.ShadyDOM?.noPatch === true ? window.ShadyDOM.wrap : (node) => node; /** * Tests if a value is a primitive value. * * See https://tc39.github.io/ecma262/#sec-typeof-operator */ export const isPrimitive = (value) => value === null || (typeof value != 'object' && typeof value != 'function'); export const TemplateResultType = { HTML: 1, SVG: 2, }; /** * Tests if a value is a TemplateResult or a CompiledTemplateResult. */ export const isTemplateResult = (value, type) => type === undefined ? // This property needs to remain unminified. value?.['_$litType$'] !== undefined : value?.['_$litType$'] === type; /** * Tests if a value is a CompiledTemplateResult. */ export const isCompiledTemplateResult = (value) => { return value?.['_$litType$']?.h != null; }; /** * Tests if a value is a DirectiveResult. */ export const isDirectiveResult = (value) => // This property needs to remain unminified. value?.['_$litDirective$'] !== undefined; /** * Retrieves the Directive class for a DirectiveResult */ export const getDirectiveClass = (value) => // This property needs to remain unminified. value?.['_$litDirective$']; /** * Tests whether a part has only a single-expression with no strings to * interpolate between. * * Only AttributePart and PropertyPart can have multiple expressions. * Multi-expression parts have a `strings` property and single-expression * parts do not. */ export const isSingleExpression = (part) => part.strings === undefined; const createMarker = () => document.createComment(''); /** * Inserts a ChildPart into the given container ChildPart's DOM, either at the * end of the container ChildPart, or before the optional `refPart`. * * This does not add the part to the containerPart's committed value. That must * be done by callers. * * @param containerPart Part within which to add the new ChildPart * @param refPart Part before which to add the new ChildPart; when omitted the * part added to the end of the `containerPart` * @param part Part to insert, or undefined to create a new part */ export const insertPart = (containerPart, refPart, part) => { const container = wrap(containerPart._$startNode).parentNode; const refNode = refPart === undefined ? containerPart._$endNode : refPart._$startNode; if (part === undefined) { const startNode = wrap(container).insertBefore(createMarker(), refNode); const endNode = wrap(container).insertBefore(createMarker(), refNode); part = new ChildPart(startNode, endNode, containerPart, containerPart.options); } else { const endNode = wrap(part._$endNode).nextSibling; const oldParent = part._$parent; const parentChanged = oldParent !== containerPart; if (parentChanged) { part._$reparentDisconnectables?.(containerPart); // Note that although `_$reparentDisconnectables` updates the part's // `_$parent` reference after unlinking from its current parent, that // method only exists if Disconnectables are present, so we need to // unconditionally set it here part._$parent = containerPart; // Since the _$isConnected getter is somewhat costly, only // read it once we know the subtree has directives that need // to be notified let newConnectionState; if (part._$notifyConnectionChanged !== undefined && (newConnectionState = containerPart._$isConnected) !== oldParent._$isConnected) { part._$notifyConnectionChanged(newConnectionState); } } if (endNode !== refNode || parentChanged) { let start = part._$startNode; while (start !== endNode) { const n = wrap(start).nextSibling; wrap(container).insertBefore(start, refNode); start = n; } } } return part; }; /** * Sets the value of a Part. * * Note that this should only be used to set/update the value of user-created * parts (i.e. those created using `insertPart`); it should not be used * by directives to set the value of the directive's container part. Directives * should return a value from `update`/`render` to update their part state. * * For directives that require setting their part value asynchronously, they * should extend `AsyncDirective` and call `this.setValue()`. * * @param part Part to set * @param value Value to set * @param index For `AttributePart`s, the index to set * @param directiveParent Used internally; should not be set by user */ export const setChildPartValue = (part, value, directiveParent = part) => { part._$setValue(value, directiveParent); return part; }; // A sentinel value that can never appear as a part value except when set by // live(). Used to force a dirty-check to fail and cause a re-render. const RESET_VALUE = {}; /** * Sets the committed value of a ChildPart directly without triggering the * commit stage of the part. * * This is useful in cases where a directive needs to update the part such * that the next update detects a value change or not. When value is omitted, * the next update will be guaranteed to be detected as a change. * * @param part * @param value */ export const setCommittedValue = (part, value = RESET_VALUE) => (part._$committedValue = value); /** * Returns the committed value of a ChildPart. * * The committed value is used for change detection and efficient updates of * the part. It can differ from the value set by the template or directive in * cases where the template value is transformed before being committed. * * - `TemplateResult`s are committed as a `TemplateInstance` * - Iterables are committed as `Array` * - All other types are committed as the template value or value returned or * set by a directive. * * @param part */ export const getCommittedValue = (part) => part._$committedValue; /** * Removes a ChildPart from the DOM, including any of its content. * * @param part The Part to remove */ export const removePart = (part) => { part._$notifyConnectionChanged?.(false, true); let start = part._$startNode; const end = wrap(part._$endNode).nextSibling; while (start !== end) { const n = wrap(start).nextSibling; wrap(start).remove(); start = n; } }; export const clearPart = (part) => { part._$clear(); }; //# sourceMappingURL=directive-helpers.js.map