build(store): build26 from 45504a2b

This commit is contained in:
publish
2026-08-05 18:57:36 +02:00
commit 3f9bdddf36
102 changed files with 2265 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
import { SnapshotController, SnapshotControllerHost } from "./snapshot-controller.js";
import { StoreController, StoreControllerHost } from "./store-controller.js";
import { SubscriptionController, SubscriptionControllerHost } from "./subscription-controller.js";
export { SnapshotController, type SnapshotControllerHost, StoreController, type StoreControllerHost, SubscriptionController, type SubscriptionControllerHost };
+43
View File
@@ -0,0 +1,43 @@
import { State } from "../../core/state.js";
import { Selector } from "../../core/shallow-equal.js";
import { ReactiveController, ReactiveControllerHost } from "@videojs/element";
//#region src/html/controllers/snapshot-controller.d.ts
type SnapshotControllerHost = ReactiveControllerHost & HTMLElement;
/**
* Subscribe to a `State<T>` container with optional selector.
*
* Without selector: returns full state, re-renders on any state change.
* With selector: returns selected slice, re-renders only when the slice changes (shallowEqual).
*
* @example
* ```ts
* #state = new SnapshotController(this, sliderState, (s) => s.value);
* ```
*/
declare class SnapshotController<T extends object, R = T> implements ReactiveController {
#private;
/**
* @label Without Selector
* @param host - The host element that owns this controller.
* @param state - The State container to subscribe to.
*/
constructor(host: ReactiveControllerHost, state: State<T>);
/**
* @label With Selector
* @param host - The host element that owns this controller.
* @param state - The State container to subscribe to.
* @param selector - Derives a value from the state.
*/
constructor(host: ReactiveControllerHost, state: State<T>, selector: Selector<T, R>);
get value(): R;
/** Switch to tracking a different state container. */
track(state: State<T>): void;
hostConnected(): void;
hostDisconnected(): void;
}
declare namespace SnapshotController {
type Host = SnapshotControllerHost;
}
//#endregion
export { SnapshotController, SnapshotControllerHost };
//# sourceMappingURL=snapshot-controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"snapshot-controller.d.ts","names":[],"sources":["../../../../src/html/controllers/snapshot-controller.ts"],"mappings":";;;;KAMY,yBAAyB,yBAAyB;;;;;;;;;;;;cAajD,mBAAmB,kBAAkB,IAAI,cAAc;;;;;;;EAalE,YAAY,MAAM,wBAAwB,OAAO,MAAM;;;;;;;EAOvD,YAAY,MAAM,wBAAwB,OAAO,MAAM,IAAI,UAAU,SAAS,GAAG;MAQ7E,SAAS;;EAUb,MAAM,OAAO,MAAM;EAKnB;EAIA;;kBA2Be;OACH,OAAO"}
+65
View File
@@ -0,0 +1,65 @@
import { shallowEqual } from "../../core/shallow-equal.js";
import { noop } from "@videojs/utils/function";
//#region src/html/controllers/snapshot-controller.ts
/**
* Subscribe to a `State<T>` container with optional selector.
*
* Without selector: returns full state, re-renders on any state change.
* With selector: returns selected slice, re-renders only when the slice changes (shallowEqual).
*
* @example
* ```ts
* #state = new SnapshotController(this, sliderState, (s) => s.value);
* ```
*/
var SnapshotController = class {
#host;
#selector;
#state;
#cached;
#unsubscribe = noop;
constructor(host, state, selector) {
this.#host = host;
this.#state = state;
this.#selector = selector;
host.addController(this);
}
get value() {
if (!this.#selector) return this.#state.current;
this.#cached ??= this.#selector(this.#state.current);
return this.#cached;
}
/** Switch to tracking a different state container. */
track(state) {
this.#state = state;
this.#subscribe();
}
hostConnected() {
this.#subscribe();
}
hostDisconnected() {
this.#unsubscribe();
this.#unsubscribe = noop;
this.#cached = void 0;
}
#subscribe() {
this.#unsubscribe();
if (!this.#selector) {
this.#unsubscribe = this.#state.subscribe(() => this.#host.requestUpdate());
return;
}
const selector = this.#selector;
this.#cached = selector(this.#state.current);
this.#unsubscribe = this.#state.subscribe(() => {
const next = selector(this.#state.current);
if (!shallowEqual(this.#cached, next)) {
this.#cached = next;
this.#host.requestUpdate();
}
});
}
};
//#endregion
export { SnapshotController };
//# sourceMappingURL=snapshot-controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"snapshot-controller.js","names":["#host","#selector","#state","#cached","#subscribe","#unsubscribe"],"sources":["../../../../src/html/controllers/snapshot-controller.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from '@videojs/element';\nimport { noop } from '@videojs/utils/function';\nimport type { Selector } from '../../core/shallow-equal';\nimport { shallowEqual } from '../../core/shallow-equal';\nimport type { State } from '../../core/state';\n\nexport type SnapshotControllerHost = ReactiveControllerHost & HTMLElement;\n\n/**\n * Subscribe to a `State<T>` container with optional selector.\n *\n * Without selector: returns full state, re-renders on any state change.\n * With selector: returns selected slice, re-renders only when the slice changes (shallowEqual).\n *\n * @example\n * ```ts\n * #state = new SnapshotController(this, sliderState, (s) => s.value);\n * ```\n */\nexport class SnapshotController<T extends object, R = T> implements ReactiveController {\n readonly #host: ReactiveControllerHost;\n readonly #selector: Selector<T, R> | undefined;\n\n #state: State<T>;\n #cached: R | undefined;\n #unsubscribe = noop;\n\n /**\n * @label Without Selector\n * @param host - The host element that owns this controller.\n * @param state - The State container to subscribe to.\n */\n constructor(host: ReactiveControllerHost, state: State<T>);\n /**\n * @label With Selector\n * @param host - The host element that owns this controller.\n * @param state - The State container to subscribe to.\n * @param selector - Derives a value from the state.\n */\n constructor(host: ReactiveControllerHost, state: State<T>, selector: Selector<T, R>);\n constructor(host: ReactiveControllerHost, state: State<T>, selector?: Selector<T, R>) {\n this.#host = host;\n this.#state = state;\n this.#selector = selector;\n host.addController(this);\n }\n\n get value(): R {\n if (!this.#selector) {\n return this.#state.current as unknown as R;\n }\n\n this.#cached ??= this.#selector(this.#state.current);\n return this.#cached;\n }\n\n /** Switch to tracking a different state container. */\n track(state: State<T>): void {\n this.#state = state;\n this.#subscribe();\n }\n\n hostConnected(): void {\n this.#subscribe();\n }\n\n hostDisconnected(): void {\n this.#unsubscribe();\n this.#unsubscribe = noop;\n this.#cached = undefined;\n }\n\n #subscribe(): void {\n this.#unsubscribe();\n\n if (!this.#selector) {\n this.#unsubscribe = this.#state.subscribe(() => this.#host.requestUpdate());\n return;\n }\n\n const selector = this.#selector;\n this.#cached = selector(this.#state.current);\n\n this.#unsubscribe = this.#state.subscribe(() => {\n const next = selector(this.#state.current);\n if (!shallowEqual(this.#cached, next)) {\n this.#cached = next;\n this.#host.requestUpdate();\n }\n });\n }\n}\n\nexport namespace SnapshotController {\n export type Host = SnapshotControllerHost;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,IAAa,qBAAb,MAAuF;CACrF;CACA;CAEA;CACA;CACA,eAAe;CAef,YAAY,MAA8B,OAAiB,UAA2B;EACpF,KAAKA,QAAQ;EACb,KAAKE,SAAS;EACd,KAAKD,YAAY;EACjB,KAAK,cAAc,IAAI;CACzB;CAEA,IAAI,QAAW;EACb,IAAI,CAAC,KAAKA,WACR,OAAO,KAAKC,OAAO;EAGrB,KAAKC,YAAY,KAAKF,UAAU,KAAKC,OAAO,OAAO;EACnD,OAAO,KAAKC;CACd;;CAGA,MAAM,OAAuB;EAC3B,KAAKD,SAAS;EACd,KAAKE,WAAW;CAClB;CAEA,gBAAsB;EACpB,KAAKA,WAAW;CAClB;CAEA,mBAAyB;EACvB,KAAKC,aAAa;EAClB,KAAKA,eAAe;EACpB,KAAKF,UAAU,KAAA;CACjB;CAEA,aAAmB;EACjB,KAAKE,aAAa;EAElB,IAAI,CAAC,KAAKJ,WAAW;GACnB,KAAKI,eAAe,KAAKH,OAAO,gBAAgB,KAAKF,MAAM,cAAc,CAAC;GAC1E;EACF;EAEA,MAAM,WAAW,KAAKC;EACtB,KAAKE,UAAU,SAAS,KAAKD,OAAO,OAAO;EAE3C,KAAKG,eAAe,KAAKH,OAAO,gBAAgB;GAC9C,MAAM,OAAO,SAAS,KAAKA,OAAO,OAAO;GACzC,IAAI,CAAC,aAAa,KAAKC,SAAS,IAAI,GAAG;IACrC,KAAKA,UAAU;IACf,KAAKH,MAAM,cAAc;GAC3B;EACF,CAAC;CACH;AACF"}
+61
View File
@@ -0,0 +1,61 @@
import { AnyStore, InferStoreState } from "../../core/store.js";
import { Selector } from "../../core/shallow-equal.js";
import { StoreSource } from "../store-accessor.js";
import { ReactiveController, ReactiveControllerHost } from "@videojs/element";
//#region src/html/controllers/store-controller.d.ts
type StoreControllerHost = ReactiveControllerHost & HTMLElement;
/**
* Access store state and actions.
*
* Without selector: Returns the store, does NOT subscribe to changes.
* With selector: Returns selected state, triggers update when selected state changes (shallowEqual).
*
* @example
* ```ts
* // Store access (no subscription) - access actions
* class Controls extends LitElement {
* #store = new StoreController(this, storeSource);
*
* handleClick() {
* this.#store.value.setVolume(0.5);
* }
* }
*
* // Selector-based subscription - re-renders when playback changes
* class PlayButton extends LitElement {
* #playback = new StoreController(this, storeSource, selectPlayback);
*
* render() {
* const playback = this.#playback.value;
* if (!playback) return nothing;
* return html`<button @click=${playback.toggle}>
* ${playback.paused ? 'Play' : 'Pause'}
* </button>`;
* }
* }
* ```
*/
declare class StoreController<Store extends AnyStore, Result = Store> implements ReactiveController {
#private;
/**
* @label Without Selector
* @param host - The host element that owns this controller.
* @param source - Store instance or context to resolve the store from.
*/
constructor(host: StoreControllerHost, source: StoreSource<Store>);
/**
* @label With Selector
* @param host - The host element that owns this controller.
* @param source - Store instance or context to resolve the store from.
* @param selector - Derives a value from the store state.
*/
constructor(host: StoreControllerHost, source: StoreSource<Store>, selector: Selector<InferStoreState<Store>, Result>);
get value(): Result;
hostConnected(): void;
}
declare namespace StoreController {
type Host = StoreControllerHost;
}
//#endregion
export { StoreController, StoreControllerHost };
//# sourceMappingURL=store-controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"store-controller.d.ts","names":[],"sources":["../../../../src/html/controllers/store-controller.ts"],"mappings":";;;;;KAOY,sBAAsB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiC9C,gBAAgB,cAAc,UAAU,SAAS,kBAAkB;;;;;;;EAY9E,YAAY,MAAM,qBAAqB,QAAQ,YAAY;;;;;;;EAO3D,YACE,MAAM,qBACN,QAAQ,YAAY,QACpB,UAAU,SAAS,gBAAgB,QAAQ;MAazC,SAAS;EAgBb;;kBAee;OACH,OAAO"}
+63
View File
@@ -0,0 +1,63 @@
import { SnapshotController } from "./snapshot-controller.js";
import { StoreAccessor } from "../store-accessor.js";
import { isNull, isUndefined } from "@videojs/utils/predicate";
//#region src/html/controllers/store-controller.ts
/**
* Access store state and actions.
*
* Without selector: Returns the store, does NOT subscribe to changes.
* With selector: Returns selected state, triggers update when selected state changes (shallowEqual).
*
* @example
* ```ts
* // Store access (no subscription) - access actions
* class Controls extends LitElement {
* #store = new StoreController(this, storeSource);
*
* handleClick() {
* this.#store.value.setVolume(0.5);
* }
* }
*
* // Selector-based subscription - re-renders when playback changes
* class PlayButton extends LitElement {
* #playback = new StoreController(this, storeSource, selectPlayback);
*
* render() {
* const playback = this.#playback.value;
* if (!playback) return nothing;
* return html`<button @click=${playback.toggle}>
* ${playback.paused ? 'Play' : 'Pause'}
* </button>`;
* }
* }
* ```
*/
var StoreController = class {
#host;
#selector;
#accessor;
#snapshot = null;
constructor(host, source, selector) {
this.#host = host;
this.#selector = selector;
this.#accessor = new StoreAccessor(host, source, (store) => this.#connect(store));
host.addController(this);
}
get value() {
const store = this.#accessor.value;
if (isNull(store)) throw new Error("Store not available");
if (isUndefined(this.#selector)) return store;
return this.#snapshot.value;
}
hostConnected() {}
#connect(store) {
if (isUndefined(this.#selector)) return;
if (!this.#snapshot) this.#snapshot = new SnapshotController(this.#host, store.$state, this.#selector);
else this.#snapshot.track(store.$state);
}
};
//#endregion
export { StoreController };
//# sourceMappingURL=store-controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"store-controller.js","names":["#host","#selector","#accessor","#connect","#snapshot"],"sources":["../../../../src/html/controllers/store-controller.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from '@videojs/element';\nimport { isNull, isUndefined } from '@videojs/utils/predicate';\nimport type { Selector } from '../../core/shallow-equal';\nimport type { AnyStore, InferStoreState } from '../../core/store';\nimport { StoreAccessor, type StoreSource } from '../store-accessor';\nimport { SnapshotController } from './snapshot-controller';\n\nexport type StoreControllerHost = ReactiveControllerHost & HTMLElement;\n\n/**\n * Access store state and actions.\n *\n * Without selector: Returns the store, does NOT subscribe to changes.\n * With selector: Returns selected state, triggers update when selected state changes (shallowEqual).\n *\n * @example\n * ```ts\n * // Store access (no subscription) - access actions\n * class Controls extends LitElement {\n * #store = new StoreController(this, storeSource);\n *\n * handleClick() {\n * this.#store.value.setVolume(0.5);\n * }\n * }\n *\n * // Selector-based subscription - re-renders when playback changes\n * class PlayButton extends LitElement {\n * #playback = new StoreController(this, storeSource, selectPlayback);\n *\n * render() {\n * const playback = this.#playback.value;\n * if (!playback) return nothing;\n * return html`<button @click=${playback.toggle}>\n * ${playback.paused ? 'Play' : 'Pause'}\n * </button>`;\n * }\n * }\n * ```\n */\nexport class StoreController<Store extends AnyStore, Result = Store> implements ReactiveController {\n readonly #host: StoreControllerHost;\n readonly #selector: Selector<InferStoreState<Store>, Result> | undefined;\n readonly #accessor: StoreAccessor<Store>;\n\n #snapshot: SnapshotController<object, Result> | null = null;\n\n /**\n * @label Without Selector\n * @param host - The host element that owns this controller.\n * @param source - Store instance or context to resolve the store from.\n */\n constructor(host: StoreControllerHost, source: StoreSource<Store>);\n /**\n * @label With Selector\n * @param host - The host element that owns this controller.\n * @param source - Store instance or context to resolve the store from.\n * @param selector - Derives a value from the store state.\n */\n constructor(\n host: StoreControllerHost,\n source: StoreSource<Store>,\n selector: Selector<InferStoreState<Store>, Result>\n );\n constructor(\n host: StoreControllerHost,\n source: StoreSource<Store>,\n selector?: Selector<InferStoreState<Store>, Result>\n ) {\n this.#host = host;\n this.#selector = selector;\n this.#accessor = new StoreAccessor(host, source, (store) => this.#connect(store));\n host.addController(this);\n }\n\n get value(): Result {\n const store = this.#accessor.value;\n\n if (isNull(store)) {\n throw new Error('Store not available');\n }\n\n // Without selector: return store\n if (isUndefined(this.#selector)) {\n return store as unknown as Result;\n }\n\n // With selector: delegate to snapshot controller\n return this.#snapshot!.value;\n }\n\n hostConnected(): void {\n // StoreAccessor + SnapshotController handle their own lifecycle.\n }\n\n #connect(store: Store): void {\n if (isUndefined(this.#selector)) return;\n\n if (!this.#snapshot) {\n this.#snapshot = new SnapshotController(this.#host, store.$state, this.#selector as Selector<object, Result>);\n } else {\n this.#snapshot.track(store.$state);\n }\n }\n}\n\nexport namespace StoreController {\n export type Host = StoreControllerHost;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,IAAa,kBAAb,MAAmG;CACjG;CACA;CACA;CAEA,YAAuD;CAmBvD,YACE,MACA,QACA,UACA;EACA,KAAKA,QAAQ;EACb,KAAKC,YAAY;EACjB,KAAKC,YAAY,IAAI,cAAc,MAAM,SAAS,UAAU,KAAKC,SAAS,KAAK,CAAC;EAChF,KAAK,cAAc,IAAI;CACzB;CAEA,IAAI,QAAgB;EAClB,MAAM,QAAQ,KAAKD,UAAU;EAE7B,IAAI,OAAO,KAAK,GACd,MAAM,IAAI,MAAM,qBAAqB;EAIvC,IAAI,YAAY,KAAKD,SAAS,GAC5B,OAAO;EAIT,OAAO,KAAKG,UAAW;CACzB;CAEA,gBAAsB,CAEtB;CAEA,SAAS,OAAoB;EAC3B,IAAI,YAAY,KAAKH,SAAS,GAAG;EAEjC,IAAI,CAAC,KAAKG,WACR,KAAKA,YAAY,IAAI,mBAAmB,KAAKJ,OAAO,MAAM,QAAQ,KAAKC,SAAqC;OAE5G,KAAKG,UAAU,MAAM,MAAM,MAAM;CAErC;AACF"}
+51
View File
@@ -0,0 +1,51 @@
import { AnyStore } from "../../core/store.js";
import { StoreSource } from "../store-accessor.js";
import { ReactiveController, ReactiveControllerHost } from "@videojs/element";
//#region src/html/controllers/subscription-controller.d.ts
type SubscriptionControllerHost = ReactiveControllerHost & HTMLElement;
interface SubscriptionControllerConfig<Store extends AnyStore, Value> {
getValue: (store: Store) => Value;
subscribe: (store: Store, onChange: () => void) => () => void;
}
/**
* Resolves a store from context or direct source and manages subscription lifecycle.
*
* Combines store resolution (direct or context) with subscription management.
* Use as a building block for controllers that need store access with subscriptions.
*
* @example
* ```ts
* class MyController<Store extends AnyStore> {
* #ctrl: SubscriptionController<Store, Tasks>;
*
* constructor(host: Host, source: StoreSource<Store>) {
* this.#ctrl = new SubscriptionController(host, source, {
* subscribe: (store, onChange) => store.queue.subscribe(onChange),
* getValue: (store) => store.queue.tasks,
* });
* }
*
* get value() {
* return this.#ctrl.value;
* }
* }
* ```
*/
declare class SubscriptionController<Store extends AnyStore, Value> implements ReactiveController {
#private;
/**
* @param host - The host element that owns this controller.
* @param source - Store instance or context to resolve the store from.
* @param config - Subscription and value extraction configuration.
*/
constructor(host: SubscriptionControllerHost, source: StoreSource<Store>, config: SubscriptionControllerConfig<Store, Value>);
get value(): Value;
hostDisconnected(): void;
}
declare namespace SubscriptionController {
type Host = SubscriptionControllerHost;
type Config<Store extends AnyStore, Value> = SubscriptionControllerConfig<Store, Value>;
}
//#endregion
export { SubscriptionController, SubscriptionControllerConfig, SubscriptionControllerHost };
//# sourceMappingURL=subscription-controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"subscription-controller.d.ts","names":[],"sources":["../../../../src/html/controllers/subscription-controller.ts"],"mappings":";;;;KAMY,6BAA6B,yBAAyB;UAEjD,6BAA6B,cAAc,UAAU;EACpE,WAAW,OAAO,UAAU;EAC5B,YAAY,OAAO,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;cA2Bf,uBAAuB,cAAc,UAAU,kBAAkB;;;;;;;EAY5E,YACE,MAAM,4BACN,QAAQ,YAAY,QACpB,QAAQ,6BAA6B,OAAO;MAS1C,SAAS;EAUb;;kBAae;OACH,OAAO;OACP,OAAO,cAAc,UAAU,SAAS,6BAA6B,OAAO"}
+64
View File
@@ -0,0 +1,64 @@
import { StoreAccessor } from "../store-accessor.js";
import { noop } from "@videojs/utils/function";
import { isNull } from "@videojs/utils/predicate";
//#region src/html/controllers/subscription-controller.ts
/**
* Resolves a store from context or direct source and manages subscription lifecycle.
*
* Combines store resolution (direct or context) with subscription management.
* Use as a building block for controllers that need store access with subscriptions.
*
* @example
* ```ts
* class MyController<Store extends AnyStore> {
* #ctrl: SubscriptionController<Store, Tasks>;
*
* constructor(host: Host, source: StoreSource<Store>) {
* this.#ctrl = new SubscriptionController(host, source, {
* subscribe: (store, onChange) => store.queue.subscribe(onChange),
* getValue: (store) => store.queue.tasks,
* });
* }
*
* get value() {
* return this.#ctrl.value;
* }
* }
* ```
*/
var SubscriptionController = class {
#host;
#config;
#accessor;
#unsubscribe = noop;
/**
* @param host - The host element that owns this controller.
* @param source - Store instance or context to resolve the store from.
* @param config - Subscription and value extraction configuration.
*/
constructor(host, source, config) {
this.#host = host;
this.#config = config;
this.#accessor = new StoreAccessor(host, source, (store) => this.#connect(store));
host.addController(this);
}
get value() {
const store = this.#accessor.value;
if (isNull(store)) throw new Error("Store not available");
return this.#config.getValue(store);
}
hostDisconnected() {
this.#unsubscribe();
this.#unsubscribe = noop;
}
#connect(store) {
this.#unsubscribe();
this.#unsubscribe = this.#config.subscribe(store, () => {
this.#host.requestUpdate();
});
}
};
//#endregion
export { SubscriptionController };
//# sourceMappingURL=subscription-controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"subscription-controller.js","names":["#host","#config","#accessor","#connect","#unsubscribe"],"sources":["../../../../src/html/controllers/subscription-controller.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from '@videojs/element';\nimport { noop } from '@videojs/utils/function';\nimport { isNull } from '@videojs/utils/predicate';\nimport type { AnyStore } from '../../core/store';\nimport { StoreAccessor, type StoreSource } from '../store-accessor';\n\nexport type SubscriptionControllerHost = ReactiveControllerHost & HTMLElement;\n\nexport interface SubscriptionControllerConfig<Store extends AnyStore, Value> {\n getValue: (store: Store) => Value;\n subscribe: (store: Store, onChange: () => void) => () => void;\n}\n\n/**\n * Resolves a store from context or direct source and manages subscription lifecycle.\n *\n * Combines store resolution (direct or context) with subscription management.\n * Use as a building block for controllers that need store access with subscriptions.\n *\n * @example\n * ```ts\n * class MyController<Store extends AnyStore> {\n * #ctrl: SubscriptionController<Store, Tasks>;\n *\n * constructor(host: Host, source: StoreSource<Store>) {\n * this.#ctrl = new SubscriptionController(host, source, {\n * subscribe: (store, onChange) => store.queue.subscribe(onChange),\n * getValue: (store) => store.queue.tasks,\n * });\n * }\n *\n * get value() {\n * return this.#ctrl.value;\n * }\n * }\n * ```\n */\nexport class SubscriptionController<Store extends AnyStore, Value> implements ReactiveController {\n readonly #host: SubscriptionControllerHost;\n readonly #config: SubscriptionControllerConfig<Store, Value>;\n readonly #accessor: StoreAccessor<Store>;\n\n #unsubscribe = noop;\n\n /**\n * @param host - The host element that owns this controller.\n * @param source - Store instance or context to resolve the store from.\n * @param config - Subscription and value extraction configuration.\n */\n constructor(\n host: SubscriptionControllerHost,\n source: StoreSource<Store>,\n config: SubscriptionControllerConfig<Store, Value>\n ) {\n this.#host = host;\n this.#config = config;\n this.#accessor = new StoreAccessor(host, source, (store) => this.#connect(store));\n\n host.addController(this);\n }\n\n get value(): Value {\n const store = this.#accessor.value;\n\n if (isNull(store)) {\n throw new Error('Store not available');\n }\n\n return this.#config.getValue(store);\n }\n\n hostDisconnected(): void {\n this.#unsubscribe();\n this.#unsubscribe = noop;\n }\n\n #connect(store: Store): void {\n this.#unsubscribe();\n this.#unsubscribe = this.#config.subscribe(store, () => {\n this.#host.requestUpdate();\n });\n }\n}\n\nexport namespace SubscriptionController {\n export type Host = SubscriptionControllerHost;\n export type Config<Store extends AnyStore, Value> = SubscriptionControllerConfig<Store, Value>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,yBAAb,MAAiG;CAC/F;CACA;CACA;CAEA,eAAe;;;;;;CAOf,YACE,MACA,QACA,QACA;EACA,KAAKA,QAAQ;EACb,KAAKC,UAAU;EACf,KAAKC,YAAY,IAAI,cAAc,MAAM,SAAS,UAAU,KAAKC,SAAS,KAAK,CAAC;EAEhF,KAAK,cAAc,IAAI;CACzB;CAEA,IAAI,QAAe;EACjB,MAAM,QAAQ,KAAKD,UAAU;EAE7B,IAAI,OAAO,KAAK,GACd,MAAM,IAAI,MAAM,qBAAqB;EAGvC,OAAO,KAAKD,QAAQ,SAAS,KAAK;CACpC;CAEA,mBAAyB;EACvB,KAAKG,aAAa;EAClB,KAAKA,eAAe;CACtB;CAEA,SAAS,OAAoB;EAC3B,KAAKA,aAAa;EAClB,KAAKA,eAAe,KAAKH,QAAQ,UAAU,aAAa;GACtD,KAAKD,MAAM,cAAc;EAC3B,CAAC;CACH;AACF"}