@lit/reactive-element
Version:
92 lines • 3.68 kB
JavaScript
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const standardProperty = (options, element) => {
// When decorating an accessor, pass it through and add property metadata.
// Note, the `hasOwnProperty` check in `createProperty` ensures we don't
// stomp over the user's accessor.
if (element.kind === 'method' &&
element.descriptor &&
!('value' in element.descriptor)) {
return {
...element,
finisher(clazz) {
clazz.createProperty(element.key, options);
},
};
}
else {
// createProperty() takes care of defining the property, but we still
// must return some kind of descriptor, so return a descriptor for an
// unused prototype field. The finisher calls createProperty().
return {
kind: 'field',
key: Symbol(),
placement: 'own',
descriptor: {},
// store the original key so subsequent decorators have access to it.
originalKey: element.key,
// When @babel/plugin-proposal-decorators implements initializers,
// do this instead of the initializer below. See:
// https://github.com/babel/babel/issues/9260 extras: [
// {
// kind: 'initializer',
// placement: 'own',
// initializer: descriptor.initializer,
// }
// ],
initializer() {
if (typeof element.initializer === 'function') {
this[element.key] = element.initializer.call(this);
}
},
finisher(clazz) {
clazz.createProperty(element.key, options);
},
};
}
};
const legacyProperty = (options, proto, name) => {
proto.constructor.createProperty(name, options);
};
/**
* A property decorator which creates a reactive property that reflects a
* corresponding attribute value. When a decorated property is set
* the element will update and render. A {@linkcode PropertyDeclaration} may
* optionally be supplied to configure property features.
*
* This decorator should only be used for public fields. As public fields,
* properties should be considered as primarily settable by element users,
* either via attribute or the property itself.
*
* Generally, properties that are changed by the element should be private or
* protected fields and should use the {@linkcode state} decorator.
*
* However, sometimes element code does need to set a public property. This
* should typically only be done in response to user interaction, and an event
* should be fired informing the user; for example, a checkbox sets its
* `checked` property when clicked and fires a `changed` event. Mutating public
* properties should typically not be done for non-primitive (object or array)
* properties. In other cases when an element needs to manage state, a private
* property decorated via the {@linkcode state} decorator should be used. When
* needed, state properties can be initialized via public properties to
* facilitate complex interactions.
*
* ```ts
* class MyElement {
* @property({ type: Boolean })
* clicked = false;
* }
* ```
* @category Decorator
* @ExportDecoratedItems
*/
export function property(options) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (protoOrDescriptor, name) => name !== undefined
? legacyProperty(options, protoOrDescriptor, name)
: standardProperty(options, protoOrDescriptor);
}
//# sourceMappingURL=property.js.map