-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvoyager.ts
53 lines (41 loc) · 1.78 KB
/
voyager.ts
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
import type { VoyageIslandConstructor } from './island';
import { StyleLoader, VoyageLoader } from './loader';
import { ScriptLoader } from './loader';
import { VoyageNode } from './node';
interface VoyagerConfig<T> {
/**
* An object stores all necessary values and objects that should be shared across
* a webpage: stores, services, pub-sub, etc.
*/
context: T;
/** The main island, aka the entry point of an application. */
el: Element | null;
/** The path to the island's JS and CSS folder. */
dir: string;
}
export class Voyager<T> {
private createNode = VoyageNode.of;
private scriptLoader: VoyageLoader<VoyageIslandConstructor<T>> = new ScriptLoader(this.config.dir);
private styleLoader: VoyageLoader<void> = new StyleLoader(this.config.dir);
// TODO: add delayed hydration (e.g. when the component becomes visible)
// TODO: create and observer for the component in/out of the viewport
constructor(private config: VoyagerConfig<T>) {}
async launch(): Promise<void> {
await this.hydrate(this.config.el);
// Here you can kickstart you magic like delayed hydration or some kind of observer.
}
private async hydrate(el: unknown): Promise<void> {
/** Create a system node that contains element validation and useful utility methods. */
const node = this.createNode(el);
/** Download CSS. */
await this.styleLoader.load(node);
/** Download and mount an island with its HTMLElement and the global context. */
const Island = await this.scriptLoader.load(node);
await new Island(node.el, this.config.context).mount();
/** Mount the island's children. */
for await (const childEl of node.getChildren()) this.hydrate(childEl);
}
static of<T>(config: VoyagerConfig<T>): Voyager<T> {
return new Voyager(config);
}
}