import { type TemplateResult, noChange } from 'lit'; import { AsyncDirective, directive } from 'lit/async-directive.js'; import { rxjs } from '@push.rocks/smartrx'; /** * Subscribes to an observable and applies a template function to each emission. * @param observable - the source Observable * @param templateFn - function mapping each emitted value to a TemplateResult or other renderable content */ class SubscribeWithTemplateDirective extends AsyncDirective { private observable?: rxjs.Observable; private templateFn?: (value: unknown) => TemplateResult | unknown; private sub: rxjs.Subscription | null = null; render( observable: rxjs.Observable, templateFn: (value: unknown) => TemplateResult | unknown ) { const changed = this.observable !== observable || this.templateFn !== templateFn; if (changed) { this.sub?.unsubscribe(); this.observable = observable; this.templateFn = templateFn; if (this.isConnected) { this.startSubscription(); } } return noChange; } private startSubscription() { this.sub = this.observable!.subscribe((v: unknown) => { const out = this.templateFn!(v); this.setValue(out); }); } disconnected() { this.sub?.unsubscribe(); } reconnected() { this.startSubscription(); } } /** * Directive that renders templates for each emission of an Observable. * Usage: html`${subscribeWithTemplate(myObservable, v => html`${v}`)}` */ export const subscribeWithTemplate = directive(SubscribeWithTemplateDirective);