1import { DiffuseElement, query } from "@common/element.js";
2import { computed, signal } from "@common/signal.js";
3
4/**
5 * @import { OutputElement, OutputManagerDeputy } from "../../output/types.d.ts"
6 */
7
8/**
9 * @template [T=null]
10 */
11export class OutputTransformer extends DiffuseElement {
12 // SIGNALS
13
14 #output = signal(/** @type {OutputElement<T> | undefined} */ (undefined));
15 #outputWhenDefined = Promise.withResolvers();
16
17 output = {
18 whenDefined: this.#outputWhenDefined.promise,
19 signal: this.#output.get,
20 };
21
22 // LIFECYCLE
23
24 /**
25 * @override
26 */
27 connectedCallback() {
28 super.connectedCallback();
29
30 /** @type {OutputElement<T>} */
31 const output = query(this, "output-selector");
32
33 // When defined
34 customElements.whenDefined(output.localName).then(() => {
35 this.#output.value = output;
36 this.#outputWhenDefined.resolve(null);
37 });
38 }
39
40 // MANAGER
41
42 base() {
43 /** @type {OutputManagerDeputy<T | undefined>} */
44 const m = {
45 facets: {
46 collection: computed(() => {
47 return this.output.signal()?.facets?.collection();
48 }),
49 reload: () => {
50 return this.output.signal()?.facets?.reload() ??
51 Promise.resolve();
52 },
53 save: async (newFacets) => {
54 if (newFacets === undefined) return;
55 await this.output.whenDefined;
56 await this.output.signal()?.facets.save(newFacets);
57 },
58 state: computed(() => {
59 return this.output.signal()?.facets.state() ?? "sleeping";
60 }),
61 },
62 playlists: {
63 collection: computed(() => {
64 return this.output.signal()?.playlists?.collection();
65 }),
66 reload: () => {
67 return this.output.signal()?.playlists?.reload() ??
68 Promise.resolve();
69 },
70 save: async (newPlaylists) => {
71 if (newPlaylists === undefined) return;
72 await this.output.whenDefined;
73 await this.output.signal()?.playlists.save(newPlaylists);
74 },
75 state: computed(() => {
76 return this.output.signal()?.playlists.state() ?? "sleeping";
77 }),
78 },
79 themes: {
80 collection: computed(() => {
81 return this.output.signal()?.themes?.collection();
82 }),
83 reload: () => {
84 return this.output.signal()?.themes?.reload() ??
85 Promise.resolve();
86 },
87 save: async (newThemes) => {
88 if (newThemes === undefined) return;
89 await this.output.whenDefined;
90 await this.output.signal()?.themes.save(newThemes);
91 },
92 state: computed(() => {
93 return this.output.signal()?.themes.state() ?? "sleeping";
94 }),
95 },
96 tracks: {
97 collection: computed(() => {
98 return this.output.signal()?.tracks?.collection();
99 }),
100 reload: () => {
101 return this.output.signal()?.tracks?.reload() ?? Promise.resolve();
102 },
103 save: async (newTracks) => {
104 if (newTracks === undefined) return;
105 await this.output.whenDefined;
106 await this.output.signal()?.tracks.save(newTracks);
107 },
108 state: computed(() => {
109 return this.output.signal()?.tracks.state() ?? "sleeping";
110 }),
111 },
112 };
113
114 return m;
115 }
116}