@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
|
-
*
|
|
123
|
-
*
|
|
64
|
+
* Get route path for a given state
|
|
65
|
+
*
|
|
66
|
+
* @param {string} state - State name
|
|
124
67
|
*
|
|
125
|
-
* @
|
|
68
|
+
* @returns {string} Route path or null if no mapping
|
|
126
69
|
*/
|
|
127
|
-
|
|
70
|
+
getPathForState(state: string): string;
|
|
128
71
|
/**
|
|
129
|
-
*
|
|
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
|
-
|
|
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(
|
|
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 = (
|
|
306
|
+
const done = (/** @type {string} */ nextState) => {
|
|
301
307
|
if (!doneCalled && nextState && nextState !== newState) {
|
|
302
308
|
doneCalled = true;
|
|
303
309
|
this.#isTransitioning = false;
|
|
304
|
-
this
|
|
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
|
|
372
|
+
* @returns {string} Route path or null if no mapping
|
|
367
373
|
*/
|
|
368
374
|
getPathForState(state) {
|
|
369
|
-
|
|
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
|
/**
|