element-vir 12.3.1 → 12.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -219,7 +219,7 @@ export const MyWithAssignmentCleanupCallbackElement = defineElementNoInputs({
219
219
  },
220
220
  initCallback: ({updateState}) => {
221
221
  updateState({
222
- intervalId: window.setInterval(() => console.log('hi'), 1000),
222
+ intervalId: window.setInterval(() => console.info('hi'), 1000),
223
223
  });
224
224
  },
225
225
  renderCallback: () => html`
@@ -1,15 +1,15 @@
1
1
  import { CSSResult } from 'lit';
2
2
  import { RequireNonVoidReturn } from '../augments/type';
3
3
  import { DeclarativeElementDefinitionOptions } from './definition-options';
4
- import { MaybeAsyncStateToSync } from './properties/async-state';
5
4
  import { CssVarsInitMap } from './properties/css-vars';
6
5
  import { EventsInitMap } from './properties/element-events';
7
6
  import { PropertyInitMapBase } from './properties/element-properties';
8
7
  import { HostClassesInitMap } from './properties/host-classes';
8
+ import { FlattenObservablePropertyGetters } from './properties/observable-property/observable-property-handler';
9
9
  import { StylesCallback } from './properties/styles';
10
10
  import { InitCallback, RenderCallback } from './render-callback';
11
11
  export type CustomElementTagName = `${string}-${string}`;
12
- export type DeclarativeElementInit<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitMaybeAsyncGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeysGeneric extends string, CssVarKeysGeneric extends string, RenderOutputGeneric> = {
12
+ export type DeclarativeElementInit<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeysGeneric extends string, CssVarKeysGeneric extends string, RenderOutputGeneric> = {
13
13
  /**
14
14
  * HTML tag name. This should not be used directly, as interpolating it with the html tagged
15
15
  * template from this package is preferred.
@@ -18,7 +18,7 @@ export type DeclarativeElementInit<TagNameGeneric extends CustomElementTagName,
18
18
  /** Static styles. These should not and cannot change. */
19
19
  styles?: CSSResult | StylesCallback<HostClassKeysGeneric, CssVarKeysGeneric>;
20
20
  /** Element properties. (These can be thought of as "inputs".) */
21
- stateInit?: StateInitMaybeAsyncGeneric;
21
+ stateInit?: StateInitGeneric;
22
22
  /** Events that the element can dispatch. (These can be thought of as "outputs".) */
23
23
  events?: EventsInitGeneric;
24
24
  /**
@@ -26,7 +26,7 @@ export type DeclarativeElementInit<TagNameGeneric extends CustomElementTagName,
26
26
  * based on current instance state or inputs, or just undefined to indicate that the host class
27
27
  * will only be manually set.
28
28
  */
29
- hostClasses?: HostClassesInitMap<HostClassKeysGeneric, InputsGeneric, MaybeAsyncStateToSync<StateInitMaybeAsyncGeneric>>;
29
+ hostClasses?: HostClassesInitMap<HostClassKeysGeneric, FlattenObservablePropertyGetters<InputsGeneric>, FlattenObservablePropertyGetters<StateInitGeneric>>;
30
30
  /**
31
31
  * CSS Vars for the component. Keys of this object should be camelCased (or whatever your casing
32
32
  * convention is). They will be transformed, at runtime, to CSS vars with kebab-casing, to match
@@ -39,8 +39,8 @@ export type DeclarativeElementInit<TagNameGeneric extends CustomElementTagName,
39
39
  */
40
40
  cssVars?: CssVarsInitMap<CssVarKeysGeneric>;
41
41
  /** Called as part of the first renderCallback call, before the first renderCallback call. */
42
- initCallback?: InitCallback<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric>;
43
- renderCallback: RequireNonVoidReturn<RenderOutputGeneric, RenderCallback<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric, RenderOutputGeneric>>;
44
- cleanupCallback?: InitCallback<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric>;
42
+ initCallback?: InitCallback<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric>;
43
+ renderCallback: RequireNonVoidReturn<RenderOutputGeneric, RenderCallback<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric, RenderOutputGeneric>>;
44
+ cleanupCallback?: InitCallback<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeysGeneric, CssVarKeysGeneric>;
45
45
  options?: Partial<DeclarativeElementDefinitionOptions> | undefined;
46
46
  };
@@ -1,17 +1,17 @@
1
1
  import { RequiredAndNotNullBy, RequiredBy } from '@augment-vir/common';
2
2
  import { CSSResult, LitElement } from 'lit';
3
3
  import { CustomElementTagName, DeclarativeElementInit } from './declarative-element-init';
4
- import { AsyncStateHandlerMap, MaybeAsyncStateToSync } from './properties/async-state';
5
4
  import { CssVarNameOrValueMap } from './properties/css-vars';
6
5
  import { EventDescriptorMap, EventsInitMap } from './properties/element-events';
7
6
  import { ElementPropertyDescriptorMap, PropertyInitMapBase } from './properties/element-properties';
8
7
  import { HostClassNamesMap } from './properties/host-classes';
8
+ import { AllowObservablePropertySetter, FlattenObservablePropertyGetters, ObservablePropertyHandlerMap } from './properties/observable-property/observable-property-handler';
9
9
  import { RenderCallback, RenderParams } from './render-callback';
10
- export type HostInstanceType<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitMaybeAsyncGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = RequiredAndNotNullBy<DeclarativeElement<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, any>, 'shadowRoot'>;
11
- export type DeclarativeElementDefinition<TagNameGeneric extends CustomElementTagName = any, InputsGeneric extends PropertyInitMapBase = any, StateInitMaybeAsyncGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string, RenderOutputGeneric = any> = (new () => HostInstanceType<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) & StaticDeclarativeElementProperties<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric> & {
12
- instanceType: HostInstanceType<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
10
+ export type HostInstanceType<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = RequiredAndNotNullBy<DeclarativeElement<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, any>, 'shadowRoot'>;
11
+ export type DeclarativeElementDefinition<TagNameGeneric extends CustomElementTagName = any, InputsGeneric extends PropertyInitMapBase = any, StateInitGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string, RenderOutputGeneric = any> = (new () => HostInstanceType<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) & StaticDeclarativeElementProperties<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric> & {
12
+ instanceType: HostInstanceType<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
13
13
  };
14
- export declare abstract class DeclarativeElement<TagNameGeneric extends CustomElementTagName = any, InputsGeneric extends PropertyInitMapBase = any, StateInitMaybeAsyncGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string, RenderOutputGeneric = any> extends LitElement {
14
+ export declare abstract class DeclarativeElement<TagNameGeneric extends CustomElementTagName = any, InputsGeneric extends PropertyInitMapBase = any, StateInitGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string, RenderOutputGeneric = any> extends LitElement {
15
15
  static readonly tagName: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['tagName'];
16
16
  static readonly styles: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['styles'];
17
17
  static readonly isStrictInstance: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['isStrictInstance'];
@@ -24,25 +24,25 @@ export declare abstract class DeclarativeElement<TagNameGeneric extends CustomEl
24
24
  static readonly hostClasses: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['hostClasses'];
25
25
  static readonly cssVarNames: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['cssVarNames'];
26
26
  static readonly cssVarValues: StaticDeclarativeElementProperties<CustomElementTagName, PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string, unknown>['cssVarValues'];
27
- abstract lastRenderedProps: Pick<RenderParams<any, InputsGeneric, StateInitMaybeAsyncGeneric, any, any, any>, 'inputs' | 'state'>;
27
+ abstract lastRenderedProps: Pick<RenderParams<any, InputsGeneric, StateInitGeneric, any, any, any>, 'inputs' | 'state'>;
28
28
  abstract render(): unknown;
29
- abstract readonly instanceState: MaybeAsyncStateToSync<StateInitMaybeAsyncGeneric>;
30
- abstract readonly asyncStateHandlerMap: AsyncStateHandlerMap<StateInitMaybeAsyncGeneric>;
31
- abstract readonly instanceInputs: InputsGeneric;
29
+ abstract readonly instanceState: FlattenObservablePropertyGetters<StateInitGeneric>;
30
+ abstract readonly observablePropertyHandlerMap: ObservablePropertyHandlerMap<StateInitGeneric>;
31
+ abstract readonly instanceInputs: FlattenObservablePropertyGetters<InputsGeneric>;
32
32
  abstract assignInputs(inputs: {} extends Required<InputsGeneric> ? never : Partial<InputsGeneric>): void;
33
33
  abstract haveInputsBeenSet: boolean;
34
34
  abstract markInputsAsHavingBeenSet(): void;
35
- abstract readonly definition: DeclarativeElementDefinition<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
35
+ abstract readonly definition: DeclarativeElementDefinition<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
36
36
  }
37
- export interface StaticDeclarativeElementProperties<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitMaybeAsyncGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string, RenderOutputGeneric> {
37
+ export interface StaticDeclarativeElementProperties<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string, RenderOutputGeneric> {
38
38
  /** Pass through the render callback for direct unit testability */
39
- readonly renderCallback: RenderCallback<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
39
+ readonly renderCallback: RenderCallback<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
40
40
  events: EventDescriptorMap<EventsInitGeneric>;
41
- stateInit: ElementPropertyDescriptorMap<StateInitMaybeAsyncGeneric>;
42
- init: RequiredBy<DeclarativeElementInit<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>, 'stateInit' | 'events'>;
43
- inputsType: InputsGeneric;
44
- stateType: MaybeAsyncStateToSync<StateInitMaybeAsyncGeneric>;
45
- isStrictInstance: (element: unknown) => element is DeclarativeElement<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
41
+ stateInit: ElementPropertyDescriptorMap<StateInitGeneric>;
42
+ init: RequiredBy<DeclarativeElementInit<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>, 'stateInit' | 'events'>;
43
+ inputsType: AllowObservablePropertySetter<InputsGeneric>;
44
+ stateType: FlattenObservablePropertyGetters<StateInitGeneric>;
45
+ isStrictInstance: (element: unknown) => element is DeclarativeElement<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
46
46
  hostClasses: HostClassNamesMap<string, HostClassKeys>;
47
47
  cssVarNames: CssVarNameOrValueMap<CssVarKeys>;
48
48
  cssVarValues: CssVarNameOrValueMap<CssVarKeys>;
@@ -2,4 +2,4 @@ import { DeclarativeElementDefinition } from './declarative-element';
2
2
  import { CustomElementTagName, DeclarativeElementInit } from './declarative-element-init';
3
3
  import { EventsInitMap } from './properties/element-events';
4
4
  import { PropertyInitMapBase } from './properties/element-properties';
5
- export declare function defineElementNoInputs<TagNameGeneric extends CustomElementTagName = '-', InputsGeneric extends PropertyInitMapBase = {}, StateInitMaybeAsyncGeneric extends PropertyInitMapBase = {}, EventsInitGeneric extends EventsInitMap = {}, HostClassKeys extends string = '', CssVarKeys extends string = '', RenderOutputGeneric = any>(initInput: DeclarativeElementInit<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>): DeclarativeElementDefinition<TagNameGeneric, InputsGeneric, StateInitMaybeAsyncGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
5
+ export declare function defineElementNoInputs<TagNameGeneric extends CustomElementTagName = '-', InputsGeneric extends PropertyInitMapBase = {}, StateInitGeneric extends PropertyInitMapBase = {}, EventsInitGeneric extends EventsInitMap = {}, HostClassKeys extends string = '', CssVarKeys extends string = '', RenderOutputGeneric = any>(initInput: DeclarativeElementInit<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>): DeclarativeElementDefinition<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>;
@@ -113,7 +113,7 @@ export function defineElementNoInputs(initInput) {
113
113
  this.haveInputsBeenSet = false;
114
114
  // this is set below in Object.defineProperties
115
115
  this.definition = {};
116
- this.asyncStateHandlerMap = {};
116
+ this.observablePropertyHandlerMap = {};
117
117
  this.instanceInputs = createElementUpdaterProxy(this, false);
118
118
  this.instanceState = createElementUpdaterProxy(this, true);
119
119
  const stateInit = initInput.stateInit ||
@@ -1,7 +1,8 @@
1
1
  import { DirectiveResult } from 'lit/directive.js';
2
2
  import { PropertyInitMapBase } from '../properties/element-properties';
3
+ import { AllowObservablePropertySetter } from '../properties/observable-property/observable-property-handler';
3
4
  export type ElementDefinitionWithInputsType<InputsType extends PropertyInitMapBase = PropertyInitMapBase> = {
4
- inputsType: InputsType;
5
+ inputsType: AllowObservablePropertySetter<InputsType>;
5
6
  };
6
7
  /** Assign an object matching an element's inputs to its inputs. */
7
8
  export declare function assign<DeclarativeElementGeneric extends ElementDefinitionWithInputsType>(declarativeElement: DeclarativeElementGeneric, inputsObject: {} extends Required<DeclarativeElementGeneric['inputsType']> ? never : DeclarativeElementGeneric['inputsType']): DirectiveResult;
@@ -0,0 +1,3 @@
1
+ import { UnPromise } from '@augment-vir/common';
2
+ import { AsyncState } from '../properties/async-state';
3
+ export declare function isRenderReady<T>(asyncStateInput: AsyncState<T>): asyncStateInput is UnPromise<T>;
@@ -0,0 +1,12 @@
1
+ import { isPromiseLike } from '@augment-vir/common';
2
+ export function isRenderReady(asyncStateInput) {
3
+ if (asyncStateInput instanceof Error) {
4
+ return false;
5
+ }
6
+ else if (isPromiseLike(asyncStateInput)) {
7
+ return false;
8
+ }
9
+ else {
10
+ return true;
11
+ }
12
+ }
@@ -1,9 +1,8 @@
1
1
  import { JsonCompatibleValue, UnPromise } from '@augment-vir/common';
2
2
  import { PickAndBlockOthers } from '../../augments/type';
3
- import { PropertyInitMapBase } from './element-properties';
3
+ import { ObservablePropertyHandler, observablePropertyHandlerMarkerKey, ObservablePropertyListener } from './observable-property/observable-property-handler';
4
4
  export type AsyncState<ValueGeneric> = Error | UnPromise<ValueGeneric> | Promise<UnPromise<ValueGeneric>>;
5
5
  declare const notSetSymbol: unique symbol;
6
- export declare function isRenderReady<T>(asyncStateInput: AsyncState<T>): asyncStateInput is UnPromise<T>;
7
6
  type AllSetValueProperties<ValueGeneric> = {
8
7
  /** Set a new value directly without using any promises. */
9
8
  resolvedValue: UnPromise<ValueGeneric>;
@@ -22,28 +21,19 @@ type AllSetValueProperties<ValueGeneric> = {
22
21
  forceUpdate: true;
23
22
  };
24
23
  export type AsyncStateSetValue<ValueGeneric> = PickAndBlockOthers<AllSetValueProperties<ValueGeneric>, 'createPromise' | 'trigger'> | PickAndBlockOthers<AllSetValueProperties<ValueGeneric>, 'newPromise'> | PickAndBlockOthers<AllSetValueProperties<ValueGeneric>, 'forceUpdate'> | PickAndBlockOthers<AllSetValueProperties<ValueGeneric>, 'resolvedValue'>;
25
- export type MaybeAsyncStateToSync<PropertyMapInit extends PropertyInitMapBase> = {
26
- [Prop in keyof PropertyMapInit]: PropertyMapInit[Prop] extends AsyncStateHandler<infer ValueGeneric> | AsyncStateInit<infer ValueGeneric> ? AsyncState<ValueGeneric> : PropertyMapInit[Prop];
27
- };
28
- export type AsyncStateInputs<PropertyMapInit extends PropertyInitMapBase> = {
29
- [Prop in keyof PropertyMapInit]: PropertyMapInit[Prop] extends AsyncStateHandler<infer ValueGeneric> | AsyncStateInit<infer ValueGeneric> ? AsyncStateSetValue<ValueGeneric> : PropertyMapInit[Prop];
30
- };
31
- export type AsyncStateHandlerMap<OriginalObjectGeneric extends PropertyInitMapBase> = Partial<Record<keyof OriginalObjectGeneric, AsyncStateHandler<any>>>;
32
- export type AsyncStateHandlerListener<ValueGeneric> = (handler: AsyncStateHandler<ValueGeneric>) => void;
33
- export declare class AsyncStateHandler<ValueGeneric> {
24
+ export declare class AsyncObservablePropertyHandler<ValueGeneric> implements asyncObservablePropertyHandler<ValueGeneric> {
34
25
  #private;
35
- readonly asyncMarkerSymbol: symbol;
36
- constructor(initialValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol | AsyncStateInit<ValueGeneric>, listener: AsyncStateHandlerListener<ValueGeneric>);
37
- resetValue(rawValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol | AsyncStateInit<ValueGeneric>): void;
26
+ [observablePropertyHandlerMarkerKey]: true;
27
+ constructor(initialValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol);
28
+ resetValue(rawValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol): void;
38
29
  setValue(setInputs: AsyncStateSetValue<ValueGeneric>): void;
39
30
  getValue(): AsyncState<ValueGeneric>;
40
- addSettleListener(callback: AsyncStateHandlerListener<ValueGeneric>): void;
41
- removeSettleListener(callback: AsyncStateHandlerListener<ValueGeneric>): void;
42
- }
43
- export declare class AsyncStateInit<ValueGeneric> {
44
- readonly initialValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol;
45
- constructor(initialValue: Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric | typeof notSetSymbol);
46
- readonly asyncMarkerSymbol: symbol;
31
+ addListener(fireImmediately: boolean, listener: ObservablePropertyListener<AsyncState<ValueGeneric>>): void;
32
+ addMultipleListeners(listeners: ReadonlySet<ObservablePropertyListener<AsyncState<ValueGeneric>>>): void;
33
+ getAllListeners(): Set<ObservablePropertyListener<AsyncState<ValueGeneric>>>;
34
+ removeListener(listener: ObservablePropertyListener<AsyncState<ValueGeneric>>): boolean;
35
+ removeAllListeners(): number;
47
36
  }
48
- export declare function asyncState<ValueGeneric>(...args: [Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric] | []): AsyncStateInit<ValueGeneric>;
37
+ export type asyncObservablePropertyHandler<ValueGeneric> = ObservablePropertyHandler<AsyncStateSetValue<ValueGeneric>, AsyncState<ValueGeneric>>;
38
+ export declare function asyncState<ValueGeneric>(...args: [Promise<UnPromise<ValueGeneric>> | UnPromise<ValueGeneric> | ValueGeneric] | []): AsyncObservablePropertyHandler<ValueGeneric>;
49
39
  export {};
@@ -9,39 +9,24 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _AsyncStateHandler_instances, _AsyncStateHandler_lastTrigger, _AsyncStateHandler_resolutionValue, _AsyncStateHandler_rejectionError, _AsyncStateHandler_listeners, _AsyncStateHandler_lastSetPromise, _AsyncStateHandler_waitingForValuePromise, _AsyncStateHandler_fireListeners, _AsyncStateHandler_setPromise, _AsyncStateHandler_resolveValue, _AsyncStateHandler_resetWaitingForValuePromise;
13
- import { areJsonEqual, createDeferredPromiseWrapper, ensureError, isLengthAtLeast, isPromiseLike, } from '@augment-vir/common';
14
- const asyncMarkerSymbol = Symbol('element-vir-async-state-marker');
12
+ var _AsyncObservablePropertyHandler_instances, _AsyncObservablePropertyHandler_lastTrigger, _AsyncObservablePropertyHandler_resolutionValue, _AsyncObservablePropertyHandler_rejectionError, _AsyncObservablePropertyHandler_listeners, _AsyncObservablePropertyHandler_lastSetPromise, _AsyncObservablePropertyHandler_waitingForValuePromise, _AsyncObservablePropertyHandler_fireListeners, _AsyncObservablePropertyHandler_setPromise, _AsyncObservablePropertyHandler_resolveValue, _AsyncObservablePropertyHandler_resetWaitingForValuePromise, _a;
13
+ import { areJsonEqual, createDeferredPromiseWrapper, ensureError, isLengthAtLeast, } from '@augment-vir/common';
14
+ import { observablePropertyHandlerMarkerKey, } from './observable-property/observable-property-handler';
15
15
  const notSetSymbol = Symbol('not set');
16
- export function isRenderReady(asyncStateInput) {
17
- if (asyncStateInput instanceof Error) {
18
- return false;
19
- }
20
- else if (isPromiseLike(asyncStateInput)) {
21
- return false;
22
- }
23
- else {
24
- return true;
25
- }
26
- }
27
- export class AsyncStateHandler {
28
- constructor(initialValue, listener) {
29
- _AsyncStateHandler_instances.add(this);
30
- _AsyncStateHandler_lastTrigger.set(this, notSetSymbol);
31
- _AsyncStateHandler_resolutionValue.set(this, notSetSymbol);
32
- _AsyncStateHandler_rejectionError.set(this, notSetSymbol);
33
- _AsyncStateHandler_listeners.set(this, []);
34
- _AsyncStateHandler_lastSetPromise.set(this, void 0);
35
- _AsyncStateHandler_waitingForValuePromise.set(this, createDeferredPromiseWrapper());
36
- this.asyncMarkerSymbol = asyncMarkerSymbol;
37
- this.addSettleListener(listener);
16
+ export class AsyncObservablePropertyHandler {
17
+ constructor(initialValue) {
18
+ _AsyncObservablePropertyHandler_instances.add(this);
19
+ _AsyncObservablePropertyHandler_lastTrigger.set(this, notSetSymbol);
20
+ _AsyncObservablePropertyHandler_resolutionValue.set(this, notSetSymbol);
21
+ _AsyncObservablePropertyHandler_rejectionError.set(this, notSetSymbol);
22
+ _AsyncObservablePropertyHandler_listeners.set(this, new Set());
23
+ _AsyncObservablePropertyHandler_lastSetPromise.set(this, void 0);
24
+ _AsyncObservablePropertyHandler_waitingForValuePromise.set(this, createDeferredPromiseWrapper());
25
+ this[_a] = true;
38
26
  this.resetValue(initialValue);
39
27
  }
40
28
  resetValue(rawValue) {
41
- if (rawValue instanceof AsyncStateInit) {
42
- rawValue = rawValue.initialValue;
43
- }
44
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resetWaitingForValuePromise).call(this);
29
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resetWaitingForValuePromise).call(this);
45
30
  if (rawValue !== notSetSymbol) {
46
31
  if (rawValue instanceof Promise) {
47
32
  this.setValue({ newPromise: rawValue });
@@ -53,115 +38,135 @@ export class AsyncStateHandler {
53
38
  }
54
39
  setValue(setInputs) {
55
40
  if ('createPromise' in setInputs) {
56
- if (__classPrivateFieldGet(this, _AsyncStateHandler_lastTrigger, "f") === notSetSymbol ||
57
- !areJsonEqual(setInputs.trigger, __classPrivateFieldGet(this, _AsyncStateHandler_lastTrigger, "f"))) {
58
- __classPrivateFieldSet(this, _AsyncStateHandler_lastTrigger, setInputs.trigger, "f");
41
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastTrigger, "f") === notSetSymbol ||
42
+ !areJsonEqual(setInputs.trigger, __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastTrigger, "f"))) {
43
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_lastTrigger, setInputs.trigger, "f");
59
44
  const newValue = setInputs.createPromise();
60
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_setPromise).call(this, newValue);
45
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_setPromise).call(this, newValue);
46
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_fireListeners).call(this);
61
47
  }
62
48
  }
63
49
  else if ('newPromise' in setInputs) {
64
- __classPrivateFieldGet(this, _AsyncStateHandler_lastTrigger, "f") === notSetSymbol;
65
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_setPromise).call(this, setInputs.newPromise);
50
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastTrigger, "f") === notSetSymbol;
51
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_setPromise).call(this, setInputs.newPromise);
66
52
  // force a re-render
67
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_fireListeners).call(this);
53
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_fireListeners).call(this);
68
54
  }
69
55
  else if ('resolvedValue' in setInputs) {
70
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resolveValue).call(this, setInputs.resolvedValue);
56
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resolveValue).call(this, setInputs.resolvedValue);
71
57
  }
72
58
  else if ('forceUpdate' in setInputs) {
73
- __classPrivateFieldSet(this, _AsyncStateHandler_lastTrigger, notSetSymbol, "f");
74
- __classPrivateFieldSet(this, _AsyncStateHandler_resolutionValue, notSetSymbol, "f");
75
- if (!__classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").isSettled()) {
76
- __classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").reject('Canceled by force update');
59
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_lastTrigger, notSetSymbol, "f");
60
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_resolutionValue, notSetSymbol, "f");
61
+ if (!__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").isSettled()) {
62
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").reject('Canceled by force update');
77
63
  }
78
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resetWaitingForValuePromise).call(this);
64
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resetWaitingForValuePromise).call(this);
79
65
  // force a re-render
80
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_fireListeners).call(this);
66
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_fireListeners).call(this);
81
67
  }
82
68
  else {
83
69
  this.resetValue(setInputs);
84
70
  }
85
71
  }
86
72
  getValue() {
87
- if (__classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").isSettled()) {
88
- if (__classPrivateFieldGet(this, _AsyncStateHandler_rejectionError, "f") !== notSetSymbol) {
89
- return __classPrivateFieldGet(this, _AsyncStateHandler_rejectionError, "f");
73
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").isSettled()) {
74
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_rejectionError, "f") !== notSetSymbol) {
75
+ return __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_rejectionError, "f");
90
76
  }
91
- else if (__classPrivateFieldGet(this, _AsyncStateHandler_resolutionValue, "f") === notSetSymbol) {
77
+ else if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_resolutionValue, "f") === notSetSymbol) {
92
78
  throw new Error('Promise says it has settled but resolution value was not set!');
93
79
  }
94
80
  else {
95
- return __classPrivateFieldGet(this, _AsyncStateHandler_resolutionValue, "f");
81
+ return __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_resolutionValue, "f");
96
82
  }
97
83
  }
98
84
  else {
99
- return __classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").promise;
85
+ return __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").promise;
86
+ }
87
+ }
88
+ addListener(fireImmediately, listener) {
89
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").add(listener);
90
+ if (fireImmediately) {
91
+ listener(this.getValue());
100
92
  }
101
93
  }
102
- addSettleListener(callback) {
103
- __classPrivateFieldGet(this, _AsyncStateHandler_listeners, "f").push(callback);
94
+ addMultipleListeners(listeners) {
95
+ listeners.forEach((listener) => __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").add(listener));
104
96
  }
105
- removeSettleListener(callback) {
106
- __classPrivateFieldSet(this, _AsyncStateHandler_listeners, __classPrivateFieldGet(this, _AsyncStateHandler_listeners, "f").filter((listener) => listener !== callback), "f");
97
+ getAllListeners() {
98
+ return __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f");
99
+ }
100
+ removeListener(listener) {
101
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").has(listener)) {
102
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").delete(listener);
103
+ return true;
104
+ }
105
+ else {
106
+ return false;
107
+ }
108
+ }
109
+ removeAllListeners() {
110
+ const count = __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").size;
111
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").clear();
112
+ return count;
107
113
  }
108
114
  }
109
- _AsyncStateHandler_lastTrigger = new WeakMap(), _AsyncStateHandler_resolutionValue = new WeakMap(), _AsyncStateHandler_rejectionError = new WeakMap(), _AsyncStateHandler_listeners = new WeakMap(), _AsyncStateHandler_lastSetPromise = new WeakMap(), _AsyncStateHandler_waitingForValuePromise = new WeakMap(), _AsyncStateHandler_instances = new WeakSet(), _AsyncStateHandler_fireListeners = function _AsyncStateHandler_fireListeners() {
110
- __classPrivateFieldGet(this, _AsyncStateHandler_listeners, "f").forEach((listener) => {
111
- listener(this);
115
+ _AsyncObservablePropertyHandler_lastTrigger = new WeakMap(), _AsyncObservablePropertyHandler_resolutionValue = new WeakMap(), _AsyncObservablePropertyHandler_rejectionError = new WeakMap(), _AsyncObservablePropertyHandler_listeners = new WeakMap(), _AsyncObservablePropertyHandler_lastSetPromise = new WeakMap(), _AsyncObservablePropertyHandler_waitingForValuePromise = new WeakMap(), _AsyncObservablePropertyHandler_instances = new WeakSet(), _a = observablePropertyHandlerMarkerKey, _AsyncObservablePropertyHandler_fireListeners = function _AsyncObservablePropertyHandler_fireListeners() {
116
+ const value = this.getValue();
117
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_listeners, "f").forEach((listener) => {
118
+ listener(value);
112
119
  });
113
- }, _AsyncStateHandler_setPromise = function _AsyncStateHandler_setPromise(newPromise) {
114
- if (newPromise === __classPrivateFieldGet(this, _AsyncStateHandler_lastSetPromise, "f")) {
120
+ }, _AsyncObservablePropertyHandler_setPromise = function _AsyncObservablePropertyHandler_setPromise(newPromise) {
121
+ if (newPromise === __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastSetPromise, "f")) {
115
122
  // abort setting the promise if we already have set this promise
116
123
  return;
117
124
  }
118
- __classPrivateFieldSet(this, _AsyncStateHandler_resolutionValue, notSetSymbol, "f");
119
- __classPrivateFieldSet(this, _AsyncStateHandler_rejectionError, notSetSymbol, "f");
120
- __classPrivateFieldSet(this, _AsyncStateHandler_lastSetPromise, newPromise, "f");
121
- if (__classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").isSettled()) {
122
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resetWaitingForValuePromise).call(this);
125
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_resolutionValue, notSetSymbol, "f");
126
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_rejectionError, notSetSymbol, "f");
127
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_lastSetPromise, newPromise, "f");
128
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").isSettled()) {
129
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resetWaitingForValuePromise).call(this);
123
130
  }
124
131
  newPromise
125
132
  .then((value) => {
126
133
  // make sure we're still actually waiting for this promise
127
- if (__classPrivateFieldGet(this, _AsyncStateHandler_lastSetPromise, "f") === newPromise) {
128
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resolveValue).call(this, value);
134
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastSetPromise, "f") === newPromise) {
135
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resolveValue).call(this, value);
129
136
  }
130
137
  })
131
138
  .catch((reason) => {
132
139
  // make sure we're still actually waiting for this promise
133
- if (__classPrivateFieldGet(this, _AsyncStateHandler_lastSetPromise, "f") === newPromise) {
134
- __classPrivateFieldSet(this, _AsyncStateHandler_rejectionError, ensureError(reason), "f");
135
- __classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").promise.catch(() => {
140
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_lastSetPromise, "f") === newPromise) {
141
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_rejectionError, ensureError(reason), "f");
142
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").promise.catch(() => {
136
143
  /**
137
144
  * Don't actually do anything, we just want to make sure the error is
138
145
  * handled so it doesn't throw errors in the browser.
139
146
  */
140
147
  });
141
- __classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").reject(reason);
142
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_fireListeners).call(this);
148
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").reject(reason);
149
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_fireListeners).call(this);
143
150
  }
144
151
  });
145
- }, _AsyncStateHandler_resolveValue = function _AsyncStateHandler_resolveValue(value) {
146
- if (value !== __classPrivateFieldGet(this, _AsyncStateHandler_resolutionValue, "f")) {
147
- __classPrivateFieldSet(this, _AsyncStateHandler_rejectionError, notSetSymbol, "f");
148
- __classPrivateFieldSet(this, _AsyncStateHandler_resolutionValue, value, "f");
149
- if (__classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").isSettled()) {
150
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_resetWaitingForValuePromise).call(this);
152
+ }, _AsyncObservablePropertyHandler_resolveValue = function _AsyncObservablePropertyHandler_resolveValue(value) {
153
+ if (value !== __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_resolutionValue, "f")) {
154
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_rejectionError, notSetSymbol, "f");
155
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_resolutionValue, value, "f");
156
+ if (__classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").isSettled()) {
157
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_resetWaitingForValuePromise).call(this);
151
158
  }
152
- __classPrivateFieldGet(this, _AsyncStateHandler_waitingForValuePromise, "f").resolve(value);
153
- __classPrivateFieldGet(this, _AsyncStateHandler_instances, "m", _AsyncStateHandler_fireListeners).call(this);
159
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, "f").resolve(value);
160
+ __classPrivateFieldGet(this, _AsyncObservablePropertyHandler_instances, "m", _AsyncObservablePropertyHandler_fireListeners).call(this);
154
161
  }
155
- }, _AsyncStateHandler_resetWaitingForValuePromise = function _AsyncStateHandler_resetWaitingForValuePromise() {
156
- __classPrivateFieldSet(this, _AsyncStateHandler_waitingForValuePromise, createDeferredPromiseWrapper(), "f");
162
+ }, _AsyncObservablePropertyHandler_resetWaitingForValuePromise = function _AsyncObservablePropertyHandler_resetWaitingForValuePromise() {
163
+ __classPrivateFieldSet(this, _AsyncObservablePropertyHandler_waitingForValuePromise, createDeferredPromiseWrapper(), "f");
157
164
  };
158
- export class AsyncStateInit {
159
- constructor(initialValue) {
160
- this.initialValue = initialValue;
161
- this.asyncMarkerSymbol = asyncMarkerSymbol;
162
- }
163
- }
164
165
  export function asyncState(...args) {
166
+ /**
167
+ * Distinguish between an explicitly passed value of undefined or simply a lack of any arguments
168
+ * at all.
169
+ */
165
170
  const initValue = isLengthAtLeast(args, 1) ? args[0] : notSetSymbol;
166
- return new AsyncStateInit(initValue);
171
+ return new AsyncObservablePropertyHandler(initValue);
167
172
  }
@@ -1,4 +1,4 @@
1
- import { AsyncStateHandler, AsyncStateInit } from './async-state';
1
+ import { isObservablePropertyHandler } from './observable-property/observable-property-handler';
2
2
  function assertValidPropertyName(propKey, element, elementTagName) {
3
3
  if (typeof propKey !== 'string' && typeof propKey !== 'number' && typeof propKey !== 'symbol') {
4
4
  throw new Error(`Property name must be a string, got type '${typeof propKey}' from: '${String(propKey)}' for '${elementTagName.toLowerCase()}'`);
@@ -18,13 +18,7 @@ export function createElementUpdaterProxy(element, verifyExists) {
18
18
  if (verifyExists) {
19
19
  assertValidPropertyName(propertyKey, element, element.tagName);
20
20
  }
21
- const asyncState = element.asyncStateHandlerMap[propertyKey];
22
- if (asyncState) {
23
- return asyncState.getValue();
24
- }
25
- else {
26
- return elementAsProps[propertyKey];
27
- }
21
+ return elementAsProps[propertyKey];
28
22
  }
29
23
  const propsProxy = new Proxy({}, {
30
24
  get: valueGetter,
@@ -32,33 +26,37 @@ export function createElementUpdaterProxy(element, verifyExists) {
32
26
  if (verifyExists) {
33
27
  assertValidPropertyName(propertyKey, element, element.tagName);
34
28
  }
35
- /**
36
- * We need to at least set the property on target so we can detect it in "ownKeys" and
37
- * "getOwnPropertyDescriptor". We don't need duplicates of the values stored in target
38
- * but doing so makes console logging more effective it actually works).
39
- */
40
- target[propertyKey] = newValue;
41
- const existingAsyncStateHandler = element.asyncStateHandlerMap[propertyKey];
42
- // if we're creating a new async prop
43
- if (newValue instanceof AsyncStateInit) {
44
- if (existingAsyncStateHandler) {
45
- existingAsyncStateHandler.resetValue(newValue);
29
+ const existingObservablePropertyHandler = element.observablePropertyHandlerMap[propertyKey];
30
+ function setValueOnElement(value) {
31
+ /**
32
+ * We need to at least set the property on target so we can detect it in "ownKeys"
33
+ * and "getOwnPropertyDescriptor". We don't need duplicates of the values stored in
34
+ * target but doing so makes console logging more effective it actually works).
35
+ */
36
+ target[propertyKey] = value;
37
+ elementAsProps[propertyKey] = value;
38
+ }
39
+ /** If we're creating a new observable property */
40
+ if (isObservablePropertyHandler(newValue)) {
41
+ if (existingObservablePropertyHandler &&
42
+ newValue !== existingObservablePropertyHandler) {
43
+ newValue.addMultipleListeners(existingObservablePropertyHandler.getAllListeners());
44
+ /** Remove listeners from old property handlers so they can be garbage collected. */
45
+ existingObservablePropertyHandler.removeAllListeners();
46
46
  }
47
47
  else {
48
- const newHandler = new AsyncStateHandler(newValue, (handler) => {
49
- // set the prop directly on the element so that lit catches updates
50
- element[propertyKey] =
51
- handler.getValue();
48
+ newValue.addListener(true, (newObservableValue) => {
49
+ setValueOnElement(newObservableValue);
52
50
  });
53
- element.asyncStateHandlerMap[propertyKey] = newHandler;
54
51
  }
52
+ element.observablePropertyHandlerMap[propertyKey] = newValue;
55
53
  }
56
54
  else {
57
- if (existingAsyncStateHandler) {
58
- existingAsyncStateHandler.setValue(newValue);
55
+ if (existingObservablePropertyHandler) {
56
+ existingObservablePropertyHandler.setValue(newValue);
59
57
  }
60
58
  else {
61
- elementAsProps[propertyKey] = newValue;
59
+ setValueOnElement(newValue);
62
60
  }
63
61
  }
64
62
  return true;
@@ -0,0 +1,2 @@
1
+ import { ObservablePropertyHandler } from './observable-property-handler';
2
+ export declare function createObservableProperty<ValueType>(initValue: ValueType): ObservablePropertyHandler<ValueType, ValueType>;
@@ -0,0 +1,41 @@
1
+ import { observablePropertyHandlerMarkerKey, } from './observable-property-handler';
2
+ export function createObservableProperty(initValue) {
3
+ const listeners = new Set();
4
+ let value = initValue;
5
+ function fireListeners() {
6
+ listeners.forEach((listener) => listener(value));
7
+ }
8
+ const propertyHandler = {
9
+ [observablePropertyHandlerMarkerKey]: true,
10
+ setValue(newValue) {
11
+ if (value !== newValue) {
12
+ value = newValue;
13
+ fireListeners();
14
+ }
15
+ },
16
+ getValue() {
17
+ return value;
18
+ },
19
+ addListener(fireImmediately, listener) {
20
+ listeners.add(listener);
21
+ if (fireImmediately) {
22
+ listener(value);
23
+ }
24
+ },
25
+ removeListener(listener) {
26
+ return listeners.delete(listener);
27
+ },
28
+ removeAllListeners() {
29
+ const size = listeners.size;
30
+ listeners.clear();
31
+ return size;
32
+ },
33
+ getAllListeners() {
34
+ return listeners;
35
+ },
36
+ addMultipleListeners(newListeners) {
37
+ newListeners.forEach((listener) => listeners.add(listener));
38
+ },
39
+ };
40
+ return propertyHandler;
41
+ }
@@ -0,0 +1,34 @@
1
+ import { PropertyInitMapBase } from '../element-properties';
2
+ export declare const observablePropertyHandlerMarkerKey: "_is_element_vir_observable_property_handler";
3
+ export type ObservablePropertyListener<T> = (value: T) => void;
4
+ export type ObservablePropertyHandlerMap<OriginalPropertyMap extends PropertyInitMapBase> = Partial<Record<keyof OriginalPropertyMap, ObservablePropertyHandler<any, any>>>;
5
+ export type AllowObservablePropertySetter<OriginalPropertyMap extends PropertyInitMapBase> = {
6
+ [Prop in keyof OriginalPropertyMap]: OriginalPropertyMap[Prop] | ObservablePropertyHandler<any, Required<OriginalPropertyMap>[Prop]>;
7
+ };
8
+ export type FlattenObservablePropertyGetters<OriginalPropertyMap extends PropertyInitMapBase> = {
9
+ [Prop in keyof OriginalPropertyMap]: OriginalPropertyMap[Prop] extends ObservablePropertyHandler<infer SetValue, infer GetValue> ? GetValue : OriginalPropertyMap[Prop];
10
+ };
11
+ export type FlattenObservablePropertySetters<OriginalPropertyMap extends PropertyInitMapBase> = {
12
+ [Prop in keyof OriginalPropertyMap]: OriginalPropertyMap[Prop] extends ObservablePropertyHandler<infer SetValue, infer GetValue> ? SetValue : OriginalPropertyMap[Prop];
13
+ };
14
+ export type ObservablePropertyHandler<SetValue, GetValue> = {
15
+ [observablePropertyHandlerMarkerKey]: true;
16
+ setValue(input: SetValue): void;
17
+ getValue(): GetValue;
18
+ /** Add the given listener. */
19
+ addListener(fireImmediately: boolean, listener: ObservablePropertyListener<GetValue>): void;
20
+ /**
21
+ * Remove the given listener by reference. If the listener indeed existed and was removed, this
22
+ * function will return true. Otherwise, it returns false.
23
+ */
24
+ removeListener(listener: ObservablePropertyListener<GetValue>): boolean;
25
+ /** Remove all previously added listeners. Returns the number of listeners removed. */
26
+ removeAllListeners(): number;
27
+ /**
28
+ * Get all currently attached listeners. This is used to attach listeners when a new handler
29
+ * needs to replace the current handler.
30
+ */
31
+ getAllListeners(): ReadonlySet<ObservablePropertyListener<GetValue>>;
32
+ addMultipleListeners(listeners: ReadonlySet<ObservablePropertyListener<GetValue>>): void;
33
+ };
34
+ export declare function isObservablePropertyHandler(input: unknown): input is ObservablePropertyHandler<any, any>;
@@ -0,0 +1,6 @@
1
+ import { typedHasProperty } from '@augment-vir/common';
2
+ export const observablePropertyHandlerMarkerKey = '_is_element_vir_observable_property_handler';
3
+ export function isObservablePropertyHandler(input) {
4
+ return (typedHasProperty(input, observablePropertyHandlerMarkerKey) &&
5
+ input[observablePropertyHandlerMarkerKey] === true);
6
+ }
@@ -1,18 +1,18 @@
1
1
  import { TypedEvent } from '../typed-event/typed-event';
2
2
  import { DeclarativeElement, HostInstanceType } from './declarative-element';
3
3
  import { CustomElementTagName } from './declarative-element-init';
4
- import { AsyncStateInputs, MaybeAsyncStateToSync } from './properties/async-state';
5
4
  import { EventDescriptorMap, EventInitMapEventDetailExtractor, EventsInitMap } from './properties/element-events';
6
5
  import { PropertyInitMapBase } from './properties/element-properties';
6
+ import { FlattenObservablePropertyGetters, FlattenObservablePropertySetters } from './properties/observable-property/observable-property-handler';
7
7
  export type RenderCallback<TagNameGeneric extends CustomElementTagName = any, InputsGeneric extends PropertyInitMapBase = any, StateGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = any, CssVarKeys extends string = any, RenderOutputGeneric = any> = (params: RenderParams<TagNameGeneric, InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) => RenderOutputGeneric;
8
8
  export type InitCallback<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = (params: RenderParams<TagNameGeneric, InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) => void;
9
- export type UpdateStateCallback<StateGeneric extends PropertyInitMapBase> = (newState: Partial<AsyncStateInputs<StateGeneric>>) => void;
9
+ export type UpdateStateCallback<StateGeneric extends PropertyInitMapBase> = (newState: Partial<FlattenObservablePropertySetters<StateGeneric>>) => void;
10
10
  export type RenderParams<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateInitGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = {
11
- state: Readonly<MaybeAsyncStateToSync<StateInitGeneric>>;
11
+ state: Readonly<FlattenObservablePropertyGetters<StateInitGeneric>>;
12
12
  updateState: UpdateStateCallback<StateInitGeneric>;
13
13
  events: EventDescriptorMap<EventsInitGeneric>;
14
14
  host: HostInstanceType<TagNameGeneric, InputsGeneric, StateInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
15
15
  dispatch: <EventTypeNameGeneric extends keyof EventsInitGeneric>(event: TypedEvent<EventTypeNameGeneric extends string ? EventTypeNameGeneric : never, EventInitMapEventDetailExtractor<EventTypeNameGeneric, EventsInitGeneric>> | Event) => boolean;
16
- inputs: InputsGeneric;
16
+ inputs: Readonly<FlattenObservablePropertyGetters<InputsGeneric>>;
17
17
  };
18
18
  export declare function createRenderParams<TagNameGeneric extends CustomElementTagName, InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string, RenderOutputGeneric>(element: DeclarativeElement<TagNameGeneric, InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys, RenderOutputGeneric>, eventsMap: EventDescriptorMap<EventsInitGeneric>): RenderParams<TagNameGeneric, InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export type { DeclarativeElementDefinitionOptions } from './declarative-element/
8
8
  export * from './declarative-element/directives/assign-with-clean-up.directive';
9
9
  export * from './declarative-element/directives/assign.directive';
10
10
  export * from './declarative-element/directives/directive-helpers';
11
+ export * from './declarative-element/directives/is-render-ready.directive';
11
12
  export * from './declarative-element/directives/listen.directive';
12
13
  export * from './declarative-element/directives/on-dom-created.directive';
13
14
  export * from './declarative-element/directives/on-resize.directive';
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export * from './declarative-element/define-element-no-inputs';
7
7
  export * from './declarative-element/directives/assign-with-clean-up.directive';
8
8
  export * from './declarative-element/directives/assign.directive';
9
9
  export * from './declarative-element/directives/directive-helpers';
10
+ export * from './declarative-element/directives/is-render-ready.directive';
10
11
  export * from './declarative-element/directives/listen.directive';
11
12
  export * from './declarative-element/directives/on-dom-created.directive';
12
13
  export * from './declarative-element/directives/on-resize.directive';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "element-vir",
3
- "version": "12.3.1",
3
+ "version": "12.4.0",
4
4
  "keywords": [
5
5
  "custom",
6
6
  "web",