@hkdigital/lib-sveltekit 0.1.29 → 0.1.30

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.
@@ -27,17 +27,15 @@ export class PresenterState {
27
27
  currentSlideName: string;
28
28
  /** @type {string} */
29
29
  pendingSlideName: string;
30
+ /** @type {boolean} */
31
+ configured: boolean;
30
32
  /**
31
33
  * Configure the presentation
32
34
  *
33
35
  * @param {object} _
34
- * @param {boolean} [_.autostart=false] - Whether to start automatically
35
- * @param {string} [_.startSlide] - Name of the slide to start with
36
36
  * @param {Slide[]} [_.slides] - Array of slides for the presentation
37
37
  */
38
- configure({ slides, autostart, startSlide }: {
39
- autostart?: boolean;
40
- startSlide?: string;
38
+ configure({ slides }: {
41
39
  slides?: Slide[];
42
40
  }): void;
43
41
  /**
@@ -52,11 +50,15 @@ export class PresenterState {
52
50
  * @param {string} name - Name of the slide to transition to
53
51
  */
54
52
  gotoSlide(name: string): Promise<void>;
53
+ /**
54
+ * Returns a simplified presenter reference with essential methods
55
+ * for slide components to use
56
+ *
57
+ * @returns {PresenterRef} A reference object with presenter methods
58
+ */
59
+ getPresenterRef(): PresenterRef;
55
60
  #private;
56
61
  }
57
- export const createOrGetState: (instanceKey?: string | Symbol) => PresenterState;
58
- export const createState: (instanceKey?: string | Symbol) => PresenterState;
59
- export const getState: (instanceKey?: string | Symbol) => PresenterState;
60
62
  export type Slide = import("./typedef").Slide;
61
63
  export type Transition = import("./typedef").Transition;
62
64
  export type Layer = import("./typedef").Layer;
@@ -1,15 +1,11 @@
1
1
  import { tick } from 'svelte';
2
2
 
3
- import { defineStateContext } from '../../util/svelte/state-context/index.js';
4
-
5
3
  import { findFirst } from '../../util/array/index.js';
6
4
 
7
5
  import { untrack } from 'svelte';
8
6
 
9
7
  import { HkPromise } from '../../classes/promise/index.js';
10
8
 
11
- /* ----------------------------------------------------------------- typedefs */
12
-
13
9
  /**
14
10
  * @typedef {import("./typedef").Slide} Slide
15
11
  */
@@ -34,16 +30,12 @@ import { HkPromise } from '../../classes/promise/index.js';
34
30
  * @property {() => string} getCurrentSlideName - Get the current slide name
35
31
  */
36
32
 
37
- /* -------------------------------------------------------------- Constants */
38
-
39
33
  const Z_BACK = 0;
40
34
  const Z_FRONT = 10;
41
35
 
42
36
  const LABEL_A = 'A';
43
37
  const LABEL_B = 'B';
44
38
 
45
- /* ------------------------------------------------------- Define state class */
46
-
47
39
  export class PresenterState {
48
40
  /** @type {Slide[]} */
49
41
  slides = $state.raw([]);
@@ -99,11 +91,14 @@ export class PresenterState {
99
91
  /** @type {string} */
100
92
  pendingSlideName;
101
93
 
94
+ /** @type {boolean} */
95
+ configured = false;
96
+
102
97
  /**
103
98
  * Initialize the presenter state and set up reactivity
104
99
  */
105
100
  constructor() {
106
- this.#setupStageTransitions();
101
+ // this.#setupStageTransitions();
107
102
 
108
103
  let timeout;
109
104
 
@@ -130,21 +125,21 @@ export class PresenterState {
130
125
  * Set up reactivity for stage transitions between the before/after states
131
126
  * This handles the animation timing for both layers
132
127
  */
133
- #setupStageTransitions() {
134
- // Handle layer A stage transitions
135
- $effect(() => {
136
- if (this.layerA.stageBeforeIn || this.layerA.stageBeforeOut) {
137
- this.layerA = this.#processStageTransition(this.layerA);
138
- }
139
- });
140
-
141
- // Handle layer B stage transitions
142
- $effect(() => {
143
- if (this.layerB.stageBeforeIn || this.layerB.stageBeforeOut) {
144
- this.layerB = this.#processStageTransition(this.layerB);
145
- }
146
- });
147
- }
128
+ // #setupStageTransitions() {
129
+ // // Handle layer A stage transitions
130
+ // $effect(() => {
131
+ // if (this.layerA.stageBeforeIn || this.layerA.stageBeforeOut) {
132
+ // this.layerA = this.#processStageTransition(this.layerA);
133
+ // }
134
+ // });
135
+
136
+ // // Handle layer B stage transitions
137
+ // $effect(() => {
138
+ // if (this.layerB.stageBeforeIn || this.layerB.stageBeforeOut) {
139
+ // this.layerB = this.#processStageTransition(this.layerB);
140
+ // }
141
+ // });
142
+ // }
148
143
 
149
144
  /**
150
145
  * Process a single stage transition for a layer
@@ -167,17 +162,21 @@ export class PresenterState {
167
162
  }
168
163
 
169
164
  /**
170
- * Execute the transition by waiting for all promises and then
171
- * completing the transition
165
+ * Waiting for all transition timing promises to finish,
166
+ * this should be the same amount of time as it takes for the real
167
+ * transitions to finish
172
168
  *
173
- * @param {HkPromise[]} promises - Array of transition promises to wait for
169
+ * @param {HkPromise[]} promises
170
+ * Array of transition promises to wait for
174
171
  */
175
- async #executeTransition(promises) {
172
+ async #waitForTransitionPromises(promises) {
176
173
  try {
177
- // console.debug('executeTransition');
174
+ // console.debug('waitForTransitionPromises', promises);
178
175
 
179
176
  await Promise.allSettled(promises);
180
177
 
178
+ // console.debug('waitForTransitionPromises:done', promises);
179
+
181
180
  untrack(() => {
182
181
  this.#completeTransition();
183
182
  });
@@ -228,25 +227,15 @@ export class PresenterState {
228
227
  * Configure the presentation
229
228
  *
230
229
  * @param {object} _
231
- * @param {boolean} [_.autostart=false] - Whether to start automatically
232
- * @param {string} [_.startSlide] - Name of the slide to start with
233
230
  * @param {Slide[]} [_.slides] - Array of slides for the presentation
234
231
  */
235
- configure({ slides, autostart = true, startSlide }) {
236
- untrack(() => {
237
- if (slides) {
238
- // Only update slides if provided
239
- this.slides = slides;
240
- }
232
+ configure({ slides }) {
233
+ this.configured = true;
241
234
 
242
- if ((autostart || startSlide) && this.slides?.length) {
243
- if (startSlide) {
244
- this.gotoSlide(startSlide);
245
- } else {
246
- this.#gotoSlide(this.slides[0]);
247
- }
248
- }
249
- });
235
+ if (slides) {
236
+ // Only update slides if provided
237
+ this.slides = slides;
238
+ }
250
239
  }
251
240
 
252
241
  /**
@@ -264,6 +253,8 @@ export class PresenterState {
264
253
  * @param {string} name - Name of the slide to transition to
265
254
  */
266
255
  async gotoSlide(name) {
256
+ // throw new Error('gotoSlide');
257
+
267
258
  untrack(() => {
268
259
  const slide = findFirst(this.slides, { name });
269
260
 
@@ -282,6 +273,10 @@ export class PresenterState {
282
273
  * @param {Slide} slide - The slide to transition to
283
274
  */
284
275
  async #gotoSlide(slide) {
276
+ if (!this.configured) {
277
+ throw new Error('Not configured yet');
278
+ }
279
+
285
280
  if (this.busy) {
286
281
  this.pendingSlideName = slide.name;
287
282
  return;
@@ -290,7 +285,7 @@ export class PresenterState {
290
285
  this.slideLoadingPromise = null;
291
286
 
292
287
  // Get a presenter reference to pass to the slide
293
- const presenterRef = this.#getPresenterRef();
288
+ const presenterRef = this.getPresenterRef();
294
289
 
295
290
  // Create a copy of the slide to avoid mutating the original
296
291
  const slideWithProps = {
@@ -312,16 +307,16 @@ export class PresenterState {
312
307
  }
313
308
  };
314
309
 
315
- console.debug('Checkpoint 1');
310
+ // console.debug('Checkpoint 1');
316
311
 
317
312
  // Add next slide to next layer
318
313
  this.#updateSlide(this.nextLayerLabel, slideWithProps);
319
314
 
320
- console.debug('Checkpoint 2');
315
+ // console.debug('Checkpoint 2');
321
316
 
322
317
  await tick();
323
318
 
324
- console.debug('Checkpoint 3');
319
+ // console.debug('Checkpoint 3');
325
320
 
326
321
  if (this.slideLoadingPromise) {
327
322
  // console.debug('Waiting for slide to load');
@@ -334,7 +329,7 @@ export class PresenterState {
334
329
  const currentSlide = this.#getSlide(this.currentLayerLabel);
335
330
  const nextSlide = this.#getSlide(this.nextLayerLabel);
336
331
 
337
- console.debug('Checkpoint 4');
332
+ // console.debug('Checkpoint 4', currentSlide, nextSlide);
338
333
 
339
334
  // Make next layer visible, move to front, and prepare for
340
335
  // transition in
@@ -354,14 +349,44 @@ export class PresenterState {
354
349
  transitions: currentSlide?.outro ?? []
355
350
  });
356
351
 
357
- console.debug('Checkpoint 5');
352
+ // console.debug('Checkpoint 5');
353
+
354
+ // Wait briefly to ensure the stageBeforeIn/stageBeforeOut states are rendered
355
+ await tick();
356
+
357
+ // Now manually process the transitions for both layers
358
+ const layerA = this.layerA;
359
+ const layerB = this.layerB;
360
+
361
+ // Process stageBeforeIn transition for both layers
362
+ if (layerA.stageBeforeIn) {
363
+ this.layerA = this.#processStageTransition(layerA);
364
+ }
365
+
366
+ if (layerB.stageBeforeIn) {
367
+ this.layerB = this.#processStageTransition(layerB);
368
+ }
369
+
370
+ // Wait for another tick to ensure the stageIn states are rendered
371
+ await tick();
372
+
373
+ // Process stageBeforeOut transition for both layers
374
+ if (layerA.stageBeforeOut) {
375
+ this.layerA = this.#processStageTransition(layerA);
376
+ }
377
+
378
+ if (layerB.stageBeforeOut) {
379
+ this.layerB = this.#processStageTransition(layerB);
380
+ }
381
+
382
+ // console.debug('Checkpoint 7');
358
383
 
359
384
  // Start transitions
360
- this.#applyTransitions();
385
+ this.#createTransitionPromises();
361
386
 
362
- // FIXME: wait?
387
+ // console.debug('Checkpoint 8');
363
388
 
364
- await this.#executeTransition(this.transitionPromises);
389
+ await this.#waitForTransitionPromises(this.transitionPromises);
365
390
 
366
391
  // Check if there's a pending slide transition
367
392
  if (this.pendingSlideName) {
@@ -378,9 +403,10 @@ export class PresenterState {
378
403
  }
379
404
 
380
405
  /**
381
- * Apply transitions between current and next slide
406
+ * Create transition promises that can be used to determine the timing
407
+ * of the transitions between current and next slide
382
408
  */
383
- #applyTransitions() {
409
+ #createTransitionPromises() {
384
410
  // Cancel existing transitions
385
411
  let transitionPromises = this.transitionPromises;
386
412
 
@@ -397,9 +423,11 @@ export class PresenterState {
397
423
  // Apply transitions `out` from currentslide
398
424
  const transitionsOut = currentSlide?.outro;
399
425
 
426
+ // console.log('transitionsOut', transitionsOut);
427
+
400
428
  if (transitionsOut) {
401
429
  for (const transition of transitionsOut) {
402
- const promise = this.#applyTransition(transition);
430
+ const promise = this.#createTransitionPromise(transition);
403
431
  transitionPromises.push(promise);
404
432
  }
405
433
  }
@@ -407,9 +435,11 @@ export class PresenterState {
407
435
  // Apply transitions `in` from next slide
408
436
  const transitionsIn = nextSlide?.intro;
409
437
 
438
+ // console.log('transitionsIn', transitionsIn);
439
+
410
440
  if (transitionsIn) {
411
441
  for (const transition of transitionsIn) {
412
- const promise = this.#applyTransition(transition);
442
+ const promise = this.#createTransitionPromise(transition);
413
443
  transitionPromises.push(promise);
414
444
  }
415
445
  }
@@ -418,12 +448,16 @@ export class PresenterState {
418
448
  }
419
449
 
420
450
  /**
421
- * Apply a transition and return a transition promise
451
+ * Create a transition promise for the specified transition
452
+ *
422
453
  *
423
454
  * @param {Transition} transition - The transition to apply
424
- * @returns {HkPromise} Promise that resolves when transition completes
455
+ *
456
+ * @returns {HkPromise}
457
+ * Promise that resolves after the same amount of time that it
458
+ * takes for the transition to finish
425
459
  */
426
- #applyTransition(transition) {
460
+ #createTransitionPromise(transition) {
427
461
  const delay = (transition.delay ?? 0) + (transition.duration ?? 0);
428
462
 
429
463
  if (0 === delay) {
@@ -507,7 +541,7 @@ export class PresenterState {
507
541
  *
508
542
  * @returns {PresenterRef} A reference object with presenter methods
509
543
  */
510
- #getPresenterRef() {
544
+ getPresenterRef() {
511
545
  return {
512
546
  gotoSlide: (name) => this.gotoSlide(name),
513
547
  getCurrentSlideName: () => this.currentSlideName
@@ -544,8 +578,3 @@ export class PresenterState {
544
578
  };
545
579
  }
546
580
  }
547
-
548
- /* -------------------------------------- Export create & get state functions */
549
-
550
- export const [createOrGetState, createState, getState] =
551
- defineStateContext(PresenterState);
@@ -1,14 +1,11 @@
1
1
  <script>
2
- /* ---------------------------------------------------------------- Imports */
2
+ import { onMount } from 'svelte';
3
3
 
4
4
  import { GridLayers } from '../../components/layout/index.js';
5
5
 
6
6
  import { PresenterState } from './Presenter.state.svelte.js';
7
- import { getPresenterState } from './index.js';
8
7
  import { cssBefore, cssDuring, waitForRender } from './util.js';
9
8
 
10
- /* ------------------------------------------------------------------ Props */
11
-
12
9
  /**
13
10
  * @typedef {import("./typedef.js").Slide} Slide
14
11
  */
@@ -21,10 +18,7 @@
21
18
  * @type {{
22
19
  * classes?: string,
23
20
  * slides?: import("./typedef.js").Slide[],
24
- * autostart?: boolean,
25
- * startSlide?: string,
26
- * instanceKey?: Symbol | string,
27
- * presenter?: import('./Presenter.state.svelte.js').PresenterState,
21
+ * presenterRef?: import('./Presenter.state.svelte.js').PresenterRef,
28
22
  * layoutSnippet: import('svelte').Snippet<[Slide|null, Layer]>,
29
23
  * loadingSnippet?: import('svelte').Snippet,
30
24
  * }}
@@ -35,32 +29,23 @@
35
29
 
36
30
  // > Functional
37
31
  slides,
38
- autostart = false,
39
- startSlide,
40
-
41
- // State
42
- instanceKey,
43
-
44
- // presenter = $bindable(),
32
+ presenterRef = $bindable(),
45
33
 
46
34
  // Snippets
47
35
  layoutSnippet,
48
36
  loadingSnippet
49
37
  } = $props();
50
38
 
51
- // > Create presenter state object and register using setContext
52
-
53
- // FIXME: Using getPresenterState to force creation of presenter outside
54
- // the component. Otherwise transitions doe not work somehow..
55
- const presenter = getPresenterState(instanceKey);
56
-
57
- // > State
39
+ const presenter = new PresenterState();
58
40
 
59
- $effect.pre(() => {
41
+ onMount(() => {
60
42
  // Configure presenter with slides if provided
61
- presenter.configure({ slides, autostart, startSlide });
43
+ presenter.configure({ slides });
44
+ presenterRef = presenter.getPresenterRef();
62
45
  });
63
46
 
47
+ // > State
48
+
64
49
  let classesA = $state('');
65
50
  let classesB = $state('');
66
51
 
@@ -75,7 +60,14 @@
75
60
  const { stageBeforeIn, stageIn, stageBeforeOut, stageOut, transitions } =
76
61
  presenter.layerA;
77
62
 
78
- if (transitions && transitions.length) {
63
+ if (transitions?.length) {
64
+ // console.debug('layerA:transitions', transitions, {
65
+ // stageBeforeIn,
66
+ // stageIn,
67
+ // stageBeforeOut,
68
+ // stageOut
69
+ // });
70
+
79
71
  if (stageBeforeIn || stageBeforeOut) {
80
72
  ({ style: stylesA, classes: classesA } = cssBefore(transitions));
81
73
  } else if (stageIn || stageOut) {
@@ -95,7 +87,14 @@
95
87
  const { stageBeforeIn, stageIn, stageBeforeOut, stageOut, transitions } =
96
88
  presenter.layerB;
97
89
 
98
- if (transitions) {
90
+ if (transitions?.length) {
91
+ // console.debug('layerB:transitions', transitions, {
92
+ // stageBeforeIn,
93
+ // stageIn,
94
+ // stageBeforeOut,
95
+ // stageOut
96
+ // });
97
+
99
98
  if (stageBeforeIn || stageBeforeOut) {
100
99
  ({ style: stylesB, classes: classesB } = cssBefore(transitions));
101
100
  } else if (stageIn || stageOut) {
@@ -2,10 +2,7 @@ export default Presenter;
2
2
  declare const Presenter: import("svelte").Component<{
3
3
  classes?: string;
4
4
  slides?: import("./typedef.js").Slide[];
5
- autostart?: boolean;
6
- startSlide?: string;
7
- instanceKey?: Symbol | string;
8
- presenter?: import("./Presenter.state.svelte.js").PresenterState;
5
+ presenterRef?: import("./Presenter.state.svelte.js").PresenterRef;
9
6
  layoutSnippet: import("svelte").Snippet<[import("./typedef.js").Slide | null, import("./typedef.js").Layer]>;
10
7
  loadingSnippet?: import("svelte").Snippet;
11
- }, {}, "">;
8
+ }, {}, "presenterRef">;
@@ -1,6 +1,6 @@
1
1
  export { default as Presenter } from "./Presenter.svelte";
2
2
  export { default as ImageSlide } from "./ImageSlide.svelte";
3
+ export { PresenterState } from "./Presenter.state.svelte.js";
3
4
  export * from "./typedef.js";
4
5
  export * from "./constants.js";
5
6
  export * from "./util.js";
6
- export { PresenterState, createOrGetState as createOrGetPresenterState, createState as createPresenterState, getState as getPresenterState } from "./Presenter.state.svelte.js";
@@ -1,12 +1,7 @@
1
1
  export { default as Presenter } from './Presenter.svelte';
2
2
  export { default as ImageSlide } from './ImageSlide.svelte';
3
3
 
4
- export {
5
- PresenterState,
6
- createOrGetState as createOrGetPresenterState,
7
- createState as createPresenterState,
8
- getState as getPresenterState
9
- } from './Presenter.state.svelte.js';
4
+ export { PresenterState } from './Presenter.state.svelte.js';
10
5
 
11
6
  export * from './typedef.js';
12
7
  export * from './constants.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-sveltekit",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"