import { customElements, HTMLElement } from '@lit-labs/ssr-dom-shim'; import { getCompatibleStyle, adoptStyles } from './css-tag.js'; export { CSSResult, adoptStyles, css, getCompatibleStyle, supportsAdoptingStyleSheets, unsafeCSS } from './css-tag.js'; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ var _a, _b, _c, _d; var _e; const global = globalThis ; { (_a = global.customElements) !== null && _a !== void 0 ? _a : (global.customElements = customElements); } let requestUpdateThenable; let issueWarning; const trustedTypes = global .trustedTypes; // Temporary workaround for https://crbug.com/993268 // Currently, any attribute starting with "on" is considered to be a // TrustedScript source. Such boolean attributes must be set to the equivalent // trusted emptyScript value. const emptyStringForBooleanAttribute = trustedTypes ? trustedTypes.emptyScript : ''; const polyfillSupport = global.reactiveElementPolyfillSupportDevMode ; { // Ensure warnings are issued only 1x, even if multiple versions of Lit // are loaded. const issuedWarnings = ((_b = global.litIssuedWarnings) !== null && _b !== void 0 ? _b : (global.litIssuedWarnings = new Set())); // Issue a warning, if we haven't already. issueWarning = (code, warning) => { warning += ` See https://lit.dev/msg/${code} for more information.`; if (!issuedWarnings.has(warning)) { console.warn(warning); issuedWarnings.add(warning); } }; issueWarning('dev-mode', `Lit is in dev mode. Not recommended for production!`); // Issue polyfill support warning. if (((_c = global.ShadyDOM) === null || _c === void 0 ? void 0 : _c.inUse) && polyfillSupport === undefined) { issueWarning('polyfill-support-missing', `Shadow DOM is being polyfilled via \`ShadyDOM\` but ` + `the \`polyfill-support\` module has not been loaded.`); } requestUpdateThenable = (name) => ({ then: (onfulfilled, _onrejected) => { issueWarning('request-update-promise', `The \`requestUpdate\` method should no longer return a Promise but ` + `does so on \`${name}\`. Use \`updateComplete\` instead.`); if (onfulfilled !== undefined) { onfulfilled(false); } }, }); } /** * Useful for visualizing and logging insights into what the Lit template system is doing. * * Compiled out of prod mode builds. */ const debugLogEvent = (event) => { const shouldEmit = global .emitLitDebugLogEvents; if (!shouldEmit) { return; } global.dispatchEvent(new CustomEvent('lit-debug', { detail: event, })); } ; /* * When using Closure Compiler, JSCompiler_renameProperty(property, object) is * replaced at compile time by the munged name for object[property]. We cannot * alias this function, so we have to use a small shim that has the same * behavior when not compiling. */ /*@__INLINE__*/ const JSCompiler_renameProperty = (prop, _obj) => prop; const defaultConverter = { toAttribute(value, type) { switch (type) { case Boolean: value = value ? emptyStringForBooleanAttribute : null; break; case Object: case Array: // if the value is `null` or `undefined` pass this through // to allow removing/no change behavior. value = value == null ? value : JSON.stringify(value); break; } return value; }, fromAttribute(value, type) { let fromValue = value; switch (type) { case Boolean: fromValue = value !== null; break; case Number: fromValue = value === null ? null : Number(value); break; case Object: case Array: // Do *not* generate exception when invalid JSON is set as elements // don't normally complain on being mis-configured. // TODO(sorvell): Do generate exception in *dev mode*. try { // Assert to adhere to Bazel's "must type assert JSON parse" rule. fromValue = JSON.parse(value); } catch (e) { fromValue = null; } break; } return fromValue; }, }; /** * Change function that returns true if `value` is different from `oldValue`. * This method is used as the default for a property's `hasChanged` function. */ const notEqual = (value, old) => { // This ensures (old==NaN, value==NaN) always returns false return old !== value && (old === old || value === value); }; const defaultPropertyDeclaration = { attribute: true, type: String, converter: defaultConverter, reflect: false, hasChanged: notEqual, }; /** * The Closure JS Compiler doesn't currently have good support for static * property semantics where "this" is dynamic (e.g. * https://github.com/google/closure-compiler/issues/3177 and others) so we use * this hack to bypass any rewriting by the compiler. */ const finalized = 'finalized'; /** * Base element class which manages element properties and attributes. When * properties change, the `update` method is asynchronously called. This method * should be supplied by subclassers to render updates as desired. * @noInheritDoc */ class ReactiveElement // In the Node build, this `extends` clause will be substituted with // `(globalThis.HTMLElement ?? HTMLElement)`. // // This way, we will first prefer any global `HTMLElement` polyfill that the // user has assigned, and then fall back to the `HTMLElement` shim which has // been imported (see note at the top of this file about how this import is // generated by Rollup). Note that the `HTMLElement` variable has been // shadowed by this import, so it no longer refers to the global. extends (globalThis.HTMLElement ?? HTMLElement) { constructor() { super(); this.__instanceProperties = new Map(); /** * True if there is a pending update as a result of calling `requestUpdate()`. * Should only be read. * @category updates */ this.isUpdatePending = false; /** * Is set to `true` after the first update. The element code cannot assume * that `renderRoot` exists before the element `hasUpdated`. * @category updates */ this.hasUpdated = false; /** * Name of currently reflecting property */ this.__reflectingProperty = null; this.__initialize(); } /** * Adds an initializer function to the class that is called during instance * construction. * * This is useful for code that runs against a `ReactiveElement` * subclass, such as a decorator, that needs to do work for each * instance, such as setting up a `ReactiveController`. * * ```ts * const myDecorator = (target: typeof ReactiveElement, key: string) => { * target.addInitializer((instance: ReactiveElement) => { * // This is run during construction of the element * new MyController(instance); * }); * } * ``` * * Decorating a field will then cause each instance to run an initializer * that adds a controller: * * ```ts * class MyElement extends LitElement { * @myDecorator foo; * } * ``` * * Initializers are stored per-constructor. Adding an initializer to a * subclass does not add it to a superclass. Since initializers are run in * constructors, initializers will run in order of the class hierarchy, * starting with superclasses and progressing to the instance's class. * * @nocollapse */ static addInitializer(initializer) { var _a; this.finalize(); ((_a = this._initializers) !== null && _a !== void 0 ? _a : (this._initializers = [])).push(initializer); } /** * Returns a list of attributes corresponding to the registered properties. * @nocollapse * @category attributes */ static get observedAttributes() { // note: piggy backing on this to ensure we're finalized. this.finalize(); const attributes = []; // Use forEach so this works even if for/of loops are compiled to for loops // expecting arrays this.elementProperties.forEach((v, p) => { const attr = this.__attributeNameForProperty(p, v); if (attr !== undefined) { this.__attributeToPropertyMap.set(attr, p); attributes.push(attr); } }); return attributes; } /** * Creates a property accessor on the element prototype if one does not exist * and stores a {@linkcode PropertyDeclaration} for the property with the * given options. The property setter calls the property's `hasChanged` * property option or uses a strict identity check to determine whether or not * to request an update. * * This method may be overridden to customize properties; however, * when doing so, it's important to call `super.createProperty` to ensure * the property is setup correctly. This method calls * `getPropertyDescriptor` internally to get a descriptor to install. * To customize what properties do when they are get or set, override * `getPropertyDescriptor`. To customize the options for a property, * implement `createProperty` like this: * * ```ts * static createProperty(name, options) { * options = Object.assign(options, {myOption: true}); * super.createProperty(name, options); * } * ``` * * @nocollapse * @category properties */ static createProperty(name, options = defaultPropertyDeclaration) { var _a; // if this is a state property, force the attribute to false. if (options.state) { // Cast as any since this is readonly. // eslint-disable-next-line @typescript-eslint/no-explicit-any options.attribute = false; } // Note, since this can be called by the `@property` decorator which // is called before `finalize`, we ensure finalization has been kicked off. this.finalize(); this.elementProperties.set(name, options); // Do not generate an accessor if the prototype already has one, since // it would be lost otherwise and that would never be the user's intention; // Instead, we expect users to call `requestUpdate` themselves from // user-defined accessors. Note that if the super has an accessor we will // still overwrite it if (!options.noAccessor && !this.prototype.hasOwnProperty(name)) { const key = typeof name === 'symbol' ? Symbol() : `__${name}`; const descriptor = this.getPropertyDescriptor(name, key, options); if (descriptor !== undefined) { Object.defineProperty(this.prototype, name, descriptor); { // If this class doesn't have its own set, create one and initialize // with the values in the set from the nearest ancestor class, if any. if (!this.hasOwnProperty('__reactivePropertyKeys')) { this.__reactivePropertyKeys = new Set((_a = this.__reactivePropertyKeys) !== null && _a !== void 0 ? _a : []); } this.__reactivePropertyKeys.add(name); } } } } /** * Returns a property descriptor to be defined on the given named property. * If no descriptor is returned, the property will not become an accessor. * For example, * * ```ts * class MyElement extends LitElement { * static getPropertyDescriptor(name, key, options) { * const defaultDescriptor = * super.getPropertyDescriptor(name, key, options); * const setter = defaultDescriptor.set; * return { * get: defaultDescriptor.get, * set(value) { * setter.call(this, value); * // custom action. * }, * configurable: true, * enumerable: true * } * } * } * ``` * * @nocollapse * @category properties */ static getPropertyDescriptor(name, key, options) { return { // eslint-disable-next-line @typescript-eslint/no-explicit-any get() { return this[key]; }, set(value) { const oldValue = this[name]; this[key] = value; this.requestUpdate(name, oldValue, options); }, configurable: true, enumerable: true, }; } /** * Returns the property options associated with the given property. * These options are defined with a `PropertyDeclaration` via the `properties` * object or the `@property` decorator and are registered in * `createProperty(...)`. * * Note, this method should be considered "final" and not overridden. To * customize the options for a given property, override * {@linkcode createProperty}. * * @nocollapse * @final * @category properties */ static getPropertyOptions(name) { return this.elementProperties.get(name) || defaultPropertyDeclaration; } /** * Creates property accessors for registered properties, sets up element * styling, and ensures any superclasses are also finalized. Returns true if * the element was finalized. * @nocollapse */ static finalize() { if (this.hasOwnProperty(finalized)) { return false; } this[finalized] = true; // finalize any superclasses const superCtor = Object.getPrototypeOf(this); superCtor.finalize(); // Create own set of initializers for this class if any exist on the // superclass and copy them down. Note, for a small perf boost, avoid // creating initializers unless needed. if (superCtor._initializers !== undefined) { this._initializers = [...superCtor._initializers]; } this.elementProperties = new Map(superCtor.elementProperties); // initialize Map populated in observedAttributes this.__attributeToPropertyMap = new Map(); // make any properties // Note, only process "own" properties since this element will inherit // any properties defined on the superClass, and finalization ensures // the entire prototype chain is finalized. if (this.hasOwnProperty(JSCompiler_renameProperty('properties'))) { const props = this.properties; // support symbols in properties (IE11 does not support this) const propKeys = [ ...Object.getOwnPropertyNames(props), ...Object.getOwnPropertySymbols(props), ]; // This for/of is ok because propKeys is an array for (const p of propKeys) { // note, use of `any` is due to TypeScript lack of support for symbol in // index types // eslint-disable-next-line @typescript-eslint/no-explicit-any this.createProperty(p, props[p]); } } this.elementStyles = this.finalizeStyles(this.styles); // DEV mode warnings { const warnRemovedOrRenamed = (name, renamed = false) => { if (this.prototype.hasOwnProperty(name)) { issueWarning(renamed ? 'renamed-api' : 'removed-api', `\`${name}\` is implemented on class ${this.name}. It ` + `has been ${renamed ? 'renamed' : 'removed'} ` + `in this version of LitElement.`); } }; warnRemovedOrRenamed('initialize'); warnRemovedOrRenamed('requestUpdateInternal'); warnRemovedOrRenamed('_getUpdateComplete', true); } return true; } /** * Takes the styles the user supplied via the `static styles` property and * returns the array of styles to apply to the element. * Override this method to integrate into a style management system. * * Styles are deduplicated preserving the _last_ instance in the list. This * is a performance optimization to avoid duplicated styles that can occur * especially when composing via subclassing. The last item is kept to try * to preserve the cascade order with the assumption that it's most important * that last added styles override previous styles. * * @nocollapse * @category styles */ static finalizeStyles(styles) { const elementStyles = []; if (Array.isArray(styles)) { // Dedupe the flattened array in reverse order to preserve the last items. // Casting to Array works around TS error that // appears to come from trying to flatten a type CSSResultArray. const set = new Set(styles.flat(Infinity).reverse()); // Then preserve original order by adding the set items in reverse order. for (const s of set) { elementStyles.unshift(getCompatibleStyle(s)); } } else if (styles !== undefined) { elementStyles.push(getCompatibleStyle(styles)); } return elementStyles; } /** * Returns the property name for the given attribute `name`. * @nocollapse */ static __attributeNameForProperty(name, options) { const attribute = options.attribute; return attribute === false ? undefined : typeof attribute === 'string' ? attribute : typeof name === 'string' ? name.toLowerCase() : undefined; } /** * Internal only override point for customizing work done when elements * are constructed. */ __initialize() { var _a; this.__updatePromise = new Promise((res) => (this.enableUpdating = res)); this._$changedProperties = new Map(); this.__saveInstanceProperties(); // ensures first update will be caught by an early access of // `updateComplete` this.requestUpdate(); (_a = this.constructor._initializers) === null || _a === void 0 ? void 0 : _a.forEach((i) => i(this)); } /** * Registers a `ReactiveController` to participate in the element's reactive * update cycle. The element automatically calls into any registered * controllers during its lifecycle callbacks. * * If the element is connected when `addController()` is called, the * controller's `hostConnected()` callback will be immediately called. * @category controllers */ addController(controller) { var _a, _b; ((_a = this.__controllers) !== null && _a !== void 0 ? _a : (this.__controllers = [])).push(controller); // If a controller is added after the element has been connected, // call hostConnected. Note, re-using existence of `renderRoot` here // (which is set in connectedCallback) to avoid the need to track a // first connected state. if (this.renderRoot !== undefined && this.isConnected) { (_b = controller.hostConnected) === null || _b === void 0 ? void 0 : _b.call(controller); } } /** * Removes a `ReactiveController` from the element. * @category controllers */ removeController(controller) { var _a; // Note, if the indexOf is -1, the >>> will flip the sign which makes the // splice do nothing. (_a = this.__controllers) === null || _a === void 0 ? void 0 : _a.splice(this.__controllers.indexOf(controller) >>> 0, 1); } /** * Fixes any properties set on the instance before upgrade time. * Otherwise these would shadow the accessor and break these properties. * The properties are stored in a Map which is played back after the * constructor runs. Note, on very old versions of Safari (<=9) or Chrome * (<=41), properties created for native platform properties like (`id` or * `name`) may not have default values set in the element constructor. On * these browsers native properties appear on instances and therefore their * default value will overwrite any element default (e.g. if the element sets * this.id = 'id' in the constructor, the 'id' will become '' since this is * the native platform default). */ __saveInstanceProperties() { // Use forEach so this works even if for/of loops are compiled to for loops // expecting arrays this.constructor.elementProperties.forEach((_v, p) => { if (this.hasOwnProperty(p)) { this.__instanceProperties.set(p, this[p]); delete this[p]; } }); } /** * Returns the node into which the element should render and by default * creates and returns an open shadowRoot. Implement to customize where the * element's DOM is rendered. For example, to render into the element's * childNodes, return `this`. * * @return Returns a node into which to render. * @category rendering */ createRenderRoot() { var _a; const renderRoot = (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this.attachShadow(this.constructor.shadowRootOptions); adoptStyles(renderRoot, this.constructor.elementStyles); return renderRoot; } /** * On first connection, creates the element's renderRoot, sets up * element styling, and enables updating. * @category lifecycle */ connectedCallback() { var _a; // create renderRoot before first update. if (this.renderRoot === undefined) { this.renderRoot = this.createRenderRoot(); } this.enableUpdating(true); (_a = this.__controllers) === null || _a === void 0 ? void 0 : _a.forEach((c) => { var _a; return (_a = c.hostConnected) === null || _a === void 0 ? void 0 : _a.call(c); }); } /** * Note, this method should be considered final and not overridden. It is * overridden on the element instance with a function that triggers the first * update. * @category updates */ enableUpdating(_requestedUpdate) { } /** * Allows for `super.disconnectedCallback()` in extensions while * reserving the possibility of making non-breaking feature additions * when disconnecting at some point in the future. * @category lifecycle */ disconnectedCallback() { var _a; (_a = this.__controllers) === null || _a === void 0 ? void 0 : _a.forEach((c) => { var _a; return (_a = c.hostDisconnected) === null || _a === void 0 ? void 0 : _a.call(c); }); } /** * Synchronizes property values when attributes change. * * Specifically, when an attribute is set, the corresponding property is set. * You should rarely need to implement this callback. If this method is * overridden, `super.attributeChangedCallback(name, _old, value)` must be * called. * * See [using the lifecycle callbacks](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks) * on MDN for more information about the `attributeChangedCallback`. * @category attributes */ attributeChangedCallback(name, _old, value) { this._$attributeToProperty(name, value); } __propertyToAttribute(name, value, options = defaultPropertyDeclaration) { var _a; const attr = this.constructor.__attributeNameForProperty(name, options); if (attr !== undefined && options.reflect === true) { const converter = ((_a = options.converter) === null || _a === void 0 ? void 0 : _a.toAttribute) !== undefined ? options.converter : defaultConverter; const attrValue = converter.toAttribute(value, options.type); if (this.constructor.enabledWarnings.indexOf('migration') >= 0 && attrValue === undefined) { issueWarning('undefined-attribute-value', `The attribute value for the ${name} property is ` + `undefined on element ${this.localName}. The attribute will be ` + `removed, but in the previous version of \`ReactiveElement\`, ` + `the attribute would not have changed.`); } // Track if the property is being reflected to avoid // setting the property again via `attributeChangedCallback`. Note: // 1. this takes advantage of the fact that the callback is synchronous. // 2. will behave incorrectly if multiple attributes are in the reaction // stack at time of calling. However, since we process attributes // in `update` this should not be possible (or an extreme corner case // that we'd like to discover). // mark state reflecting this.__reflectingProperty = name; if (attrValue == null) { this.removeAttribute(attr); } else { this.setAttribute(attr, attrValue); } // mark state not reflecting this.__reflectingProperty = null; } } /** @internal */ _$attributeToProperty(name, value) { var _a; const ctor = this.constructor; // Note, hint this as an `AttributeMap` so closure clearly understands // the type; it has issues with tracking types through statics const propName = ctor.__attributeToPropertyMap.get(name); // Use tracking info to avoid reflecting a property value to an attribute // if it was just set because the attribute changed. if (propName !== undefined && this.__reflectingProperty !== propName) { const options = ctor.getPropertyOptions(propName); const converter = typeof options.converter === 'function' ? { fromAttribute: options.converter } : ((_a = options.converter) === null || _a === void 0 ? void 0 : _a.fromAttribute) !== undefined ? options.converter : defaultConverter; // mark state reflecting this.__reflectingProperty = propName; this[propName] = converter.fromAttribute(value, options.type // eslint-disable-next-line @typescript-eslint/no-explicit-any ); // mark state not reflecting this.__reflectingProperty = null; } } /** * Requests an update which is processed asynchronously. This should be called * when an element should update based on some state not triggered by setting * a reactive property. In this case, pass no arguments. It should also be * called when manually implementing a property setter. In this case, pass the * property `name` and `oldValue` to ensure that any configured property * options are honored. * * @param name name of requesting property * @param oldValue old value of requesting property * @param options property options to use instead of the previously * configured options * @category updates */ requestUpdate(name, oldValue, options) { let shouldRequestUpdate = true; // If we have a property key, perform property update steps. if (name !== undefined) { options = options || this.constructor.getPropertyOptions(name); const hasChanged = options.hasChanged || notEqual; if (hasChanged(this[name], oldValue)) { if (!this._$changedProperties.has(name)) { this._$changedProperties.set(name, oldValue); } // Add to reflecting properties set. // Note, it's important that every change has a chance to add the // property to `_reflectingProperties`. This ensures setting // attribute + property reflects correctly. if (options.reflect === true && this.__reflectingProperty !== name) { if (this.__reflectingProperties === undefined) { this.__reflectingProperties = new Map(); } this.__reflectingProperties.set(name, options); } } else { // Abort the request if the property should not be considered changed. shouldRequestUpdate = false; } } if (!this.isUpdatePending && shouldRequestUpdate) { this.__updatePromise = this.__enqueueUpdate(); } // Note, since this no longer returns a promise, in dev mode we return a // thenable which warns if it's called. return requestUpdateThenable(this.localName) ; } /** * Sets up the element to asynchronously update. */ async __enqueueUpdate() { this.isUpdatePending = true; try { // Ensure any previous update has resolved before updating. // This `await` also ensures that property changes are batched. await this.__updatePromise; } catch (e) { // Refire any previous errors async so they do not disrupt the update // cycle. Errors are refired so developers have a chance to observe // them, and this can be done by implementing // `window.onunhandledrejection`. Promise.reject(e); } const result = this.scheduleUpdate(); // If `scheduleUpdate` returns a Promise, we await it. This is done to // enable coordinating updates with a scheduler. Note, the result is // checked to avoid delaying an additional microtask unless we need to. if (result != null) { await result; } return !this.isUpdatePending; } /** * Schedules an element update. You can override this method to change the * timing of updates by returning a Promise. The update will await the * returned Promise, and you should resolve the Promise to allow the update * to proceed. If this method is overridden, `super.scheduleUpdate()` * must be called. * * For instance, to schedule updates to occur just before the next frame: * * ```ts * override protected async scheduleUpdate(): Promise { * await new Promise((resolve) => requestAnimationFrame(() => resolve())); * super.scheduleUpdate(); * } * ``` * @category updates */ scheduleUpdate() { return this.performUpdate(); } /** * Performs an element update. Note, if an exception is thrown during the * update, `firstUpdated` and `updated` will not be called. * * Call `performUpdate()` to immediately process a pending update. This should * generally not be needed, but it can be done in rare cases when you need to * update synchronously. * * Note: To ensure `performUpdate()` synchronously completes a pending update, * it should not be overridden. In LitElement 2.x it was suggested to override * `performUpdate()` to also customizing update scheduling. Instead, you should now * override `scheduleUpdate()`. For backwards compatibility with LitElement 2.x, * scheduling updates via `performUpdate()` continues to work, but will make * also calling `performUpdate()` to synchronously process updates difficult. * * @category updates */ performUpdate() { var _a, _b; // Abort any update if one is not pending when this is called. // This can happen if `performUpdate` is called early to "flush" // the update. if (!this.isUpdatePending) { return; } debugLogEvent === null || debugLogEvent === void 0 ? void 0 : debugLogEvent({ kind: 'update' }); // create renderRoot before first update. if (!this.hasUpdated) { // Produce warning if any class properties are shadowed by class fields { const shadowedProperties = []; (_a = this.constructor.__reactivePropertyKeys) === null || _a === void 0 ? void 0 : _a.forEach((p) => { var _a; if (this.hasOwnProperty(p) && !((_a = this.__instanceProperties) === null || _a === void 0 ? void 0 : _a.has(p))) { shadowedProperties.push(p); } }); if (shadowedProperties.length) { throw new Error(`The following properties on element ${this.localName} will not ` + `trigger updates as expected because they are set using class ` + `fields: ${shadowedProperties.join(', ')}. ` + `Native class fields and some compiled output will overwrite ` + `accessors used for detecting changes. See ` + `https://lit.dev/msg/class-field-shadowing ` + `for more information.`); } } } // Mixin instance properties once, if they exist. if (this.__instanceProperties) { // Use forEach so this works even if for/of loops are compiled to for loops // expecting arrays // eslint-disable-next-line @typescript-eslint/no-explicit-any this.__instanceProperties.forEach((v, p) => (this[p] = v)); this.__instanceProperties = undefined; } let shouldUpdate = false; const changedProperties = this._$changedProperties; try { shouldUpdate = this.shouldUpdate(changedProperties); if (shouldUpdate) { this.willUpdate(changedProperties); (_b = this.__controllers) === null || _b === void 0 ? void 0 : _b.forEach((c) => { var _a; return (_a = c.hostUpdate) === null || _a === void 0 ? void 0 : _a.call(c); }); this.update(changedProperties); } else { this.__markUpdated(); } } catch (e) { // Prevent `firstUpdated` and `updated` from running when there's an // update exception. shouldUpdate = false; // Ensure element can accept additional updates after an exception. this.__markUpdated(); throw e; } // The update is no longer considered pending and further updates are now allowed. if (shouldUpdate) { this._$didUpdate(changedProperties); } } /** * Invoked before `update()` to compute values needed during the update. * * Implement `willUpdate` to compute property values that depend on other * properties and are used in the rest of the update process. * * ```ts * willUpdate(changedProperties) { * // only need to check changed properties for an expensive computation. * if (changedProperties.has('firstName') || changedProperties.has('lastName')) { * this.sha = computeSHA(`${this.firstName} ${this.lastName}`); * } * } * * render() { * return html`SHA: ${this.sha}`; * } * ``` * * @category updates */ willUpdate(_changedProperties) { } // Note, this is an override point for polyfill-support. // @internal _$didUpdate(changedProperties) { var _a; (_a = this.__controllers) === null || _a === void 0 ? void 0 : _a.forEach((c) => { var _a; return (_a = c.hostUpdated) === null || _a === void 0 ? void 0 : _a.call(c); }); if (!this.hasUpdated) { this.hasUpdated = true; this.firstUpdated(changedProperties); } this.updated(changedProperties); if (this.isUpdatePending && this.constructor.enabledWarnings.indexOf('change-in-update') >= 0) { issueWarning('change-in-update', `Element ${this.localName} scheduled an update ` + `(generally because a property was set) ` + `after an update completed, causing a new update to be scheduled. ` + `This is inefficient and should be avoided unless the next update ` + `can only be scheduled as a side effect of the previous update.`); } } __markUpdated() { this._$changedProperties = new Map(); this.isUpdatePending = false; } /** * Returns a Promise that resolves when the element has completed updating. * The Promise value is a boolean that is `true` if the element completed the * update without triggering another update. The Promise result is `false` if * a property was set inside `updated()`. If the Promise is rejected, an * exception was thrown during the update. * * To await additional asynchronous work, override the `getUpdateComplete` * method. For example, it is sometimes useful to await a rendered element * before fulfilling this Promise. To do this, first await * `super.getUpdateComplete()`, then any subsequent state. * * @return A promise of a boolean that resolves to true if the update completed * without triggering another update. * @category updates */ get updateComplete() { return this.getUpdateComplete(); } /** * Override point for the `updateComplete` promise. * * It is not safe to override the `updateComplete` getter directly due to a * limitation in TypeScript which means it is not possible to call a * superclass getter (e.g. `super.updateComplete.then(...)`) when the target * language is ES5 (https://github.com/microsoft/TypeScript/issues/338). * This method should be overridden instead. For example: * * ```ts * class MyElement extends LitElement { * override async getUpdateComplete() { * const result = await super.getUpdateComplete(); * await this._myChild.updateComplete; * return result; * } * } * ``` * * @return A promise of a boolean that resolves to true if the update completed * without triggering another update. * @category updates */ getUpdateComplete() { return this.__updatePromise; } /** * Controls whether or not `update()` should be called when the element requests * an update. By default, this method always returns `true`, but this can be * customized to control when to update. * * @param _changedProperties Map of changed properties with old values * @category updates */ shouldUpdate(_changedProperties) { return true; } /** * Updates the element. This method reflects property values to attributes. * It can be overridden to render and keep updated element DOM. * Setting properties inside this method will *not* trigger * another update. * * @param _changedProperties Map of changed properties with old values * @category updates */ update(_changedProperties) { if (this.__reflectingProperties !== undefined) { // Use forEach so this works even if for/of loops are compiled to for // loops expecting arrays this.__reflectingProperties.forEach((v, k) => this.__propertyToAttribute(k, this[k], v)); this.__reflectingProperties = undefined; } this.__markUpdated(); } /** * Invoked whenever the element is updated. Implement to perform * post-updating tasks via DOM APIs, for example, focusing an element. * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * @param _changedProperties Map of changed properties with old values * @category updates */ updated(_changedProperties) { } /** * Invoked when the element is first updated. Implement to perform one time * work on the element after update. * * ```ts * firstUpdated() { * this.renderRoot.getElementById('my-text-area').focus(); * } * ``` * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * @param _changedProperties Map of changed properties with old values * @category updates */ firstUpdated(_changedProperties) { } } _e = finalized; /** * Marks class as having finished creating properties. */ ReactiveElement[_e] = true; /** * Memoized list of all element properties, including any superclass properties. * Created lazily on user subclasses when finalizing the class. * @nocollapse * @category properties */ ReactiveElement.elementProperties = new Map(); /** * Memoized list of all element styles. * Created lazily on user subclasses when finalizing the class. * @nocollapse * @category styles */ ReactiveElement.elementStyles = []; /** * Options used when calling `attachShadow`. Set this property to customize * the options for the shadowRoot; for example, to create a closed * shadowRoot: `{mode: 'closed'}`. * * Note, these options are used in `createRenderRoot`. If this method * is customized, options should be respected if possible. * @nocollapse * @category rendering */ ReactiveElement.shadowRootOptions = { mode: 'open' }; // Apply polyfills if available polyfillSupport === null || polyfillSupport === void 0 ? void 0 : polyfillSupport({ ReactiveElement }); // Dev mode warnings... { // Default warning set. ReactiveElement.enabledWarnings = ['change-in-update']; const ensureOwnWarnings = function (ctor) { if (!ctor.hasOwnProperty(JSCompiler_renameProperty('enabledWarnings'))) { ctor.enabledWarnings = ctor.enabledWarnings.slice(); } }; ReactiveElement.enableWarning = function (warning) { ensureOwnWarnings(this); if (this.enabledWarnings.indexOf(warning) < 0) { this.enabledWarnings.push(warning); } }; ReactiveElement.disableWarning = function (warning) { ensureOwnWarnings(this); const i = this.enabledWarnings.indexOf(warning); if (i >= 0) { this.enabledWarnings.splice(i, 1); } }; } // IMPORTANT: do not change the property name or the assignment expression. // This line will be used in regexes to search for ReactiveElement usage. ((_d = global.reactiveElementVersions) !== null && _d !== void 0 ? _d : (global.reactiveElementVersions = [])).push('1.6.3'); if (global.reactiveElementVersions.length > 1) { issueWarning('multiple-versions', `Multiple versions of Lit loaded. Loading multiple versions ` + `is not recommended.`); } export { ReactiveElement, defaultConverter, notEqual }; //# sourceMappingURL=reactive-element.js.map