@daltonr/pathwrite-svelte 0.8.0 → 0.9.0

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/README.md CHANGED
@@ -168,7 +168,7 @@ Create the engine yourself with `restoreOrStart()` and pass it via `engine`. Pat
168
168
 
169
169
  ```svelte
170
170
  <script>
171
- import { HttpStore, restoreOrStart, httpPersistence } from '@daltonr/pathwrite-store-http';
171
+ import { HttpStore, restoreOrStart, persistence } from '@daltonr/pathwrite-store';
172
172
 
173
173
  let engine = $state(null);
174
174
 
@@ -179,7 +179,7 @@ Create the engine yourself with `restoreOrStart()` and pass it via `engine`. Pat
179
179
  path: signupPath,
180
180
  initialData: { name: '' },
181
181
  observers: [
182
- httpPersistence({ store, key: 'user:onboarding', strategy: 'onNext' })
182
+ persistence({ store, key: 'user:onboarding', strategy: 'onNext' })
183
183
  ]
184
184
  });
185
185
  engine = result.engine;
@@ -467,13 +467,13 @@ const myPath = {
467
467
 
468
468
  ## Persistence
469
469
 
470
- Use with [@daltonr/pathwrite-store-http](../store-http) for automatic state persistence:
470
+ Use with [@daltonr/pathwrite-store](../store) for automatic state persistence:
471
471
 
472
472
  ```svelte
473
473
  <script lang="ts">
474
474
  import { onMount } from 'svelte';
475
475
  import { PathShell } from '@daltonr/pathwrite-svelte';
476
- import { HttpStore, restoreOrStart, httpPersistence } from '@daltonr/pathwrite-store-http';
476
+ import { HttpStore, restoreOrStart, persistence } from '@daltonr/pathwrite-store';
477
477
  import DetailsForm from './DetailsForm.svelte';
478
478
  import ReviewPanel from './ReviewPanel.svelte';
479
479
 
@@ -490,7 +490,7 @@ Use with [@daltonr/pathwrite-store-http](../store-http) for automatic state pers
490
490
  path: signupPath,
491
491
  initialData: { name: '', email: '' },
492
492
  observers: [
493
- httpPersistence({ store, key, strategy: 'onNext' })
493
+ persistence({ store, key, strategy: 'onNext' })
494
494
  ]
495
495
  });
496
496
  engine = result.engine;
@@ -537,7 +537,7 @@ MIT — © 2026 Devjoy Ltd.
537
537
  ## See Also
538
538
 
539
539
  - [@daltonr/pathwrite-core](../core) - Core engine
540
- - [@daltonr/pathwrite-store-http](../store-http) - HTTP persistence
540
+ - [@daltonr/pathwrite-store](../store) - HTTP persistence
541
541
  - [Documentation](../../docs/guides/DEVELOPER_GUIDE.md)
542
542
 
543
543
 
@@ -2,7 +2,7 @@
2
2
  import { onMount } from 'svelte';
3
3
  import { usePath, setPathContext } from './index.svelte.js';
4
4
  import type { PathDefinition, PathData, PathEngine, PathSnapshot, ProgressLayout } from './index.svelte.js';
5
- import type { Snippet } from 'svelte';
5
+ import type { Snippet, Component } from 'svelte';
6
6
 
7
7
  /** Converts a camelCase or lowercase field key to a display label. */
8
8
  function formatFieldKey(key: string): string {
@@ -49,8 +49,8 @@
49
49
  // Optional override snippets for header and footer
50
50
  header?: Snippet<[PathSnapshot<any>]>;
51
51
  footer?: Snippet<[PathSnapshot<any>, object]>;
52
- // All other props treated as step snippets keyed by step ID
53
- [key: string]: Snippet | any;
52
+ // All other props treated as step components keyed by step ID
53
+ [key: string]: Component<any> | any;
54
54
  }
55
55
 
56
56
  let {
@@ -65,7 +65,7 @@
65
65
  hideCancel = false,
66
66
  hideProgress = false,
67
67
  footerLayout = 'auto',
68
- validationDisplay = 'inline',
68
+ validationDisplay = 'summary',
69
69
  progressLayout = 'merged',
70
70
  oncomplete,
71
71
  oncancel,
@@ -190,9 +190,9 @@
190
190
  register snippets by inner step ids directly. -->
191
191
  <div class="pw-shell__body">
192
192
  {#if snap.formId && stepSnippets[snap.formId]}
193
- {@render stepSnippets[snap.formId]()}
193
+ <svelte:component this={stepSnippets[snap.formId]} />
194
194
  {:else if stepSnippets[snap.stepId]}
195
- {@render stepSnippets[snap.stepId]()}
195
+ <svelte:component this={stepSnippets[snap.stepId]} />
196
196
  {:else}
197
197
  <p>No content for step "{snap.stepId}"</p>
198
198
  {/if}
@@ -1,5 +1,5 @@
1
1
  import type { PathDefinition, PathData, PathEngine, PathSnapshot, ProgressLayout } from './index.svelte.js';
2
- import type { Snippet } from 'svelte';
2
+ import type { Snippet, Component } from 'svelte';
3
3
  interface Props {
4
4
  path?: PathDefinition<any>;
5
5
  engine?: PathEngine;
@@ -38,9 +38,9 @@ interface Props {
38
38
  onevent?: (event: any) => void;
39
39
  header?: Snippet<[PathSnapshot<any>]>;
40
40
  footer?: Snippet<[PathSnapshot<any>, object]>;
41
- [key: string]: Snippet | any;
41
+ [key: string]: Component<any> | any;
42
42
  }
43
- declare const PathShell: import("svelte").Component<Props, {
43
+ declare const PathShell: Component<Props, {
44
44
  restart: () => Promise<void>;
45
45
  }, "">;
46
46
  type PathShell = ReturnType<typeof PathShell>;
@@ -1 +1 @@
1
- {"version":3,"file":"PathShell.svelte.d.ts","sourceRoot":"","sources":["../src/PathShell.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC5G,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAE/B,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAE9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,GAAG,CAAC;CAC9B;AAyNH,QAAA,MAAM,SAAS;mBAlIQ,QAAQ,IAAI,CAAC;MAkImB,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"PathShell.svelte.d.ts","sourceRoot":"","sources":["../src/PathShell.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC5G,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAG/C,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAE/B,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAE9C,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CACrC;AAyNH,QAAA,MAAM,SAAS;mBAlIQ,QAAQ,IAAI,CAAC;MAkImB,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -3,7 +3,7 @@ export type { PathData, FieldErrors, PathDefinition, PathEngine, PathEvent, Path
3
3
  export interface UsePathOptions {
4
4
  /**
5
5
  * An externally-managed `PathEngine` to subscribe to — for example, the engine
6
- * returned by `restoreOrStart()` from `@daltonr/pathwrite-store-http`.
6
+ * returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
7
7
  *
8
8
  * When provided:
9
9
  * - `usePath` will **not** create its own engine.
@@ -16,7 +16,12 @@ export interface UsePathOptions {
16
16
  onEvent?: (event: PathEvent) => void;
17
17
  }
18
18
  export interface UsePathReturn<TData extends PathData = PathData> {
19
- /** Current path snapshot, or `null` when no path is active. Reactive via `$state`. */
19
+ /**
20
+ * Current path snapshot, or `null` when no path is active. Reactive via `$state`.
21
+ *
22
+ * ⚠️ **Do not destructure.** `const { snapshot } = usePath()` captures the value
23
+ * once and loses reactivity. Always access as `path.snapshot`.
24
+ */
20
25
  readonly snapshot: PathSnapshot<TData> | null;
21
26
  /** Start (or restart) a path. */
22
27
  start: (path: PathDefinition<any>, initialData?: PathData) => Promise<void>;
@@ -41,15 +46,42 @@ export interface UsePathReturn<TData extends PathData = PathData> {
41
46
  * given path fresh. Safe to call whether or not a path is currently active.
42
47
  * Use for "Start over" / retry flows without remounting the component.
43
48
  */
44
- restart: (path: PathDefinition<any>, initialData?: PathData) => Promise<void>;
49
+ restart: () => Promise<void>;
45
50
  }
46
51
  /**
47
52
  * Create a Pathwrite engine with Svelte 5 runes-based reactivity.
48
53
  * Call this from inside a Svelte component to get a reactive snapshot.
49
54
  * Cleanup is automatic via onDestroy.
50
55
  *
51
- * **Note:** `snapshot` is a reactive getter — access it via the returned
52
- * object (e.g. `path.snapshot`). Destructuring `snapshot` will lose reactivity.
56
+ * ---
57
+ *
58
+ * ⚠️ **Do not destructure `snapshot`.**
59
+ *
60
+ * `snapshot` is a reactive getter. Destructuring it copies the value once
61
+ * and severs the reactive connection — your component will stop updating.
62
+ *
63
+ * ```svelte
64
+ * // ❌ Broken — snapshot is captured once and never updates
65
+ * const { snapshot, next } = usePath();
66
+ *
67
+ * // ✅ Correct — snapshot is read through the live object on every render
68
+ * const path = usePath();
69
+ * // use path.snapshot in your template
70
+ * ```
71
+ *
72
+ * Other properties (`next`, `previous`, `setData`, etc.) are plain functions
73
+ * and are safe to destructure.
74
+ *
75
+ * If you need a local variable that stays reactive, use `$derived`:
76
+ * ```svelte
77
+ * const path = usePath();
78
+ * const snapshot = $derived(path.snapshot);
79
+ * ```
80
+ *
81
+ * This is expected Svelte 5 behaviour — see the
82
+ * [Svelte $state docs](https://svelte.dev/docs/svelte/$state) for details.
83
+ *
84
+ * ---
53
85
  *
54
86
  * @example
55
87
  * ```svelte
@@ -72,7 +104,7 @@ export interface UsePathReturn<TData extends PathData = PathData> {
72
104
  */
73
105
  export declare function usePath<TData extends PathData = PathData>(options?: UsePathOptions): UsePathReturn<TData>;
74
106
  export interface PathContext<TData extends PathData = PathData> {
75
- readonly snapshot: PathSnapshot<TData> | null;
107
+ readonly snapshot: PathSnapshot<TData>;
76
108
  next: () => Promise<void>;
77
109
  previous: () => Promise<void>;
78
110
  cancel: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../src/index.svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../src/index.svelte.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,35 @@ import { PathEngine as PathEngineClass } from "@daltonr/pathwrite-core";
8
8
  * Call this from inside a Svelte component to get a reactive snapshot.
9
9
  * Cleanup is automatic via onDestroy.
10
10
  *
11
- * **Note:** `snapshot` is a reactive getter — access it via the returned
12
- * object (e.g. `path.snapshot`). Destructuring `snapshot` will lose reactivity.
11
+ * ---
12
+ *
13
+ * ⚠️ **Do not destructure `snapshot`.**
14
+ *
15
+ * `snapshot` is a reactive getter. Destructuring it copies the value once
16
+ * and severs the reactive connection — your component will stop updating.
17
+ *
18
+ * ```svelte
19
+ * // ❌ Broken — snapshot is captured once and never updates
20
+ * const { snapshot, next } = usePath();
21
+ *
22
+ * // ✅ Correct — snapshot is read through the live object on every render
23
+ * const path = usePath();
24
+ * // use path.snapshot in your template
25
+ * ```
26
+ *
27
+ * Other properties (`next`, `previous`, `setData`, etc.) are plain functions
28
+ * and are safe to destructure.
29
+ *
30
+ * If you need a local variable that stays reactive, use `$derived`:
31
+ * ```svelte
32
+ * const path = usePath();
33
+ * const snapshot = $derived(path.snapshot);
34
+ * ```
35
+ *
36
+ * This is expected Svelte 5 behaviour — see the
37
+ * [Svelte $state docs](https://svelte.dev/docs/svelte/$state) for details.
38
+ *
39
+ * ---
13
40
  *
14
41
  * @example
15
42
  * ```svelte
@@ -55,7 +82,7 @@ export function usePath(options) {
55
82
  const goToStepChecked = (stepId) => engine.goToStepChecked(stepId);
56
83
  const setData = ((key, value) => engine.setData(key, value));
57
84
  const resetStep = () => engine.resetStep();
58
- const restart = (path, initialData = {}) => engine.restart(path, initialData);
85
+ const restart = () => engine.restart();
59
86
  return {
60
87
  get snapshot() { return _snapshot; },
61
88
  start,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daltonr/pathwrite-svelte",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Svelte 5 adapter for @daltonr/pathwrite-core — runes-based reactive bindings and optional PathShell component.",
@@ -52,7 +52,7 @@
52
52
  "svelte": ">=5.0.0"
53
53
  },
54
54
  "dependencies": {
55
- "@daltonr/pathwrite-core": "^0.8.0"
55
+ "@daltonr/pathwrite-core": "^0.9.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@sveltejs/package": "^2.5.7",
@@ -2,7 +2,7 @@
2
2
  import { onMount } from 'svelte';
3
3
  import { usePath, setPathContext } from './index.svelte.js';
4
4
  import type { PathDefinition, PathData, PathEngine, PathSnapshot, ProgressLayout } from './index.svelte.js';
5
- import type { Snippet } from 'svelte';
5
+ import type { Snippet, Component } from 'svelte';
6
6
 
7
7
  /** Converts a camelCase or lowercase field key to a display label. */
8
8
  function formatFieldKey(key: string): string {
@@ -49,8 +49,8 @@
49
49
  // Optional override snippets for header and footer
50
50
  header?: Snippet<[PathSnapshot<any>]>;
51
51
  footer?: Snippet<[PathSnapshot<any>, object]>;
52
- // All other props treated as step snippets keyed by step ID
53
- [key: string]: Snippet | any;
52
+ // All other props treated as step components keyed by step ID
53
+ [key: string]: Component<any> | any;
54
54
  }
55
55
 
56
56
  let {
@@ -65,7 +65,7 @@
65
65
  hideCancel = false,
66
66
  hideProgress = false,
67
67
  footerLayout = 'auto',
68
- validationDisplay = 'inline',
68
+ validationDisplay = 'summary',
69
69
  progressLayout = 'merged',
70
70
  oncomplete,
71
71
  oncancel,
@@ -190,9 +190,9 @@
190
190
  register snippets by inner step ids directly. -->
191
191
  <div class="pw-shell__body">
192
192
  {#if snap.formId && stepSnippets[snap.formId]}
193
- {@render stepSnippets[snap.formId]()}
193
+ <svelte:component this={stepSnippets[snap.formId]} />
194
194
  {:else if stepSnippets[snap.stepId]}
195
- {@render stepSnippets[snap.stepId]()}
195
+ <svelte:component this={stepSnippets[snap.stepId]} />
196
196
  {:else}
197
197
  <p>No content for step "{snap.stepId}"</p>
198
198
  {/if}
@@ -30,7 +30,7 @@ export type {
30
30
  export interface UsePathOptions {
31
31
  /**
32
32
  * An externally-managed `PathEngine` to subscribe to — for example, the engine
33
- * returned by `restoreOrStart()` from `@daltonr/pathwrite-store-http`.
33
+ * returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
34
34
  *
35
35
  * When provided:
36
36
  * - `usePath` will **not** create its own engine.
@@ -44,7 +44,12 @@ export interface UsePathOptions {
44
44
  }
45
45
 
46
46
  export interface UsePathReturn<TData extends PathData = PathData> {
47
- /** Current path snapshot, or `null` when no path is active. Reactive via `$state`. */
47
+ /**
48
+ * Current path snapshot, or `null` when no path is active. Reactive via `$state`.
49
+ *
50
+ * ⚠️ **Do not destructure.** `const { snapshot } = usePath()` captures the value
51
+ * once and loses reactivity. Always access as `path.snapshot`.
52
+ */
48
53
  readonly snapshot: PathSnapshot<TData> | null;
49
54
  /** Start (or restart) a path. */
50
55
  start: (path: PathDefinition<any>, initialData?: PathData) => Promise<void>;
@@ -69,7 +74,7 @@ export interface UsePathReturn<TData extends PathData = PathData> {
69
74
  * given path fresh. Safe to call whether or not a path is currently active.
70
75
  * Use for "Start over" / retry flows without remounting the component.
71
76
  */
72
- restart: (path: PathDefinition<any>, initialData?: PathData) => Promise<void>;
77
+ restart: () => Promise<void>;
73
78
  }
74
79
 
75
80
  // ---------------------------------------------------------------------------
@@ -81,8 +86,35 @@ export interface UsePathReturn<TData extends PathData = PathData> {
81
86
  * Call this from inside a Svelte component to get a reactive snapshot.
82
87
  * Cleanup is automatic via onDestroy.
83
88
  *
84
- * **Note:** `snapshot` is a reactive getter — access it via the returned
85
- * object (e.g. `path.snapshot`). Destructuring `snapshot` will lose reactivity.
89
+ * ---
90
+ *
91
+ * ⚠️ **Do not destructure `snapshot`.**
92
+ *
93
+ * `snapshot` is a reactive getter. Destructuring it copies the value once
94
+ * and severs the reactive connection — your component will stop updating.
95
+ *
96
+ * ```svelte
97
+ * // ❌ Broken — snapshot is captured once and never updates
98
+ * const { snapshot, next } = usePath();
99
+ *
100
+ * // ✅ Correct — snapshot is read through the live object on every render
101
+ * const path = usePath();
102
+ * // use path.snapshot in your template
103
+ * ```
104
+ *
105
+ * Other properties (`next`, `previous`, `setData`, etc.) are plain functions
106
+ * and are safe to destructure.
107
+ *
108
+ * If you need a local variable that stays reactive, use `$derived`:
109
+ * ```svelte
110
+ * const path = usePath();
111
+ * const snapshot = $derived(path.snapshot);
112
+ * ```
113
+ *
114
+ * This is expected Svelte 5 behaviour — see the
115
+ * [Svelte $state docs](https://svelte.dev/docs/svelte/$state) for details.
116
+ *
117
+ * ---
86
118
  *
87
119
  * @example
88
120
  * ```svelte
@@ -147,8 +179,7 @@ export function usePath<TData extends PathData = PathData>(
147
179
 
148
180
  const resetStep = (): Promise<void> => engine.resetStep();
149
181
 
150
- const restart = (path: PathDefinition<any>, initialData: PathData = {}): Promise<void> =>
151
- engine.restart(path, initialData);
182
+ const restart = (): Promise<void> => engine.restart();
152
183
 
153
184
  return {
154
185
  get snapshot() { return _snapshot; },
@@ -172,7 +203,7 @@ export function usePath<TData extends PathData = PathData>(
172
203
  const PATH_CONTEXT_KEY = Symbol("pathwrite-context");
173
204
 
174
205
  export interface PathContext<TData extends PathData = PathData> {
175
- readonly snapshot: PathSnapshot<TData> | null;
206
+ readonly snapshot: PathSnapshot<TData>;
176
207
  next: () => Promise<void>;
177
208
  previous: () => Promise<void>;
178
209
  cancel: () => Promise<void>;