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); }; }; } |