@hkdigital/lib-sveltekit 0.2.2 → 0.2.3
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/classes/svelte/audio/AudioScene.svelte.js +2 -6
- package/dist/classes/svelte/image/ImageLoader.svelte.js +1 -3
- package/dist/classes/svelte/image/ImageScene.svelte.js +2 -6
- package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +1 -2
- package/package.json +1 -1
- package/dist/features/presenter/(broken) Presenter.state.svelte.js__ +0 -613
- package/dist/features/presenter/Presenter.svelte__ +0 -125
@@ -9,12 +9,8 @@ import {
|
|
9
9
|
STATE_CANCELLED,
|
10
10
|
STATE_ERROR,
|
11
11
|
LOAD,
|
12
|
-
|
13
|
-
|
14
|
-
LOADED,
|
15
|
-
UNLOAD,
|
16
|
-
INITIAL
|
17
|
-
} from '$lib/classes/svelte/loading-state-machine/index.js';
|
12
|
+
LOADED
|
13
|
+
} from '../loading-state-machine/index.js';
|
18
14
|
|
19
15
|
import AudioLoader from './AudioLoader.svelte.js';
|
20
16
|
|
@@ -4,9 +4,7 @@ import { toSingleImageMeta } from '../../../util/image/index.js';
|
|
4
4
|
|
5
5
|
import {
|
6
6
|
NetworkLoader
|
7
|
-
|
8
|
-
// ERROR_TRANSFERRED
|
9
|
-
} from '$lib/classes/svelte/network-loader/index.js';
|
7
|
+
} from '../network-loader/index.js';
|
10
8
|
|
11
9
|
/**
|
12
10
|
* ImageLoader instance
|
@@ -11,12 +11,8 @@ import {
|
|
11
11
|
STATE_CANCELLED,
|
12
12
|
STATE_ERROR,
|
13
13
|
LOAD,
|
14
|
-
|
15
|
-
|
16
|
-
LOADED,
|
17
|
-
UNLOAD,
|
18
|
-
INITIAL
|
19
|
-
} from '$lib/classes/svelte/loading-state-machine/index.js';
|
14
|
+
LOADED
|
15
|
+
} from '../loading-state-machine/index.js';
|
20
16
|
|
21
17
|
import ImageLoader from './ImageLoader.svelte.js';
|
22
18
|
|
@@ -9,12 +9,11 @@ import {
|
|
9
9
|
STATE_CANCELLED,
|
10
10
|
STATE_ERROR,
|
11
11
|
LOAD,
|
12
|
-
// CANCEL,
|
13
12
|
ERROR,
|
14
13
|
LOADED,
|
15
14
|
UNLOAD,
|
16
15
|
INITIAL
|
17
|
-
} from '
|
16
|
+
} from '../loading-state-machine/index.js';
|
18
17
|
|
19
18
|
import * as expect from '../../../util/expect/index.js';
|
20
19
|
|
package/package.json
CHANGED
@@ -1,613 +0,0 @@
|
|
1
|
-
import { defineStateContext } from '$lib/util/svelte/state-context/index.js';
|
2
|
-
|
3
|
-
import { findFirst } from '$lib/util/array/index.js';
|
4
|
-
|
5
|
-
import { untrack } from 'svelte';
|
6
|
-
|
7
|
-
import { HkPromise } from '$lib/classes/promise/index.js';
|
8
|
-
|
9
|
-
/* ----------------------------------------------------------------- typedefs */
|
10
|
-
|
11
|
-
/**
|
12
|
-
* @typedef {import("./typedef").Slide} Slide
|
13
|
-
*/
|
14
|
-
|
15
|
-
/**
|
16
|
-
* @typedef {import("./typedef").Transition} Transition
|
17
|
-
*/
|
18
|
-
|
19
|
-
/**
|
20
|
-
* @typedef {import("./typedef").Layer} Layer
|
21
|
-
*/
|
22
|
-
|
23
|
-
/**
|
24
|
-
* @typedef {Object} LoadController
|
25
|
-
* @property {() => void} loaded - Function to call when loading is complete
|
26
|
-
* @property {() => void} cancel - Function to return to the previous slide
|
27
|
-
*/
|
28
|
-
|
29
|
-
/**
|
30
|
-
* @typedef {Object} PresenterRef
|
31
|
-
* @property {(name: string) => void} gotoSlide - Navigate to a slide by name
|
32
|
-
* @property {() => string} getCurrentSlideName - Get the current slide name
|
33
|
-
*/
|
34
|
-
|
35
|
-
/* -------------------------------------------------------------- Constants */
|
36
|
-
|
37
|
-
const Z_BACK = 0;
|
38
|
-
const Z_FRONT = 10;
|
39
|
-
|
40
|
-
const LABEL_A = 'A';
|
41
|
-
const LABEL_B = 'B';
|
42
|
-
|
43
|
-
/* ------------------------------------------------------- Define state class */
|
44
|
-
|
45
|
-
export class PresenterState {
|
46
|
-
/** @type {Slide[]} */
|
47
|
-
slides = $state.raw([]);
|
48
|
-
|
49
|
-
/** @type {Layer} */
|
50
|
-
layerA = $state.raw({ z: Z_BACK, visible: false, stageIdle: true });
|
51
|
-
|
52
|
-
/** @type {Layer} */
|
53
|
-
layerB = $state.raw({ z: Z_FRONT, visible: false, stageIdle: true });
|
54
|
-
|
55
|
-
/** @type {Slide|null} */
|
56
|
-
slideA = $state.raw(null);
|
57
|
-
|
58
|
-
/** @type {Slide|null} */
|
59
|
-
slideB = $state.raw(null);
|
60
|
-
|
61
|
-
/** @type {string} */
|
62
|
-
currentLayerLabel = $state(LABEL_B);
|
63
|
-
|
64
|
-
/** @type {string} */
|
65
|
-
nextLayerLabel = $state(LABEL_A);
|
66
|
-
|
67
|
-
/** @type {HkPromise[]} */
|
68
|
-
transitionPromises = $state.raw([]);
|
69
|
-
|
70
|
-
/** @type {boolean} */
|
71
|
-
isSlideLoading = $state(false);
|
72
|
-
|
73
|
-
/** @type {boolean} */
|
74
|
-
controllerRequested = $state(false);
|
75
|
-
|
76
|
-
/** @type {number} Loading timeout in milliseconds (0 = disabled) */
|
77
|
-
loadingTimeout = $state(1000);
|
78
|
-
|
79
|
-
/** @type {boolean} */
|
80
|
-
busy = $derived.by(() => {
|
81
|
-
const { layerA, layerB } = this;
|
82
|
-
|
83
|
-
const layerAStable =
|
84
|
-
layerA.stageShow || layerA.stageAfter || layerA.stageIdle;
|
85
|
-
|
86
|
-
const layerBStable =
|
87
|
-
layerB.stageShow || layerB.stageAfter || layerB.stageIdle;
|
88
|
-
|
89
|
-
return !(layerAStable && layerBStable);
|
90
|
-
});
|
91
|
-
|
92
|
-
/** @type {string} */
|
93
|
-
currentSlideName = $derived.by(() => {
|
94
|
-
const currentSlide = this.#getSlide(this.currentLayerLabel);
|
95
|
-
return currentSlide?.name || '';
|
96
|
-
});
|
97
|
-
|
98
|
-
/**
|
99
|
-
* Initialize the presenter state and set up reactivity
|
100
|
-
*/
|
101
|
-
constructor() {
|
102
|
-
this.#setupStageTransitions();
|
103
|
-
this.#setupTransitionTracking();
|
104
|
-
this.#setupLoadingTransitions();
|
105
|
-
}
|
106
|
-
|
107
|
-
/**
|
108
|
-
* Returns a simplified presenter reference with essential methods
|
109
|
-
* for slide components to use
|
110
|
-
*
|
111
|
-
* @returns {PresenterRef} A reference object with presenter methods
|
112
|
-
*/
|
113
|
-
getPresenterRef() {
|
114
|
-
return {
|
115
|
-
gotoSlide: (name) => this.gotoSlide(name),
|
116
|
-
getCurrentSlideName: () => this.currentSlideName
|
117
|
-
};
|
118
|
-
}
|
119
|
-
|
120
|
-
/**
|
121
|
-
* Set up reactivity for stage transitions between the before/after states
|
122
|
-
* This handles the animation timing for both layers
|
123
|
-
*/
|
124
|
-
#setupStageTransitions() {
|
125
|
-
// Handle layer A stage transitions
|
126
|
-
$effect(() => {
|
127
|
-
if (this.layerA.stageBeforeIn || this.layerA.stageBeforeOut) {
|
128
|
-
this.layerA = this.#processStageTransition(this.layerA);
|
129
|
-
}
|
130
|
-
});
|
131
|
-
|
132
|
-
// Handle layer B stage transitions
|
133
|
-
$effect(() => {
|
134
|
-
if (this.layerB.stageBeforeIn || this.layerB.stageBeforeOut) {
|
135
|
-
this.layerB = this.#processStageTransition(this.layerB);
|
136
|
-
}
|
137
|
-
});
|
138
|
-
}
|
139
|
-
|
140
|
-
/**
|
141
|
-
* Process a single stage transition for a layer
|
142
|
-
*
|
143
|
-
* @param {Layer} layer - The layer to process
|
144
|
-
* @returns {Layer} - The updated layer with new stage
|
145
|
-
*/
|
146
|
-
#processStageTransition(layer) {
|
147
|
-
const updatedLayer = { ...layer };
|
148
|
-
|
149
|
-
if (updatedLayer.stageBeforeIn) {
|
150
|
-
delete updatedLayer.stageBeforeIn;
|
151
|
-
updatedLayer.stageIn = true;
|
152
|
-
} else if (updatedLayer.stageBeforeOut) {
|
153
|
-
delete updatedLayer.stageBeforeOut;
|
154
|
-
updatedLayer.stageOut = true;
|
155
|
-
}
|
156
|
-
|
157
|
-
return updatedLayer;
|
158
|
-
}
|
159
|
-
|
160
|
-
/**
|
161
|
-
* Set up reactivity for tracking transition promises
|
162
|
-
* This handles the completion of animations and layer swapping
|
163
|
-
*/
|
164
|
-
#setupTransitionTracking() {
|
165
|
-
$effect(() => {
|
166
|
-
const promises = this.transitionPromises;
|
167
|
-
|
168
|
-
if (promises.length > 0) {
|
169
|
-
const nextSlide = this.#getSlide(this.nextLayerLabel);
|
170
|
-
|
171
|
-
if (!nextSlide) {
|
172
|
-
return;
|
173
|
-
}
|
174
|
-
|
175
|
-
untrack(() => {
|
176
|
-
this.#executeTransition(promises);
|
177
|
-
});
|
178
|
-
}
|
179
|
-
});
|
180
|
-
}
|
181
|
-
|
182
|
-
/**
|
183
|
-
* Set up reactivity to start transitions after component loading is complete
|
184
|
-
*/
|
185
|
-
#setupLoadingTransitions() {
|
186
|
-
$effect(() => {
|
187
|
-
// Only start transitions when loading is complete and we have a next slide
|
188
|
-
if (!this.isSlideLoading && this.#getSlide(this.nextLayerLabel)) {
|
189
|
-
const currentSlide = this.#getSlide(this.currentLayerLabel);
|
190
|
-
const nextSlide = this.#getSlide(this.nextLayerLabel);
|
191
|
-
|
192
|
-
// Prepare the next layer for its entrance transition
|
193
|
-
this.#updateLayer(this.nextLayerLabel, {
|
194
|
-
z: Z_FRONT,
|
195
|
-
visible: true,
|
196
|
-
stageBeforeIn: true,
|
197
|
-
transitions: nextSlide?.intro ?? []
|
198
|
-
});
|
199
|
-
|
200
|
-
// Prepare the current layer for its exit transition
|
201
|
-
this.#updateLayer(this.currentLayerLabel, {
|
202
|
-
z: Z_BACK,
|
203
|
-
visible: true,
|
204
|
-
stageBeforeOut: true,
|
205
|
-
transitions: currentSlide?.outro ?? []
|
206
|
-
});
|
207
|
-
|
208
|
-
// Start transitions
|
209
|
-
this.#applyTransitions();
|
210
|
-
}
|
211
|
-
});
|
212
|
-
}
|
213
|
-
|
214
|
-
/**
|
215
|
-
* Execute the transition by waiting for all promises and then
|
216
|
-
* completing the transition
|
217
|
-
*
|
218
|
-
* @param {HkPromise[]} promises - Array of transition promises to wait for
|
219
|
-
*/
|
220
|
-
async #executeTransition(promises) {
|
221
|
-
try {
|
222
|
-
await Promise.allSettled(promises);
|
223
|
-
|
224
|
-
untrack(() => {
|
225
|
-
this.#completeTransition();
|
226
|
-
});
|
227
|
-
} catch (error) {
|
228
|
-
console.log('transition promises cancelled', error);
|
229
|
-
}
|
230
|
-
}
|
231
|
-
|
232
|
-
/**
|
233
|
-
* Complete the transition by updating layers and swapping them
|
234
|
-
*/
|
235
|
-
#completeTransition() {
|
236
|
-
// Hide current layer and set stage to AFTER
|
237
|
-
this.#updateLayer(this.currentLayerLabel, {
|
238
|
-
z: Z_BACK,
|
239
|
-
visible: false,
|
240
|
-
stageAfter: true
|
241
|
-
});
|
242
|
-
|
243
|
-
// Set next layer stage to SHOW
|
244
|
-
this.#updateLayer(this.nextLayerLabel, {
|
245
|
-
z: Z_FRONT,
|
246
|
-
visible: true,
|
247
|
-
stageShow: true
|
248
|
-
});
|
249
|
-
|
250
|
-
// Remove slide from current layer
|
251
|
-
this.#updateSlide(this.currentLayerLabel, null);
|
252
|
-
|
253
|
-
// Swap current and next layer labels
|
254
|
-
this.#swapLayers();
|
255
|
-
}
|
256
|
-
|
257
|
-
// /**
|
258
|
-
// * Complete the transition by updating layers and swapping them
|
259
|
-
// * Ensures proper cleanup of all stage states
|
260
|
-
// */
|
261
|
-
// #completeTransition() {
|
262
|
-
// // Update current layer: hide it and set to AFTER state
|
263
|
-
// this.#updateLayer(this.currentLayerLabel, {
|
264
|
-
// z: Z_BACK,
|
265
|
-
// visible: false,
|
266
|
-
// stageIdle: false,
|
267
|
-
// stageBeforeIn: false,
|
268
|
-
// stageIn: false,
|
269
|
-
// stageBeforeOut: false,
|
270
|
-
// stageOut: false,
|
271
|
-
// stageShow: false,
|
272
|
-
// stageAfter: true
|
273
|
-
// });
|
274
|
-
|
275
|
-
// // Update next layer: show it and set to SHOW state
|
276
|
-
// this.#updateLayer(this.nextLayerLabel, {
|
277
|
-
// z: Z_FRONT,
|
278
|
-
// visible: true,
|
279
|
-
// stageIdle: false,
|
280
|
-
// stageBeforeIn: false,
|
281
|
-
// stageIn: false,
|
282
|
-
// stageBeforeOut: false,
|
283
|
-
// stageOut: false,
|
284
|
-
// stageAfter: false,
|
285
|
-
// stageShow: true
|
286
|
-
// });
|
287
|
-
|
288
|
-
// // Remove slide from current layer
|
289
|
-
// this.#updateSlide(this.currentLayerLabel, null);
|
290
|
-
|
291
|
-
// // Swap current and next layer labels
|
292
|
-
// this.#swapLayers();
|
293
|
-
|
294
|
-
// // Reset layer states after swap - crucial for next transition cycle
|
295
|
-
// // Reset former next layer (now current) to idle after showing
|
296
|
-
// setTimeout(() => {
|
297
|
-
// this.#updateLayer(this.currentLayerLabel, {
|
298
|
-
// stageShow: false,
|
299
|
-
// stageIdle: true,
|
300
|
-
// transitions: [] // Clear any lingering transitions
|
301
|
-
// });
|
302
|
-
|
303
|
-
// // Reset former current layer (now next) to idle after being hidden
|
304
|
-
// this.#updateLayer(this.nextLayerLabel, {
|
305
|
-
// stageAfter: false,
|
306
|
-
// stageIdle: true,
|
307
|
-
// transitions: [] // Clear any lingering transitions
|
308
|
-
// });
|
309
|
-
// }, 50); // Small delay to ensure DOM updates have completed
|
310
|
-
// }
|
311
|
-
|
312
|
-
/**
|
313
|
-
* Swap the current and next layer labels
|
314
|
-
*/
|
315
|
-
#swapLayers() {
|
316
|
-
if (this.currentLayerLabel === LABEL_A) {
|
317
|
-
this.currentLayerLabel = LABEL_B;
|
318
|
-
this.nextLayerLabel = LABEL_A;
|
319
|
-
} else {
|
320
|
-
this.currentLayerLabel = LABEL_A;
|
321
|
-
this.nextLayerLabel = LABEL_B;
|
322
|
-
}
|
323
|
-
}
|
324
|
-
|
325
|
-
/**
|
326
|
-
* Mark the slide as loaded, which triggers transitions to begin
|
327
|
-
*/
|
328
|
-
finishSlideLoading() {
|
329
|
-
this.isSlideLoading = false;
|
330
|
-
}
|
331
|
-
|
332
|
-
/**
|
333
|
-
* Returns a controller object for managing manual loading
|
334
|
-
* Components can use this to signal when they're done loading
|
335
|
-
* or to cancel and go back to the previous slide
|
336
|
-
*
|
337
|
-
* @returns {LoadController} Object with loaded() and cancel() methods
|
338
|
-
*/
|
339
|
-
getLoadingController() {
|
340
|
-
// Mark that the controller was requested
|
341
|
-
this.controllerRequested = true;
|
342
|
-
|
343
|
-
console.debug('controllerRequested');
|
344
|
-
|
345
|
-
return {
|
346
|
-
/**
|
347
|
-
* Call when component has finished loading
|
348
|
-
*/
|
349
|
-
loaded: () => {
|
350
|
-
this.finishSlideLoading();
|
351
|
-
console.debug('finishSlideLoading');
|
352
|
-
},
|
353
|
-
|
354
|
-
/**
|
355
|
-
* Call to cancel loading and return to previous slide
|
356
|
-
*/
|
357
|
-
cancel: () => {
|
358
|
-
// Return to previous slide if available
|
359
|
-
const currentSlideName = this.currentSlideName;
|
360
|
-
if (currentSlideName) {
|
361
|
-
this.gotoSlide(currentSlideName);
|
362
|
-
} else if (this.slides.length > 0) {
|
363
|
-
// Fallback to first slide if no current slide
|
364
|
-
this.gotoSlide(this.slides[0].name);
|
365
|
-
}
|
366
|
-
}
|
367
|
-
};
|
368
|
-
}
|
369
|
-
|
370
|
-
/**
|
371
|
-
* Configure the presentation
|
372
|
-
*
|
373
|
-
* @param {object} _
|
374
|
-
* @param {boolean} [_.autostart=false] - Whether to start automatically
|
375
|
-
* @param {string} [_.startSlide] - Name of the slide to start with
|
376
|
-
* @param {Slide[]} [_.slides] - Array of slides for the presentation
|
377
|
-
*/
|
378
|
-
configure({ slides, autostart = true, startSlide }) {
|
379
|
-
untrack(() => {
|
380
|
-
if (slides) {
|
381
|
-
// Only update slides if provided
|
382
|
-
this.slides = slides;
|
383
|
-
}
|
384
|
-
|
385
|
-
if ((autostart || startSlide) && this.slides?.length) {
|
386
|
-
if (startSlide) {
|
387
|
-
this.gotoSlide(startSlide);
|
388
|
-
} else {
|
389
|
-
this.#gotoSlide(this.slides[0]);
|
390
|
-
}
|
391
|
-
}
|
392
|
-
});
|
393
|
-
}
|
394
|
-
|
395
|
-
/**
|
396
|
-
* Configure the presentation slides
|
397
|
-
*
|
398
|
-
* @param {Slide[]} slides - Array of slides for the presentation
|
399
|
-
*/
|
400
|
-
configureSlides(slides) {
|
401
|
-
this.slides = slides ?? [];
|
402
|
-
}
|
403
|
-
|
404
|
-
/**
|
405
|
-
* Transition to another slide by name
|
406
|
-
*
|
407
|
-
* @param {string} name - Name of the slide to transition to
|
408
|
-
*/
|
409
|
-
async gotoSlide(name) {
|
410
|
-
untrack(() => {
|
411
|
-
const slide = findFirst(this.slides, { name });
|
412
|
-
|
413
|
-
if (!slide) {
|
414
|
-
console.log('available slides', this.slides);
|
415
|
-
throw new Error(`Slide [${name}] has not been defined`);
|
416
|
-
}
|
417
|
-
|
418
|
-
this.#gotoSlide(slide);
|
419
|
-
});
|
420
|
-
}
|
421
|
-
|
422
|
-
/**
|
423
|
-
* Internal method to transition to another slide
|
424
|
-
*
|
425
|
-
* @param {Slide} slide - The slide to transition to
|
426
|
-
*/
|
427
|
-
async #gotoSlide(slide) {
|
428
|
-
if (this.busy) {
|
429
|
-
throw new Error('Transition in progress');
|
430
|
-
}
|
431
|
-
|
432
|
-
// Reset controller requested flag
|
433
|
-
this.controllerRequested = false;
|
434
|
-
|
435
|
-
// Set loading state to true before starting transition
|
436
|
-
this.isSlideLoading = true;
|
437
|
-
|
438
|
-
// Add controller function to slide props if it has a component
|
439
|
-
if (slide.data?.component) {
|
440
|
-
// Get a presenter reference to pass to the slide
|
441
|
-
const presenterRef = this.getPresenterRef();
|
442
|
-
|
443
|
-
// Create a copy of the slide to avoid mutating the original
|
444
|
-
const slideWithExtras = {
|
445
|
-
...slide,
|
446
|
-
data: {
|
447
|
-
...slide.data,
|
448
|
-
props: {
|
449
|
-
...(slide.data.props || {}),
|
450
|
-
getLoadingController: () => this.getLoadingController(),
|
451
|
-
presenter: presenterRef // Add presenter reference to props
|
452
|
-
}
|
453
|
-
}
|
454
|
-
};
|
455
|
-
|
456
|
-
// Add next slide to next layer with controller and presenter included
|
457
|
-
this.#updateSlide(this.nextLayerLabel, slideWithExtras);
|
458
|
-
|
459
|
-
// If a timeout is configured, automatically finish loading after delay
|
460
|
-
if (this.loadingTimeout > 0) {
|
461
|
-
setTimeout(() => {
|
462
|
-
// Only auto-finish if the controller wasn't requested
|
463
|
-
if (!this.controllerRequested && this.isSlideLoading) {
|
464
|
-
// console.debug(
|
465
|
-
// `Slide '${slide.name}' didn't request loading controller, auto-finishing.`
|
466
|
-
// );
|
467
|
-
this.finishSlideLoading();
|
468
|
-
}
|
469
|
-
}, this.loadingTimeout);
|
470
|
-
}
|
471
|
-
} else {
|
472
|
-
// No component, so just use the slide as is
|
473
|
-
this.#updateSlide(this.nextLayerLabel, slide);
|
474
|
-
// No component to load, so finish loading immediately
|
475
|
-
this.finishSlideLoading();
|
476
|
-
}
|
477
|
-
|
478
|
-
// Make next layer visible, move to front
|
479
|
-
this.#updateLayer(this.nextLayerLabel, {
|
480
|
-
z: Z_FRONT,
|
481
|
-
visible: true
|
482
|
-
});
|
483
|
-
}
|
484
|
-
|
485
|
-
/**
|
486
|
-
* Apply transitions between current and next slide
|
487
|
-
*/
|
488
|
-
#applyTransitions() {
|
489
|
-
// Cancel existing transitions
|
490
|
-
let transitionPromises = this.transitionPromises;
|
491
|
-
|
492
|
-
for (const current of transitionPromises) {
|
493
|
-
current.tryCancel();
|
494
|
-
}
|
495
|
-
|
496
|
-
// Start new transitions
|
497
|
-
transitionPromises = [];
|
498
|
-
|
499
|
-
const currentSlide = this.#getSlide(this.currentLayerLabel);
|
500
|
-
const nextSlide = this.#getSlide(this.nextLayerLabel);
|
501
|
-
|
502
|
-
// Apply transitions `out` from currentslide
|
503
|
-
const transitionsOut = currentSlide?.outro;
|
504
|
-
|
505
|
-
if (transitionsOut) {
|
506
|
-
for (const transition of transitionsOut) {
|
507
|
-
const promise = this.#applyTransition(transition);
|
508
|
-
transitionPromises.push(promise);
|
509
|
-
}
|
510
|
-
}
|
511
|
-
|
512
|
-
// Apply transitions `in` from next slide
|
513
|
-
const transitionsIn = nextSlide?.intro;
|
514
|
-
|
515
|
-
if (transitionsIn) {
|
516
|
-
for (const transition of transitionsIn) {
|
517
|
-
const promise = this.#applyTransition(transition);
|
518
|
-
transitionPromises.push(promise);
|
519
|
-
}
|
520
|
-
}
|
521
|
-
|
522
|
-
this.transitionPromises = transitionPromises;
|
523
|
-
}
|
524
|
-
|
525
|
-
/**
|
526
|
-
* Apply a transition and return a transition promise
|
527
|
-
*
|
528
|
-
* @param {Transition} transition - The transition to apply
|
529
|
-
* @returns {HkPromise} Promise that resolves when transition completes
|
530
|
-
*/
|
531
|
-
#applyTransition(transition) {
|
532
|
-
const delay = (transition.delay ?? 0) + (transition.duration ?? 0);
|
533
|
-
|
534
|
-
if (0 === delay) {
|
535
|
-
const promise = new HkPromise(() => {});
|
536
|
-
promise.resolve(true);
|
537
|
-
return promise;
|
538
|
-
}
|
539
|
-
|
540
|
-
let promise = new HkPromise((/** @type {function} */ resolve) => {
|
541
|
-
if (delay) {
|
542
|
-
setTimeout(() => {
|
543
|
-
resolve(true);
|
544
|
-
}, delay);
|
545
|
-
}
|
546
|
-
});
|
547
|
-
|
548
|
-
return promise;
|
549
|
-
}
|
550
|
-
|
551
|
-
/**
|
552
|
-
* Get slide by layer label
|
553
|
-
*
|
554
|
-
* @param {string} label - Layer label (A or B)
|
555
|
-
* @returns {Slide|null} The slide for the specified layer or null
|
556
|
-
*/
|
557
|
-
#getSlide(label) {
|
558
|
-
if (label === LABEL_A) {
|
559
|
-
return this.slideA;
|
560
|
-
}
|
561
|
-
|
562
|
-
if (label === LABEL_B) {
|
563
|
-
return this.slideB;
|
564
|
-
}
|
565
|
-
|
566
|
-
return null;
|
567
|
-
}
|
568
|
-
|
569
|
-
/**
|
570
|
-
* Update layer by label
|
571
|
-
*
|
572
|
-
* @param {string} label - Layer label (A or B)
|
573
|
-
* @param {Layer} data - Layer data to update
|
574
|
-
*/
|
575
|
-
#updateLayer(label, data) {
|
576
|
-
if (label === LABEL_A) {
|
577
|
-
this.layerA = data;
|
578
|
-
return;
|
579
|
-
}
|
580
|
-
|
581
|
-
if (label === LABEL_B) {
|
582
|
-
this.layerB = data;
|
583
|
-
return;
|
584
|
-
}
|
585
|
-
|
586
|
-
throw new Error(`Missing layer [${label}]`);
|
587
|
-
}
|
588
|
-
|
589
|
-
/**
|
590
|
-
* Update slide by label
|
591
|
-
*
|
592
|
-
* @param {string} label - Layer label (A or B)
|
593
|
-
* @param {Slide|null} data - Slide data to update or null to clear
|
594
|
-
*/
|
595
|
-
#updateSlide(label, data) {
|
596
|
-
if (label === LABEL_A) {
|
597
|
-
this.slideA = data;
|
598
|
-
return;
|
599
|
-
}
|
600
|
-
|
601
|
-
if (label === LABEL_B) {
|
602
|
-
this.slideB = data;
|
603
|
-
return;
|
604
|
-
}
|
605
|
-
|
606
|
-
throw new Error(`Missing slide [${label}]`);
|
607
|
-
}
|
608
|
-
}
|
609
|
-
|
610
|
-
/* -------------------------------------- Export create & get state functions */
|
611
|
-
|
612
|
-
export const [createOrGetState, createState, getState] =
|
613
|
-
defineStateContext(PresenterState);
|
@@ -1,125 +0,0 @@
|
|
1
|
-
<script>
|
2
|
-
/* ---------------------------------------------------------------- Imports */
|
3
|
-
|
4
|
-
import { GridLayers } from '$lib/components/layout/index.js';
|
5
|
-
|
6
|
-
import { createOrGetPresenterState } from './index.js';
|
7
|
-
import { cssBefore, cssDuring } from './util.js';
|
8
|
-
|
9
|
-
/* ------------------------------------------------------------------ Props */
|
10
|
-
|
11
|
-
/**
|
12
|
-
* @typedef {import("./typedef.js").Slide} Slide
|
13
|
-
*/
|
14
|
-
|
15
|
-
/**
|
16
|
-
* @typedef {import("./typedef.js").Layer} Layer
|
17
|
-
*/
|
18
|
-
|
19
|
-
/**
|
20
|
-
* @type {{
|
21
|
-
* classes?: string,
|
22
|
-
* slides?: import("./typedef.js").Slide[],
|
23
|
-
* autostart?: boolean,
|
24
|
-
* startSlide?: string,
|
25
|
-
* instanceKey?: Symbol | string,
|
26
|
-
* layoutSnippet: import('svelte').Snippet<[Slide|null, Layer]>
|
27
|
-
* }}
|
28
|
-
*/
|
29
|
-
let {
|
30
|
-
// > Style
|
31
|
-
classes,
|
32
|
-
|
33
|
-
// > Functional
|
34
|
-
slides,
|
35
|
-
autostart = false,
|
36
|
-
startSlide,
|
37
|
-
|
38
|
-
// State
|
39
|
-
instanceKey,
|
40
|
-
|
41
|
-
// Snippets
|
42
|
-
layoutSnippet
|
43
|
-
} = $props();
|
44
|
-
|
45
|
-
/* ------------------------------------------------------------------ State */
|
46
|
-
|
47
|
-
const presenter = createOrGetPresenterState(instanceKey);
|
48
|
-
|
49
|
-
$effect.pre(() => {
|
50
|
-
// Configure presenter with slides if provided
|
51
|
-
presenter.configure({ slides, autostart, startSlide });
|
52
|
-
});
|
53
|
-
|
54
|
-
let classesA = $state('');
|
55
|
-
let classesB = $state('');
|
56
|
-
|
57
|
-
let stylesA = $state('');
|
58
|
-
let stylesB = $state('');
|
59
|
-
|
60
|
-
//> Apply stage classes and styles
|
61
|
-
|
62
|
-
$effect(() => {
|
63
|
-
// > layerA
|
64
|
-
|
65
|
-
const { stageBeforeIn, stageIn, stageBeforeOut, stageOut, transitions } =
|
66
|
-
presenter.layerA;
|
67
|
-
|
68
|
-
if (transitions && transitions.length) {
|
69
|
-
if (stageBeforeIn || stageBeforeOut) {
|
70
|
-
({ style: stylesA, classes: classesA } = cssBefore(transitions));
|
71
|
-
} else if (stageIn || stageOut) {
|
72
|
-
setTimeout(() => {
|
73
|
-
({ style: stylesA, classes: classesA } = cssDuring(transitions));
|
74
|
-
});
|
75
|
-
}
|
76
|
-
} else {
|
77
|
-
stylesA = '';
|
78
|
-
classesA = '';
|
79
|
-
}
|
80
|
-
});
|
81
|
-
|
82
|
-
$effect(() => {
|
83
|
-
// > layerB
|
84
|
-
|
85
|
-
const { stageBeforeIn, stageIn, stageBeforeOut, stageOut, transitions } =
|
86
|
-
presenter.layerB;
|
87
|
-
|
88
|
-
if (transitions) {
|
89
|
-
if (stageBeforeIn || stageBeforeOut) {
|
90
|
-
({ style: stylesB, classes: classesB } = cssBefore(transitions));
|
91
|
-
} else if (stageIn || stageOut) {
|
92
|
-
setTimeout(() => {
|
93
|
-
({ style: stylesB, classes: classesB } = cssDuring(transitions));
|
94
|
-
});
|
95
|
-
}
|
96
|
-
} else {
|
97
|
-
stylesB = '';
|
98
|
-
classesB = '';
|
99
|
-
}
|
100
|
-
});
|
101
|
-
</script>
|
102
|
-
|
103
|
-
<GridLayers data-component="presenter" {classes}>
|
104
|
-
<div
|
105
|
-
style:z-index={presenter.layerA.z}
|
106
|
-
style:visibility={presenter.layerA.visible ? 'visible' : 'hidden'}
|
107
|
-
inert={presenter.busy}
|
108
|
-
class="justify-self-stretch self-stretch overflow-hidden"
|
109
|
-
>
|
110
|
-
<div class={classesA} style={stylesA}>
|
111
|
-
{@render layoutSnippet(presenter.slideA, presenter.layerA)}
|
112
|
-
</div>
|
113
|
-
</div>
|
114
|
-
|
115
|
-
<div
|
116
|
-
style:z-index={presenter.layerB.z}
|
117
|
-
style:visibility={presenter.layerB.visible ? 'visible' : 'hidden'}
|
118
|
-
inert={presenter.busy}
|
119
|
-
class="justify-self-stretch self-stretch overflow-hidden"
|
120
|
-
>
|
121
|
-
<div class={classesB} style={stylesB}>
|
122
|
-
{@render layoutSnippet(presenter.slideB, presenter.layerB)}
|
123
|
-
</div>
|
124
|
-
</div>
|
125
|
-
</GridLayers>
|