@joycostudio/susano 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # <img src="./static/JOYCO.png" alt="JOYCO Logo" height="36" width="36" align="top" />&nbsp;&nbsp;JOYCO Susano
2
+
3
+ Asset load orchestration made easy.
4
+
5
+ ## 🤖 Automatic Workflows
6
+
7
+ 1. **Release Workflow** (`.github/workflows/release.yml`): Automates the release process using Changesets. When enabled, it will automatically create release pull requests and publish to npm when changes are pushed to the main branch.
8
+
9
+ 2. **Publish Any Commit** (`.github/workflows/publish-any-commit.yml`): A utility workflow that can build and publish packages for any commit or pull request.
10
+
11
+ ## 🦋 Version Management
12
+
13
+ This library uses [Changesets](https://github.com/changesets/changesets) to manage versions and publish releases. Here's how to use it:
14
+
15
+ ### Adding a changeset
16
+
17
+ When you make changes that need to be released:
18
+
19
+ ```bash
20
+ pnpm changeset
21
+ ```
22
+
23
+ This will prompt you to:
24
+
25
+ 1. Select which packages you want to include in the changeset
26
+ 2. Choose whether it's a major/minor/patch bump
27
+ 3. Provide a summary of the changes
28
+
29
+ ### Creating a release
30
+
31
+ To create a new version and update the changelog:
32
+
33
+ ```bash
34
+ # 1. Create new versions of packages
35
+ pnpm version:package
36
+
37
+ # 2. Release (builds and publishes to npm)
38
+ pnpm release
39
+ ```
40
+
41
+ Remember to commit all changes after creating a release.
@@ -0,0 +1,97 @@
1
+ import { TinyEmitter } from 'tiny-emitter';
2
+
3
+ type SusanoLoaderConfig<T> = {
4
+ onLoaded?: (loader: SusanoLoader<T>) => void;
5
+ };
6
+ declare class SusanoLoader<T> extends TinyEmitter implements ISusanoLoader<T> {
7
+ url: string;
8
+ loaded: boolean;
9
+ content: T;
10
+ config: SusanoLoaderConfig<T>;
11
+ constructor(url: string, _cnfg?: SusanoLoaderConfig<T>);
12
+ load(): Promise<T>;
13
+ _onLoaded(): void;
14
+ }
15
+ interface ISusanoLoader<T> {
16
+ load: () => Promise<T>;
17
+ }
18
+
19
+ type SusanoImageLoaderConfig = SusanoLoaderConfig<HTMLImageElement> & {
20
+ srcSet?: string;
21
+ sizes?: string;
22
+ };
23
+ declare class ImageLoader extends SusanoLoader<HTMLImageElement> implements ISusanoLoader<HTMLImageElement> {
24
+ static type: "image";
25
+ srcSet?: string;
26
+ sizes?: string;
27
+ constructor(url: string, cnfg?: SusanoImageLoaderConfig);
28
+ load(): Promise<HTMLImageElement>;
29
+ }
30
+
31
+ type LoadEvent = 'canplay' | 'canplaythrough';
32
+ type SusanoVideoLoaderConfig = SusanoLoaderConfig<HTMLVideoElement> & {
33
+ video?: HTMLVideoElement;
34
+ loadEvent?: LoadEvent;
35
+ };
36
+ declare class VideoLoader extends SusanoLoader<HTMLVideoElement> implements ISusanoLoader<HTMLVideoElement> {
37
+ static type: "video";
38
+ loadEvent: LoadEvent;
39
+ constructor(url: string, cnfg?: SusanoVideoLoaderConfig);
40
+ load(): Promise<HTMLVideoElement>;
41
+ }
42
+
43
+ type LoaderTypes = {
44
+ [K: string]: {
45
+ type: typeof K;
46
+ loader: typeof SusanoLoader<any>;
47
+ };
48
+ };
49
+ type LoaderMap<T extends LoaderTypes> = {
50
+ [K in keyof T]: T[K]['loader'];
51
+ };
52
+ /**
53
+ * Main loader class that manages loading of different asset types
54
+ * @template T Type definition for the loaders to be used, extending LoaderTypes
55
+ * @extends TinyEmitter
56
+ */
57
+ declare class Susano<T extends LoaderTypes> extends TinyEmitter {
58
+ private loaders;
59
+ queue: InstanceType<T[keyof T]['loader']>[];
60
+ active: InstanceType<T[keyof T]['loader']>[];
61
+ items: Map<string, InstanceType<T[keyof T]['loader']>>;
62
+ loadCount: number;
63
+ loadLength: number;
64
+ constructor();
65
+ add<K extends keyof T>(url: string, cnfg: {
66
+ type: K;
67
+ loaderArgs?: ConstructorParameters<T[K]['loader']>[1];
68
+ }): InstanceType<T[K]['loader']>;
69
+ load<K extends keyof T>(url: string, cnfg: {
70
+ type: K;
71
+ loaderArgs?: ConstructorParameters<T[K]['loader']>[1];
72
+ }): InstanceType<T[keyof T]["loader"]>;
73
+ registerLoader<K extends keyof T>(type: K, loader: T[K]['loader']): void;
74
+ _onProgress(item: SusanoLoader<unknown>): void;
75
+ start({ onCompleted, onProgress, }?: {
76
+ onCompleted?: (susano: Susano<T>) => void;
77
+ onProgress?: (progress: {
78
+ value: number;
79
+ item: SusanoLoader<unknown>;
80
+ susano: Susano<T>;
81
+ }) => void;
82
+ }): void;
83
+ }
84
+ declare const susano: Susano<{
85
+ image: {
86
+ type: "image";
87
+ loader: typeof ImageLoader;
88
+ };
89
+ video: {
90
+ type: "video";
91
+ loader: typeof VideoLoader;
92
+ };
93
+ }>;
94
+
95
+ declare const VERSION: string;
96
+
97
+ export { type LoaderMap, type LoaderTypes, Susano, VERSION, susano };
@@ -0,0 +1,97 @@
1
+ import { TinyEmitter } from 'tiny-emitter';
2
+
3
+ type SusanoLoaderConfig<T> = {
4
+ onLoaded?: (loader: SusanoLoader<T>) => void;
5
+ };
6
+ declare class SusanoLoader<T> extends TinyEmitter implements ISusanoLoader<T> {
7
+ url: string;
8
+ loaded: boolean;
9
+ content: T;
10
+ config: SusanoLoaderConfig<T>;
11
+ constructor(url: string, _cnfg?: SusanoLoaderConfig<T>);
12
+ load(): Promise<T>;
13
+ _onLoaded(): void;
14
+ }
15
+ interface ISusanoLoader<T> {
16
+ load: () => Promise<T>;
17
+ }
18
+
19
+ type SusanoImageLoaderConfig = SusanoLoaderConfig<HTMLImageElement> & {
20
+ srcSet?: string;
21
+ sizes?: string;
22
+ };
23
+ declare class ImageLoader extends SusanoLoader<HTMLImageElement> implements ISusanoLoader<HTMLImageElement> {
24
+ static type: "image";
25
+ srcSet?: string;
26
+ sizes?: string;
27
+ constructor(url: string, cnfg?: SusanoImageLoaderConfig);
28
+ load(): Promise<HTMLImageElement>;
29
+ }
30
+
31
+ type LoadEvent = 'canplay' | 'canplaythrough';
32
+ type SusanoVideoLoaderConfig = SusanoLoaderConfig<HTMLVideoElement> & {
33
+ video?: HTMLVideoElement;
34
+ loadEvent?: LoadEvent;
35
+ };
36
+ declare class VideoLoader extends SusanoLoader<HTMLVideoElement> implements ISusanoLoader<HTMLVideoElement> {
37
+ static type: "video";
38
+ loadEvent: LoadEvent;
39
+ constructor(url: string, cnfg?: SusanoVideoLoaderConfig);
40
+ load(): Promise<HTMLVideoElement>;
41
+ }
42
+
43
+ type LoaderTypes = {
44
+ [K: string]: {
45
+ type: typeof K;
46
+ loader: typeof SusanoLoader<any>;
47
+ };
48
+ };
49
+ type LoaderMap<T extends LoaderTypes> = {
50
+ [K in keyof T]: T[K]['loader'];
51
+ };
52
+ /**
53
+ * Main loader class that manages loading of different asset types
54
+ * @template T Type definition for the loaders to be used, extending LoaderTypes
55
+ * @extends TinyEmitter
56
+ */
57
+ declare class Susano<T extends LoaderTypes> extends TinyEmitter {
58
+ private loaders;
59
+ queue: InstanceType<T[keyof T]['loader']>[];
60
+ active: InstanceType<T[keyof T]['loader']>[];
61
+ items: Map<string, InstanceType<T[keyof T]['loader']>>;
62
+ loadCount: number;
63
+ loadLength: number;
64
+ constructor();
65
+ add<K extends keyof T>(url: string, cnfg: {
66
+ type: K;
67
+ loaderArgs?: ConstructorParameters<T[K]['loader']>[1];
68
+ }): InstanceType<T[K]['loader']>;
69
+ load<K extends keyof T>(url: string, cnfg: {
70
+ type: K;
71
+ loaderArgs?: ConstructorParameters<T[K]['loader']>[1];
72
+ }): InstanceType<T[keyof T]["loader"]>;
73
+ registerLoader<K extends keyof T>(type: K, loader: T[K]['loader']): void;
74
+ _onProgress(item: SusanoLoader<unknown>): void;
75
+ start({ onCompleted, onProgress, }?: {
76
+ onCompleted?: (susano: Susano<T>) => void;
77
+ onProgress?: (progress: {
78
+ value: number;
79
+ item: SusanoLoader<unknown>;
80
+ susano: Susano<T>;
81
+ }) => void;
82
+ }): void;
83
+ }
84
+ declare const susano: Susano<{
85
+ image: {
86
+ type: "image";
87
+ loader: typeof ImageLoader;
88
+ };
89
+ video: {
90
+ type: "video";
91
+ loader: typeof VideoLoader;
92
+ };
93
+ }>;
94
+
95
+ declare const VERSION: string;
96
+
97
+ export { type LoaderMap, type LoaderTypes, Susano, VERSION, susano };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var tinyEmitter=require('tiny-emitter');var l="0.0.1";var n=class extends tinyEmitter.TinyEmitter{constructor(o,e={}){super(),this.url=o,this.loaded=false,this.content=null,this.config=e;}load(){throw new Error("Method not implemented")}_onLoaded(){this.loaded=true,this.emit("loaded",this),this.config.onLoaded?.(this);}};var r=class extends n{constructor(o,e={}){super(o,e),this.content=new Image,this.srcSet=e.srcSet,this.sizes=e.sizes;}load(){return new Promise((o,e)=>{if(this.loaded){this._onLoaded.call(this),o(this.content);return}this.srcSet&&(this.content.srcset=this.srcSet),this.sizes&&(this.content.sizes=this.sizes),this.content.src=this.url,this.content.onload=()=>{this._onLoaded.call(this),o(this.content);},this.content.onerror=t=>e(t);})}};r.type="image";var a=class extends n{constructor(o,e={}){super(o,e),this.content=e.video||document.createElement("video"),this.loadEvent=e.loadEvent||"canplay";}load(){return new Promise((o,e)=>{let t=this.content;if(this.loaded){this._onLoaded.call(this),o(this.content);return}t.src=this.url,t.addEventListener(this.loadEvent,()=>{this._onLoaded.call(this),o(this.content);}),t.addEventListener("error",s=>e(s));})}};a.type="video";var p=class extends tinyEmitter.TinyEmitter{constructor(){super();this.loaders={};this.queue=[];this.active=[];this.items=new Map;this.loadCount=0;this.loadLength=0;}add(e,t){let s=this.loaders[t.type];if(!s)throw new Error(`Loader for type ${String(t.type)} not found`);let i=this.items.get(e);return i||(i=new s(e,t.loaderArgs),this.items.set(e,i)),this.queue.push(i),i}load(e,t){let s=this.loaders[t.type];if(!s)throw new Error(`Loader for type ${String(t.type)} not found`);let i=this.items.get(e);return i||(i=new s(e,t.loaderArgs),this.items.set(e,i)),i.load(),i}registerLoader(e,t){this.loaders[e]=t;}_onProgress(e){this.loadCount++;let t=this.loadCount/this.loadLength;if(this.emit("progress",{value:t,item:e,susano:this}),t===1){this.emit("completed",this);return}}start({onCompleted:e,onProgress:t}={}){this.active=this.queue.splice(0,this.queue.length),this.loadLength=this.active.length,this.loadCount=0,this.emit("start",this),t&&this.on("progress",t),this.once("completed",()=>{e?.(this),t&&this.off("progress",t);}),this.active.map(s=>{s.once("loaded",()=>{this._onProgress(s);}),s.load();});}},c=new p;c.registerLoader(r.type,r);c.registerLoader(a.type,a);var H=l;exports.Susano=p;exports.VERSION=H;exports.susano=c;//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/loaders/loader.ts","../src/loaders/image.ts","../src/loaders/video.ts","../src/core.tsx","../src/index.ts"],"names":["version","SusanoLoader","TinyEmitter","url","_cnfg","ImageLoader","cnfg","resolve","reject","e","VideoLoader","video","Susano","Loader","item","type","loader","progress","onCompleted","onProgress","susano","VERSION"],"mappings":"qDAME,IAAAA,CAAW,CAAA,OAAA,CCAN,IAAMC,CAAAA,CAAN,cAA8BC,uBAAwC,CAM3E,WAAA,CAAYC,CAAaC,CAAAA,CAAAA,CAA+B,EAAC,CAAG,CAC1D,KAAA,EACA,CAAA,IAAA,CAAK,GAAMD,CAAAA,CAAAA,CACX,IAAK,CAAA,MAAA,CAAS,MACd,IAAK,CAAA,OAAA,CAAU,IACf,CAAA,IAAA,CAAK,MAASC,CAAAA,EAChB,CAEA,IAAA,EAAmB,CACjB,MAAM,IAAI,KAAA,CAAM,wBAAwB,CAC1C,CAEA,SAAA,EAAY,CACV,IAAA,CAAK,MAAS,CAAA,IAAA,CACd,IAAK,CAAA,IAAA,CAAK,QAAU,CAAA,IAAI,CACxB,CAAA,IAAA,CAAK,MAAO,CAAA,QAAA,GAAW,IAAI,EAC7B,CACF,CAAA,CCtBO,IAAMC,CAAN,CAAA,cAA0BJ,CAA0E,CAKzG,WAAYE,CAAAA,CAAAA,CAAaG,CAAgC,CAAA,EAAI,CAAA,CAC3D,KAAMH,CAAAA,CAAAA,CAAKG,CAAI,CAAA,CACf,IAAK,CAAA,OAAA,CAAU,IAAI,KAAA,CACnB,IAAK,CAAA,MAAA,CAASA,CAAK,CAAA,MAAA,CACnB,IAAK,CAAA,KAAA,CAAQA,CAAK,CAAA,MACpB,CAEA,IAAA,EAAkC,CAChC,OAAO,IAAI,OAAA,CAAQ,CAACC,CAASC,CAAAA,CAAAA,GAAW,CACtC,GAAI,IAAK,CAAA,MAAA,CAAQ,CACf,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,IAAI,CAAA,CACxBD,CAAQ,CAAA,IAAA,CAAK,OAAO,CAAA,CACpB,MACF,CAEI,IAAA,CAAK,MAAQ,GAAA,IAAA,CAAK,OAAQ,CAAA,MAAA,CAAS,IAAK,CAAA,MAAA,CAAA,CACxC,IAAK,CAAA,KAAA,GAAO,IAAK,CAAA,OAAA,CAAQ,KAAQ,CAAA,IAAA,CAAK,KAC1C,CAAA,CAAA,IAAA,CAAK,QAAQ,GAAM,CAAA,IAAA,CAAK,GAExB,CAAA,IAAA,CAAK,OAAQ,CAAA,MAAA,CAAS,IAAM,CAC1B,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBA,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,EACtB,CAAA,CAEA,IAAK,CAAA,OAAA,CAAQ,OAAWE,CAAAA,CAAAA,EAAMD,CAAOC,CAAAA,CAAC,EACxC,CAAC,CACH,CACF,CAhCaJ,CAAAA,CAAAA,CACG,IAAO,CAAA,OAAA,CCChB,IAAMK,CAAN,CAAA,cAA0BT,CAA0E,CAIzG,WAAYE,CAAAA,CAAAA,CAAaG,CAAgC,CAAA,EAAI,CAAA,CAC3D,KAAMH,CAAAA,CAAAA,CAAKG,CAAI,CAAA,CACf,IAAK,CAAA,OAAA,CAAUA,CAAK,CAAA,KAAA,EAAS,QAAS,CAAA,aAAA,CAAc,OAAO,CAAA,CAC3D,IAAK,CAAA,SAAA,CAAYA,CAAK,CAAA,SAAA,EAAa,UACrC,CAEA,IAAkC,EAAA,CAChC,OAAO,IAAI,QAAQ,CAACC,CAAAA,CAASC,CAAW,GAAA,CACtC,IAAMG,CAAAA,CAAQ,IAAK,CAAA,OAAA,CAEnB,GAAI,IAAA,CAAK,MAAQ,CAAA,CACf,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBJ,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,CACpB,CAAA,MACF,CAEAI,CAAAA,CAAM,GAAM,CAAA,IAAA,CAAK,GAEjBA,CAAAA,CAAAA,CAAM,gBAAiB,CAAA,IAAA,CAAK,SAAW,CAAA,IAAM,CAC3C,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBJ,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,EACtB,CAAC,CAEDI,CAAAA,CAAAA,CAAM,gBAAiB,CAAA,OAAA,CAAUF,CAAMD,EAAAA,CAAAA,CAAOC,CAAC,CAAC,EAClD,CAAC,CACH,CACF,CAAA,CA9BaC,CACG,CAAA,IAAA,CAAO,OCWhB,CAAA,IAAME,CAAN,CAAA,cAA4CV,uBAAY,CAQ7D,WAAc,EAAA,CACZ,OARF,CAAA,IAAA,CAAQ,OAAwB,CAAA,EAChC,CAAA,IAAA,CAAO,KAA8C,CAAA,EACrD,CAAA,IAAA,CAAO,MAA+C,CAAA,EACtD,CAAA,IAAA,CAAO,KAAyD,CAAA,IAAI,GACpE,CAAA,IAAA,CAAO,SAAoB,CAAA,CAAA,CAC3B,IAAO,CAAA,UAAA,CAAqB,EAI5B,CAEA,GACEC,CAAAA,CAAAA,CACAG,CAI8B,CAAA,CAC9B,IAAMO,CAAAA,CAAS,IAAK,CAAA,OAAA,CAAQP,EAAK,IAAI,CAAA,CAErC,GAAI,CAACO,CAAQ,CAAA,MAAM,IAAI,KAAA,CAAM,CAAmB,gBAAA,EAAA,MAAA,CAAOP,CAAK,CAAA,IAAI,CAAC,CAAA,UAAA,CAAY,CAE7E,CAAA,IAAIQ,CAAO,CAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAIX,CAAG,CAAA,CAE7B,OAAKW,CAAAA,GACHA,CAAO,CAAA,IAAID,CAAOV,CAAAA,CAAAA,CAAKG,CAAK,CAAA,UAAU,CACtC,CAAA,IAAA,CAAK,MAAM,GAAIH,CAAAA,CAAAA,CAAKW,CAAI,CAAA,CAAA,CAG1B,IAAK,CAAA,KAAA,CAAM,IAAKA,CAAAA,CAAI,CAEbA,CAAAA,CACT,CAEA,IAAA,CACEX,CACAG,CAAAA,CAAAA,CAIA,CACA,IAAMO,CAAS,CAAA,IAAA,CAAK,OAAQP,CAAAA,CAAAA,CAAK,IAAI,CAAA,CACrC,GAAI,CAACO,CAAQ,CAAA,MAAM,IAAI,KAAA,CAAM,CAAmB,gBAAA,EAAA,MAAA,CAAOP,CAAK,CAAA,IAAI,CAAC,CAAY,UAAA,CAAA,CAAA,CAE7E,IAAIQ,CAAAA,CAAO,IAAK,CAAA,KAAA,CAAM,GAAIX,CAAAA,CAAG,CAE7B,CAAA,OAAKW,CACHA,GAAAA,CAAAA,CAAO,IAAID,CAAAA,CAAOV,CAAKG,CAAAA,CAAAA,CAAK,UAAU,CACtC,CAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAIH,CAAKW,CAAAA,CAAI,CAG1BA,CAAAA,CAAAA,CAAAA,CAAK,IAAK,EAAA,CAEHA,CACT,CAEA,cAAkCC,CAAAA,CAAAA,CAASC,CAAwB,CAAA,CACjE,KAAK,OAAQD,CAAAA,CAAI,CAAIC,CAAAA,EACvB,CAEA,WAAA,CAAYF,CAA6B,CAAA,CACvC,IAAK,CAAA,SAAA,EAAA,CAKL,IAAMG,CAAAA,CAAW,IAAK,CAAA,SAAA,CAAY,IAAK,CAAA,UAAA,CAQvC,GANA,IAAA,CAAK,IAAK,CAAA,UAAA,CAAY,CACpB,KAAA,CAAOA,CACP,CAAA,IAAA,CAAMH,CACN,CAAA,MAAA,CAAQ,IACV,CAAC,CAEGG,CAAAA,CAAAA,GAAa,CAAG,CAAA,CAClB,KAAK,IAAK,CAAA,WAAA,CAAa,IAAI,CAAA,CAC3B,MACF,CACF,CAEA,KAAA,CAAM,CACJ,WAAA,CAAAC,CACA,CAAA,UAAA,CAAAC,CACF,CAAA,CAGI,EAAC,CAAG,CACN,IAAK,CAAA,MAAA,CAAS,IAAK,CAAA,KAAA,CAAM,MAAO,CAAA,CAAA,CAAG,IAAK,CAAA,KAAA,CAAM,MAAM,CAAA,CACpD,IAAK,CAAA,UAAA,CAAa,IAAK,CAAA,MAAA,CAAO,MAC9B,CAAA,IAAA,CAAK,UAAY,CAEjB,CAAA,IAAA,CAAK,IAAK,CAAA,OAAA,CAAS,IAAI,CAAA,CAEnBA,CAAY,EAAA,IAAA,CAAK,EAAG,CAAA,UAAA,CAAYA,CAAU,CAAA,CAE9C,IAAK,CAAA,IAAA,CAAK,WAAa,CAAA,IAAM,CAC3BD,CAAAA,GAAc,IAAI,CAAA,CACdC,CAAY,EAAA,IAAA,CAAK,GAAI,CAAA,UAAA,CAAYA,CAAU,EACjD,CAAC,CAAA,CAED,IAAK,CAAA,MAAA,CAAO,GAAKL,CAAAA,CAAAA,EAAS,CACxBA,CAAK,CAAA,IAAA,CAAK,QAAU,CAAA,IAAM,CACxB,IAAA,CAAK,WAAYA,CAAAA,CAAI,EACvB,CAAC,CAEDA,CAAAA,CAAAA,CAAK,IAAK,GACZ,CAAC,EACH,CACF,CAEaM,CAAAA,CAAAA,CAAS,IAAIR,EAW1BQ,CAAO,CAAA,cAAA,CAAef,CAAY,CAAA,IAAA,CAAMA,CAAW,CAAA,CACnDe,CAAO,CAAA,cAAA,CAAeV,CAAY,CAAA,IAAA,CAAMA,CAAW,CAAA,KC9ItCW,CAAUrB,CAAAA","file":"index.js","sourcesContent":["{\n \"name\": \"@joycostudio/susano\",\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org\",\n \"access\": \"public\"\n },\n \"version\": \"0.0.1\",\n \"description\": \"Asset load orchestration made easy\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"version:package\": \"pnpm changeset version\",\n \"release\": \"pnpm build && pnpm changeset publish\"\n },\n \"author\": \"@joycostudio\",\n \"license\": \"ISC\",\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.11\",\n \"@eslint/js\": \"^9.18.0\",\n \"@types/node\": \"^20.11.24\",\n \"@types/react\": \"^18.2.61\",\n \"@typescript-eslint/eslint-plugin\": \"^8.21.0\",\n \"@typescript-eslint/parser\": \"^8.21.0\",\n \"eslint\": \"^9.18.0\",\n \"eslint-config-prettier\": \"^10.0.1\",\n \"eslint-plugin-prettier\": \"^5.2.3\",\n \"eslint-plugin-react\": \"^7.37.4\",\n \"eslint-plugin-react-compiler\": \"19.0.0-beta-decd7b8-20250118\",\n \"globals\": \"^15.14.0\",\n \"prettier\": \"^3.4.2\",\n \"react\": \"^18.2.0\",\n \"tsup\": \"^8.0.2\",\n \"typescript\": \"^5.7.3\",\n \"typescript-eslint\": \"^8.21.0\"\n },\n \"peerDependencies\": {\n \"react\": \">=16.8.0\"\n },\n \"dependencies\": {\n \"tiny-emitter\": \"^2.1.0\"\n }\n}\n","import { TinyEmitter } from 'tiny-emitter'\n\nexport type SusanoLoaderConfig<T> = {\n onLoaded?: (loader: SusanoLoader<T>) => void\n}\n\nexport class SusanoLoader<T> extends TinyEmitter implements ISusanoLoader<T> {\n public url: string\n public loaded: boolean\n public content: T\n public config: SusanoLoaderConfig<T>\n\n constructor(url: string, _cnfg: SusanoLoaderConfig<T> = {}) {\n super()\n this.url = url\n this.loaded = false\n this.content = null as unknown as T\n this.config = _cnfg\n }\n\n load(): Promise<T> {\n throw new Error('Method not implemented')\n }\n\n _onLoaded() {\n this.loaded = true\n this.emit('loaded', this)\n this.config.onLoaded?.(this)\n }\n}\n\nexport interface ISusanoLoader<T> {\n load: () => Promise<T>\n}\n","import { ISusanoLoader, SusanoLoaderConfig, SusanoLoader } from './loader'\n\nexport type SusanoImageLoaderConfig = SusanoLoaderConfig<HTMLImageElement> & {\n srcSet?: string\n sizes?: string\n}\n\nexport class ImageLoader extends SusanoLoader<HTMLImageElement> implements ISusanoLoader<HTMLImageElement> {\n public static type = 'image' as const\n public srcSet?: string\n public sizes?: string\n\n constructor(url: string, cnfg: SusanoImageLoaderConfig = {}) {\n super(url, cnfg)\n this.content = new Image()\n this.srcSet = cnfg.srcSet\n this.sizes = cnfg.sizes\n }\n\n load(): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (this.loaded) {\n this._onLoaded.call(this)\n resolve(this.content)\n return\n }\n\n if (this.srcSet) this.content.srcset = this.srcSet\n if (this.sizes) this.content.sizes = this.sizes\n this.content.src = this.url\n\n this.content.onload = () => {\n this._onLoaded.call(this)\n resolve(this.content)\n }\n\n this.content.onerror = (e) => reject(e)\n })\n }\n}\n","import { ISusanoLoader, SusanoLoaderConfig, SusanoLoader } from './loader'\n\ntype LoadEvent = 'canplay' | 'canplaythrough'\n\nexport type SusanoVideoLoaderConfig = SusanoLoaderConfig<HTMLVideoElement> & {\n video?: HTMLVideoElement\n loadEvent?: LoadEvent\n}\n\nexport class VideoLoader extends SusanoLoader<HTMLVideoElement> implements ISusanoLoader<HTMLVideoElement> {\n public static type = 'video' as const\n public loadEvent: LoadEvent\n\n constructor(url: string, cnfg: SusanoVideoLoaderConfig = {}) {\n super(url, cnfg)\n this.content = cnfg.video || document.createElement('video')\n this.loadEvent = cnfg.loadEvent || 'canplay'\n }\n\n load(): Promise<HTMLVideoElement> {\n return new Promise((resolve, reject) => {\n const video = this.content\n\n if (this.loaded) {\n this._onLoaded.call(this)\n resolve(this.content)\n return\n }\n\n video.src = this.url\n\n video.addEventListener(this.loadEvent, () => {\n this._onLoaded.call(this)\n resolve(this.content)\n })\n\n video.addEventListener('error', (e) => reject(e))\n })\n }\n}\n","import { TinyEmitter } from 'tiny-emitter'\nimport { ImageLoader } from './loaders/image'\nimport { SusanoLoader } from './loaders/loader'\nimport { VideoLoader } from './loaders/video'\n\nexport type LoaderTypes = {\n [K: string]: {\n type: typeof K\n loader: typeof SusanoLoader<any>\n }\n}\n\nexport type LoaderMap<T extends LoaderTypes> = {\n [K in keyof T]: T[K]['loader']\n}\n\n/**\n * Main loader class that manages loading of different asset types\n * @template T Type definition for the loaders to be used, extending LoaderTypes\n * @extends TinyEmitter\n */\nexport class Susano<T extends LoaderTypes> extends TinyEmitter {\n private loaders: LoaderMap<T> = {} as LoaderMap<T>\n public queue: InstanceType<T[keyof T]['loader']>[] = []\n public active: InstanceType<T[keyof T]['loader']>[] = []\n public items: Map<string, InstanceType<T[keyof T]['loader']>> = new Map()\n public loadCount: number = 0\n public loadLength: number = 0\n\n constructor() {\n super()\n }\n\n add<K extends keyof T>(\n url: string,\n cnfg: {\n type: K\n loaderArgs?: ConstructorParameters<T[K]['loader']>[1]\n }\n ): InstanceType<T[K]['loader']> {\n const Loader = this.loaders[cnfg.type]\n\n if (!Loader) throw new Error(`Loader for type ${String(cnfg.type)} not found`)\n\n let item = this.items.get(url)\n\n if (!item) {\n item = new Loader(url, cnfg.loaderArgs) as InstanceType<T[K]['loader']>\n this.items.set(url, item)\n }\n\n this.queue.push(item)\n\n return item\n }\n\n load<K extends keyof T>(\n url: string,\n cnfg: {\n type: K\n loaderArgs?: ConstructorParameters<T[K]['loader']>[1]\n }\n ) {\n const Loader = this.loaders[cnfg.type]\n if (!Loader) throw new Error(`Loader for type ${String(cnfg.type)} not found`)\n\n let item = this.items.get(url)\n\n if (!item) {\n item = new Loader(url, cnfg.loaderArgs) as InstanceType<T[K]['loader']>\n this.items.set(url, item)\n }\n\n item.load()\n\n return item\n }\n\n registerLoader<K extends keyof T>(type: K, loader: T[K]['loader']) {\n this.loaders[type] = loader\n }\n\n _onProgress(item: SusanoLoader<unknown>) {\n this.loadCount++\n\n // const idx = this.active.indexOf(item);\n // this.active.splice(idx, 1);\n\n const progress = this.loadCount / this.loadLength\n\n this.emit('progress', {\n value: progress,\n item: item,\n susano: this,\n })\n\n if (progress === 1) {\n this.emit('completed', this)\n return\n }\n }\n\n start({\n onCompleted,\n onProgress,\n }: {\n onCompleted?: (susano: Susano<T>) => void\n onProgress?: (progress: { value: number; item: SusanoLoader<unknown>; susano: Susano<T> }) => void\n } = {}) {\n this.active = this.queue.splice(0, this.queue.length)\n this.loadLength = this.active.length\n this.loadCount = 0\n\n this.emit('start', this)\n\n if (onProgress) this.on('progress', onProgress)\n\n this.once('completed', () => {\n onCompleted?.(this)\n if (onProgress) this.off('progress', onProgress)\n })\n\n this.active.map((item) => {\n item.once('loaded', () => {\n this._onProgress(item)\n })\n\n item.load()\n })\n }\n}\n\nexport const susano = new Susano<{\n image: {\n type: 'image'\n loader: typeof ImageLoader\n }\n video: {\n type: 'video'\n loader: typeof VideoLoader\n }\n}>()\n\nsusano.registerLoader(ImageLoader.type, ImageLoader)\nsusano.registerLoader(VideoLoader.type, VideoLoader)\n","import { version } from '../package.json'\n\nexport const VERSION = version\nexport * from './core'\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import {TinyEmitter}from'tiny-emitter';var l="0.0.1";var n=class extends TinyEmitter{constructor(o,e={}){super(),this.url=o,this.loaded=false,this.content=null,this.config=e;}load(){throw new Error("Method not implemented")}_onLoaded(){this.loaded=true,this.emit("loaded",this),this.config.onLoaded?.(this);}};var r=class extends n{constructor(o,e={}){super(o,e),this.content=new Image,this.srcSet=e.srcSet,this.sizes=e.sizes;}load(){return new Promise((o,e)=>{if(this.loaded){this._onLoaded.call(this),o(this.content);return}this.srcSet&&(this.content.srcset=this.srcSet),this.sizes&&(this.content.sizes=this.sizes),this.content.src=this.url,this.content.onload=()=>{this._onLoaded.call(this),o(this.content);},this.content.onerror=t=>e(t);})}};r.type="image";var a=class extends n{constructor(o,e={}){super(o,e),this.content=e.video||document.createElement("video"),this.loadEvent=e.loadEvent||"canplay";}load(){return new Promise((o,e)=>{let t=this.content;if(this.loaded){this._onLoaded.call(this),o(this.content);return}t.src=this.url,t.addEventListener(this.loadEvent,()=>{this._onLoaded.call(this),o(this.content);}),t.addEventListener("error",s=>e(s));})}};a.type="video";var p=class extends TinyEmitter{constructor(){super();this.loaders={};this.queue=[];this.active=[];this.items=new Map;this.loadCount=0;this.loadLength=0;}add(e,t){let s=this.loaders[t.type];if(!s)throw new Error(`Loader for type ${String(t.type)} not found`);let i=this.items.get(e);return i||(i=new s(e,t.loaderArgs),this.items.set(e,i)),this.queue.push(i),i}load(e,t){let s=this.loaders[t.type];if(!s)throw new Error(`Loader for type ${String(t.type)} not found`);let i=this.items.get(e);return i||(i=new s(e,t.loaderArgs),this.items.set(e,i)),i.load(),i}registerLoader(e,t){this.loaders[e]=t;}_onProgress(e){this.loadCount++;let t=this.loadCount/this.loadLength;if(this.emit("progress",{value:t,item:e,susano:this}),t===1){this.emit("completed",this);return}}start({onCompleted:e,onProgress:t}={}){this.active=this.queue.splice(0,this.queue.length),this.loadLength=this.active.length,this.loadCount=0,this.emit("start",this),t&&this.on("progress",t),this.once("completed",()=>{e?.(this),t&&this.off("progress",t);}),this.active.map(s=>{s.once("loaded",()=>{this._onProgress(s);}),s.load();});}},c=new p;c.registerLoader(r.type,r);c.registerLoader(a.type,a);var H=l;export{p as Susano,H as VERSION,c as susano};//# sourceMappingURL=index.mjs.map
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../package.json","../src/loaders/loader.ts","../src/loaders/image.ts","../src/loaders/video.ts","../src/core.tsx","../src/index.ts"],"names":["version","SusanoLoader","TinyEmitter","url","_cnfg","ImageLoader","cnfg","resolve","reject","e","VideoLoader","video","Susano","Loader","item","type","loader","progress","onCompleted","onProgress","susano","VERSION"],"mappings":"uCAME,IAAAA,CAAW,CAAA,OAAA,CCAN,IAAMC,CAAAA,CAAN,cAA8BC,WAAwC,CAM3E,WAAA,CAAYC,CAAaC,CAAAA,CAAAA,CAA+B,EAAC,CAAG,CAC1D,KAAA,EACA,CAAA,IAAA,CAAK,GAAMD,CAAAA,CAAAA,CACX,IAAK,CAAA,MAAA,CAAS,MACd,IAAK,CAAA,OAAA,CAAU,IACf,CAAA,IAAA,CAAK,MAASC,CAAAA,EAChB,CAEA,IAAA,EAAmB,CACjB,MAAM,IAAI,KAAA,CAAM,wBAAwB,CAC1C,CAEA,SAAA,EAAY,CACV,IAAA,CAAK,MAAS,CAAA,IAAA,CACd,IAAK,CAAA,IAAA,CAAK,QAAU,CAAA,IAAI,CACxB,CAAA,IAAA,CAAK,MAAO,CAAA,QAAA,GAAW,IAAI,EAC7B,CACF,CAAA,CCtBO,IAAMC,CAAN,CAAA,cAA0BJ,CAA0E,CAKzG,WAAYE,CAAAA,CAAAA,CAAaG,CAAgC,CAAA,EAAI,CAAA,CAC3D,KAAMH,CAAAA,CAAAA,CAAKG,CAAI,CAAA,CACf,IAAK,CAAA,OAAA,CAAU,IAAI,KAAA,CACnB,IAAK,CAAA,MAAA,CAASA,CAAK,CAAA,MAAA,CACnB,IAAK,CAAA,KAAA,CAAQA,CAAK,CAAA,MACpB,CAEA,IAAA,EAAkC,CAChC,OAAO,IAAI,OAAA,CAAQ,CAACC,CAASC,CAAAA,CAAAA,GAAW,CACtC,GAAI,IAAK,CAAA,MAAA,CAAQ,CACf,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,IAAI,CAAA,CACxBD,CAAQ,CAAA,IAAA,CAAK,OAAO,CAAA,CACpB,MACF,CAEI,IAAA,CAAK,MAAQ,GAAA,IAAA,CAAK,OAAQ,CAAA,MAAA,CAAS,IAAK,CAAA,MAAA,CAAA,CACxC,IAAK,CAAA,KAAA,GAAO,IAAK,CAAA,OAAA,CAAQ,KAAQ,CAAA,IAAA,CAAK,KAC1C,CAAA,CAAA,IAAA,CAAK,QAAQ,GAAM,CAAA,IAAA,CAAK,GAExB,CAAA,IAAA,CAAK,OAAQ,CAAA,MAAA,CAAS,IAAM,CAC1B,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBA,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,EACtB,CAAA,CAEA,IAAK,CAAA,OAAA,CAAQ,OAAWE,CAAAA,CAAAA,EAAMD,CAAOC,CAAAA,CAAC,EACxC,CAAC,CACH,CACF,CAhCaJ,CAAAA,CAAAA,CACG,IAAO,CAAA,OAAA,CCChB,IAAMK,CAAN,CAAA,cAA0BT,CAA0E,CAIzG,WAAYE,CAAAA,CAAAA,CAAaG,CAAgC,CAAA,EAAI,CAAA,CAC3D,KAAMH,CAAAA,CAAAA,CAAKG,CAAI,CAAA,CACf,IAAK,CAAA,OAAA,CAAUA,CAAK,CAAA,KAAA,EAAS,QAAS,CAAA,aAAA,CAAc,OAAO,CAAA,CAC3D,IAAK,CAAA,SAAA,CAAYA,CAAK,CAAA,SAAA,EAAa,UACrC,CAEA,IAAkC,EAAA,CAChC,OAAO,IAAI,QAAQ,CAACC,CAAAA,CAASC,CAAW,GAAA,CACtC,IAAMG,CAAAA,CAAQ,IAAK,CAAA,OAAA,CAEnB,GAAI,IAAA,CAAK,MAAQ,CAAA,CACf,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBJ,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,CACpB,CAAA,MACF,CAEAI,CAAAA,CAAM,GAAM,CAAA,IAAA,CAAK,GAEjBA,CAAAA,CAAAA,CAAM,gBAAiB,CAAA,IAAA,CAAK,SAAW,CAAA,IAAM,CAC3C,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,IAAI,CACxBJ,CAAAA,CAAAA,CAAQ,IAAK,CAAA,OAAO,EACtB,CAAC,CAEDI,CAAAA,CAAAA,CAAM,gBAAiB,CAAA,OAAA,CAAUF,CAAMD,EAAAA,CAAAA,CAAOC,CAAC,CAAC,EAClD,CAAC,CACH,CACF,CAAA,CA9BaC,CACG,CAAA,IAAA,CAAO,OCWhB,CAAA,IAAME,CAAN,CAAA,cAA4CV,WAAY,CAQ7D,WAAc,EAAA,CACZ,OARF,CAAA,IAAA,CAAQ,OAAwB,CAAA,EAChC,CAAA,IAAA,CAAO,KAA8C,CAAA,EACrD,CAAA,IAAA,CAAO,MAA+C,CAAA,EACtD,CAAA,IAAA,CAAO,KAAyD,CAAA,IAAI,GACpE,CAAA,IAAA,CAAO,SAAoB,CAAA,CAAA,CAC3B,IAAO,CAAA,UAAA,CAAqB,EAI5B,CAEA,GACEC,CAAAA,CAAAA,CACAG,CAI8B,CAAA,CAC9B,IAAMO,CAAAA,CAAS,IAAK,CAAA,OAAA,CAAQP,EAAK,IAAI,CAAA,CAErC,GAAI,CAACO,CAAQ,CAAA,MAAM,IAAI,KAAA,CAAM,CAAmB,gBAAA,EAAA,MAAA,CAAOP,CAAK,CAAA,IAAI,CAAC,CAAA,UAAA,CAAY,CAE7E,CAAA,IAAIQ,CAAO,CAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAIX,CAAG,CAAA,CAE7B,OAAKW,CAAAA,GACHA,CAAO,CAAA,IAAID,CAAOV,CAAAA,CAAAA,CAAKG,CAAK,CAAA,UAAU,CACtC,CAAA,IAAA,CAAK,MAAM,GAAIH,CAAAA,CAAAA,CAAKW,CAAI,CAAA,CAAA,CAG1B,IAAK,CAAA,KAAA,CAAM,IAAKA,CAAAA,CAAI,CAEbA,CAAAA,CACT,CAEA,IAAA,CACEX,CACAG,CAAAA,CAAAA,CAIA,CACA,IAAMO,CAAS,CAAA,IAAA,CAAK,OAAQP,CAAAA,CAAAA,CAAK,IAAI,CAAA,CACrC,GAAI,CAACO,CAAQ,CAAA,MAAM,IAAI,KAAA,CAAM,CAAmB,gBAAA,EAAA,MAAA,CAAOP,CAAK,CAAA,IAAI,CAAC,CAAY,UAAA,CAAA,CAAA,CAE7E,IAAIQ,CAAAA,CAAO,IAAK,CAAA,KAAA,CAAM,GAAIX,CAAAA,CAAG,CAE7B,CAAA,OAAKW,CACHA,GAAAA,CAAAA,CAAO,IAAID,CAAAA,CAAOV,CAAKG,CAAAA,CAAAA,CAAK,UAAU,CACtC,CAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAIH,CAAKW,CAAAA,CAAI,CAG1BA,CAAAA,CAAAA,CAAAA,CAAK,IAAK,EAAA,CAEHA,CACT,CAEA,cAAkCC,CAAAA,CAAAA,CAASC,CAAwB,CAAA,CACjE,KAAK,OAAQD,CAAAA,CAAI,CAAIC,CAAAA,EACvB,CAEA,WAAA,CAAYF,CAA6B,CAAA,CACvC,IAAK,CAAA,SAAA,EAAA,CAKL,IAAMG,CAAAA,CAAW,IAAK,CAAA,SAAA,CAAY,IAAK,CAAA,UAAA,CAQvC,GANA,IAAA,CAAK,IAAK,CAAA,UAAA,CAAY,CACpB,KAAA,CAAOA,CACP,CAAA,IAAA,CAAMH,CACN,CAAA,MAAA,CAAQ,IACV,CAAC,CAEGG,CAAAA,CAAAA,GAAa,CAAG,CAAA,CAClB,KAAK,IAAK,CAAA,WAAA,CAAa,IAAI,CAAA,CAC3B,MACF,CACF,CAEA,KAAA,CAAM,CACJ,WAAA,CAAAC,CACA,CAAA,UAAA,CAAAC,CACF,CAAA,CAGI,EAAC,CAAG,CACN,IAAK,CAAA,MAAA,CAAS,IAAK,CAAA,KAAA,CAAM,MAAO,CAAA,CAAA,CAAG,IAAK,CAAA,KAAA,CAAM,MAAM,CAAA,CACpD,IAAK,CAAA,UAAA,CAAa,IAAK,CAAA,MAAA,CAAO,MAC9B,CAAA,IAAA,CAAK,UAAY,CAEjB,CAAA,IAAA,CAAK,IAAK,CAAA,OAAA,CAAS,IAAI,CAAA,CAEnBA,CAAY,EAAA,IAAA,CAAK,EAAG,CAAA,UAAA,CAAYA,CAAU,CAAA,CAE9C,IAAK,CAAA,IAAA,CAAK,WAAa,CAAA,IAAM,CAC3BD,CAAAA,GAAc,IAAI,CAAA,CACdC,CAAY,EAAA,IAAA,CAAK,GAAI,CAAA,UAAA,CAAYA,CAAU,EACjD,CAAC,CAAA,CAED,IAAK,CAAA,MAAA,CAAO,GAAKL,CAAAA,CAAAA,EAAS,CACxBA,CAAK,CAAA,IAAA,CAAK,QAAU,CAAA,IAAM,CACxB,IAAA,CAAK,WAAYA,CAAAA,CAAI,EACvB,CAAC,CAEDA,CAAAA,CAAAA,CAAK,IAAK,GACZ,CAAC,EACH,CACF,CAEaM,CAAAA,CAAAA,CAAS,IAAIR,EAW1BQ,CAAO,CAAA,cAAA,CAAef,CAAY,CAAA,IAAA,CAAMA,CAAW,CAAA,CACnDe,CAAO,CAAA,cAAA,CAAeV,CAAY,CAAA,IAAA,CAAMA,CAAW,CAAA,KC9ItCW,CAAUrB,CAAAA","file":"index.mjs","sourcesContent":["{\n \"name\": \"@joycostudio/susano\",\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org\",\n \"access\": \"public\"\n },\n \"version\": \"0.0.1\",\n \"description\": \"Asset load orchestration made easy\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"version:package\": \"pnpm changeset version\",\n \"release\": \"pnpm build && pnpm changeset publish\"\n },\n \"author\": \"@joycostudio\",\n \"license\": \"ISC\",\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.11\",\n \"@eslint/js\": \"^9.18.0\",\n \"@types/node\": \"^20.11.24\",\n \"@types/react\": \"^18.2.61\",\n \"@typescript-eslint/eslint-plugin\": \"^8.21.0\",\n \"@typescript-eslint/parser\": \"^8.21.0\",\n \"eslint\": \"^9.18.0\",\n \"eslint-config-prettier\": \"^10.0.1\",\n \"eslint-plugin-prettier\": \"^5.2.3\",\n \"eslint-plugin-react\": \"^7.37.4\",\n \"eslint-plugin-react-compiler\": \"19.0.0-beta-decd7b8-20250118\",\n \"globals\": \"^15.14.0\",\n \"prettier\": \"^3.4.2\",\n \"react\": \"^18.2.0\",\n \"tsup\": \"^8.0.2\",\n \"typescript\": \"^5.7.3\",\n \"typescript-eslint\": \"^8.21.0\"\n },\n \"peerDependencies\": {\n \"react\": \">=16.8.0\"\n },\n \"dependencies\": {\n \"tiny-emitter\": \"^2.1.0\"\n }\n}\n","import { TinyEmitter } from 'tiny-emitter'\n\nexport type SusanoLoaderConfig<T> = {\n onLoaded?: (loader: SusanoLoader<T>) => void\n}\n\nexport class SusanoLoader<T> extends TinyEmitter implements ISusanoLoader<T> {\n public url: string\n public loaded: boolean\n public content: T\n public config: SusanoLoaderConfig<T>\n\n constructor(url: string, _cnfg: SusanoLoaderConfig<T> = {}) {\n super()\n this.url = url\n this.loaded = false\n this.content = null as unknown as T\n this.config = _cnfg\n }\n\n load(): Promise<T> {\n throw new Error('Method not implemented')\n }\n\n _onLoaded() {\n this.loaded = true\n this.emit('loaded', this)\n this.config.onLoaded?.(this)\n }\n}\n\nexport interface ISusanoLoader<T> {\n load: () => Promise<T>\n}\n","import { ISusanoLoader, SusanoLoaderConfig, SusanoLoader } from './loader'\n\nexport type SusanoImageLoaderConfig = SusanoLoaderConfig<HTMLImageElement> & {\n srcSet?: string\n sizes?: string\n}\n\nexport class ImageLoader extends SusanoLoader<HTMLImageElement> implements ISusanoLoader<HTMLImageElement> {\n public static type = 'image' as const\n public srcSet?: string\n public sizes?: string\n\n constructor(url: string, cnfg: SusanoImageLoaderConfig = {}) {\n super(url, cnfg)\n this.content = new Image()\n this.srcSet = cnfg.srcSet\n this.sizes = cnfg.sizes\n }\n\n load(): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n if (this.loaded) {\n this._onLoaded.call(this)\n resolve(this.content)\n return\n }\n\n if (this.srcSet) this.content.srcset = this.srcSet\n if (this.sizes) this.content.sizes = this.sizes\n this.content.src = this.url\n\n this.content.onload = () => {\n this._onLoaded.call(this)\n resolve(this.content)\n }\n\n this.content.onerror = (e) => reject(e)\n })\n }\n}\n","import { ISusanoLoader, SusanoLoaderConfig, SusanoLoader } from './loader'\n\ntype LoadEvent = 'canplay' | 'canplaythrough'\n\nexport type SusanoVideoLoaderConfig = SusanoLoaderConfig<HTMLVideoElement> & {\n video?: HTMLVideoElement\n loadEvent?: LoadEvent\n}\n\nexport class VideoLoader extends SusanoLoader<HTMLVideoElement> implements ISusanoLoader<HTMLVideoElement> {\n public static type = 'video' as const\n public loadEvent: LoadEvent\n\n constructor(url: string, cnfg: SusanoVideoLoaderConfig = {}) {\n super(url, cnfg)\n this.content = cnfg.video || document.createElement('video')\n this.loadEvent = cnfg.loadEvent || 'canplay'\n }\n\n load(): Promise<HTMLVideoElement> {\n return new Promise((resolve, reject) => {\n const video = this.content\n\n if (this.loaded) {\n this._onLoaded.call(this)\n resolve(this.content)\n return\n }\n\n video.src = this.url\n\n video.addEventListener(this.loadEvent, () => {\n this._onLoaded.call(this)\n resolve(this.content)\n })\n\n video.addEventListener('error', (e) => reject(e))\n })\n }\n}\n","import { TinyEmitter } from 'tiny-emitter'\nimport { ImageLoader } from './loaders/image'\nimport { SusanoLoader } from './loaders/loader'\nimport { VideoLoader } from './loaders/video'\n\nexport type LoaderTypes = {\n [K: string]: {\n type: typeof K\n loader: typeof SusanoLoader<any>\n }\n}\n\nexport type LoaderMap<T extends LoaderTypes> = {\n [K in keyof T]: T[K]['loader']\n}\n\n/**\n * Main loader class that manages loading of different asset types\n * @template T Type definition for the loaders to be used, extending LoaderTypes\n * @extends TinyEmitter\n */\nexport class Susano<T extends LoaderTypes> extends TinyEmitter {\n private loaders: LoaderMap<T> = {} as LoaderMap<T>\n public queue: InstanceType<T[keyof T]['loader']>[] = []\n public active: InstanceType<T[keyof T]['loader']>[] = []\n public items: Map<string, InstanceType<T[keyof T]['loader']>> = new Map()\n public loadCount: number = 0\n public loadLength: number = 0\n\n constructor() {\n super()\n }\n\n add<K extends keyof T>(\n url: string,\n cnfg: {\n type: K\n loaderArgs?: ConstructorParameters<T[K]['loader']>[1]\n }\n ): InstanceType<T[K]['loader']> {\n const Loader = this.loaders[cnfg.type]\n\n if (!Loader) throw new Error(`Loader for type ${String(cnfg.type)} not found`)\n\n let item = this.items.get(url)\n\n if (!item) {\n item = new Loader(url, cnfg.loaderArgs) as InstanceType<T[K]['loader']>\n this.items.set(url, item)\n }\n\n this.queue.push(item)\n\n return item\n }\n\n load<K extends keyof T>(\n url: string,\n cnfg: {\n type: K\n loaderArgs?: ConstructorParameters<T[K]['loader']>[1]\n }\n ) {\n const Loader = this.loaders[cnfg.type]\n if (!Loader) throw new Error(`Loader for type ${String(cnfg.type)} not found`)\n\n let item = this.items.get(url)\n\n if (!item) {\n item = new Loader(url, cnfg.loaderArgs) as InstanceType<T[K]['loader']>\n this.items.set(url, item)\n }\n\n item.load()\n\n return item\n }\n\n registerLoader<K extends keyof T>(type: K, loader: T[K]['loader']) {\n this.loaders[type] = loader\n }\n\n _onProgress(item: SusanoLoader<unknown>) {\n this.loadCount++\n\n // const idx = this.active.indexOf(item);\n // this.active.splice(idx, 1);\n\n const progress = this.loadCount / this.loadLength\n\n this.emit('progress', {\n value: progress,\n item: item,\n susano: this,\n })\n\n if (progress === 1) {\n this.emit('completed', this)\n return\n }\n }\n\n start({\n onCompleted,\n onProgress,\n }: {\n onCompleted?: (susano: Susano<T>) => void\n onProgress?: (progress: { value: number; item: SusanoLoader<unknown>; susano: Susano<T> }) => void\n } = {}) {\n this.active = this.queue.splice(0, this.queue.length)\n this.loadLength = this.active.length\n this.loadCount = 0\n\n this.emit('start', this)\n\n if (onProgress) this.on('progress', onProgress)\n\n this.once('completed', () => {\n onCompleted?.(this)\n if (onProgress) this.off('progress', onProgress)\n })\n\n this.active.map((item) => {\n item.once('loaded', () => {\n this._onProgress(item)\n })\n\n item.load()\n })\n }\n}\n\nexport const susano = new Susano<{\n image: {\n type: 'image'\n loader: typeof ImageLoader\n }\n video: {\n type: 'video'\n loader: typeof VideoLoader\n }\n}>()\n\nsusano.registerLoader(ImageLoader.type, ImageLoader)\nsusano.registerLoader(VideoLoader.type, VideoLoader)\n","import { version } from '../package.json'\n\nexport const VERSION = version\nexport * from './core'\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@joycostudio/susano",
3
+ "publishConfig": {
4
+ "registry": "https://registry.npmjs.org",
5
+ "access": "public"
6
+ },
7
+ "version": "0.0.1",
8
+ "description": "Asset load orchestration made easy",
9
+ "main": "dist/index.js",
10
+ "module": "dist/index.mjs",
11
+ "types": "dist/index.d.ts",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "author": "@joycostudio",
16
+ "license": "ISC",
17
+ "devDependencies": {
18
+ "@changesets/cli": "^2.27.11",
19
+ "@eslint/js": "^9.18.0",
20
+ "@types/node": "^20.11.24",
21
+ "@types/react": "^18.2.61",
22
+ "@typescript-eslint/eslint-plugin": "^8.21.0",
23
+ "@typescript-eslint/parser": "^8.21.0",
24
+ "eslint": "^9.18.0",
25
+ "eslint-config-prettier": "^10.0.1",
26
+ "eslint-plugin-prettier": "^5.2.3",
27
+ "eslint-plugin-react": "^7.37.4",
28
+ "eslint-plugin-react-compiler": "19.0.0-beta-decd7b8-20250118",
29
+ "globals": "^15.14.0",
30
+ "prettier": "^3.4.2",
31
+ "react": "^18.2.0",
32
+ "tsup": "^8.0.2",
33
+ "typescript": "^5.7.3",
34
+ "typescript-eslint": "^8.21.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": ">=16.8.0"
38
+ },
39
+ "dependencies": {
40
+ "tiny-emitter": "^2.1.0"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "typecheck": "tsc --noEmit",
46
+ "version:package": "pnpm changeset version",
47
+ "release": "pnpm build && pnpm changeset publish"
48
+ }
49
+ }