@hkdigital/lib-core 0.4.59 → 0.4.61
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/dist/media/services/client/AudioService.svelte.d.ts +71 -0
- package/dist/media/services/client/AudioService.svelte.js +168 -0
- package/dist/media/services/client/ImageService.svelte.d.ts +73 -0
- package/dist/media/services/client/ImageService.svelte.js +127 -0
- package/dist/media/services/client.d.ts +1 -0
- package/dist/media/services/client.js +1 -0
- package/dist/network/loaders/base/SceneBase.svelte.js +20 -8
- package/dist/network/loaders/base/typedef.d.ts +4 -0
- package/dist/network/loaders/base/typedef.js +1 -0
- package/dist/ui/components/rows/panel-grid-row/PanelGridRow.svelte.d.ts +2 -2
- package/dist/ui/components/rows/panel-row-2/PanelRow2.svelte.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** @typedef {import('../../../network/loaders/typedef.js').SceneLoadingProgress} SceneLoadingProgress */
|
|
2
|
+
export default class AudioService extends ServiceBase {
|
|
3
|
+
/** @type {Record<string, AudioScene>} */
|
|
4
|
+
scenes: Record<string, AudioScene>;
|
|
5
|
+
muted: boolean;
|
|
6
|
+
mute(): void;
|
|
7
|
+
unmute(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Play a sound from the specified audio scene
|
|
10
|
+
*
|
|
11
|
+
* @param {string} sceneLabel
|
|
12
|
+
* @param {string} soundLabel
|
|
13
|
+
* @param {{delay?:number, loop?:boolean}} options
|
|
14
|
+
*
|
|
15
|
+
* @returns {Promise<{stop: ()=>void, sourceNode:AudioBufferSourceNode}>}
|
|
16
|
+
*/
|
|
17
|
+
playSound(sceneLabel: string, soundLabel: string, options?: {
|
|
18
|
+
delay?: number;
|
|
19
|
+
loop?: boolean;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
stop: () => void;
|
|
22
|
+
sourceNode: AudioBufferSourceNode;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Get an audio scene
|
|
26
|
+
*
|
|
27
|
+
* @param {string} sceneLabel
|
|
28
|
+
* @param {import('../../../network/loaders/typedef.js').MemorySourceParams[]} memorySources
|
|
29
|
+
*
|
|
30
|
+
* @returns {AudioScene}
|
|
31
|
+
*/
|
|
32
|
+
createScene(sceneLabel: string, memorySources: import("../../../network/loaders/typedef.js").MemorySourceParams[]): AudioScene;
|
|
33
|
+
/**
|
|
34
|
+
* Get an audio scene
|
|
35
|
+
*
|
|
36
|
+
* @param {string} label
|
|
37
|
+
*/
|
|
38
|
+
destroyScene(label: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get an audio scene
|
|
41
|
+
*
|
|
42
|
+
* @param {string} label
|
|
43
|
+
*
|
|
44
|
+
* @param {object} [options]
|
|
45
|
+
* @param {number} [options.timeoutMs=10000]
|
|
46
|
+
* Timeout in milliseconds
|
|
47
|
+
* @param {(progress: SceneLoadingProgress) => void} [options.onProgress]
|
|
48
|
+
* Progress callback function
|
|
49
|
+
*
|
|
50
|
+
* @returns {{promise: Promise<AudioScene>, abort: Function}}
|
|
51
|
+
* Object with promise that resolves when loaded and abort function
|
|
52
|
+
*/
|
|
53
|
+
preloadScene(label: string, options?: {
|
|
54
|
+
timeoutMs?: number | undefined;
|
|
55
|
+
onProgress?: ((progress: SceneLoadingProgress) => void) | undefined;
|
|
56
|
+
}): {
|
|
57
|
+
promise: Promise<AudioScene>;
|
|
58
|
+
abort: Function;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Get an audio scene
|
|
62
|
+
*
|
|
63
|
+
* @param {string} label
|
|
64
|
+
*
|
|
65
|
+
* @returns {AudioScene}
|
|
66
|
+
*/
|
|
67
|
+
getScene(label: string): AudioScene;
|
|
68
|
+
}
|
|
69
|
+
export type SceneLoadingProgress = import("../../../network/loaders/typedef.js").SceneLoadingProgress;
|
|
70
|
+
import { ServiceBase } from '../../../services/index.js';
|
|
71
|
+
import { AudioScene } from '../../../network/loaders.js';
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { ServiceBase } from '../../../services/index.js';
|
|
2
|
+
|
|
3
|
+
import { AudioScene } from '../../../network/loaders.js';
|
|
4
|
+
|
|
5
|
+
/** @typedef {import('../../../network/loaders/typedef.js').SceneLoadingProgress} SceneLoadingProgress */
|
|
6
|
+
|
|
7
|
+
export default class AudioService extends ServiceBase {
|
|
8
|
+
/** @type {Record<string, AudioScene>} */
|
|
9
|
+
scenes = {};
|
|
10
|
+
|
|
11
|
+
muted = $state(false);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configure the service (handles both initial config and reconfiguration)
|
|
15
|
+
*
|
|
16
|
+
* @param {any} newConfig - Configuration to apply
|
|
17
|
+
* @param {any} [oldConfig=null] - Previous config (null = initial setup)
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line no-unused-vars
|
|
20
|
+
async _configure(newConfig, oldConfig) {
|
|
21
|
+
// console.debug('Configure AudioService');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
mute() {
|
|
25
|
+
//this.logger.debug('mute all');
|
|
26
|
+
|
|
27
|
+
for (const label in this.scenes) {
|
|
28
|
+
const scene = this.scenes[label];
|
|
29
|
+
scene.mute();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.muted = true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
unmute() {
|
|
36
|
+
// this.logger.debug('unmute all');
|
|
37
|
+
|
|
38
|
+
for (const label in this.scenes) {
|
|
39
|
+
const scene = this.scenes[label];
|
|
40
|
+
scene.unmute();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.muted = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Play a sound from the specified audio scene
|
|
48
|
+
*
|
|
49
|
+
* @param {string} sceneLabel
|
|
50
|
+
* @param {string} soundLabel
|
|
51
|
+
* @param {{delay?:number, loop?:boolean}} options
|
|
52
|
+
*
|
|
53
|
+
* @returns {Promise<{stop: ()=>void, sourceNode:AudioBufferSourceNode}>}
|
|
54
|
+
*/
|
|
55
|
+
async playSound(sceneLabel, soundLabel, options = {}) {
|
|
56
|
+
const audioScene = await this.getScene(sceneLabel);
|
|
57
|
+
|
|
58
|
+
const sourceNode = await audioScene.getSourceNode(soundLabel);
|
|
59
|
+
|
|
60
|
+
const { delay = 0, loop = false } = options;
|
|
61
|
+
|
|
62
|
+
sourceNode.loop = loop;
|
|
63
|
+
|
|
64
|
+
let started = false;
|
|
65
|
+
|
|
66
|
+
/** @type {ReturnType<typeof setTimeout>|null} */
|
|
67
|
+
let timer = setTimeout(() => {
|
|
68
|
+
// console.debug('playSound', soundLabel);
|
|
69
|
+
sourceNode.start();
|
|
70
|
+
started = true;
|
|
71
|
+
}, delay);
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
stop: () => {
|
|
75
|
+
if (timer) {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
timer = null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (started) {
|
|
81
|
+
sourceNode.stop();
|
|
82
|
+
started = false;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
sourceNode
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get an audio scene
|
|
91
|
+
*
|
|
92
|
+
* @param {string} sceneLabel
|
|
93
|
+
* @param {import('../../../network/loaders/typedef.js').MemorySourceParams[]} memorySources
|
|
94
|
+
*
|
|
95
|
+
* @returns {AudioScene}
|
|
96
|
+
*/
|
|
97
|
+
createScene(sceneLabel, memorySources) {
|
|
98
|
+
let audioScene = this.scenes[sceneLabel];
|
|
99
|
+
|
|
100
|
+
if (audioScene) {
|
|
101
|
+
// Scene already created
|
|
102
|
+
// => Do nothing
|
|
103
|
+
return audioScene;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
audioScene = new AudioScene();
|
|
107
|
+
|
|
108
|
+
for (const memorySource of memorySources) {
|
|
109
|
+
audioScene.defineMemorySource(memorySource);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.scenes[sceneLabel] = audioScene;
|
|
113
|
+
|
|
114
|
+
return audioScene;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get an audio scene
|
|
119
|
+
*
|
|
120
|
+
* @param {string} label
|
|
121
|
+
*/
|
|
122
|
+
destroyScene(label) {
|
|
123
|
+
const scene = this.scenes[label];
|
|
124
|
+
|
|
125
|
+
if (scene) {
|
|
126
|
+
scene.destroy();
|
|
127
|
+
delete this.scenes[label];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get an audio scene
|
|
133
|
+
*
|
|
134
|
+
* @param {string} label
|
|
135
|
+
*
|
|
136
|
+
* @param {object} [options]
|
|
137
|
+
* @param {number} [options.timeoutMs=10000]
|
|
138
|
+
* Timeout in milliseconds
|
|
139
|
+
* @param {(progress: SceneLoadingProgress) => void} [options.onProgress]
|
|
140
|
+
* Progress callback function
|
|
141
|
+
*
|
|
142
|
+
* @returns {{promise: Promise<AudioScene>, abort: Function}}
|
|
143
|
+
* Object with promise that resolves when loaded and abort function
|
|
144
|
+
*/
|
|
145
|
+
preloadScene(label, options) {
|
|
146
|
+
const audioScene = this.getScene(label);
|
|
147
|
+
|
|
148
|
+
// @ts-ignore (AudioScene extends SceneBase)
|
|
149
|
+
return audioScene.preload(options);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get an audio scene
|
|
154
|
+
*
|
|
155
|
+
* @param {string} label
|
|
156
|
+
*
|
|
157
|
+
* @returns {AudioScene}
|
|
158
|
+
*/
|
|
159
|
+
getScene(label) {
|
|
160
|
+
const audioScene = this.scenes[label];
|
|
161
|
+
|
|
162
|
+
if (!audioScene) {
|
|
163
|
+
throw new Error(`AudioScene [${label}] not found`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return audioScene;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** @typedef {import('../../../network/loaders/typedef.js').SceneLoadingProgress} SceneLoadingProgress */
|
|
2
|
+
export default class ImageService extends ServiceBase {
|
|
3
|
+
/** @type {Record<string, ImageScene>} */
|
|
4
|
+
scenes: Record<string, ImageScene>;
|
|
5
|
+
/**
|
|
6
|
+
* Get an image from the specified image scene
|
|
7
|
+
*
|
|
8
|
+
* @param {string} sceneLabel
|
|
9
|
+
* @param {string} imageLabel
|
|
10
|
+
*
|
|
11
|
+
* @returns {string} Object URL for the image
|
|
12
|
+
*/
|
|
13
|
+
getObjectURL(sceneLabel: string, imageLabel: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get image metadata from the specified image scene
|
|
16
|
+
*
|
|
17
|
+
* @param {string} sceneLabel
|
|
18
|
+
* @param {string} imageLabel
|
|
19
|
+
*
|
|
20
|
+
* @returns {import('../../../network/loaders/image/typedef.js').ImageMeta}
|
|
21
|
+
*/
|
|
22
|
+
getImageMeta(sceneLabel: string, imageLabel: string): import("../../../network/loaders/image/typedef.js").ImageMeta;
|
|
23
|
+
/**
|
|
24
|
+
* Create an image scene
|
|
25
|
+
*
|
|
26
|
+
* @param {string} sceneLabel
|
|
27
|
+
* @param {Array<{label: string, imageSource: import('../../../config/typedef.js').ImageSource}>} imageSources
|
|
28
|
+
*
|
|
29
|
+
* @returns {ImageScene}
|
|
30
|
+
*/
|
|
31
|
+
createScene(sceneLabel: string, imageSources: Array<{
|
|
32
|
+
label: string;
|
|
33
|
+
imageSource: import("../../../config/typedef.js").ImageSource;
|
|
34
|
+
}>): ImageScene;
|
|
35
|
+
/**
|
|
36
|
+
* Destroy an image scene
|
|
37
|
+
*
|
|
38
|
+
* @param {string} label
|
|
39
|
+
*/
|
|
40
|
+
destroyScene(label: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get an image scene
|
|
43
|
+
*
|
|
44
|
+
* @param {string} label
|
|
45
|
+
*
|
|
46
|
+
* @param {object} [options]
|
|
47
|
+
* @param {number} [options.timeoutMs=10000]
|
|
48
|
+
* Timeout in milliseconds
|
|
49
|
+
* @param {(progress: SceneLoadingProgress) => void} [options.onProgress]
|
|
50
|
+
* Progress callback function
|
|
51
|
+
*
|
|
52
|
+
* @returns {{promise: Promise<ImageScene>, abort: Function}}
|
|
53
|
+
* Object with promise that resolves when loaded and abort function
|
|
54
|
+
*/
|
|
55
|
+
preloadScene(label: string, options?: {
|
|
56
|
+
timeoutMs?: number | undefined;
|
|
57
|
+
onProgress?: ((progress: SceneLoadingProgress) => void) | undefined;
|
|
58
|
+
}): {
|
|
59
|
+
promise: Promise<ImageScene>;
|
|
60
|
+
abort: Function;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Get an image scene
|
|
64
|
+
*
|
|
65
|
+
* @param {string} label
|
|
66
|
+
*
|
|
67
|
+
* @returns {ImageScene}
|
|
68
|
+
*/
|
|
69
|
+
getScene(label: string): ImageScene;
|
|
70
|
+
}
|
|
71
|
+
export type SceneLoadingProgress = import("../../../network/loaders/typedef.js").SceneLoadingProgress;
|
|
72
|
+
import { ServiceBase } from '../../../services/index.js';
|
|
73
|
+
import { ImageScene } from '../../../network/loaders.js';
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ServiceBase } from '../../../services/index.js';
|
|
2
|
+
|
|
3
|
+
import { ImageScene } from '../../../network/loaders.js';
|
|
4
|
+
|
|
5
|
+
/** @typedef {import('../../../network/loaders/typedef.js').SceneLoadingProgress} SceneLoadingProgress */
|
|
6
|
+
|
|
7
|
+
export default class ImageService extends ServiceBase {
|
|
8
|
+
/** @type {Record<string, ImageScene>} */
|
|
9
|
+
scenes = {};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configure the service (handles both initial config and reconfiguration)
|
|
13
|
+
*
|
|
14
|
+
* @param {any} newConfig - Configuration to apply
|
|
15
|
+
* @param {any} [oldConfig=null] - Previous config (null = initial setup)
|
|
16
|
+
*/
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
async _configure(newConfig, oldConfig) {
|
|
19
|
+
// console.debug('Configure ImageService');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get an image from the specified image scene
|
|
24
|
+
*
|
|
25
|
+
* @param {string} sceneLabel
|
|
26
|
+
* @param {string} imageLabel
|
|
27
|
+
*
|
|
28
|
+
* @returns {string} Object URL for the image
|
|
29
|
+
*/
|
|
30
|
+
getObjectURL(sceneLabel, imageLabel) {
|
|
31
|
+
const imageScene = this.getScene(sceneLabel);
|
|
32
|
+
return imageScene.getObjectURL(imageLabel);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get image metadata from the specified image scene
|
|
37
|
+
*
|
|
38
|
+
* @param {string} sceneLabel
|
|
39
|
+
* @param {string} imageLabel
|
|
40
|
+
*
|
|
41
|
+
* @returns {import('../../../network/loaders/image/typedef.js').ImageMeta}
|
|
42
|
+
*/
|
|
43
|
+
getImageMeta(sceneLabel, imageLabel) {
|
|
44
|
+
const imageScene = this.getScene(sceneLabel);
|
|
45
|
+
return imageScene.getImageMeta(imageLabel);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create an image scene
|
|
50
|
+
*
|
|
51
|
+
* @param {string} sceneLabel
|
|
52
|
+
* @param {Array<{label: string, imageSource: import('../../../config/typedef.js').ImageSource}>} imageSources
|
|
53
|
+
*
|
|
54
|
+
* @returns {ImageScene}
|
|
55
|
+
*/
|
|
56
|
+
createScene(sceneLabel, imageSources) {
|
|
57
|
+
let imageScene = this.scenes[sceneLabel];
|
|
58
|
+
|
|
59
|
+
if (imageScene) {
|
|
60
|
+
// Scene already created
|
|
61
|
+
// => Do nothing
|
|
62
|
+
return imageScene;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
imageScene = new ImageScene();
|
|
66
|
+
|
|
67
|
+
for (const imageSource of imageSources) {
|
|
68
|
+
imageScene.defineImage(imageSource);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.scenes[sceneLabel] = imageScene;
|
|
72
|
+
|
|
73
|
+
return imageScene;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Destroy an image scene
|
|
78
|
+
*
|
|
79
|
+
* @param {string} label
|
|
80
|
+
*/
|
|
81
|
+
destroyScene(label) {
|
|
82
|
+
const scene = this.scenes[label];
|
|
83
|
+
|
|
84
|
+
if (scene) {
|
|
85
|
+
scene.destroy();
|
|
86
|
+
delete this.scenes[label];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get an image scene
|
|
92
|
+
*
|
|
93
|
+
* @param {string} label
|
|
94
|
+
*
|
|
95
|
+
* @param {object} [options]
|
|
96
|
+
* @param {number} [options.timeoutMs=10000]
|
|
97
|
+
* Timeout in milliseconds
|
|
98
|
+
* @param {(progress: SceneLoadingProgress) => void} [options.onProgress]
|
|
99
|
+
* Progress callback function
|
|
100
|
+
*
|
|
101
|
+
* @returns {{promise: Promise<ImageScene>, abort: Function}}
|
|
102
|
+
* Object with promise that resolves when loaded and abort function
|
|
103
|
+
*/
|
|
104
|
+
preloadScene(label, options) {
|
|
105
|
+
const imageScene = this.getScene(label);
|
|
106
|
+
|
|
107
|
+
// @ts-ignore (ImageScene extends SceneBase)
|
|
108
|
+
return imageScene.preload(options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get an image scene
|
|
113
|
+
*
|
|
114
|
+
* @param {string} label
|
|
115
|
+
*
|
|
116
|
+
* @returns {ImageScene}
|
|
117
|
+
*/
|
|
118
|
+
getScene(label) {
|
|
119
|
+
const imageScene = this.scenes[label];
|
|
120
|
+
|
|
121
|
+
if (!imageScene) {
|
|
122
|
+
throw new Error(`ImageScene [${label}] not found`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return imageScene;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as AudioService } from "./client/AudioService.svelte.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as AudioService } from './client/AudioService.svelte.js';
|
|
@@ -64,11 +64,24 @@ export default class SceneBase {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
let percentageLoaded;
|
|
68
|
+
if (totalSize > 0) {
|
|
69
|
+
// Byte-based progress
|
|
70
|
+
percentageLoaded = Math.round((totalBytesLoaded / totalSize) * 100);
|
|
71
|
+
} else if (numberOfSources > 0) {
|
|
72
|
+
// Source-based progress
|
|
73
|
+
percentageLoaded = Math.round((sourcesLoaded / numberOfSources) * 100);
|
|
74
|
+
} else {
|
|
75
|
+
// No sources to load
|
|
76
|
+
percentageLoaded = 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
return {
|
|
68
80
|
totalBytesLoaded,
|
|
69
81
|
totalSize,
|
|
70
82
|
sourcesLoaded,
|
|
71
|
-
numberOfSources
|
|
83
|
+
numberOfSources,
|
|
84
|
+
percentageLoaded
|
|
72
85
|
};
|
|
73
86
|
});
|
|
74
87
|
|
|
@@ -201,7 +214,7 @@ export default class SceneBase {
|
|
|
201
214
|
// Set up progress tracking with polling
|
|
202
215
|
if (onProgress) {
|
|
203
216
|
progressIntervalId = setInterval(() => {
|
|
204
|
-
if (!isAborted) {
|
|
217
|
+
if (!isAborted && this.state === STATE_LOADING) {
|
|
205
218
|
const currentProgress = this.progress;
|
|
206
219
|
lastSentProgress = currentProgress;
|
|
207
220
|
onProgress(currentProgress);
|
|
@@ -234,17 +247,16 @@ export default class SceneBase {
|
|
|
234
247
|
}
|
|
235
248
|
|
|
236
249
|
if (progressIntervalId) {
|
|
250
|
+
clearInterval(progressIntervalId);
|
|
251
|
+
progressIntervalId = null;
|
|
252
|
+
|
|
237
253
|
if (onProgress) {
|
|
238
254
|
const finalProgress = this.progress;
|
|
239
|
-
//
|
|
240
|
-
if (
|
|
241
|
-
finalProgress.sourcesLoaded !== lastSentProgress.sourcesLoaded ||
|
|
242
|
-
finalProgress.totalBytesLoaded !== lastSentProgress.totalBytesLoaded) {
|
|
255
|
+
// Always send final progress when loading completes
|
|
256
|
+
if (this.loaded) {
|
|
243
257
|
onProgress(finalProgress);
|
|
244
258
|
}
|
|
245
259
|
}
|
|
246
|
-
clearInterval(progressIntervalId);
|
|
247
|
-
progressIntervalId = null;
|
|
248
260
|
}
|
|
249
261
|
|
|
250
262
|
if (isAborted || this.state === STATE_ABORTED) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @property {number} totalSize - Total size across all sources
|
|
5
5
|
* @property {number} sourcesLoaded - Number of sources fully loaded
|
|
6
6
|
* @property {number} numberOfSources - Total number of sources
|
|
7
|
+
* @property {number} percentageLoaded - Loading percentage (0-100)
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
export default {};
|
|
@@ -4,8 +4,8 @@ type PanelGridRow = {
|
|
|
4
4
|
$set?(props: Partial<{
|
|
5
5
|
base?: string | undefined;
|
|
6
6
|
bg?: string | undefined;
|
|
7
|
-
justify?: "normal" | "
|
|
8
|
-
justifyItems?: "
|
|
7
|
+
justify?: "normal" | "start" | "center" | "end" | "between" | "around" | "evenly" | "stretch" | undefined;
|
|
8
|
+
justifyItems?: "start" | "center" | "end" | "stretch" | undefined;
|
|
9
9
|
gap?: string | undefined;
|
|
10
10
|
classes?: string | undefined;
|
|
11
11
|
children?: Snippet<[]> | undefined;
|
|
@@ -4,8 +4,8 @@ type PanelRow2 = {
|
|
|
4
4
|
$set?(props: Partial<{
|
|
5
5
|
base?: string | undefined;
|
|
6
6
|
bg?: string | undefined;
|
|
7
|
-
justify?: "normal" | "
|
|
8
|
-
justifyItems?: "
|
|
7
|
+
justify?: "normal" | "start" | "center" | "end" | "between" | "around" | "evenly" | "stretch" | undefined;
|
|
8
|
+
justifyItems?: "start" | "center" | "end" | "stretch" | undefined;
|
|
9
9
|
gap?: string | undefined;
|
|
10
10
|
classes?: string | undefined;
|
|
11
11
|
children?: Snippet<[]> | undefined;
|