reactive-element.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. /**
  2. * @license
  3. * Copyright 2017 Google LLC
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. var _a, _b, _c;
  7. var _d;
  8. /**
  9. * Use this module if you want to create your own base class extending
  10. * {@link ReactiveElement}.
  11. * @packageDocumentation
  12. */
  13. import { getCompatibleStyle, adoptStyles, } from './css-tag.js';
  14. export * from './css-tag.js';
  15. const DEV_MODE = true;
  16. let requestUpdateThenable;
  17. let issueWarning;
  18. const trustedTypes = window
  19. .trustedTypes;
  20. // Temporary workaround for https://crbug.com/993268
  21. // Currently, any attribute starting with "on" is considered to be a
  22. // TrustedScript source. Such boolean attributes must be set to the equivalent
  23. // trusted emptyScript value.
  24. const emptyStringForBooleanAttribute = trustedTypes
  25. ? trustedTypes.emptyScript
  26. : '';
  27. const polyfillSupport = DEV_MODE
  28. ? window.reactiveElementPolyfillSupportDevMode
  29. : window.reactiveElementPolyfillSupport;
  30. if (DEV_MODE) {
  31. // Ensure warnings are issued only 1x, even if multiple versions of Lit
  32. // are loaded.
  33. const issuedWarnings = ((_a = globalThis.litIssuedWarnings) !== null && _a !== void 0 ? _a : (globalThis.litIssuedWarnings = new Set()));
  34. // Issue a warning, if we haven't already.
  35. issueWarning = (code, warning) => {
  36. warning += ` See https://lit.dev/msg/${code} for more information.`;
  37. if (!issuedWarnings.has(warning)) {
  38. console.warn(warning);
  39. issuedWarnings.add(warning);
  40. }
  41. };
  42. issueWarning('dev-mode', `Lit is in dev mode. Not recommended for production!`);
  43. // Issue polyfill support warning.
  44. if (((_b = window.ShadyDOM) === null || _b === void 0 ? void 0 : _b.inUse) && polyfillSupport === undefined) {
  45. issueWarning('polyfill-support-missing', `Shadow DOM is being polyfilled via \`ShadyDOM\` but ` +
  46. `the \`polyfill-support\` module has not been loaded.`);
  47. }
  48. requestUpdateThenable = (name) => ({
  49. then: (onfulfilled, _onrejected) => {
  50. issueWarning('request-update-promise', `The \`requestUpdate\` method should no longer return a Promise but ` +
  51. `does so on \`${name}\`. Use \`updateComplete\` instead.`);
  52. if (onfulfilled !== undefined) {
  53. onfulfilled(false);
  54. }
  55. },
  56. });
  57. }
  58. /**
  59. * Useful for visualizing and logging insights into what the Lit template system is doing.
  60. *
  61. * Compiled out of prod mode builds.
  62. */
  63. const debugLogEvent = DEV_MODE
  64. ? (event) => {
  65. const shouldEmit = window
  66. .emitLitDebugLogEvents;
  67. if (shouldEmit) {
  68. window.dispatchEvent(new CustomEvent('lit-debug', {
  69. detail: event,
  70. }));
  71. }
  72. }
  73. : undefined;
  74. /*
  75. * When using Closure Compiler, JSCompiler_renameProperty(property, object) is
  76. * replaced at compile time by the munged name for object[property]. We cannot
  77. * alias this function, so we have to use a small shim that has the same
  78. * behavior when not compiling.
  79. */
  80. /*@__INLINE__*/
  81. const JSCompiler_renameProperty = (prop, _obj) => prop;
  82. export const defaultConverter = {
  83. toAttribute(value, type) {
  84. switch (type) {
  85. case Boolean:
  86. value = value ? emptyStringForBooleanAttribute : null;
  87. break;
  88. case Object:
  89. case Array:
  90. // if the value is `null` or `undefined` pass this through
  91. // to allow removing/no change behavior.
  92. value = value == null ? value : JSON.stringify(value);
  93. break;
  94. }
  95. return value;
  96. },
  97. fromAttribute(value, type) {
  98. let fromValue = value;
  99. switch (type) {
  100. case Boolean:
  101. fromValue = value !== null;
  102. break;
  103. case Number:
  104. fromValue = value === null ? null : Number(value);
  105. break;
  106. case Object:
  107. case Array:
  108. // Do *not* generate exception when invalid JSON is set as elements
  109. // don't normally complain on being mis-configured.
  110. // TODO(sorvell): Do generate exception in *dev mode*.
  111. try {
  112. // Assert to adhere to Bazel's "must type assert JSON parse" rule.
  113. fromValue = JSON.parse(value);
  114. }
  115. catch (e) {
  116. fromValue = null;
  117. }
  118. break;
  119. }
  120. return fromValue;
  121. },
  122. };
  123. /**
  124. * Change function that returns true if `value` is different from `oldValue`.
  125. * This method is used as the default for a property's `hasChanged` function.
  126. */
  127. export const notEqual = (value, old) => {
  128. // This ensures (old==NaN, value==NaN) always returns false
  129. return old !== value && (old === old || value === value);
  130. };
  131. const defaultPropertyDeclaration = {
  132. attribute: true,
  133. type: String,
  134. converter: defaultConverter,
  135. reflect: false,
  136. hasChanged: notEqual,
  137. };
  138. /**
  139. * The Closure JS Compiler doesn't currently have good support for static
  140. * property semantics where "this" is dynamic (e.g.
  141. * https://github.com/google/closure-compiler/issues/3177 and others) so we use
  142. * this hack to bypass any rewriting by the compiler.
  143. */
  144. const finalized = 'finalized';
  145. /**
  146. * Base element class which manages element properties and attributes. When
  147. * properties change, the `update` method is asynchronously called. This method
  148. * should be supplied by subclassers to render updates as desired.
  149. * @noInheritDoc
  150. */
  151. export class ReactiveElement extends HTMLElement {
  152. constructor() {
  153. super();
  154. this.__instanceProperties = new Map();
  155. /**
  156. * True if there is a pending update as a result of calling `requestUpdate()`.
  157. * Should only be read.
  158. * @category updates
  159. */
  160. this.isUpdatePending = false;
  161. /**
  162. * Is set to `true` after the first update. The element code cannot assume
  163. * that `renderRoot` exists before the element `hasUpdated`.
  164. * @category updates
  165. */
  166. this.hasUpdated = false;
  167. /**
  168. * Name of currently reflecting property
  169. */
  170. this.__reflectingProperty = null;
  171. this._initialize();
  172. }
  173. /**
  174. * Adds an initializer function to the class that is called during instance
  175. * construction.
  176. *
  177. * This is useful for code that runs against a `ReactiveElement`
  178. * subclass, such as a decorator, that needs to do work for each
  179. * instance, such as setting up a `ReactiveController`.
  180. *
  181. * ```ts
  182. * const myDecorator = (target: typeof ReactiveElement, key: string) => {
  183. * target.addInitializer((instance: ReactiveElement) => {
  184. * // This is run during construction of the element
  185. * new MyController(instance);
  186. * });
  187. * }
  188. * ```
  189. *
  190. * Decorating a field will then cause each instance to run an initializer
  191. * that adds a controller:
  192. *
  193. * ```ts
  194. * class MyElement extends LitElement {
  195. * @myDecorator foo;
  196. * }
  197. * ```
  198. *
  199. * Initializers are stored per-constructor. Adding an initializer to a
  200. * subclass does not add it to a superclass. Since initializers are run in
  201. * constructors, initializers will run in order of the class hierarchy,
  202. * starting with superclasses and progressing to the instance's class.
  203. *
  204. * @nocollapse
  205. */
  206. static addInitializer(initializer) {
  207. var _a;
  208. (_a = this._initializers) !== null && _a !== void 0 ? _a : (this._initializers = []);
  209. this._initializers.push(initializer);
  210. }
  211. /**
  212. * Returns a list of attributes corresponding to the registered properties.
  213. * @nocollapse
  214. * @category attributes
  215. */
  216. static get observedAttributes() {
  217. // note: piggy backing on this to ensure we're finalized.
  218. this.finalize();
  219. const attributes = [];
  220. // Use forEach so this works even if for/of loops are compiled to for loops
  221. // expecting arrays
  222. this.elementProperties.forEach((v, p) => {
  223. const attr = this.__attributeNameForProperty(p, v);
  224. if (attr !== undefined) {
  225. this.__attributeToPropertyMap.set(attr, p);
  226. attributes.push(attr);
  227. }
  228. });
  229. return attributes;
  230. }
  231. /**
  232. * Creates a property accessor on the element prototype if one does not exist
  233. * and stores a {@linkcode PropertyDeclaration} for the property with the
  234. * given options. The property setter calls the property's `hasChanged`
  235. * property option or uses a strict identity check to determine whether or not
  236. * to request an update.
  237. *
  238. * This method may be overridden to customize properties; however,
  239. * when doing so, it's important to call `super.createProperty` to ensure
  240. * the property is setup correctly. This method calls
  241. * `getPropertyDescriptor` internally to get a descriptor to install.
  242. * To customize what properties do when they are get or set, override
  243. * `getPropertyDescriptor`. To customize the options for a property,
  244. * implement `createProperty` like this:
  245. *
  246. * ```ts
  247. * static createProperty(name, options) {
  248. * options = Object.assign(options, {myOption: true});
  249. * super.createProperty(name, options);
  250. * }
  251. * ```
  252. *
  253. * @nocollapse
  254. * @category properties
  255. */
  256. static createProperty(name, options = defaultPropertyDeclaration) {
  257. var _a;
  258. // if this is a state property, force the attribute to false.
  259. if (options.state) {
  260. // Cast as any since this is readonly.
  261. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  262. options.attribute = false;
  263. }
  264. // Note, since this can be called by the `@property` decorator which
  265. // is called before `finalize`, we ensure finalization has been kicked off.
  266. this.finalize();
  267. this.elementProperties.set(name, options);
  268. // Do not generate an accessor if the prototype already has one, since
  269. // it would be lost otherwise and that would never be the user's intention;
  270. // Instead, we expect users to call `requestUpdate` themselves from
  271. // user-defined accessors. Note that if the super has an accessor we will
  272. // still overwrite it
  273. if (!options.noAccessor && !this.prototype.hasOwnProperty(name)) {
  274. const key = typeof name === 'symbol' ? Symbol() : `__${name}`;
  275. const descriptor = this.getPropertyDescriptor(name, key, options);
  276. if (descriptor !== undefined) {
  277. Object.defineProperty(this.prototype, name, descriptor);
  278. if (DEV_MODE) {
  279. // If this class doesn't have its own set, create one and initialize
  280. // with the values in the set from the nearest ancestor class, if any.
  281. if (!this.hasOwnProperty('__reactivePropertyKeys')) {
  282. this.__reactivePropertyKeys = new Set((_a = this.__reactivePropertyKeys) !== null && _a !== void 0 ? _a : []);
  283. }
  284. this.__reactivePropertyKeys.add(name);
  285. }
  286. }
  287. }
  288. }
  289. /**
  290. * Returns a property descriptor to be defined on the given named property.
  291. * If no descriptor is returned, the property will not become an accessor.
  292. * For example,
  293. *
  294. * ```ts
  295. * class MyElement extends LitElement {
  296. * static getPropertyDescriptor(name, key, options) {
  297. * const defaultDescriptor =
  298. * super.getPropertyDescriptor(name, key, options);
  299. * const setter = defaultDescriptor.set;
  300. * return {
  301. * get: defaultDescriptor.get,
  302. * set(value) {
  303. * setter.call(this, value);
  304. * // custom action.
  305. * },
  306. * configurable: true,
  307. * enumerable: true
  308. * }
  309. * }
  310. * }
  311. * ```
  312. *
  313. * @nocollapse
  314. * @category properties
  315. */
  316. static getPropertyDescriptor(name, key, options) {
  317. return {
  318. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  319. get() {
  320. return this[key];
  321. },
  322. set(value) {
  323. const oldValue = this[name];
  324. this[key] = value;
  325. this.requestUpdate(name, oldValue, options);
  326. },
  327. configurable: true,
  328. enumerable: true,
  329. };
  330. }
  331. /**
  332. * Returns the property options associated with the given property.
  333. * These options are defined with a `PropertyDeclaration` via the `properties`
  334. * object or the `@property` decorator and are registered in
  335. * `createProperty(...)`.
  336. *
  337. * Note, this method should be considered "final" and not overridden. To
  338. * customize the options for a given property, override
  339. * {@linkcode createProperty}.
  340. *
  341. * @nocollapse
  342. * @final
  343. * @category properties
  344. */
  345. static getPropertyOptions(name) {
  346. return this.elementProperties.get(name) || defaultPropertyDeclaration;
  347. }
  348. /**
  349. * Creates property accessors for registered properties, sets up element
  350. * styling, and ensures any superclasses are also finalized. Returns true if
  351. * the element was finalized.
  352. * @nocollapse
  353. */
  354. static finalize() {
  355. if (this.hasOwnProperty(finalized)) {
  356. return false;
  357. }
  358. this[finalized] = true;
  359. // finalize any superclasses
  360. const superCtor = Object.getPrototypeOf(this);
  361. superCtor.finalize();
  362. this.elementProperties = new Map(superCtor.elementProperties);
  363. // initialize Map populated in observedAttributes
  364. this.__attributeToPropertyMap = new Map();
  365. // make any properties
  366. // Note, only process "own" properties since this element will inherit
  367. // any properties defined on the superClass, and finalization ensures
  368. // the entire prototype chain is finalized.
  369. if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) {
  370. const props = this.properties;
  371. // support symbols in properties (IE11 does not support this)
  372. const propKeys = [
  373. ...Object.getOwnPropertyNames(props),
  374. ...Object.getOwnPropertySymbols(props),
  375. ];
  376. // This for/of is ok because propKeys is an array
  377. for (const p of propKeys) {
  378. // note, use of `any` is due to TypeScript lack of support for symbol in
  379. // index types
  380. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  381. this.createProperty(p, props[p]);
  382. }
  383. }
  384. this.elementStyles = this.finalizeStyles(this.styles);
  385. // DEV mode warnings
  386. if (DEV_MODE) {
  387. const warnRemovedOrRenamed = (name, renamed = false) => {
  388. if (this.prototype.hasOwnProperty(name)) {
  389. issueWarning(renamed ? 'renamed-api' : 'removed-api', `\`${name}\` is implemented on class ${this.name}. It ` +
  390. `has been ${renamed ? 'renamed' : 'removed'} ` +
  391. `in this version of LitElement.`);
  392. }
  393. };
  394. warnRemovedOrRenamed('initialize');
  395. warnRemovedOrRenamed('requestUpdateInternal');
  396. warnRemovedOrRenamed('_getUpdateComplete', true);
  397. }
  398. return true;
  399. }
  400. /**
  401. * Takes the styles the user supplied via the `static styles` property and
  402. * returns the array of styles to apply to the element.
  403. * Override this method to integrate into a style management system.
  404. *
  405. * Styles are deduplicated preserving the _last_ instance in the list. This
  406. * is a performance optimization to avoid duplicated styles that can occur
  407. * especially when composing via subclassing. The last item is kept to try
  408. * to preserve the cascade order with the assumption that it's most important
  409. * that last added styles override previous styles.
  410. *
  411. * @nocollapse
  412. * @category styles
  413. */
  414. static finalizeStyles(styles) {
  415. const elementStyles = [];
  416. if (Array.isArray(styles)) {
  417. // Dedupe the flattened array in reverse order to preserve the last items.
  418. // Casting to Array<unknown> works around TS error that
  419. // appears to come from trying to flatten a type CSSResultArray.
  420. const set = new Set(styles.flat(Infinity).reverse());
  421. // Then preserve original order by adding the set items in reverse order.
  422. for (const s of set) {
  423. elementStyles.unshift(getCompatibleStyle(s));
  424. }
  425. }
  426. else if (styles !== undefined) {
  427. elementStyles.push(getCompatibleStyle(styles));
  428. }
  429. return elementStyles;
  430. }
  431. /**
  432. * Returns the property name for the given attribute `name`.
  433. * @nocollapse
  434. */
  435. static __attributeNameForProperty(name, options) {
  436. const attribute = options.attribute;
  437. return attribute === false
  438. ? undefined
  439. : typeof attribute === 'string'
  440. ? attribute
  441. : typeof name === 'string'
  442. ? name.toLowerCase()
  443. : undefined;
  444. }
  445. /**
  446. * Internal only override point for customizing work done when elements
  447. * are constructed.
  448. *
  449. * @internal
  450. */
  451. _initialize() {
  452. var _a;
  453. this.__updatePromise = new Promise((res) => (this.enableUpdating = res));
  454. this._$changedProperties = new Map();
  455. this.__saveInstanceProperties();
  456. // ensures first update will be caught by an early access of
  457. // `updateComplete`
  458. this.requestUpdate();
  459. (_a = this.constructor._initializers) === null || _a === void 0 ? void 0 : _a.forEach((i) => i(this));
  460. }
  461. /**
  462. * Registers a `ReactiveController` to participate in the element's reactive
  463. * update cycle. The element automatically calls into any registered
  464. * controllers during its lifecycle callbacks.
  465. *
  466. * If the element is connected when `addController()` is called, the
  467. * controller's `hostConnected()` callback will be immediately called.
  468. * @category controllers
  469. */
  470. addController(controller) {
  471. var _a, _b;
  472. ((_a = this.__controllers) !== null && _a !== void 0 ? _a : (this.__controllers = [])).push(controller);
  473. // If a controller is added after the element has been connected,
  474. // call hostConnected. Note, re-using existence of `renderRoot` here
  475. // (which is set in connectedCallback) to avoid the need to track a
  476. // first connected state.
  477. if (this.renderRoot !== undefined && this.isConnected) {
  478. (_b = controller.hostConnected) === null || _b === void 0 ? void 0 : _b.call(controller);
  479. }
  480. }
  481. /**
  482. * Removes a `ReactiveController` from the element.
  483. * @category controllers
  484. */
  485. removeController(controller) {
  486. var _a;
  487. // Note, if the indexOf is -1, the >>> will flip the sign which makes the
  488. // splice do nothing.
  489. (_a = this.__controllers) === null || _a === void 0 ? void 0 : _a.splice(this.__controllers.indexOf(controller) >>> 0, 1);
  490. }
  491. /**
  492. * Fixes any properties set on the instance before upgrade time.
  493. * Otherwise these would shadow the accessor and break these properties.
  494. * The properties are stored in a Map which is played back after the
  495. * constructor runs. Note, on very old versions of Safari (<=9) or Chrome
  496. * (<=41), properties created for native platform properties like (`id` or
  497. * `name`) may not have default values set in the element constructor. On
  498. * these browsers native properties appear on instances and therefore their
  499. * default value will overwrite any element default (e.g. if the element sets
  500. * this.id = 'id' in the constructor, the 'id' will become '' since this is
  501. * the native platform default).
  502. */
  503. __saveInstanceProperties() {
  504. // Use forEach so this works even if for/of loops are compiled to for loops
  505. // expecting arrays
  506. this.constructor.elementProperties.forEach((_v, p) => {
  507. if (this.hasOwnProperty(p)) {
  508. this.__instanceProperties.set(p, this[p]);
  509. delete this[p];
  510. }
  511. });
  512. }
  513. /**
  514. * Returns the node into which the element should render and by default
  515. * creates and returns an open shadowRoot. Implement to customize where the
  516. * element's DOM is rendered. For example, to render into the element's
  517. * childNodes, return `this`.
  518. *
  519. * @return Returns a node into which to render.
  520. * @category rendering
  521. */
  522. createRenderRoot() {
  523. var _a;
  524. const renderRoot = (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this.attachShadow(this.constructor.shadowRootOptions);
  525. adoptStyles(renderRoot, this.constructor.elementStyles);
  526. return renderRoot;
  527. }
  528. /**
  529. * On first connection, creates the element's renderRoot, sets up
  530. * element styling, and enables updating.
  531. * @category lifecycle
  532. */
  533. connectedCallback() {
  534. var _a;
  535. // create renderRoot before first update.
  536. if (this.renderRoot === undefined) {
  537. this.renderRoot = this.createRenderRoot();
  538. }
  539. this.enableUpdating(true);
  540. (_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); });
  541. }
  542. /**
  543. * Note, this method should be considered final and not overridden. It is
  544. * overridden on the element instance with a function that triggers the first
  545. * update.
  546. * @category updates
  547. */
  548. enableUpdating(_requestedUpdate) { }
  549. /**
  550. * Allows for `super.disconnectedCallback()` in extensions while
  551. * reserving the possibility of making non-breaking feature additions
  552. * when disconnecting at some point in the future.
  553. * @category lifecycle
  554. */
  555. disconnectedCallback() {
  556. var _a;
  557. (_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); });
  558. }
  559. /**
  560. * Synchronizes property values when attributes change.
  561. *
  562. * Specifically, when an attribute is set, the corresponding property is set.
  563. * You should rarely need to implement this callback. If this method is
  564. * overridden, `super.attributeChangedCallback(name, _old, value)` must be
  565. * called.
  566. *
  567. * See [using the lifecycle callbacks](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks)
  568. * on MDN for more information about the `attributeChangedCallback`.
  569. * @category attributes
  570. */
  571. attributeChangedCallback(name, _old, value) {
  572. this._$attributeToProperty(name, value);
  573. }
  574. __propertyToAttribute(name, value, options = defaultPropertyDeclaration) {
  575. var _a, _b;
  576. const attr = this.constructor.__attributeNameForProperty(name, options);
  577. if (attr !== undefined && options.reflect === true) {
  578. const toAttribute = (_b = (_a = options.converter) === null || _a === void 0 ? void 0 : _a.toAttribute) !== null && _b !== void 0 ? _b : defaultConverter.toAttribute;
  579. const attrValue = toAttribute(value, options.type);
  580. if (DEV_MODE &&
  581. this.constructor.enabledWarnings.indexOf('migration') >= 0 &&
  582. attrValue === undefined) {
  583. issueWarning('undefined-attribute-value', `The attribute value for the ${name} property is ` +
  584. `undefined on element ${this.localName}. The attribute will be ` +
  585. `removed, but in the previous version of \`ReactiveElement\`, ` +
  586. `the attribute would not have changed.`);
  587. }
  588. // Track if the property is being reflected to avoid
  589. // setting the property again via `attributeChangedCallback`. Note:
  590. // 1. this takes advantage of the fact that the callback is synchronous.
  591. // 2. will behave incorrectly if multiple attributes are in the reaction
  592. // stack at time of calling. However, since we process attributes
  593. // in `update` this should not be possible (or an extreme corner case
  594. // that we'd like to discover).
  595. // mark state reflecting
  596. this.__reflectingProperty = name;
  597. if (attrValue == null) {
  598. this.removeAttribute(attr);
  599. }
  600. else {
  601. this.setAttribute(attr, attrValue);
  602. }
  603. // mark state not reflecting
  604. this.__reflectingProperty = null;
  605. }
  606. }
  607. /** @internal */
  608. _$attributeToProperty(name, value) {
  609. var _a, _b, _c;
  610. const ctor = this.constructor;
  611. // Note, hint this as an `AttributeMap` so closure clearly understands
  612. // the type; it has issues with tracking types through statics
  613. const propName = ctor.__attributeToPropertyMap.get(name);
  614. // Use tracking info to avoid reflecting a property value to an attribute
  615. // if it was just set because the attribute changed.
  616. if (propName !== undefined && this.__reflectingProperty !== propName) {
  617. const options = ctor.getPropertyOptions(propName);
  618. const converter = options.converter;
  619. const fromAttribute = (_c = (_b = (_a = converter) === null || _a === void 0 ? void 0 : _a.fromAttribute) !== null && _b !== void 0 ? _b : (typeof converter === 'function'
  620. ? converter
  621. : null)) !== null && _c !== void 0 ? _c : defaultConverter.fromAttribute;
  622. // mark state reflecting
  623. this.__reflectingProperty = propName;
  624. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  625. this[propName] = fromAttribute(value, options.type);
  626. // mark state not reflecting
  627. this.__reflectingProperty = null;
  628. }
  629. }
  630. /**
  631. * Requests an update which is processed asynchronously. This should be called
  632. * when an element should update based on some state not triggered by setting
  633. * a reactive property. In this case, pass no arguments. It should also be
  634. * called when manually implementing a property setter. In this case, pass the
  635. * property `name` and `oldValue` to ensure that any configured property
  636. * options are honored.
  637. *
  638. * @param name name of requesting property
  639. * @param oldValue old value of requesting property
  640. * @param options property options to use instead of the previously
  641. * configured options
  642. * @category updates
  643. */
  644. requestUpdate(name, oldValue, options) {
  645. let shouldRequestUpdate = true;
  646. // If we have a property key, perform property update steps.
  647. if (name !== undefined) {
  648. options =
  649. options ||
  650. this.constructor.getPropertyOptions(name);
  651. const hasChanged = options.hasChanged || notEqual;
  652. if (hasChanged(this[name], oldValue)) {
  653. if (!this._$changedProperties.has(name)) {
  654. this._$changedProperties.set(name, oldValue);
  655. }
  656. // Add to reflecting properties set.
  657. // Note, it's important that every change has a chance to add the
  658. // property to `_reflectingProperties`. This ensures setting
  659. // attribute + property reflects correctly.
  660. if (options.reflect === true && this.__reflectingProperty !== name) {
  661. if (this.__reflectingProperties === undefined) {
  662. this.__reflectingProperties = new Map();
  663. }
  664. this.__reflectingProperties.set(name, options);
  665. }
  666. }
  667. else {
  668. // Abort the request if the property should not be considered changed.
  669. shouldRequestUpdate = false;
  670. }
  671. }
  672. if (!this.isUpdatePending && shouldRequestUpdate) {
  673. this.__updatePromise = this.__enqueueUpdate();
  674. }
  675. // Note, since this no longer returns a promise, in dev mode we return a
  676. // thenable which warns if it's called.
  677. return DEV_MODE
  678. ? requestUpdateThenable(this.localName)
  679. : undefined;
  680. }
  681. /**
  682. * Sets up the element to asynchronously update.
  683. */
  684. async __enqueueUpdate() {
  685. this.isUpdatePending = true;
  686. try {
  687. // Ensure any previous update has resolved before updating.
  688. // This `await` also ensures that property changes are batched.
  689. await this.__updatePromise;
  690. }
  691. catch (e) {
  692. // Refire any previous errors async so they do not disrupt the update
  693. // cycle. Errors are refired so developers have a chance to observe
  694. // them, and this can be done by implementing
  695. // `window.onunhandledrejection`.
  696. Promise.reject(e);
  697. }
  698. const result = this.scheduleUpdate();
  699. // If `scheduleUpdate` returns a Promise, we await it. This is done to
  700. // enable coordinating updates with a scheduler. Note, the result is
  701. // checked to avoid delaying an additional microtask unless we need to.
  702. if (result != null) {
  703. await result;
  704. }
  705. return !this.isUpdatePending;
  706. }
  707. /**
  708. * Schedules an element update. You can override this method to change the
  709. * timing of updates by returning a Promise. The update will await the
  710. * returned Promise, and you should resolve the Promise to allow the update
  711. * to proceed. If this method is overridden, `super.scheduleUpdate()`
  712. * must be called.
  713. *
  714. * For instance, to schedule updates to occur just before the next frame:
  715. *
  716. * ```ts
  717. * override protected async scheduleUpdate(): Promise<unknown> {
  718. * await new Promise((resolve) => requestAnimationFrame(() => resolve()));
  719. * super.scheduleUpdate();
  720. * }
  721. * ```
  722. * @category updates
  723. */
  724. scheduleUpdate() {
  725. return this.performUpdate();
  726. }
  727. /**
  728. * Performs an element update. Note, if an exception is thrown during the
  729. * update, `firstUpdated` and `updated` will not be called.
  730. *
  731. * Call `performUpdate()` to immediately process a pending update. This should
  732. * generally not be needed, but it can be done in rare cases when you need to
  733. * update synchronously.
  734. *
  735. * Note: To ensure `performUpdate()` synchronously completes a pending update,
  736. * it should not be overridden. In LitElement 2.x it was suggested to override
  737. * `performUpdate()` to also customizing update scheduling. Instead, you should now
  738. * override `scheduleUpdate()`. For backwards compatibility with LitElement 2.x,
  739. * scheduling updates via `performUpdate()` continues to work, but will make
  740. * also calling `performUpdate()` to synchronously process updates difficult.
  741. *
  742. * @category updates
  743. */
  744. performUpdate() {
  745. var _a, _b;
  746. // Abort any update if one is not pending when this is called.
  747. // This can happen if `performUpdate` is called early to "flush"
  748. // the update.
  749. if (!this.isUpdatePending) {
  750. return;
  751. }
  752. debugLogEvent === null || debugLogEvent === void 0 ? void 0 : debugLogEvent({ kind: 'update' });
  753. // create renderRoot before first update.
  754. if (!this.hasUpdated) {
  755. // Produce warning if any class properties are shadowed by class fields
  756. if (DEV_MODE) {
  757. const shadowedProperties = [];
  758. (_a = this.constructor.__reactivePropertyKeys) === null || _a === void 0 ? void 0 : _a.forEach((p) => {
  759. var _a;
  760. if (this.hasOwnProperty(p) && !((_a = this.__instanceProperties) === null || _a === void 0 ? void 0 : _a.has(p))) {
  761. shadowedProperties.push(p);
  762. }
  763. });
  764. if (shadowedProperties.length) {
  765. throw new Error(`The following properties on element ${this.localName} will not ` +
  766. `trigger updates as expected because they are set using class ` +
  767. `fields: ${shadowedProperties.join(', ')}. ` +
  768. `Native class fields and some compiled output will overwrite ` +
  769. `accessors used for detecting changes. See ` +
  770. `https://lit.dev/msg/class-field-shadowing ` +
  771. `for more information.`);
  772. }
  773. }
  774. }
  775. // Mixin instance properties once, if they exist.
  776. if (this.__instanceProperties) {
  777. // Use forEach so this works even if for/of loops are compiled to for loops
  778. // expecting arrays
  779. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  780. this.__instanceProperties.forEach((v, p) => (this[p] = v));
  781. this.__instanceProperties = undefined;
  782. }
  783. let shouldUpdate = false;
  784. const changedProperties = this._$changedProperties;
  785. try {
  786. shouldUpdate = this.shouldUpdate(changedProperties);
  787. if (shouldUpdate) {
  788. this.willUpdate(changedProperties);
  789. (_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); });
  790. this.update(changedProperties);
  791. }
  792. else {
  793. this.__markUpdated();
  794. }
  795. }
  796. catch (e) {
  797. // Prevent `firstUpdated` and `updated` from running when there's an
  798. // update exception.
  799. shouldUpdate = false;
  800. // Ensure element can accept additional updates after an exception.
  801. this.__markUpdated();
  802. throw e;
  803. }
  804. // The update is no longer considered pending and further updates are now allowed.
  805. if (shouldUpdate) {
  806. this._$didUpdate(changedProperties);
  807. }
  808. }
  809. /**
  810. * Invoked before `update()` to compute values needed during the update.
  811. *
  812. * Implement `willUpdate` to compute property values that depend on other
  813. * properties and are used in the rest of the update process.
  814. *
  815. * ```ts
  816. * willUpdate(changedProperties) {
  817. * // only need to check changed properties for an expensive computation.
  818. * if (changedProperties.has('firstName') || changedProperties.has('lastName')) {
  819. * this.sha = computeSHA(`${this.firstName} ${this.lastName}`);
  820. * }
  821. * }
  822. *
  823. * render() {
  824. * return html`SHA: ${this.sha}`;
  825. * }
  826. * ```
  827. *
  828. * @category updates
  829. */
  830. willUpdate(_changedProperties) { }
  831. // Note, this is an override point for polyfill-support.
  832. // @internal
  833. _$didUpdate(changedProperties) {
  834. var _a;
  835. (_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); });
  836. if (!this.hasUpdated) {
  837. this.hasUpdated = true;
  838. this.firstUpdated(changedProperties);
  839. }
  840. this.updated(changedProperties);
  841. if (DEV_MODE &&
  842. this.isUpdatePending &&
  843. this.constructor.enabledWarnings.indexOf('change-in-update') >= 0) {
  844. issueWarning('change-in-update', `Element ${this.localName} scheduled an update ` +
  845. `(generally because a property was set) ` +
  846. `after an update completed, causing a new update to be scheduled. ` +
  847. `This is inefficient and should be avoided unless the next update ` +
  848. `can only be scheduled as a side effect of the previous update.`);
  849. }
  850. }
  851. __markUpdated() {
  852. this._$changedProperties = new Map();
  853. this.isUpdatePending = false;
  854. }
  855. /**
  856. * Returns a Promise that resolves when the element has completed updating.
  857. * The Promise value is a boolean that is `true` if the element completed the
  858. * update without triggering another update. The Promise result is `false` if
  859. * a property was set inside `updated()`. If the Promise is rejected, an
  860. * exception was thrown during the update.
  861. *
  862. * To await additional asynchronous work, override the `getUpdateComplete`
  863. * method. For example, it is sometimes useful to await a rendered element
  864. * before fulfilling this Promise. To do this, first await
  865. * `super.getUpdateComplete()`, then any subsequent state.
  866. *
  867. * @return A promise of a boolean that resolves to true if the update completed
  868. * without triggering another update.
  869. * @category updates
  870. */
  871. get updateComplete() {
  872. return this.getUpdateComplete();
  873. }
  874. /**
  875. * Override point for the `updateComplete` promise.
  876. *
  877. * It is not safe to override the `updateComplete` getter directly due to a
  878. * limitation in TypeScript which means it is not possible to call a
  879. * superclass getter (e.g. `super.updateComplete.then(...)`) when the target
  880. * language is ES5 (https://github.com/microsoft/TypeScript/issues/338).
  881. * This method should be overridden instead. For example:
  882. *
  883. * ```ts
  884. * class MyElement extends LitElement {
  885. * override async getUpdateComplete() {
  886. * const result = await super.getUpdateComplete();
  887. * await this._myChild.updateComplete;
  888. * return result;
  889. * }
  890. * }
  891. * ```
  892. *
  893. * @return A promise of a boolean that resolves to true if the update completed
  894. * without triggering another update.
  895. * @category updates
  896. */
  897. getUpdateComplete() {
  898. return this.__updatePromise;
  899. }
  900. /**
  901. * Controls whether or not `update()` should be called when the element requests
  902. * an update. By default, this method always returns `true`, but this can be
  903. * customized to control when to update.
  904. *
  905. * @param _changedProperties Map of changed properties with old values
  906. * @category updates
  907. */
  908. shouldUpdate(_changedProperties) {
  909. return true;
  910. }
  911. /**
  912. * Updates the element. This method reflects property values to attributes.
  913. * It can be overridden to render and keep updated element DOM.
  914. * Setting properties inside this method will *not* trigger
  915. * another update.
  916. *
  917. * @param _changedProperties Map of changed properties with old values
  918. * @category updates
  919. */
  920. update(_changedProperties) {
  921. if (this.__reflectingProperties !== undefined) {
  922. // Use forEach so this works even if for/of loops are compiled to for
  923. // loops expecting arrays
  924. this.__reflectingProperties.forEach((v, k) => this.__propertyToAttribute(k, this[k], v));
  925. this.__reflectingProperties = undefined;
  926. }
  927. this.__markUpdated();
  928. }
  929. /**
  930. * Invoked whenever the element is updated. Implement to perform
  931. * post-updating tasks via DOM APIs, for example, focusing an element.
  932. *
  933. * Setting properties inside this method will trigger the element to update
  934. * again after this update cycle completes.
  935. *
  936. * @param _changedProperties Map of changed properties with old values
  937. * @category updates
  938. */
  939. updated(_changedProperties) { }
  940. /**
  941. * Invoked when the element is first updated. Implement to perform one time
  942. * work on the element after update.
  943. *
  944. * ```ts
  945. * firstUpdated() {
  946. * this.renderRoot.getElementById('my-text-area').focus();
  947. * }
  948. * ```
  949. *
  950. * Setting properties inside this method will trigger the element to update
  951. * again after this update cycle completes.
  952. *
  953. * @param _changedProperties Map of changed properties with old values
  954. * @category updates
  955. */
  956. firstUpdated(_changedProperties) { }
  957. }
  958. _d = finalized;
  959. /**
  960. * Marks class as having finished creating properties.
  961. */
  962. ReactiveElement[_d] = true;
  963. /**
  964. * Memoized list of all element properties, including any superclass properties.
  965. * Created lazily on user subclasses when finalizing the class.
  966. * @nocollapse
  967. * @category properties
  968. */
  969. ReactiveElement.elementProperties = new Map();
  970. /**
  971. * Memoized list of all element styles.
  972. * Created lazily on user subclasses when finalizing the class.
  973. * @nocollapse
  974. * @category styles
  975. */
  976. ReactiveElement.elementStyles = [];
  977. /**
  978. * Options used when calling `attachShadow`. Set this property to customize
  979. * the options for the shadowRoot; for example, to create a closed
  980. * shadowRoot: `{mode: 'closed'}`.
  981. *
  982. * Note, these options are used in `createRenderRoot`. If this method
  983. * is customized, options should be respected if possible.
  984. * @nocollapse
  985. * @category rendering
  986. */
  987. ReactiveElement.shadowRootOptions = { mode: 'open' };
  988. // Apply polyfills if available
  989. polyfillSupport === null || polyfillSupport === void 0 ? void 0 : polyfillSupport({ ReactiveElement });
  990. // Dev mode warnings...
  991. if (DEV_MODE) {
  992. // Default warning set.
  993. ReactiveElement.enabledWarnings = ['change-in-update'];
  994. const ensureOwnWarnings = function (ctor) {
  995. if (!ctor.hasOwnProperty(JSCompiler_renameProperty('enabledWarnings', ctor))) {
  996. ctor.enabledWarnings = ctor.enabledWarnings.slice();
  997. }
  998. };
  999. ReactiveElement.enableWarning = function (warning) {
  1000. ensureOwnWarnings(this);
  1001. if (this.enabledWarnings.indexOf(warning) < 0) {
  1002. this.enabledWarnings.push(warning);
  1003. }
  1004. };
  1005. ReactiveElement.disableWarning = function (warning) {
  1006. ensureOwnWarnings(this);
  1007. const i = this.enabledWarnings.indexOf(warning);
  1008. if (i >= 0) {
  1009. this.enabledWarnings.splice(i, 1);
  1010. }
  1011. };
  1012. }
  1013. // IMPORTANT: do not change the property name or the assignment expression.
  1014. // This line will be used in regexes to search for ReactiveElement usage.
  1015. ((_c = globalThis.reactiveElementVersions) !== null && _c !== void 0 ? _c : (globalThis.reactiveElementVersions = [])).push('1.3.0');
  1016. if (DEV_MODE && globalThis.reactiveElementVersions.length > 1) {
  1017. issueWarning('multiple-versions', `Multiple versions of Lit loaded. Loading multiple versions ` +
  1018. `is not recommended.`);
  1019. }
  1020. //# sourceMappingURL=reactive-element.js.map