Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 6x 6x 6x 6x 6x 6x 7x 7x 7x 7x 7x 7x 7x 7x 7x 4x 7x 7x 7x 7x 6x 6x 6x 7x 1x 1x | import { Mutable, assign } from '@sgrud/core';
import { ObservableInput, from } from 'rxjs';
import { Component } from './component';
/**
* {@link Component} prototype property decorator factory. Applying this
* **Fluctuate** decorator to a property of a custom {@link Component} while
* supplying a `streamFactory` that returns an {@link ObservableInput} upon
* invocation will subscribe the {@link Component.fluctuationChangedCallback}
* method to each emission from this {@link ObservableInput} and replace the
* decorated property with a getter returning its last emitted value. Further,
* the resulting subscription, referenced by the decorated property, is assigned
* to the {@link Component.observedFluctuations} property and may be terminated
* by unsubscribing manually. Finally, the {@link Component} will seize to
* **Fluctuate** automatically when it's disconnected from the {@link Document}.
*
* @param streamFactory - A forward reference to an {@link ObservableInput}.
* @returns A {@link Component} prototype property decorator.
*
* @example
* A {@link Component} that **Fluctuate**s:
* ```tsx
* import { Component, Fluctuate } from '@sgrud/shell';
* import { fromEvent } from 'rxjs';
*
* declare global {
* interface HTMLElementTagNameMap {
* 'example-component': ExampleComponent;
* }
* }
*
* @Component('example-component')
* export class ExampleComponent extends HTMLElement implements Component {
*
* @Fluctuate(() => fromEvent(document, 'click'))
* private readonly pointer?: MouseEvent;
*
* public get template(): JSX.Element {
* return <span>Clicked at ({this.pointer?.x}, {this.pointer?.y})</span>;
* }
*
* }
* ```
*
* @see {@link Component}
*/
export function Fluctuate(streamFactory: () => ObservableInput<unknown>) {
/**
* @param prototype - The {@link Component} `prototype` to be decorated.
* @param propertyKey - The {@link Component} property to be decorated.
*/
return function(prototype: Component, propertyKey: PropertyKey): void {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { connectedCallback, disconnectedCallback } = prototype;
prototype.connectedCallback = function(this: Component): void {
let fluctuation: unknown;
assign((this as Mutable<Component>).observedFluctuations ||= {}, {
[propertyKey]: from(streamFactory()).subscribe((next) => {
this.fluctuationChangedCallback?.(
propertyKey,
fluctuation,
fluctuation = next
);
})
});
Object.defineProperty(this, propertyKey, {
enumerable: true,
get: (): unknown => fluctuation,
set: Function.prototype as (...args: any[]) => any
});
return connectedCallback
? connectedCallback.call(this)
: this.renderComponent?.();
};
prototype.disconnectedCallback = function(this: Component): void {
this.observedFluctuations![propertyKey].unsubscribe();
disconnectedCallback?.call(this);
};
};
}
|