@hkdigital/lib-core 0.5.51 → 0.5.53

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.
@@ -1,61 +1,3 @@
1
- /**
2
- * Base class for page state machines with URL route mapping
3
- *
4
- * Simple state tracker that maps states to URL routes.
5
- * Does NOT enforce FSM transitions - allows free navigation
6
- * (because users can navigate to any URL via browser).
7
- *
8
- * Features:
9
- * - State-to-route mapping and sync
10
- * - Start path management
11
- * - Data properties for business/domain state
12
- * - Visited states tracking
13
- * - onEnter hooks with abort/complete handlers for animations
14
- *
15
- * Basic usage:
16
- * ```javascript
17
- * const machine = new PageMachine({
18
- * startPath: '/intro/start',
19
- * routeMap: {
20
- * [STATE_START]: '/intro/start',
21
- * [STATE_PROFILE]: '/intro/profile'
22
- * }
23
- * });
24
- *
25
- * // Sync machine state with URL changes
26
- * $effect(() => {
27
- * machine.syncFromPath($page.url.pathname);
28
- * });
29
- * ```
30
- *
31
- * With onEnter hooks (for animations):
32
- * ```javascript
33
- * const machine = new PageMachine({
34
- * startPath: '/game/animate',
35
- * routeMap: {
36
- * [STATE_ANIMATE]: '/game/animate',
37
- * [STATE_PLAY]: '/game/play'
38
- * },
39
- * onEnterHooks: {
40
- * [STATE_ANIMATE]: (done) => {
41
- * const animation = playAnimation(1000);
42
- * animation.finished.then(() => done(STATE_PLAY));
43
- *
44
- * return {
45
- * abort: () => animation.cancel(),
46
- * complete: () => animation.finish()
47
- * };
48
- * }
49
- * }
50
- * });
51
- *
52
- * // Fast-forward animation
53
- * machine.completeTransitions();
54
- *
55
- * // Cancel animation
56
- * machine.abortTransitions();
57
- * ```
58
- */
59
1
  export default class PageMachine {
60
2
  /**
61
3
  * Constructor
@@ -111,7 +53,7 @@ export default class PageMachine {
111
53
  * Synchronize machine state with URL path
112
54
  *
113
55
  * Call this in a $effect that watches $page.url.pathname
114
- * Automatically tracks visited states
56
+ * Automatically tracks visited states and triggers onEnter hooks
115
57
  *
116
58
  * @param {string} currentPath - Current URL pathname
117
59
  *
@@ -119,20 +61,19 @@ export default class PageMachine {
119
61
  */
120
62
  syncFromPath(currentPath: string): boolean;
121
63
  /**
122
- * Set the current state directly
123
- * Handles onEnter hooks and auto-transitions
64
+ * Get route path for a given state
65
+ *
66
+ * @param {string} state - State name
124
67
  *
125
- * @param {string} newState - Target state
68
+ * @returns {string} Route path or null if no mapping
126
69
  */
127
- setState(newState: string): Promise<void>;
70
+ getPathForState(state: string): string;
128
71
  /**
129
- * Get route path for a given state
72
+ * Navigate to the route path for a given state
130
73
  *
131
74
  * @param {string} state - State name
132
- *
133
- * @returns {string|null} Route path or null if no mapping
134
75
  */
135
- getPathForState(state: string): string | null;
76
+ navigateToState(state: string): void;
136
77
  /**
137
78
  * Get route path for current state
138
79
  *
@@ -56,6 +56,8 @@
56
56
  * machine.abortTransitions();
57
57
  * ```
58
58
  */
59
+ import { switchToPage } from '../../../util/sveltekit.js';
60
+
59
61
  export default class PageMachine {
60
62
  /**
61
63
  * Logger instance for state machine
@@ -241,7 +243,7 @@ export default class PageMachine {
241
243
  * Synchronize machine state with URL path
242
244
  *
243
245
  * Call this in a $effect that watches $page.url.pathname
244
- * Automatically tracks visited states
246
+ * Automatically tracks visited states and triggers onEnter hooks
245
247
  *
246
248
  * @param {string} currentPath - Current URL pathname
247
249
  *
@@ -251,13 +253,13 @@ export default class PageMachine {
251
253
  const targetState = this.#getStateFromPath(currentPath);
252
254
 
253
255
  if (targetState && targetState !== this.#current) {
254
- // const oldState = this.#current;
255
- this.#current = targetState;
256
- this.#visitedStates.add(targetState);
257
- this.#revision++;
258
-
259
256
  // Log state transition from URL sync
260
- this.logger?.debug(`syncFromPath: ${currentPath} → targetState: ${targetState}`);
257
+ this.logger?.debug(
258
+ `syncFromPath: ${currentPath} → targetState: ${targetState}`
259
+ );
260
+
261
+ // Use #setState to handle onEnter hooks
262
+ this.#setState(targetState);
261
263
 
262
264
  return true;
263
265
  }
@@ -266,12 +268,16 @@ export default class PageMachine {
266
268
  }
267
269
 
268
270
  /**
269
- * Set the current state directly
271
+ * Set the current state directly (internal use only)
270
272
  * Handles onEnter hooks and auto-transitions
271
273
  *
274
+ * Note: This is private to enforce URL-first navigation.
275
+ * To change state, navigate to the URL using switchToPage()
276
+ * and let syncFromPath() update the state.
277
+ *
272
278
  * @param {string} newState - Target state
273
279
  */
274
- async setState(newState) {
280
+ async #setState(newState) {
275
281
  if (newState === this.#current || this.#isTransitioning) {
276
282
  return;
277
283
  }
@@ -297,11 +303,11 @@ export default class PageMachine {
297
303
  // Create done callback for auto-transition
298
304
  let doneCalled = false;
299
305
 
300
- const done = ( /** @type {string} */ nextState) => {
306
+ const done = (/** @type {string} */ nextState) => {
301
307
  if (!doneCalled && nextState && nextState !== newState) {
302
308
  doneCalled = true;
303
309
  this.#isTransitioning = false;
304
- this.setState(nextState);
310
+ this.#setState(nextState);
305
311
  }
306
312
  };
307
313
 
@@ -363,10 +369,26 @@ export default class PageMachine {
363
369
  *
364
370
  * @param {string} state - State name
365
371
  *
366
- * @returns {string|null} Route path or null if no mapping
372
+ * @returns {string} Route path or null if no mapping
367
373
  */
368
374
  getPathForState(state) {
369
- return this.#routeMap[state] || null;
375
+ const path = this.#routeMap[state];
376
+
377
+ if (!path) {
378
+ throw new Error(`No path found for state [${state}]`);
379
+ }
380
+
381
+ return path;
382
+ }
383
+
384
+ /**
385
+ * Navigate to the route path for a given state
386
+ *
387
+ * @param {string} state - State name
388
+ */
389
+ navigateToState(state) {
390
+ const path = this.getPathForState(state);
391
+ switchToPage(path);
370
392
  }
371
393
 
372
394
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.51",
3
+ "version": "0.5.53",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"