@hkdigital/lib-sveltekit 0.0.81 → 0.0.83

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.
Files changed (44) hide show
  1. package/dist/classes/svelte/audio/AudioLoader.svelte.d.ts +30 -0
  2. package/dist/classes/svelte/audio/AudioLoader.svelte.js +58 -0
  3. package/dist/classes/svelte/audio/AudioScene.svelte.d.ts +52 -0
  4. package/dist/classes/svelte/audio/AudioScene.svelte.js +282 -0
  5. package/dist/classes/svelte/audio/mocks.d.ts +7 -0
  6. package/dist/classes/svelte/audio/mocks.js +35 -0
  7. package/dist/classes/svelte/final-state-machine/FiniteStateMachine.svelte.d.ts +50 -0
  8. package/dist/classes/svelte/final-state-machine/FiniteStateMachine.svelte.js +133 -0
  9. package/dist/classes/svelte/final-state-machine/index.d.ts +1 -0
  10. package/dist/classes/svelte/final-state-machine/index.js +1 -0
  11. package/dist/classes/svelte/image/ImageLoader.svelte.d.ts +8 -0
  12. package/dist/classes/svelte/image/ImageLoader.svelte.js +12 -0
  13. package/dist/classes/svelte/image/ImageVariantsLoader.svelte.d.ts +39 -0
  14. package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +151 -0
  15. package/dist/classes/svelte/image/index.d.ts +2 -0
  16. package/dist/classes/svelte/image/index.js +4 -0
  17. package/dist/classes/svelte/image/mocks.d.ts +7 -0
  18. package/dist/classes/svelte/image/mocks.js +38 -0
  19. package/dist/classes/svelte/image/typedef.d.ts +16 -0
  20. package/dist/classes/svelte/image/typedef.js +10 -0
  21. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.d.ts +12 -0
  22. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +107 -0
  23. package/dist/classes/svelte/loading-state-machine/constants.d.ts +12 -0
  24. package/dist/classes/svelte/loading-state-machine/constants.js +16 -0
  25. package/dist/classes/svelte/loading-state-machine/index.d.ts +2 -0
  26. package/dist/classes/svelte/loading-state-machine/index.js +3 -0
  27. package/dist/classes/svelte/network-loader/NetworkLoader.svelte.d.ts +85 -0
  28. package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +295 -0
  29. package/dist/classes/svelte/network-loader/constants.d.ts +2 -0
  30. package/dist/classes/svelte/network-loader/constants.js +3 -0
  31. package/dist/classes/svelte/network-loader/index.d.ts +2 -0
  32. package/dist/classes/svelte/network-loader/index.js +3 -0
  33. package/dist/components/image/ResponsiveImage.svelte +103 -0
  34. package/dist/components/image/ResponsiveImage.svelte.d.ts +15 -0
  35. package/dist/components/image/index.d.ts +4 -1
  36. package/dist/components/image/index.js +5 -1
  37. package/dist/types/imagetools.d.ts +16 -13
  38. package/dist/types/imagetools.js +8 -0
  39. package/dist/util/expect/arrays.d.ts +4 -0
  40. package/dist/util/expect/arrays.js +6 -1
  41. package/dist/util/http/response.js +1 -0
  42. package/dist/util/svelte/wait/index.d.ts +15 -0
  43. package/dist/util/svelte/wait/index.js +38 -0
  44. package/package.json +3 -1
@@ -0,0 +1,39 @@
1
+ export default class ImageVariantsLoader {
2
+ /**
3
+ * @param {ImageVariant[]} imagesMeta
4
+ */
5
+ constructor(imagesMeta: ImageVariant[], { devicePixelRatio }?: {
6
+ devicePixelRatio?: number;
7
+ });
8
+ /**
9
+ * Set new optimal image variant or keep current
10
+ *
11
+ * @param {number} containerWidth
12
+ */
13
+ updateOptimalImageVariant(containerWidth: number): void;
14
+ get loaded(): boolean;
15
+ get variant(): import("./typedef.js").ImageVariant;
16
+ /**
17
+ * Get object URL that can be used as src parameter of an HTML image
18
+ *
19
+ * @note the objectURL should be revoked when no longer used
20
+ *
21
+ * @returns {string|null}
22
+ */
23
+ getObjectUrl(): string | null;
24
+ get progress(): {
25
+ bytesLoaded: number;
26
+ size: number;
27
+ loaded: boolean;
28
+ };
29
+ /**
30
+ * Get optimal image variant
31
+ *
32
+ * @param {number} containerWidth
33
+ *
34
+ * @returns {ImageVariant|null}
35
+ */
36
+ getOptimalImageVariant(containerWidth: number): ImageVariant | null;
37
+ #private;
38
+ }
39
+ export type ImageVariant = import("./typedef.js").ImageVariant;
@@ -0,0 +1,151 @@
1
+ /** @typedef {import('./typedef.js').ImageVariant} ImageVariant */
2
+
3
+ // import * as expect from '@hkdigital/lib-sveltekit/util/expect/index.js';
4
+
5
+ import { untrack } from 'svelte';
6
+
7
+ import ImageLoader from './ImageLoader.svelte.js';
8
+
9
+ export default class ImageVariantsLoader {
10
+ /** @type {number} */
11
+ #devicePixelRatio;
12
+
13
+ /** @type {ImageVariant[]} */
14
+ #imagesMeta;
15
+
16
+ /** @type {ImageVariant|null} */
17
+ #imageVariant = $state(null);
18
+
19
+ /** @type {ImageLoader|null} */
20
+ #imageLoader = $state(null);
21
+
22
+ #progress = $derived.by(() => {
23
+ if (this.#imageLoader) {
24
+ // const progress = this.#imageLoader.progress;
25
+
26
+ return this.#imageLoader.progress;
27
+ } else {
28
+ return { bytesLoaded: 0, size: 0, loaded: false };
29
+ }
30
+ });
31
+
32
+ #loaded = $derived(this.#progress.loaded);
33
+
34
+ /**
35
+ * @param {ImageVariant[]} imagesMeta
36
+ */
37
+ constructor(imagesMeta, { devicePixelRatio = 1 } = {}) {
38
+ // expect.notEmptyArray( imagesMeta );
39
+
40
+ this.#devicePixelRatio = devicePixelRatio ?? 1;
41
+
42
+ // Sort images meta by width ascending
43
+ this.#imagesMeta = [...imagesMeta].sort((a, b) => a.width - b.width);
44
+
45
+ $effect(() => {
46
+ const variant = this.#imageVariant;
47
+
48
+ if (variant) {
49
+ // console.log('Load new variant', $state.snapshot(variant));
50
+
51
+ // TODO: abort loading if imageLoader exists
52
+
53
+ untrack(() => {
54
+ const loader = (this.#imageLoader = new ImageLoader({
55
+ url: variant.src
56
+ }));
57
+
58
+ loader.load();
59
+ });
60
+ }
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Set new optimal image variant or keep current
66
+ *
67
+ * @param {number} containerWidth
68
+ */
69
+ updateOptimalImageVariant(containerWidth) {
70
+ const newVariant = this.getOptimalImageVariant(containerWidth);
71
+
72
+ if (
73
+ !newVariant ||
74
+ !this.#imageVariant ||
75
+ newVariant.width > this.#imageVariant.width
76
+ ) {
77
+ // Only update imageVariant is width is larger
78
+ this.#imageVariant = newVariant;
79
+ }
80
+ }
81
+
82
+ get loaded() {
83
+ return this.#loaded;
84
+ }
85
+
86
+ get variant() {
87
+ return this.#imageVariant;
88
+ }
89
+
90
+ /**
91
+ * Get object URL that can be used as src parameter of an HTML image
92
+ *
93
+ * @note the objectURL should be revoked when no longer used
94
+ *
95
+ * @returns {string|null}
96
+ */
97
+ getObjectUrl() {
98
+ // Example usage:
99
+ //
100
+ // $effect(() => {
101
+ // if (variantsLoader.loaded) {
102
+ // // @ts-ignore
103
+ // imageUrl = variantsLoader.getObjectUrl();
104
+ // }
105
+
106
+ // return () => {
107
+ // if (imageUrl) {
108
+ // URL.revokeObjectURL(imageUrl);
109
+ // imageUrl = null;
110
+ // }
111
+ // };
112
+ // });
113
+
114
+ const blob = this.#imageLoader?.getBlob();
115
+
116
+ const url = blob ? URL.createObjectURL(blob) : null;
117
+
118
+ return url;
119
+ }
120
+
121
+ get progress() {
122
+ return this.#progress;
123
+ }
124
+
125
+ /**
126
+ * Get optimal image variant
127
+ *
128
+ * @param {number} containerWidth
129
+ *
130
+ * @returns {ImageVariant|null}
131
+ */
132
+ getOptimalImageVariant(containerWidth) {
133
+ if (!containerWidth) {
134
+ return null;
135
+ }
136
+
137
+ // Calculate the required width (container * DPR)
138
+ const requiredWidth = containerWidth * this.#devicePixelRatio;
139
+
140
+ const imagesMeta = this.#imagesMeta;
141
+
142
+ // Find the smallest image that's larger than our required width
143
+
144
+ const optimal = imagesMeta.find(
145
+ (current) => current.width >= requiredWidth
146
+ );
147
+
148
+ // Fall back to the largest image if nothing is big enough
149
+ return optimal || imagesMeta[imagesMeta.length - 1];
150
+ }
151
+ } // end class
@@ -0,0 +1,2 @@
1
+ export { default as ImageLoader } from "./ImageLoader.svelte";
2
+ export { default as ImageVariantsLoader } from "./ImageVariantsLoader.svelte";
@@ -0,0 +1,4 @@
1
+ export { default as ImageLoader } from './ImageLoader.svelte';
2
+ export { default as ImageVariantsLoader } from './ImageVariantsLoader.svelte';
3
+
4
+ // export * from './constants.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Create a response value that can be used by a mocked
3
+ * fetch function
4
+ *
5
+ * @returns {Response}
6
+ */
7
+ export function createPngResponse(): Response;
@@ -0,0 +1,38 @@
1
+ import {
2
+ CONTENT_TYPE,
3
+ CONTENT_LENGTH
4
+ } from '@hkdigital/lib-sveltekit/constants/http/index.js';
5
+
6
+ import { IMAGE_PNG } from '@hkdigital/lib-sveltekit/constants/mime/image.js';
7
+
8
+ /**
9
+ * A minimal 1x1 black PNG encoded as base64
10
+ * @constant {string}
11
+ */
12
+ const BASE64_PNG =
13
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
14
+
15
+ /**
16
+ * Create a response value that can be used by a mocked
17
+ * fetch function
18
+ *
19
+ * @returns {Response}
20
+ */
21
+ export function createPngResponse(/* data , options */) {
22
+ // Convert base64 to binary
23
+ const binaryString = atob(BASE64_PNG);
24
+ const bytes = new Uint8Array(binaryString.length);
25
+
26
+ for (let i = 0; i < binaryString.length; i++) {
27
+ bytes[i] = binaryString.charCodeAt(i);
28
+ }
29
+
30
+ const response = new Response(bytes, {
31
+ headers: new Headers({
32
+ [CONTENT_TYPE]: IMAGE_PNG,
33
+ [CONTENT_LENGTH]: String(bytes.length)
34
+ })
35
+ });
36
+
37
+ return response;
38
+ }
@@ -0,0 +1,16 @@
1
+ declare const _default: {};
2
+ export default _default;
3
+ export type ImageVariant = {
4
+ /**
5
+ * - URL of the image
6
+ */
7
+ src: string;
8
+ /**
9
+ * - Width of the image
10
+ */
11
+ width: number;
12
+ /**
13
+ * - Height of the image
14
+ */
15
+ height: number;
16
+ };
@@ -0,0 +1,10 @@
1
+ // /** @typedef {import('@hkdigital/lib-sveltekit/types/imagetools.js').ImageVariant} ImageVariant */
2
+
3
+ /**
4
+ * @typedef {Object} ImageVariant
5
+ * @property {string} src - URL of the image
6
+ * @property {number} width - Width of the image
7
+ * @property {number} height - Height of the image
8
+ */
9
+
10
+ export default {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * extends FiniteStateMachine<StatesT, EventsT>
3
+ */
4
+ export default class LoadingStateMachine extends FiniteStateMachine {
5
+ constructor();
6
+ /** @type {(( state: string )=>void)|null} */
7
+ onenter: ((state: string) => void) | null;
8
+ /** The last error */
9
+ get error(): Error;
10
+ #private;
11
+ }
12
+ import { FiniteStateMachine } from '../final-state-machine/index.js';
@@ -0,0 +1,107 @@
1
+ //import { FiniteStateMachine } from 'runed';
2
+
3
+ import { FiniteStateMachine } from '../final-state-machine/index.js';
4
+
5
+ import {
6
+ // > States
7
+ STATE_INITIAL,
8
+ STATE_LOADING,
9
+ STATE_UNLOADING,
10
+ STATE_LOADED,
11
+ STATE_CANCELLED,
12
+ STATE_ERROR,
13
+
14
+ // > Signals
15
+ INITIAL,
16
+ LOAD,
17
+ CANCEL,
18
+ ERROR,
19
+ LOADED,
20
+ UNLOAD
21
+ } from './constants.js';
22
+
23
+ /**
24
+ * extends FiniteStateMachine<StatesT, EventsT>
25
+ */
26
+ export default class LoadingStateMachine extends FiniteStateMachine {
27
+ // Inherited from parent class (getter)
28
+ // current = $state(<string>)
29
+
30
+ /** @type {Error|null} */
31
+ #error = null;
32
+
33
+ /** @type {(( state: string )=>void)|null} */
34
+ onenter = null;
35
+
36
+ constructor() {
37
+ let superCalled = false;
38
+ super(STATE_INITIAL, {
39
+ [STATE_INITIAL]: {
40
+ _enter: () => {
41
+ if (superCalled) {
42
+ this.onenter?.(STATE_INITIAL);
43
+ }
44
+ superCalled = true;
45
+ },
46
+ [LOAD]: STATE_LOADING
47
+ },
48
+ [STATE_LOADING]: {
49
+ _enter: () => {
50
+ this.onenter?.(STATE_LOADING);
51
+ },
52
+ [CANCEL]: STATE_CANCELLED,
53
+ [ERROR]: STATE_ERROR,
54
+ [LOADED]: STATE_LOADED
55
+ },
56
+ [STATE_LOADED]: {
57
+ _enter: () => {
58
+ this.onenter?.(STATE_LOADED);
59
+ },
60
+ [LOAD]: STATE_LOADING,
61
+ [UNLOAD]: STATE_UNLOADING
62
+ },
63
+ [STATE_UNLOADING]: {
64
+ _enter: () => {
65
+ this.onenter?.(STATE_UNLOADING);
66
+ },
67
+ [ERROR]: STATE_ERROR,
68
+ [INITIAL]: STATE_INITIAL
69
+ },
70
+ [STATE_CANCELLED]: {
71
+ _enter: () => {
72
+ this.onenter?.(STATE_CANCELLED);
73
+ },
74
+ [LOAD]: STATE_LOADING,
75
+ [UNLOAD]: STATE_UNLOADING
76
+ },
77
+ [STATE_ERROR]: {
78
+ _enter: ({ /*from, to, event,*/ args }) => {
79
+ if (args[0] instanceof Error) {
80
+ this.#error = args[0];
81
+ } else {
82
+ const tmp = args[0]?.error;
83
+ if (tmp instanceof Error) {
84
+ this.#error = tmp;
85
+ } else if (typeof tmp === 'string') {
86
+ this.#error = new Error(tmp);
87
+ } else {
88
+ this.#error = new Error('The state machine entered STATE_ERROR');
89
+ }
90
+ }
91
+
92
+ this.onenter?.(STATE_CANCELLED);
93
+ },
94
+ _leave: () => {
95
+ this.#error = null;
96
+ },
97
+ [LOAD]: STATE_LOADING,
98
+ [UNLOAD]: STATE_UNLOADING
99
+ }
100
+ });
101
+ }
102
+
103
+ /** The last error */
104
+ get error() {
105
+ return this.#error;
106
+ }
107
+ }
@@ -0,0 +1,12 @@
1
+ export const STATE_INITIAL: "initial";
2
+ export const STATE_LOADING: "loading";
3
+ export const STATE_UNLOADING: "unloading";
4
+ export const STATE_LOADED: "loaded";
5
+ export const STATE_CANCELLED: "cancelled";
6
+ export const STATE_ERROR: "error";
7
+ export const INITIAL: "initial";
8
+ export const LOAD: "load";
9
+ export const CANCEL: "cancel";
10
+ export const ERROR: "error";
11
+ export const LOADED: "loaded";
12
+ export const UNLOAD: "unload";
@@ -0,0 +1,16 @@
1
+ export const STATE_INITIAL = 'initial';
2
+ export const STATE_LOADING = 'loading';
3
+ export const STATE_UNLOADING = 'unloading';
4
+ export const STATE_LOADED = 'loaded';
5
+
6
+ export const STATE_CANCELLED = 'cancelled';
7
+ export const STATE_ERROR = 'error';
8
+
9
+ // > Signals
10
+
11
+ export const INITIAL = 'initial';
12
+ export const LOAD = 'load';
13
+ export const CANCEL = 'cancel';
14
+ export const ERROR = 'error';
15
+ export const LOADED = 'loaded';
16
+ export const UNLOAD = 'unload';
@@ -0,0 +1,2 @@
1
+ export { default as LoadingStateMachine } from "./LoadingStateMachine.svelte.js";
2
+ export * from "./constants.js";
@@ -0,0 +1,3 @@
1
+ export { default as LoadingStateMachine } from './LoadingStateMachine.svelte.js';
2
+
3
+ export * from './constants.js';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * NetworkLoader instance
3
+ * - Loads network data from network into an ArrayBuffer
4
+ * - Loaded data can be transferred to an AudioBufferSourceNode
5
+ */
6
+ export default class NetworkLoader {
7
+ /**
8
+ * Construct NetworkLoader
9
+ *
10
+ * @param {object} _
11
+ * @param {string} _.url
12
+ */
13
+ constructor({ url }: {
14
+ url: string;
15
+ });
16
+ _state: LoadingStateMachine;
17
+ state: string;
18
+ loaded: boolean;
19
+ /** @type {string|null} */
20
+ _url: string | null;
21
+ /** @type {number} */
22
+ _bytesLoaded: number;
23
+ /** @type {number} */
24
+ _size: number;
25
+ /**
26
+ * Response headers
27
+ * @type {Headers|null}
28
+ */
29
+ _headers: Headers | null;
30
+ /** @type {ArrayBuffer|null} */
31
+ _buffer: ArrayBuffer | null;
32
+ progress: {
33
+ bytesLoaded: number;
34
+ size: number;
35
+ loaded: boolean;
36
+ };
37
+ /** @type {null|(()=>void)} */
38
+ _abortLoading: null | (() => void);
39
+ /**
40
+ * Start loading all network data
41
+ */
42
+ load(): void;
43
+ /**
44
+ * Unoad all network data
45
+ */
46
+ unload(): void;
47
+ /**
48
+ * Get network data size in bytes
49
+ * - Info comes from the content length response header
50
+ *
51
+ * @returns {number}
52
+ */
53
+ get size(): number;
54
+ /**
55
+ * Get content type from response header
56
+ *
57
+ * @returns {string|null}
58
+ */
59
+ getContentType(): string | null;
60
+ /**
61
+ * Get data as array buffer
62
+ *
63
+ * @note If the data has been transferred, the data is
64
+ * no longer available as ArrayBuffer
65
+ *
66
+ * @returns {ArrayBuffer}
67
+ */
68
+ getArrayBuffer(): ArrayBuffer;
69
+ /**
70
+ * Get data as Uint8Array
71
+ *
72
+ * @returns {Uint8Array}
73
+ */
74
+ getUint8Array(): Uint8Array;
75
+ /**
76
+ * Get data as Blob
77
+ * - The Blob type is set using the response header
78
+ * content type
79
+ *
80
+ * @returns {Blob}
81
+ */
82
+ getBlob(): Blob;
83
+ #private;
84
+ }
85
+ import { LoadingStateMachine } from '../loading-state-machine/index.js';