// @defaultValue decorator // // Runs when the corresponding attribute of the observed property changes, e.g. after calling Element.setAttribute or after updating // the observed property. // // The decorator checks whether the value of the attribute is different from the value of the property and in that case // it saves the new value. // // // Usage: // // @property({ type: Boolean, reflect: true }) checked = false; // // @defaultValue('checked') defaultChecked = false; // import { defaultConverter } from 'lit'; import type { ReactiveElement } from 'lit'; export const defaultValue = (propertyName = 'value') => (proto: ReactiveElement, key: string) => { const ctor = proto.constructor as typeof ReactiveElement; const attributeChangedCallback = ctor.prototype.attributeChangedCallback; ctor.prototype.attributeChangedCallback = function ( this: ReactiveElement & { [name: string]: unknown }, name, old, value ) { const options = ctor.getPropertyOptions(propertyName); const attributeName = typeof options.attribute === 'string' ? options.attribute : propertyName; if (name === attributeName) { const converter = options.converter || defaultConverter; const fromAttribute = typeof converter === 'function' ? converter : converter?.fromAttribute ?? defaultConverter.fromAttribute; const newValue: unknown = fromAttribute!(value, options.type); if (this[propertyName] !== newValue) { this[key] = newValue; } } attributeChangedCallback.call(this, name, old, value); }; };