@rxova/journey-react 0.6.4 → 1.0.0-rc.1
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 +97 -148
- package/dist/client.cjs +2 -0
- package/dist/client.cjs.map +7 -0
- package/dist/client.d.cts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +7 -0
- package/dist/createJourney.d.cts +15 -0
- package/dist/createJourney.d.ts +15 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/provider.d.cts +9 -0
- package/dist/provider.d.ts +9 -0
- package/dist/runtime-hooks.d.cts +17 -0
- package/dist/runtime-hooks.d.ts +17 -0
- package/dist/types.d.cts +58 -0
- package/dist/types.d.ts +49 -35
- package/package.json +19 -10
- package/dist/bindings/Provider.d.ts +0 -8
- package/dist/bindings/StepRenderer.d.ts +0 -13
- package/dist/bindings/index.d.ts +0 -6
- package/dist/bindings/useJourneyApi.d.ts +0 -17
- package/dist/bindings/useJourneyMachine.d.ts +0 -4
- package/dist/bindings/useJourneySnapshot.d.ts +0 -5
package/README.md
CHANGED
|
@@ -1,200 +1,149 @@
|
|
|
1
1
|
# @rxova/journey-react
|
|
2
2
|
|
|
3
|
-
Typed React bindings for
|
|
3
|
+
Typed React bindings for multi-step UI flows.
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://www.npmjs.com/package/@rxova/journey-react">
|
|
7
|
+
<img src="https://img.shields.io/npm/v/@rxova/journey-react?color=0f8f6a" alt="npm" />
|
|
8
|
+
</a>
|
|
9
|
+
<img src="https://img.shields.io/badge/6.3%20kB-brotli-0f8f6a" alt="size" />
|
|
10
|
+
<img src="https://img.shields.io/badge/React%2018+-black" alt="React 18+" />
|
|
11
|
+
<img src="https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript&logoColor=white" alt="TypeScript" />
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
`@rxova/journey-react` is approaching a `1.0.0-rc` contract freeze. The key runtime rule is unchanged:
|
|
15
|
+
one `createJourney(...)` call creates one machine instance immediately, and the returned hooks/components stay bound to that instance.
|
|
4
16
|
|
|
5
17
|
## Install
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
|
-
npm i @rxova/journey-react
|
|
20
|
+
npm i @rxova/journey-react @rxova/journey-core
|
|
9
21
|
```
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`@rxova/journey-react` is bindings-first:
|
|
14
|
-
|
|
15
|
-
- `createJourneyBindings(journey)` returns a typed bundle that contains:
|
|
16
|
-
- `Provider`
|
|
17
|
-
- `StepRenderer`
|
|
18
|
-
- `useJourneyApi`
|
|
19
|
-
- `useJourneySnapshot`
|
|
20
|
-
- `useJourneyMachine`
|
|
21
|
-
|
|
22
|
-
No per-hook generic arguments are needed at callsites.
|
|
23
|
+
Use the root entry for server-safe imports. When a Next.js App Router client boundary should be explicit,
|
|
24
|
+
import from `@rxova/journey-react/client`.
|
|
23
25
|
|
|
24
26
|
## Quickstart
|
|
25
27
|
|
|
26
28
|
```tsx
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
+
import { createJourney, type JourneyViews } from "@rxova/journey-react";
|
|
30
|
+
import type { JourneyDefinition } from "@rxova/journey-core";
|
|
29
31
|
|
|
30
32
|
type StepId = "start" | "review";
|
|
31
|
-
type
|
|
32
|
-
|
|
33
|
-
let bindings: ReturnType<typeof createJourneyBindings<Ctx, StepId>>;
|
|
34
|
-
|
|
35
|
-
const Start = () => {
|
|
36
|
-
const api = bindings.useJourneyApi();
|
|
37
|
-
return <button onClick={() => void api.goToNextStep()}>Next</button>;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const Review = () => {
|
|
41
|
-
const api = bindings.useJourneyApi();
|
|
42
|
-
return <button onClick={() => void api.completeJourney()}>Submit</button>;
|
|
43
|
-
};
|
|
33
|
+
type Context = { name: string };
|
|
44
34
|
|
|
45
|
-
const
|
|
35
|
+
const definition: JourneyDefinition<Context, StepId> = {
|
|
46
36
|
initial: "start",
|
|
47
37
|
context: { name: "" },
|
|
48
|
-
steps: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{ from: "start", event: "goToNextStep", to: "review" },
|
|
54
|
-
{ from: "review", event: "completeJourney" }
|
|
55
|
-
]
|
|
38
|
+
steps: { start: {}, review: {} },
|
|
39
|
+
transitions: {
|
|
40
|
+
start: { goToNextStep: [{ to: "review" }] },
|
|
41
|
+
review: { completeJourney: true }
|
|
42
|
+
}
|
|
56
43
|
};
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export const App = () => {
|
|
61
|
-
const Provider = bindings.Provider;
|
|
62
|
-
const StepRenderer = bindings.StepRenderer;
|
|
45
|
+
const signup = createJourney(definition);
|
|
63
46
|
|
|
47
|
+
const Start = () => {
|
|
48
|
+
const api = signup.useJourneyApi();
|
|
49
|
+
const snap = signup.useJourneySnapshot();
|
|
64
50
|
return (
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
|
|
51
|
+
<div>
|
|
52
|
+
<p>Hello, {snap.context.name || "stranger"}</p>
|
|
53
|
+
<button onClick={() => void api.goToNextStep()}>Next</button>
|
|
54
|
+
</div>
|
|
68
55
|
);
|
|
69
56
|
};
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Split Files Pattern (Hooks In Steps)
|
|
73
|
-
|
|
74
|
-
If step components live in separate files and call Journey hooks, export bindings as `let`:
|
|
75
57
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
import { Start, Review } from "./steps";
|
|
80
|
-
|
|
81
|
-
type StepId = "start" | "review";
|
|
82
|
-
type Ctx = { name: string };
|
|
83
|
-
|
|
84
|
-
export let bindings: ReturnType<typeof createJourneyBindings<Ctx, StepId>>;
|
|
85
|
-
|
|
86
|
-
const journey: JourneyReactDefinition<Ctx, StepId> = {
|
|
87
|
-
initial: "start",
|
|
88
|
-
context: { name: "" },
|
|
89
|
-
steps: {
|
|
90
|
-
start: { component: Start },
|
|
91
|
-
review: { component: Review }
|
|
92
|
-
},
|
|
93
|
-
transitions: [
|
|
94
|
-
{ from: "start", event: "goToNextStep", to: "review" },
|
|
95
|
-
{ from: "review", event: "completeJourney" }
|
|
96
|
-
]
|
|
58
|
+
const Review = () => {
|
|
59
|
+
const api = signup.useJourneyApi();
|
|
60
|
+
return <button onClick={() => void api.completeJourney()}>Submit</button>;
|
|
97
61
|
};
|
|
98
62
|
|
|
99
|
-
|
|
63
|
+
const views: JourneyViews<StepId> = { start: Start, review: Review };
|
|
64
|
+
|
|
65
|
+
export const App = () => (
|
|
66
|
+
<signup.JourneyProvider views={views}>
|
|
67
|
+
<signup.StepRenderer />
|
|
68
|
+
</signup.JourneyProvider>
|
|
69
|
+
);
|
|
100
70
|
```
|
|
101
71
|
|
|
102
72
|
## Hooks
|
|
103
73
|
|
|
104
|
-
|
|
105
|
-
- `useJourneyApi()` returns typed commands.
|
|
106
|
-
- `useJourneyMachine()` returns the underlying core machine instance.
|
|
107
|
-
|
|
108
|
-
## Journey API Helpers
|
|
109
|
-
|
|
110
|
-
From `bindings.useJourneyApi()`:
|
|
74
|
+
`createJourney()` returns a runtime with bound hooks:
|
|
111
75
|
|
|
112
|
-
- `
|
|
113
|
-
- `
|
|
114
|
-
- `
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
- `goToLastVisitedStep()`
|
|
118
|
-
- `updateContext`
|
|
119
|
-
- `updateStepMetadata`
|
|
120
|
-
- `clearStepError`, `resetJourney`
|
|
76
|
+
- **`useJourneySnapshot()`** — full snapshot: `currentStepId`, `context`, `history`, `status`, `async`
|
|
77
|
+
- **`useJourneyApi()`** — runtime commands: `start`, `goToNextStep`, `goToPreviousStep`, `completeJourney`, `send`, etc.
|
|
78
|
+
- **`useJourneyComputed()`** — derived state: `mode`, `activeStepId`, `isLoading`, `isFirstStep`, `isLastStep`
|
|
79
|
+
- **`useJourneySelector(selector, eq?)`** — subscribe to a slice of the snapshot
|
|
80
|
+
- **`useJourneyEvent(listener)`** — stream lifecycle events for analytics
|
|
121
81
|
|
|
122
|
-
|
|
82
|
+
## Navigation
|
|
123
83
|
|
|
124
84
|
```ts
|
|
125
|
-
|
|
85
|
+
const api = signup.useJourneyApi();
|
|
86
|
+
|
|
87
|
+
await api.start();
|
|
88
|
+
await api.goToNextStep();
|
|
89
|
+
await api.goToPreviousStep();
|
|
90
|
+
await api.goToLastVisitedStep();
|
|
91
|
+
await api.completeJourney();
|
|
92
|
+
await api.terminateJourney();
|
|
93
|
+
await api.goToStepById("review");
|
|
94
|
+
|
|
95
|
+
api.updateContext((ctx) => ({ ...ctx, name: "Ada" }));
|
|
96
|
+
api.resetJourney();
|
|
126
97
|
```
|
|
127
98
|
|
|
128
|
-
|
|
99
|
+
Transition failures resolve through `result.error` instead of rejecting, so `void api.goToNextStep()` is safe from unhandled promise rejections.
|
|
129
100
|
|
|
130
|
-
|
|
131
|
-
- `<Provider journey={...} />` lets you pass a different journey definition at runtime.
|
|
132
|
-
- Internal machine is preserved across `journey` prop changes by default.
|
|
133
|
-
- Set `resetOnJourneyChange` to rebuild internal machine when `journey` identity changes.
|
|
134
|
-
- `<Provider machine={externalMachine} />` uses your machine directly.
|
|
135
|
-
- `persistence` applies only when Provider owns the internal machine.
|
|
101
|
+
## Custom Step Renderer
|
|
136
102
|
|
|
137
|
-
|
|
138
|
-
<bindings.Provider journey={dynamicJourney} resetOnJourneyChange>
|
|
139
|
-
<bindings.StepRenderer />
|
|
140
|
-
</bindings.Provider>
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Async and Error UI
|
|
144
|
-
|
|
145
|
-
Core async state is exposed via snapshot:
|
|
103
|
+
`StepRenderer` is a convenience — it just looks up the current step's view from the `views` record and renders it. You can build your own if you need transitions, animations, or a different rendering strategy:
|
|
146
104
|
|
|
147
105
|
```tsx
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (currentAsync.phase === "error") {
|
|
155
|
-
return (
|
|
156
|
-
<div>
|
|
157
|
-
<p>Something failed.</p>
|
|
158
|
-
<button onClick={() => api.clearStepError()}>Dismiss</button>
|
|
159
|
-
</div>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
106
|
+
const MyStepRenderer = () => {
|
|
107
|
+
const { currentStepId } = signup.useJourneySnapshot();
|
|
108
|
+
const View = views[currentStepId];
|
|
109
|
+
if (!View) return <p>Unknown step</p>;
|
|
110
|
+
return <View />;
|
|
111
|
+
};
|
|
162
112
|
```
|
|
163
113
|
|
|
164
|
-
##
|
|
165
|
-
|
|
166
|
-
Use `useJourneyMachine()` and attach the devtools bridge from an effect:
|
|
114
|
+
## Plugins
|
|
167
115
|
|
|
168
116
|
```tsx
|
|
169
|
-
import
|
|
170
|
-
import { attachJourneyDevtools } from "@rxova/journey-devtools-bridge";
|
|
171
|
-
|
|
172
|
-
const JourneyDevtoolsBridge = () => {
|
|
173
|
-
const machine = bindings.useJourneyMachine();
|
|
117
|
+
import { createPersistencePlugin } from "@rxova/journey-core/persistence";
|
|
174
118
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return null;
|
|
180
|
-
};
|
|
119
|
+
const signup = createJourney(definition, {
|
|
120
|
+
plugins: [createPersistencePlugin({ key: "signup", version: 1 })],
|
|
121
|
+
defaultTimeoutMs: 30_000
|
|
122
|
+
});
|
|
181
123
|
```
|
|
182
124
|
|
|
183
|
-
##
|
|
125
|
+
## Runtime Ownership
|
|
184
126
|
|
|
185
|
-
|
|
127
|
+
Each `createJourney()` call creates one machine instance. The returned hooks are permanently bound to it.
|
|
186
128
|
|
|
187
|
-
|
|
188
|
-
|
|
129
|
+
- Rendering multiple providers from the same runtime shares one journey state
|
|
130
|
+
- `JourneyProvider` auto-starts an `idled` runtime, but does not dispose it by default
|
|
131
|
+
- Provider-free flows can start manually through `useJourneyApi().start()` or `machine.start()`
|
|
132
|
+
- Provider-owned startup failures are reported through `onError(error, { phase: "start" })`
|
|
133
|
+
- Set `disposeOnUnmount` when a provider fully owns a component-scoped runtime
|
|
134
|
+
- Independent instances require separate `createJourney()` calls
|
|
135
|
+
- `createJourneyFactory()` returns a typed helper for producing fresh runtimes from the same definition/options pair and is the preferred path when request-scoped or boundary-scoped isolation matters
|
|
136
|
+
- `dispose()` tears down subscriptions when the runtime is no longer needed
|
|
189
137
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
)
|
|
194
|
-
|
|
138
|
+
## Documentation
|
|
139
|
+
|
|
140
|
+
- [Pre-1.0 Migration](https://rxova.org/docs/core/pre-1-0-migration)
|
|
141
|
+
- [Stability Contract](https://rxova.org/docs/core/stability)
|
|
142
|
+
- [React Quickstart](https://rxova.org/docs/react/quickstart)
|
|
143
|
+
- [Provider and Hooks](https://rxova.org/docs/react/provider-and-hooks)
|
|
144
|
+
- [Patterns](https://rxova.org/docs/react/patterns)
|
|
145
|
+
- [Core Docs](https://rxova.org/docs/core/getting-started)
|
|
195
146
|
|
|
196
|
-
##
|
|
147
|
+
## License
|
|
197
148
|
|
|
198
|
-
|
|
199
|
-
- In React Server Components environments, call bindings/hooks from client components.
|
|
200
|
-
- Server-side rendering is supported (Provider + StepRenderer render safely on the server).
|
|
149
|
+
MIT
|
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";"use client";var D=Object.create;var h=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var z=(t,r)=>{for(var u in r)h(t,u,{get:r[u],enumerable:!0})},w=(t,r,u,d)=>{if(r&&typeof r=="object"||typeof r=="function")for(let a of B(r))!U.call(t,a)&&a!==u&&h(t,a,{get:()=>r[a],enumerable:!(d=N(r,a))||d.enumerable});return t};var k=(t,r,u)=>(u=t!=null?D($(t)):{},w(r||!t||!t.__esModule?h(u,"default",{value:t,enumerable:!0}):u,t)),G=t=>w(h({},"__esModule",{value:!0}),t);var X={};z(X,{createJourney:()=>b,createJourneyFactory:()=>q});module.exports=G(X);var F=require("@rxova/journey-core");var c=k(require("react"),1),S=require("react/jsx-runtime"),M=typeof window>"u"?c.default.useEffect:c.default.useLayoutEffect,K=(t,r,u)=>{if(u){u(t,r);return}console.error(`JourneyProvider ${r.phase} failed.`,t)},j=(t,r)=>{let u=c.default.createContext(null),d=(e="hook")=>{let n=c.default.useContext(u);if(!n)throw new Error(`${e} must be used within JourneyProvider.`);return n},a=({runtimeMachine:e,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T})=>{let v=c.default.useRef(n),y=c.default.useRef(o),i=c.default.useRef(s),f=c.default.useRef(l),x=c.default.useRef(null),E=n!==void 0,m=o!==void 0,C=s!==void 0;v.current=n,y.current=o,i.current=s,f.current=l,M(()=>{x.current!==null&&(globalThis.clearTimeout(x.current),x.current=null)});let R=c.default.useCallback(J=>J.status,[e]),A=c.default.useCallback(J=>e.subscribeSelector(R,()=>{J()}),[e,R]),I=c.default.useCallback(()=>e.getSnapshot().status,[e]),O=c.default.useSyncExternalStore(A,I,I);return M(()=>{if(!E&&!m&&!C)return;let J=E?e.subscribeStart(g=>{v.current?.(g)}):void 0,V=m?e.subscribeComplete(g=>{y.current?.(g)}):void 0,W=C?e.subscribeTerminate(g=>{i.current?.(g)}):void 0;return()=>{J?.(),V?.(),W?.()}},[e,m,E,C]),M(()=>{O==="idled"&&e.start().catch(J=>{K(J,{phase:"start"},f.current)})},[e,O]),M(()=>{if(T)return()=>{x.current=globalThis.setTimeout(()=>{x.current=null,e.dispose()},0)}},[e,T]),null};return{JourneyProvider:({views:e,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T=!1,children:v})=>{let y=t;return(0,S.jsxs)(u.Provider,{value:e,children:[v,(0,S.jsx)(a,{runtimeMachine:y,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T})]})},StepRenderer:({fallback:e=null})=>{let n=r(T=>T.currentStepId),s=d("StepRenderer")[n];if(!s)return(0,S.jsx)(S.Fragment,{children:e});let l=s;return(0,S.jsx)(c.default.Fragment,{children:(0,S.jsx)(l,{})},n)}}};var p=k(require("react"),1),Q=typeof window>"u"?p.default.useEffect:p.default.useLayoutEffect,H=t=>{let r=()=>{let e=t,n=p.default.useCallback(()=>e.getSnapshot(),[e]),o=p.default.useCallback(s=>e.subscribe(s),[e]);return p.default.useSyncExternalStore(o,n,n)},u=()=>{let e=r(),n=t;return p.default.useMemo(()=>n.getComputed(),[n,e])},d=(e,n)=>{let o=t,s=n??Object.is,l=p.default.useRef(null),T=p.default.useCallback(()=>{let y=o.getSnapshot(),i=l.current;if(i&&Object.is(i.machine,o)&&Object.is(i.selector,e)&&Object.is(i.isEqual,s)&&Object.is(i.snapshot,y))return i.selected;let f=e(y);return i&&Object.is(i.machine,o)&&Object.is(i.selector,e)&&Object.is(i.isEqual,s)&&s(i.selected,f)?(l.current={machine:o,snapshot:y,selected:i.selected,selector:e,isEqual:s},i.selected):(l.current={machine:o,snapshot:y,selected:f,selector:e,isEqual:s},f)},[o,s,e]),v=p.default.useCallback(y=>o.subscribeSelector(e,()=>{y()},s),[o,s,e]);return p.default.useSyncExternalStore(v,T,T)},a=e=>{let n=t,o=p.default.useRef(e);o.current=e,Q(()=>n.subscribeEvent(s=>{o.current(s)}),[n])};return{useJourneySnapshot:r,useJourneyComputed:u,useJourneySelector:d,useJourneyApi:()=>{let e=t;return p.default.useMemo(()=>({start:e.start,send:e.send,goToNextStep:e.goToNextStep,goToStepById:e.goToStepById,terminateJourney:e.terminateJourney,completeJourney:e.completeJourney,goToPreviousStep:e.goToPreviousStep,goToLastVisitedStep:e.goToLastVisitedStep,clearStepError:e.clearStepError,updateContext:e.updateContext,getStepMeta:e.getStepMeta,resetJourney:()=>e.resetJourney()}),[e])},useJourneyEvent:a,useJourneyStepLifecycle:(e,n)=>{a(o=>{o.type==="step.enter"&&o.stepId===e?n.onEnter?.({context:t.getSnapshot().context}):o.type==="step.exit"&&o.stepId===e&&n.onLeave?.({context:t.getSnapshot().context})})}}};var b=(t,r)=>{let d=(0,F.createJourneyMachine)(t,r),a=H(d),P=j(d,a.useJourneySelector);return{machine:d,dispose:()=>d.dispose(),...a,...P}},q=(t,r)=>()=>b(t,r);0&&(module.exports={createJourney,createJourneyFactory});
|
|
2
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client.ts", "../src/createJourney.tsx", "../src/provider.tsx", "../src/runtime-hooks.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\";\n\nexport * from \"./index\";\n", "import { createJourneyMachine } from \"@rxova/journey-core\";\nimport type {\n JourneyDefinition,\n JourneyJsonObject,\n JourneyMachineOptions,\n JourneyMachinePlugin,\n JourneyMachineWithPlugins\n} from \"@rxova/journey-core\";\nimport { createJourneyProviderArtifacts } from \"./provider\";\nimport { createJourneyHooks } from \"./runtime-hooks\";\nimport type { JourneyRuntime, JourneyRuntimeFactory } from \"./types\";\n\ntype JourneyOptionsInput<TPlugins extends readonly JourneyMachinePlugin[]> = JourneyMachineOptions<\n TPlugins extends [] ? readonly JourneyMachinePlugin[] : TPlugins\n>;\n\n/**\n * Creates a journey machine and returns React hooks/components bound to that machine.\n * Hooks work without a provider; `JourneyProvider` is only required for `StepRenderer`.\n */\nexport const createJourney = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyOptionsInput<TPlugins>\n): JourneyRuntime<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers> => {\n const machineOptions = options as JourneyMachineOptions<TPlugins> | undefined;\n const machine = createJourneyMachine<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >(definition, machineOptions) as JourneyMachineWithPlugins<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >;\n const hooks = createJourneyHooks<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>(\n machine\n );\n const providerArtifacts = createJourneyProviderArtifacts<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >(machine, hooks.useJourneySelector);\n\n return {\n machine,\n dispose: () => machine.dispose(),\n ...hooks,\n ...providerArtifacts\n };\n};\n\n/**\n * Creates a typed factory for producing fresh React-bound journey runtimes.\n * Use this when a component or route boundary needs independent instances\n * from the same definition/options pair.\n */\nexport const createJourneyFactory = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyOptionsInput<TPlugins>\n): JourneyRuntimeFactory<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers> => {\n return () =>\n createJourney<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>(\n definition,\n options\n );\n};\n", "import React from \"react\";\n\nimport type {\n JourneyEqualityFn,\n JourneyJsonObject,\n JourneySelector,\n JourneyMachineWithPlugins,\n JourneyMachinePlugin\n} from \"@rxova/journey-core\";\nimport type { JourneyProviderErrorContext, JourneyProviderProps, JourneyViews } from \"./types\";\n\nconst useSafeLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nconst reportProviderError = (\n error: unknown,\n context: JourneyProviderErrorContext,\n listener?: ((error: unknown, context: JourneyProviderErrorContext) => void) | undefined\n) => {\n if (listener) {\n listener(error, context);\n return;\n }\n\n console.error(`JourneyProvider ${context.phase} failed.`, error);\n};\n\nexport const createJourneyProviderArtifacts = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n machine: JourneyMachineWithPlugins<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>,\n useJourneySelector: <TSelected>(\n selector: JourneySelector<TContext, TStepId, TSelected>,\n equalityFn?: JourneyEqualityFn<TSelected>\n ) => TSelected\n) => {\n const ViewsContext = React.createContext<JourneyViews<TStepId> | null>(null);\n\n const useJourneyViews = (hookName = \"hook\") => {\n const views = React.useContext(ViewsContext);\n if (!views) {\n throw new Error(`${hookName} must be used within JourneyProvider.`);\n }\n return views;\n };\n\n const ProviderController = ({\n runtimeMachine,\n onStart,\n onComplete,\n onTerminate,\n onError,\n disposeOnUnmount\n }: {\n runtimeMachine: typeof machine;\n onStart: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onStart\"] | undefined;\n onComplete: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onComplete\"] | undefined;\n onTerminate: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onTerminate\"] | undefined;\n onError: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onError\"] | undefined;\n disposeOnUnmount: boolean;\n }) => {\n const onStartRef = React.useRef(onStart);\n const onCompleteRef = React.useRef(onComplete);\n const onTerminateRef = React.useRef(onTerminate);\n const onErrorRef = React.useRef(onError);\n const scheduledDisposeRef = React.useRef<ReturnType<typeof globalThis.setTimeout> | null>(null);\n const hasOnStart = onStart !== undefined;\n const hasOnComplete = onComplete !== undefined;\n const hasOnTerminate = onTerminate !== undefined;\n\n onStartRef.current = onStart;\n onCompleteRef.current = onComplete;\n onTerminateRef.current = onTerminate;\n onErrorRef.current = onError;\n\n useSafeLayoutEffect(() => {\n if (scheduledDisposeRef.current === null) {\n return;\n }\n\n globalThis.clearTimeout(scheduledDisposeRef.current);\n scheduledDisposeRef.current = null;\n });\n\n const selectStatus = React.useCallback(\n (snapshot: ReturnType<typeof runtimeMachine.getSnapshot>) => snapshot.status,\n [runtimeMachine]\n );\n const subscribeToStatus = React.useCallback(\n (onStoreChange: () => void) =>\n runtimeMachine.subscribeSelector(selectStatus, () => {\n onStoreChange();\n }),\n [runtimeMachine, selectStatus]\n );\n const getStatus = React.useCallback(\n () => runtimeMachine.getSnapshot().status,\n [runtimeMachine]\n );\n const status = React.useSyncExternalStore(subscribeToStatus, getStatus, getStatus);\n\n useSafeLayoutEffect(() => {\n if (!hasOnStart && !hasOnComplete && !hasOnTerminate) {\n return;\n }\n\n const unsubStart = hasOnStart\n ? runtimeMachine.subscribeStart((event) => {\n onStartRef.current?.(event);\n })\n : undefined;\n\n const unsubComplete = hasOnComplete\n ? runtimeMachine.subscribeComplete((event) => {\n onCompleteRef.current?.(event);\n })\n : undefined;\n\n const unsubTerminate = hasOnTerminate\n ? runtimeMachine.subscribeTerminate((event) => {\n onTerminateRef.current?.(event);\n })\n : undefined;\n\n return () => {\n unsubStart?.();\n unsubComplete?.();\n unsubTerminate?.();\n };\n }, [runtimeMachine, hasOnComplete, hasOnStart, hasOnTerminate]);\n\n useSafeLayoutEffect(() => {\n if (status === \"idled\") {\n void runtimeMachine.start().catch((error) => {\n reportProviderError(error, { phase: \"start\" }, onErrorRef.current);\n });\n }\n }, [runtimeMachine, status]);\n\n useSafeLayoutEffect(() => {\n if (!disposeOnUnmount) {\n return;\n }\n\n return () => {\n scheduledDisposeRef.current = globalThis.setTimeout(() => {\n scheduledDisposeRef.current = null;\n runtimeMachine.dispose();\n }, 0);\n };\n }, [runtimeMachine, disposeOnUnmount]);\n\n return null;\n };\n\n const JourneyProvider = ({\n views,\n onStart,\n onComplete,\n onTerminate,\n onError,\n disposeOnUnmount = false,\n children\n }: JourneyProviderProps<TStepId, TEventMap, TStepMeta>) => {\n const runtimeMachine = machine;\n\n return (\n <ViewsContext.Provider value={views}>\n {children}\n <ProviderController\n runtimeMachine={runtimeMachine}\n onStart={onStart}\n onComplete={onComplete}\n onTerminate={onTerminate}\n onError={onError}\n disposeOnUnmount={disposeOnUnmount}\n />\n </ViewsContext.Provider>\n );\n };\n\n const StepRenderer = ({ fallback = null }: { fallback?: React.ReactNode }) => {\n const currentStepId = useJourneySelector((snapshot) => snapshot.currentStepId);\n const views = useJourneyViews(\"StepRenderer\");\n const StepComponent = views[currentStepId];\n\n if (!StepComponent) {\n return <>{fallback}</>;\n }\n\n const StepView = StepComponent as React.ComponentType;\n\n return (\n <React.Fragment key={currentStepId}>\n <StepView />\n </React.Fragment>\n );\n };\n\n return {\n JourneyProvider,\n StepRenderer\n };\n};\n", "import React from \"react\";\n\nimport type {\n JourneyComputed,\n JourneyEqualityFn,\n JourneyJsonObject,\n JourneyMachinePlugin,\n JourneyMachineWithPlugins,\n JourneyObservationEvent,\n JourneySelector,\n JourneySnapshot\n} from \"@rxova/journey-core\";\nimport type { JourneyApi } from \"./types\";\n\ntype SelectorCache<TContext extends JourneyJsonObject, TStepId extends string, TSelected> = {\n machine: unknown;\n snapshot: JourneySnapshot<TContext, TStepId>;\n selected: TSelected;\n selector: unknown;\n isEqual: JourneyEqualityFn<TSelected>;\n};\n\nconst useSafeLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nexport const createJourneyHooks = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n machine: JourneyMachineWithPlugins<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>\n) => {\n const useJourneySnapshot = (): JourneySnapshot<TContext, TStepId> => {\n const runtimeMachine = machine;\n const getSnapshot = React.useCallback(() => runtimeMachine.getSnapshot(), [runtimeMachine]);\n const subscribe = React.useCallback(\n (onStoreChange: () => void) => runtimeMachine.subscribe(onStoreChange),\n [runtimeMachine]\n );\n\n return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n };\n\n const useJourneyComputed = (): JourneyComputed<TStepId> => {\n const snapshot = useJourneySnapshot();\n const runtimeMachine = machine;\n return React.useMemo(() => {\n void snapshot;\n return runtimeMachine.getComputed();\n }, [runtimeMachine, snapshot]);\n };\n\n const useJourneySelector = <TSelected,>(\n selector: JourneySelector<TContext, TStepId, TSelected>,\n equalityFn?: JourneyEqualityFn<TSelected>\n ): TSelected => {\n const runtimeMachine = machine;\n const isEqual = equalityFn ?? Object.is;\n const cacheRef = React.useRef<SelectorCache<TContext, TStepId, TSelected> | null>(null);\n\n const getSelectedSnapshot = React.useCallback(() => {\n const nextSnapshot = runtimeMachine.getSnapshot();\n const cached = cacheRef.current;\n\n if (\n cached &&\n Object.is(cached.machine, runtimeMachine) &&\n Object.is(cached.selector, selector) &&\n Object.is(cached.isEqual, isEqual) &&\n Object.is(cached.snapshot, nextSnapshot)\n ) {\n return cached.selected;\n }\n\n const nextSelected = selector(nextSnapshot);\n\n if (\n cached &&\n Object.is(cached.machine, runtimeMachine) &&\n Object.is(cached.selector, selector) &&\n Object.is(cached.isEqual, isEqual) &&\n isEqual(cached.selected, nextSelected)\n ) {\n cacheRef.current = {\n machine: runtimeMachine,\n snapshot: nextSnapshot,\n selected: cached.selected,\n selector,\n isEqual\n };\n return cached.selected;\n }\n\n cacheRef.current = {\n machine: runtimeMachine,\n snapshot: nextSnapshot,\n selected: nextSelected,\n selector,\n isEqual\n };\n return nextSelected;\n }, [runtimeMachine, isEqual, selector]);\n\n const subscribeToSelectedSnapshot = React.useCallback(\n (onStoreChange: () => void) =>\n runtimeMachine.subscribeSelector(\n selector,\n () => {\n onStoreChange();\n },\n isEqual\n ),\n [runtimeMachine, isEqual, selector]\n );\n\n return React.useSyncExternalStore(\n subscribeToSelectedSnapshot,\n getSelectedSnapshot,\n getSelectedSnapshot\n );\n };\n\n const useJourneyEvent = (\n listener: (event: JourneyObservationEvent<TStepId, TEventMap>) => void\n ): void => {\n const runtimeMachine = machine;\n const listenerRef = React.useRef(listener);\n listenerRef.current = listener;\n\n useSafeLayoutEffect(() => {\n return runtimeMachine.subscribeEvent((event) => {\n listenerRef.current(event);\n });\n }, [runtimeMachine]);\n };\n\n const useJourneyStepLifecycle = (\n stepId: TStepId,\n callbacks: {\n onEnter?: (args: { context: TContext }) => void;\n onLeave?: (args: { context: TContext }) => void;\n }\n ): void => {\n useJourneyEvent((event) => {\n if (event.type === \"step.enter\" && event.stepId === stepId) {\n callbacks.onEnter?.({ context: machine.getSnapshot().context });\n } else if (event.type === \"step.exit\" && event.stepId === stepId) {\n callbacks.onLeave?.({ context: machine.getSnapshot().context });\n }\n });\n };\n\n const useJourneyApi = (): JourneyApi<TContext, TStepId, TEventMap, TStepMeta> => {\n const runtimeMachine = machine;\n return React.useMemo(\n () => ({\n start: runtimeMachine.start,\n send: runtimeMachine.send,\n goToNextStep: runtimeMachine.goToNextStep,\n goToStepById: runtimeMachine.goToStepById,\n terminateJourney: runtimeMachine.terminateJourney,\n completeJourney: runtimeMachine.completeJourney,\n goToPreviousStep: runtimeMachine.goToPreviousStep,\n goToLastVisitedStep: runtimeMachine.goToLastVisitedStep,\n clearStepError: runtimeMachine.clearStepError,\n updateContext: runtimeMachine.updateContext,\n getStepMeta: runtimeMachine.getStepMeta,\n resetJourney: () => runtimeMachine.resetJourney()\n }),\n [runtimeMachine]\n );\n };\n\n return {\n useJourneySnapshot,\n useJourneyComputed,\n useJourneySelector,\n useJourneyApi,\n useJourneyEvent,\n useJourneyStepLifecycle\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["client_exports", "__export", "createJourney", "createJourneyFactory", "__toCommonJS", "import_journey_core", "import_react", "import_jsx_runtime", "useSafeLayoutEffect", "React", "reportProviderError", "error", "context", "listener", "createJourneyProviderArtifacts", "machine", "useJourneySelector", "ViewsContext", "useJourneyViews", "hookName", "views", "ProviderController", "runtimeMachine", "onStart", "onComplete", "onTerminate", "onError", "disposeOnUnmount", "onStartRef", "onCompleteRef", "onTerminateRef", "onErrorRef", "scheduledDisposeRef", "hasOnStart", "hasOnComplete", "hasOnTerminate", "selectStatus", "snapshot", "subscribeToStatus", "onStoreChange", "getStatus", "status", "unsubStart", "event", "unsubComplete", "unsubTerminate", "children", "fallback", "currentStepId", "StepComponent", "StepView", "import_react", "useSafeLayoutEffect", "React", "createJourneyHooks", "machine", "useJourneySnapshot", "runtimeMachine", "getSnapshot", "subscribe", "onStoreChange", "useJourneyComputed", "snapshot", "useJourneySelector", "selector", "equalityFn", "isEqual", "cacheRef", "getSelectedSnapshot", "nextSnapshot", "cached", "nextSelected", "subscribeToSelectedSnapshot", "useJourneyEvent", "listener", "listenerRef", "event", "stepId", "callbacks", "createJourney", "definition", "options", "machine", "hooks", "createJourneyHooks", "providerArtifacts", "createJourneyProviderArtifacts", "createJourneyFactory"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index";
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index";
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";import{createJourneyMachine as W}from"@rxova/journey-core";import u from"react";import{Fragment as A,jsx as h,jsxs as L}from"react/jsx-runtime";var g=typeof window>"u"?u.useEffect:u.useLayoutEffect,q=(r,c,y)=>{if(y){y(r,c);return}console.error(`JourneyProvider ${c.phase} failed.`,r)},I=(r,c)=>{let y=u.createContext(null),l=(e="hook")=>{let t=u.useContext(y);if(!t)throw new Error(`${e} must be used within JourneyProvider.`);return t},T=({runtimeMachine:e,onStart:t,onComplete:n,onTerminate:o,onError:p,disposeOnUnmount:d})=>{let J=u.useRef(t),a=u.useRef(n),s=u.useRef(o),v=u.useRef(p),f=u.useRef(null),P=t!==void 0,E=n!==void 0,m=o!==void 0;J.current=t,a.current=n,s.current=o,v.current=p,g(()=>{f.current!==null&&(globalThis.clearTimeout(f.current),f.current=null)});let C=u.useCallback(S=>S.status,[e]),j=u.useCallback(S=>e.subscribeSelector(C,()=>{S()}),[e,C]),b=u.useCallback(()=>e.getSnapshot().status,[e]),R=u.useSyncExternalStore(j,b,b);return g(()=>{if(!P&&!E&&!m)return;let S=P?e.subscribeStart(x=>{J.current?.(x)}):void 0,H=E?e.subscribeComplete(x=>{a.current?.(x)}):void 0,F=m?e.subscribeTerminate(x=>{s.current?.(x)}):void 0;return()=>{S?.(),H?.(),F?.()}},[e,E,P,m]),g(()=>{R==="idled"&&e.start().catch(S=>{q(S,{phase:"start"},v.current)})},[e,R]),g(()=>{if(d)return()=>{f.current=globalThis.setTimeout(()=>{f.current=null,e.dispose()},0)}},[e,d]),null};return{JourneyProvider:({views:e,onStart:t,onComplete:n,onTerminate:o,onError:p,disposeOnUnmount:d=!1,children:J})=>{let a=r;return L(y.Provider,{value:e,children:[J,h(T,{runtimeMachine:a,onStart:t,onComplete:n,onTerminate:o,onError:p,disposeOnUnmount:d})]})},StepRenderer:({fallback:e=null})=>{let t=c(d=>d.currentStepId),o=l("StepRenderer")[t];if(!o)return h(A,{children:e});let p=o;return h(u.Fragment,{children:h(p,{})},t)}}};import i from"react";var V=typeof window>"u"?i.useEffect:i.useLayoutEffect,O=r=>{let c=()=>{let e=r,t=i.useCallback(()=>e.getSnapshot(),[e]),n=i.useCallback(o=>e.subscribe(o),[e]);return i.useSyncExternalStore(n,t,t)},y=()=>{let e=c(),t=r;return i.useMemo(()=>t.getComputed(),[t,e])},l=(e,t)=>{let n=r,o=t??Object.is,p=i.useRef(null),d=i.useCallback(()=>{let a=n.getSnapshot(),s=p.current;if(s&&Object.is(s.machine,n)&&Object.is(s.selector,e)&&Object.is(s.isEqual,o)&&Object.is(s.snapshot,a))return s.selected;let v=e(a);return s&&Object.is(s.machine,n)&&Object.is(s.selector,e)&&Object.is(s.isEqual,o)&&o(s.selected,v)?(p.current={machine:n,snapshot:a,selected:s.selected,selector:e,isEqual:o},s.selected):(p.current={machine:n,snapshot:a,selected:v,selector:e,isEqual:o},v)},[n,o,e]),J=i.useCallback(a=>n.subscribeSelector(e,()=>{a()},o),[n,o,e]);return i.useSyncExternalStore(J,d,d)},T=e=>{let t=r,n=i.useRef(e);n.current=e,V(()=>t.subscribeEvent(o=>{n.current(o)}),[t])};return{useJourneySnapshot:c,useJourneyComputed:y,useJourneySelector:l,useJourneyApi:()=>{let e=r;return i.useMemo(()=>({start:e.start,send:e.send,goToNextStep:e.goToNextStep,goToStepById:e.goToStepById,terminateJourney:e.terminateJourney,completeJourney:e.completeJourney,goToPreviousStep:e.goToPreviousStep,goToLastVisitedStep:e.goToLastVisitedStep,clearStepError:e.clearStepError,updateContext:e.updateContext,getStepMeta:e.getStepMeta,resetJourney:()=>e.resetJourney()}),[e])},useJourneyEvent:T,useJourneyStepLifecycle:(e,t)=>{T(n=>{n.type==="step.enter"&&n.stepId===e?t.onEnter?.({context:r.getSnapshot().context}):n.type==="step.exit"&&n.stepId===e&&t.onLeave?.({context:r.getSnapshot().context})})}}};var w=(r,c)=>{let l=W(r,c),T=O(l),M=I(l,T.useJourneySelector);return{machine:l,dispose:()=>l.dispose(),...T,...M}},D=(r,c)=>()=>w(r,c);export{w as createJourney,D as createJourneyFactory};
|
|
2
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/createJourney.tsx", "../src/provider.tsx", "../src/runtime-hooks.tsx"],
|
|
4
|
+
"sourcesContent": ["import { createJourneyMachine } from \"@rxova/journey-core\";\nimport type {\n JourneyDefinition,\n JourneyJsonObject,\n JourneyMachineOptions,\n JourneyMachinePlugin,\n JourneyMachineWithPlugins\n} from \"@rxova/journey-core\";\nimport { createJourneyProviderArtifacts } from \"./provider\";\nimport { createJourneyHooks } from \"./runtime-hooks\";\nimport type { JourneyRuntime, JourneyRuntimeFactory } from \"./types\";\n\ntype JourneyOptionsInput<TPlugins extends readonly JourneyMachinePlugin[]> = JourneyMachineOptions<\n TPlugins extends [] ? readonly JourneyMachinePlugin[] : TPlugins\n>;\n\n/**\n * Creates a journey machine and returns React hooks/components bound to that machine.\n * Hooks work without a provider; `JourneyProvider` is only required for `StepRenderer`.\n */\nexport const createJourney = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyOptionsInput<TPlugins>\n): JourneyRuntime<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers> => {\n const machineOptions = options as JourneyMachineOptions<TPlugins> | undefined;\n const machine = createJourneyMachine<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >(definition, machineOptions) as JourneyMachineWithPlugins<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >;\n const hooks = createJourneyHooks<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>(\n machine\n );\n const providerArtifacts = createJourneyProviderArtifacts<\n TContext,\n TStepId,\n TEventMap,\n TStepMeta,\n THandlers,\n TPlugins\n >(machine, hooks.useJourneySelector);\n\n return {\n machine,\n dispose: () => machine.dispose(),\n ...hooks,\n ...providerArtifacts\n };\n};\n\n/**\n * Creates a typed factory for producing fresh React-bound journey runtimes.\n * Use this when a component or route boundary needs independent instances\n * from the same definition/options pair.\n */\nexport const createJourneyFactory = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyOptionsInput<TPlugins>\n): JourneyRuntimeFactory<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers> => {\n return () =>\n createJourney<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>(\n definition,\n options\n );\n};\n", "import React from \"react\";\n\nimport type {\n JourneyEqualityFn,\n JourneyJsonObject,\n JourneySelector,\n JourneyMachineWithPlugins,\n JourneyMachinePlugin\n} from \"@rxova/journey-core\";\nimport type { JourneyProviderErrorContext, JourneyProviderProps, JourneyViews } from \"./types\";\n\nconst useSafeLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nconst reportProviderError = (\n error: unknown,\n context: JourneyProviderErrorContext,\n listener?: ((error: unknown, context: JourneyProviderErrorContext) => void) | undefined\n) => {\n if (listener) {\n listener(error, context);\n return;\n }\n\n console.error(`JourneyProvider ${context.phase} failed.`, error);\n};\n\nexport const createJourneyProviderArtifacts = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n machine: JourneyMachineWithPlugins<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>,\n useJourneySelector: <TSelected>(\n selector: JourneySelector<TContext, TStepId, TSelected>,\n equalityFn?: JourneyEqualityFn<TSelected>\n ) => TSelected\n) => {\n const ViewsContext = React.createContext<JourneyViews<TStepId> | null>(null);\n\n const useJourneyViews = (hookName = \"hook\") => {\n const views = React.useContext(ViewsContext);\n if (!views) {\n throw new Error(`${hookName} must be used within JourneyProvider.`);\n }\n return views;\n };\n\n const ProviderController = ({\n runtimeMachine,\n onStart,\n onComplete,\n onTerminate,\n onError,\n disposeOnUnmount\n }: {\n runtimeMachine: typeof machine;\n onStart: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onStart\"] | undefined;\n onComplete: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onComplete\"] | undefined;\n onTerminate: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onTerminate\"] | undefined;\n onError: JourneyProviderProps<TStepId, TEventMap, TStepMeta>[\"onError\"] | undefined;\n disposeOnUnmount: boolean;\n }) => {\n const onStartRef = React.useRef(onStart);\n const onCompleteRef = React.useRef(onComplete);\n const onTerminateRef = React.useRef(onTerminate);\n const onErrorRef = React.useRef(onError);\n const scheduledDisposeRef = React.useRef<ReturnType<typeof globalThis.setTimeout> | null>(null);\n const hasOnStart = onStart !== undefined;\n const hasOnComplete = onComplete !== undefined;\n const hasOnTerminate = onTerminate !== undefined;\n\n onStartRef.current = onStart;\n onCompleteRef.current = onComplete;\n onTerminateRef.current = onTerminate;\n onErrorRef.current = onError;\n\n useSafeLayoutEffect(() => {\n if (scheduledDisposeRef.current === null) {\n return;\n }\n\n globalThis.clearTimeout(scheduledDisposeRef.current);\n scheduledDisposeRef.current = null;\n });\n\n const selectStatus = React.useCallback(\n (snapshot: ReturnType<typeof runtimeMachine.getSnapshot>) => snapshot.status,\n [runtimeMachine]\n );\n const subscribeToStatus = React.useCallback(\n (onStoreChange: () => void) =>\n runtimeMachine.subscribeSelector(selectStatus, () => {\n onStoreChange();\n }),\n [runtimeMachine, selectStatus]\n );\n const getStatus = React.useCallback(\n () => runtimeMachine.getSnapshot().status,\n [runtimeMachine]\n );\n const status = React.useSyncExternalStore(subscribeToStatus, getStatus, getStatus);\n\n useSafeLayoutEffect(() => {\n if (!hasOnStart && !hasOnComplete && !hasOnTerminate) {\n return;\n }\n\n const unsubStart = hasOnStart\n ? runtimeMachine.subscribeStart((event) => {\n onStartRef.current?.(event);\n })\n : undefined;\n\n const unsubComplete = hasOnComplete\n ? runtimeMachine.subscribeComplete((event) => {\n onCompleteRef.current?.(event);\n })\n : undefined;\n\n const unsubTerminate = hasOnTerminate\n ? runtimeMachine.subscribeTerminate((event) => {\n onTerminateRef.current?.(event);\n })\n : undefined;\n\n return () => {\n unsubStart?.();\n unsubComplete?.();\n unsubTerminate?.();\n };\n }, [runtimeMachine, hasOnComplete, hasOnStart, hasOnTerminate]);\n\n useSafeLayoutEffect(() => {\n if (status === \"idled\") {\n void runtimeMachine.start().catch((error) => {\n reportProviderError(error, { phase: \"start\" }, onErrorRef.current);\n });\n }\n }, [runtimeMachine, status]);\n\n useSafeLayoutEffect(() => {\n if (!disposeOnUnmount) {\n return;\n }\n\n return () => {\n scheduledDisposeRef.current = globalThis.setTimeout(() => {\n scheduledDisposeRef.current = null;\n runtimeMachine.dispose();\n }, 0);\n };\n }, [runtimeMachine, disposeOnUnmount]);\n\n return null;\n };\n\n const JourneyProvider = ({\n views,\n onStart,\n onComplete,\n onTerminate,\n onError,\n disposeOnUnmount = false,\n children\n }: JourneyProviderProps<TStepId, TEventMap, TStepMeta>) => {\n const runtimeMachine = machine;\n\n return (\n <ViewsContext.Provider value={views}>\n {children}\n <ProviderController\n runtimeMachine={runtimeMachine}\n onStart={onStart}\n onComplete={onComplete}\n onTerminate={onTerminate}\n onError={onError}\n disposeOnUnmount={disposeOnUnmount}\n />\n </ViewsContext.Provider>\n );\n };\n\n const StepRenderer = ({ fallback = null }: { fallback?: React.ReactNode }) => {\n const currentStepId = useJourneySelector((snapshot) => snapshot.currentStepId);\n const views = useJourneyViews(\"StepRenderer\");\n const StepComponent = views[currentStepId];\n\n if (!StepComponent) {\n return <>{fallback}</>;\n }\n\n const StepView = StepComponent as React.ComponentType;\n\n return (\n <React.Fragment key={currentStepId}>\n <StepView />\n </React.Fragment>\n );\n };\n\n return {\n JourneyProvider,\n StepRenderer\n };\n};\n", "import React from \"react\";\n\nimport type {\n JourneyComputed,\n JourneyEqualityFn,\n JourneyJsonObject,\n JourneyMachinePlugin,\n JourneyMachineWithPlugins,\n JourneyObservationEvent,\n JourneySelector,\n JourneySnapshot\n} from \"@rxova/journey-core\";\nimport type { JourneyApi } from \"./types\";\n\ntype SelectorCache<TContext extends JourneyJsonObject, TStepId extends string, TSelected> = {\n machine: unknown;\n snapshot: JourneySnapshot<TContext, TStepId>;\n selected: TSelected;\n selector: unknown;\n isEqual: JourneyEqualityFn<TSelected>;\n};\n\nconst useSafeLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nexport const createJourneyHooks = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>,\n TPlugins extends readonly JourneyMachinePlugin[] = []\n>(\n machine: JourneyMachineWithPlugins<TContext, TStepId, TEventMap, TStepMeta, THandlers, TPlugins>\n) => {\n const useJourneySnapshot = (): JourneySnapshot<TContext, TStepId> => {\n const runtimeMachine = machine;\n const getSnapshot = React.useCallback(() => runtimeMachine.getSnapshot(), [runtimeMachine]);\n const subscribe = React.useCallback(\n (onStoreChange: () => void) => runtimeMachine.subscribe(onStoreChange),\n [runtimeMachine]\n );\n\n return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n };\n\n const useJourneyComputed = (): JourneyComputed<TStepId> => {\n const snapshot = useJourneySnapshot();\n const runtimeMachine = machine;\n return React.useMemo(() => {\n void snapshot;\n return runtimeMachine.getComputed();\n }, [runtimeMachine, snapshot]);\n };\n\n const useJourneySelector = <TSelected,>(\n selector: JourneySelector<TContext, TStepId, TSelected>,\n equalityFn?: JourneyEqualityFn<TSelected>\n ): TSelected => {\n const runtimeMachine = machine;\n const isEqual = equalityFn ?? Object.is;\n const cacheRef = React.useRef<SelectorCache<TContext, TStepId, TSelected> | null>(null);\n\n const getSelectedSnapshot = React.useCallback(() => {\n const nextSnapshot = runtimeMachine.getSnapshot();\n const cached = cacheRef.current;\n\n if (\n cached &&\n Object.is(cached.machine, runtimeMachine) &&\n Object.is(cached.selector, selector) &&\n Object.is(cached.isEqual, isEqual) &&\n Object.is(cached.snapshot, nextSnapshot)\n ) {\n return cached.selected;\n }\n\n const nextSelected = selector(nextSnapshot);\n\n if (\n cached &&\n Object.is(cached.machine, runtimeMachine) &&\n Object.is(cached.selector, selector) &&\n Object.is(cached.isEqual, isEqual) &&\n isEqual(cached.selected, nextSelected)\n ) {\n cacheRef.current = {\n machine: runtimeMachine,\n snapshot: nextSnapshot,\n selected: cached.selected,\n selector,\n isEqual\n };\n return cached.selected;\n }\n\n cacheRef.current = {\n machine: runtimeMachine,\n snapshot: nextSnapshot,\n selected: nextSelected,\n selector,\n isEqual\n };\n return nextSelected;\n }, [runtimeMachine, isEqual, selector]);\n\n const subscribeToSelectedSnapshot = React.useCallback(\n (onStoreChange: () => void) =>\n runtimeMachine.subscribeSelector(\n selector,\n () => {\n onStoreChange();\n },\n isEqual\n ),\n [runtimeMachine, isEqual, selector]\n );\n\n return React.useSyncExternalStore(\n subscribeToSelectedSnapshot,\n getSelectedSnapshot,\n getSelectedSnapshot\n );\n };\n\n const useJourneyEvent = (\n listener: (event: JourneyObservationEvent<TStepId, TEventMap>) => void\n ): void => {\n const runtimeMachine = machine;\n const listenerRef = React.useRef(listener);\n listenerRef.current = listener;\n\n useSafeLayoutEffect(() => {\n return runtimeMachine.subscribeEvent((event) => {\n listenerRef.current(event);\n });\n }, [runtimeMachine]);\n };\n\n const useJourneyStepLifecycle = (\n stepId: TStepId,\n callbacks: {\n onEnter?: (args: { context: TContext }) => void;\n onLeave?: (args: { context: TContext }) => void;\n }\n ): void => {\n useJourneyEvent((event) => {\n if (event.type === \"step.enter\" && event.stepId === stepId) {\n callbacks.onEnter?.({ context: machine.getSnapshot().context });\n } else if (event.type === \"step.exit\" && event.stepId === stepId) {\n callbacks.onLeave?.({ context: machine.getSnapshot().context });\n }\n });\n };\n\n const useJourneyApi = (): JourneyApi<TContext, TStepId, TEventMap, TStepMeta> => {\n const runtimeMachine = machine;\n return React.useMemo(\n () => ({\n start: runtimeMachine.start,\n send: runtimeMachine.send,\n goToNextStep: runtimeMachine.goToNextStep,\n goToStepById: runtimeMachine.goToStepById,\n terminateJourney: runtimeMachine.terminateJourney,\n completeJourney: runtimeMachine.completeJourney,\n goToPreviousStep: runtimeMachine.goToPreviousStep,\n goToLastVisitedStep: runtimeMachine.goToLastVisitedStep,\n clearStepError: runtimeMachine.clearStepError,\n updateContext: runtimeMachine.updateContext,\n getStepMeta: runtimeMachine.getStepMeta,\n resetJourney: () => runtimeMachine.resetJourney()\n }),\n [runtimeMachine]\n );\n };\n\n return {\n useJourneySnapshot,\n useJourneyComputed,\n useJourneySelector,\n useJourneyApi,\n useJourneyEvent,\n useJourneyStepLifecycle\n };\n};\n"],
|
|
5
|
+
"mappings": "aAAA,OAAS,wBAAAA,MAA4B,sBCArC,OAAOC,MAAW,QA2KZ,OAoBO,YAAAC,EAlBL,OAAAC,EAFF,QAAAC,MAAA,oBAhKN,IAAMC,EAAsB,OAAO,OAAW,IAAcJ,EAAM,UAAYA,EAAM,gBAE9EK,EAAsB,CAC1BC,EACAC,EACAC,IACG,CACH,GAAIA,EAAU,CACZA,EAASF,EAAOC,CAAO,EACvB,MACF,CAEA,QAAQ,MAAM,mBAAmBA,EAAQ,KAAK,WAAYD,CAAK,CACjE,EAEaG,EAAiC,CAQ5CC,EACAC,IAIG,CACH,IAAMC,EAAeZ,EAAM,cAA4C,IAAI,EAErEa,EAAkB,CAACC,EAAW,SAAW,CAC7C,IAAMC,EAAQf,EAAM,WAAWY,CAAY,EAC3C,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,GAAGD,CAAQ,uCAAuC,EAEpE,OAAOC,CACT,EAEMC,EAAqB,CAAC,CAC1B,eAAAC,EACA,QAAAC,EACA,WAAAC,EACA,YAAAC,EACA,QAAAC,EACA,iBAAAC,CACF,IAOM,CACJ,IAAMC,EAAavB,EAAM,OAAOkB,CAAO,EACjCM,EAAgBxB,EAAM,OAAOmB,CAAU,EACvCM,EAAiBzB,EAAM,OAAOoB,CAAW,EACzCM,EAAa1B,EAAM,OAAOqB,CAAO,EACjCM,EAAsB3B,EAAM,OAAwD,IAAI,EACxF4B,EAAaV,IAAY,OACzBW,EAAgBV,IAAe,OAC/BW,EAAiBV,IAAgB,OAEvCG,EAAW,QAAUL,EACrBM,EAAc,QAAUL,EACxBM,EAAe,QAAUL,EACzBM,EAAW,QAAUL,EAErBjB,EAAoB,IAAM,CACpBuB,EAAoB,UAAY,OAIpC,WAAW,aAAaA,EAAoB,OAAO,EACnDA,EAAoB,QAAU,KAChC,CAAC,EAED,IAAMI,EAAe/B,EAAM,YACxBgC,GAA4DA,EAAS,OACtE,CAACf,CAAc,CACjB,EACMgB,EAAoBjC,EAAM,YAC7BkC,GACCjB,EAAe,kBAAkBc,EAAc,IAAM,CACnDG,EAAc,CAChB,CAAC,EACH,CAACjB,EAAgBc,CAAY,CAC/B,EACMI,EAAYnC,EAAM,YACtB,IAAMiB,EAAe,YAAY,EAAE,OACnC,CAACA,CAAc,CACjB,EACMmB,EAASpC,EAAM,qBAAqBiC,EAAmBE,EAAWA,CAAS,EAEjF,OAAA/B,EAAoB,IAAM,CACxB,GAAI,CAACwB,GAAc,CAACC,GAAiB,CAACC,EACpC,OAGF,IAAMO,EAAaT,EACfX,EAAe,eAAgBqB,GAAU,CACvCf,EAAW,UAAUe,CAAK,CAC5B,CAAC,EACD,OAEEC,EAAgBV,EAClBZ,EAAe,kBAAmBqB,GAAU,CAC1Cd,EAAc,UAAUc,CAAK,CAC/B,CAAC,EACD,OAEEE,EAAiBV,EACnBb,EAAe,mBAAoBqB,GAAU,CAC3Cb,EAAe,UAAUa,CAAK,CAChC,CAAC,EACD,OAEJ,MAAO,IAAM,CACXD,IAAa,EACbE,IAAgB,EAChBC,IAAiB,CACnB,CACF,EAAG,CAACvB,EAAgBY,EAAeD,EAAYE,CAAc,CAAC,EAE9D1B,EAAoB,IAAM,CACpBgC,IAAW,SACRnB,EAAe,MAAM,EAAE,MAAOX,GAAU,CAC3CD,EAAoBC,EAAO,CAAE,MAAO,OAAQ,EAAGoB,EAAW,OAAO,CACnE,CAAC,CAEL,EAAG,CAACT,EAAgBmB,CAAM,CAAC,EAE3BhC,EAAoB,IAAM,CACxB,GAAKkB,EAIL,MAAO,IAAM,CACXK,EAAoB,QAAU,WAAW,WAAW,IAAM,CACxDA,EAAoB,QAAU,KAC9BV,EAAe,QAAQ,CACzB,EAAG,CAAC,CACN,CACF,EAAG,CAACA,EAAgBK,CAAgB,CAAC,EAE9B,IACT,EA8CA,MAAO,CACL,gBA7CsB,CAAC,CACvB,MAAAP,EACA,QAAAG,EACA,WAAAC,EACA,YAAAC,EACA,QAAAC,EACA,iBAAAC,EAAmB,GACnB,SAAAmB,CACF,IAA2D,CACzD,IAAMxB,EAAiBP,EAEvB,OACEP,EAACS,EAAa,SAAb,CAAsB,MAAOG,EAC3B,UAAA0B,EACDvC,EAACc,EAAA,CACC,eAAgBC,EAChB,QAASC,EACT,WAAYC,EACZ,YAAaC,EACb,QAASC,EACT,iBAAkBC,EACpB,GACF,CAEJ,EAsBE,aApBmB,CAAC,CAAE,SAAAoB,EAAW,IAAK,IAAsC,CAC5E,IAAMC,EAAgBhC,EAAoBqB,GAAaA,EAAS,aAAa,EAEvEY,EADQ/B,EAAgB,cAAc,EAChB8B,CAAa,EAEzC,GAAI,CAACC,EACH,OAAO1C,EAAAD,EAAA,CAAG,SAAAyC,EAAS,EAGrB,IAAMG,EAAWD,EAEjB,OACE1C,EAACF,EAAM,SAAN,CACC,SAAAE,EAAC2C,EAAA,EAAS,GADSF,CAErB,CAEJ,CAKA,CACF,EC/MA,OAAOG,MAAW,QAsBlB,IAAMC,EAAsB,OAAO,OAAW,IAAcD,EAAM,UAAYA,EAAM,gBAEvEE,EAQXC,GACG,CACH,IAAMC,EAAqB,IAA0C,CACnE,IAAMC,EAAiBF,EACjBG,EAAcN,EAAM,YAAY,IAAMK,EAAe,YAAY,EAAG,CAACA,CAAc,CAAC,EACpFE,EAAYP,EAAM,YACrBQ,GAA8BH,EAAe,UAAUG,CAAa,EACrE,CAACH,CAAc,CACjB,EAEA,OAAOL,EAAM,qBAAqBO,EAAWD,EAAaA,CAAW,CACvE,EAEMG,EAAqB,IAAgC,CACzD,IAAMC,EAAWN,EAAmB,EAC9BC,EAAiBF,EACvB,OAAOH,EAAM,QAAQ,IAEZK,EAAe,YAAY,EACjC,CAACA,EAAgBK,CAAQ,CAAC,CAC/B,EAEMC,EAAqB,CACzBC,EACAC,IACc,CACd,IAAMR,EAAiBF,EACjBW,EAAUD,GAAc,OAAO,GAC/BE,EAAWf,EAAM,OAA2D,IAAI,EAEhFgB,EAAsBhB,EAAM,YAAY,IAAM,CAClD,IAAMiB,EAAeZ,EAAe,YAAY,EAC1Ca,EAASH,EAAS,QAExB,GACEG,GACA,OAAO,GAAGA,EAAO,QAASb,CAAc,GACxC,OAAO,GAAGa,EAAO,SAAUN,CAAQ,GACnC,OAAO,GAAGM,EAAO,QAASJ,CAAO,GACjC,OAAO,GAAGI,EAAO,SAAUD,CAAY,EAEvC,OAAOC,EAAO,SAGhB,IAAMC,EAAeP,EAASK,CAAY,EAE1C,OACEC,GACA,OAAO,GAAGA,EAAO,QAASb,CAAc,GACxC,OAAO,GAAGa,EAAO,SAAUN,CAAQ,GACnC,OAAO,GAAGM,EAAO,QAASJ,CAAO,GACjCA,EAAQI,EAAO,SAAUC,CAAY,GAErCJ,EAAS,QAAU,CACjB,QAASV,EACT,SAAUY,EACV,SAAUC,EAAO,SACjB,SAAAN,EACA,QAAAE,CACF,EACOI,EAAO,WAGhBH,EAAS,QAAU,CACjB,QAASV,EACT,SAAUY,EACV,SAAUE,EACV,SAAAP,EACA,QAAAE,CACF,EACOK,EACT,EAAG,CAACd,EAAgBS,EAASF,CAAQ,CAAC,EAEhCQ,EAA8BpB,EAAM,YACvCQ,GACCH,EAAe,kBACbO,EACA,IAAM,CACJJ,EAAc,CAChB,EACAM,CACF,EACF,CAACT,EAAgBS,EAASF,CAAQ,CACpC,EAEA,OAAOZ,EAAM,qBACXoB,EACAJ,EACAA,CACF,CACF,EAEMK,EACJC,GACS,CACT,IAAMjB,EAAiBF,EACjBoB,EAAcvB,EAAM,OAAOsB,CAAQ,EACzCC,EAAY,QAAUD,EAEtBrB,EAAoB,IACXI,EAAe,eAAgBmB,GAAU,CAC9CD,EAAY,QAAQC,CAAK,CAC3B,CAAC,EACA,CAACnB,CAAc,CAAC,CACrB,EAuCA,MAAO,CACL,mBAAAD,EACA,mBAAAK,EACA,mBAAAE,EACA,cAzBoB,IAA2D,CAC/E,IAAMN,EAAiBF,EACvB,OAAOH,EAAM,QACX,KAAO,CACL,MAAOK,EAAe,MACtB,KAAMA,EAAe,KACrB,aAAcA,EAAe,aAC7B,aAAcA,EAAe,aAC7B,iBAAkBA,EAAe,iBACjC,gBAAiBA,EAAe,gBAChC,iBAAkBA,EAAe,iBACjC,oBAAqBA,EAAe,oBACpC,eAAgBA,EAAe,eAC/B,cAAeA,EAAe,cAC9B,YAAaA,EAAe,YAC5B,aAAc,IAAMA,EAAe,aAAa,CAClD,GACA,CAACA,CAAc,CACjB,CACF,EAOE,gBAAAgB,EACA,wBA3C8B,CAC9BI,EACAC,IAIS,CACTL,EAAiBG,GAAU,CACrBA,EAAM,OAAS,cAAgBA,EAAM,SAAWC,EAClDC,EAAU,UAAU,CAAE,QAASvB,EAAQ,YAAY,EAAE,OAAQ,CAAC,EACrDqB,EAAM,OAAS,aAAeA,EAAM,SAAWC,GACxDC,EAAU,UAAU,CAAE,QAASvB,EAAQ,YAAY,EAAE,OAAQ,CAAC,CAElE,CAAC,CACH,CA8BA,CACF,EFnKO,IAAMwB,EAAgB,CAQ3BC,EACAC,IACiF,CAEjF,IAAMC,EAAUC,EAOdH,EARqBC,CAQK,EAQtBG,EAAQC,EACZH,CACF,EACMI,EAAoBC,EAOxBL,EAASE,EAAM,kBAAkB,EAEnC,MAAO,CACL,QAAAF,EACA,QAAS,IAAMA,EAAQ,QAAQ,EAC/B,GAAGE,EACH,GAAGE,CACL,CACF,EAOaE,EAAuB,CAQlCR,EACAC,IAEO,IACLF,EACEC,EACAC,CACF",
|
|
6
|
+
"names": ["createJourneyMachine", "React", "Fragment", "jsx", "jsxs", "useSafeLayoutEffect", "reportProviderError", "error", "context", "listener", "createJourneyProviderArtifacts", "machine", "useJourneySelector", "ViewsContext", "useJourneyViews", "hookName", "views", "ProviderController", "runtimeMachine", "onStart", "onComplete", "onTerminate", "onError", "disposeOnUnmount", "onStartRef", "onCompleteRef", "onTerminateRef", "onErrorRef", "scheduledDisposeRef", "hasOnStart", "hasOnComplete", "hasOnTerminate", "selectStatus", "snapshot", "subscribeToStatus", "onStoreChange", "getStatus", "status", "unsubStart", "event", "unsubComplete", "unsubTerminate", "children", "fallback", "currentStepId", "StepComponent", "StepView", "React", "useSafeLayoutEffect", "createJourneyHooks", "machine", "useJourneySnapshot", "runtimeMachine", "getSnapshot", "subscribe", "onStoreChange", "useJourneyComputed", "snapshot", "useJourneySelector", "selector", "equalityFn", "isEqual", "cacheRef", "getSelectedSnapshot", "nextSnapshot", "cached", "nextSelected", "subscribeToSelectedSnapshot", "useJourneyEvent", "listener", "listenerRef", "event", "stepId", "callbacks", "createJourney", "definition", "options", "machine", "createJourneyMachine", "hooks", "createJourneyHooks", "providerArtifacts", "createJourneyProviderArtifacts", "createJourneyFactory"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JourneyDefinition, JourneyJsonObject, JourneyMachineOptions, JourneyMachinePlugin } from "@rxova/journey-core";
|
|
2
|
+
import type { JourneyRuntime, JourneyRuntimeFactory } from "./types";
|
|
3
|
+
type JourneyOptionsInput<TPlugins extends readonly JourneyMachinePlugin[]> = JourneyMachineOptions<TPlugins extends [] ? readonly JourneyMachinePlugin[] : TPlugins>;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a journey machine and returns React hooks/components bound to that machine.
|
|
6
|
+
* Hooks work without a provider; `JourneyProvider` is only required for `StepRenderer`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createJourney: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>, TPlugins extends readonly JourneyMachinePlugin[] = []>(definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>, options?: JourneyOptionsInput<TPlugins>) => JourneyRuntime<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a typed factory for producing fresh React-bound journey runtimes.
|
|
11
|
+
* Use this when a component or route boundary needs independent instances
|
|
12
|
+
* from the same definition/options pair.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createJourneyFactory: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>, TPlugins extends readonly JourneyMachinePlugin[] = []>(definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>, options?: JourneyOptionsInput<TPlugins>) => JourneyRuntimeFactory<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JourneyDefinition, JourneyJsonObject, JourneyMachineOptions, JourneyMachinePlugin } from "@rxova/journey-core";
|
|
2
|
+
import type { JourneyRuntime, JourneyRuntimeFactory } from "./types";
|
|
3
|
+
type JourneyOptionsInput<TPlugins extends readonly JourneyMachinePlugin[]> = JourneyMachineOptions<TPlugins extends [] ? readonly JourneyMachinePlugin[] : TPlugins>;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a journey machine and returns React hooks/components bound to that machine.
|
|
6
|
+
* Hooks work without a provider; `JourneyProvider` is only required for `StepRenderer`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createJourney: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>, TPlugins extends readonly JourneyMachinePlugin[] = []>(definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>, options?: JourneyOptionsInput<TPlugins>) => JourneyRuntime<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a typed factory for producing fresh React-bound journey runtimes.
|
|
11
|
+
* Use this when a component or route boundary needs independent instances
|
|
12
|
+
* from the same definition/options pair.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createJourneyFactory: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>, TPlugins extends readonly JourneyMachinePlugin[] = []>(definition: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>, options?: JourneyOptionsInput<TPlugins>) => JourneyRuntimeFactory<TContext, TStepId, TEventMap, TStepMeta, TPlugins, THandlers>;
|
|
15
|
+
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";var D=Object.create;var h=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var z=(t,r)=>{for(var u in r)h(t,u,{get:r[u],enumerable:!0})},w=(t,r,u,d)=>{if(r&&typeof r=="object"||typeof r=="function")for(let a of B(r))!U.call(t,a)&&a!==u&&h(t,a,{get:()=>r[a],enumerable:!(d=N(r,a))||d.enumerable});return t};var k=(t,r,u)=>(u=t!=null?D($(t)):{},w(r||!t||!t.__esModule?h(u,"default",{value:t,enumerable:!0}):u,t)),G=t=>w(h({},"__esModule",{value:!0}),t);var X={};z(X,{createJourney:()=>b,createJourneyFactory:()=>q});module.exports=G(X);var F=require("@rxova/journey-core");var c=k(require("react"),1),S=require("react/jsx-runtime"),M=typeof window>"u"?c.default.useEffect:c.default.useLayoutEffect,K=(t,r,u)=>{if(u){u(t,r);return}console.error(`JourneyProvider ${r.phase} failed.`,t)},j=(t,r)=>{let u=c.default.createContext(null),d=(e="hook")=>{let n=c.default.useContext(u);if(!n)throw new Error(`${e} must be used within JourneyProvider.`);return n},a=({runtimeMachine:e,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T})=>{let v=c.default.useRef(n),y=c.default.useRef(o),i=c.default.useRef(s),f=c.default.useRef(l),x=c.default.useRef(null),E=n!==void 0,m=o!==void 0,C=s!==void 0;v.current=n,y.current=o,i.current=s,f.current=l,M(()=>{x.current!==null&&(globalThis.clearTimeout(x.current),x.current=null)});let R=c.default.useCallback(J=>J.status,[e]),A=c.default.useCallback(J=>e.subscribeSelector(R,()=>{J()}),[e,R]),I=c.default.useCallback(()=>e.getSnapshot().status,[e]),O=c.default.useSyncExternalStore(A,I,I);return M(()=>{if(!E&&!m&&!C)return;let J=E?e.subscribeStart(g=>{v.current?.(g)}):void 0,V=m?e.subscribeComplete(g=>{y.current?.(g)}):void 0,W=C?e.subscribeTerminate(g=>{i.current?.(g)}):void 0;return()=>{J?.(),V?.(),W?.()}},[e,m,E,C]),M(()=>{O==="idled"&&e.start().catch(J=>{K(J,{phase:"start"},f.current)})},[e,O]),M(()=>{if(T)return()=>{x.current=globalThis.setTimeout(()=>{x.current=null,e.dispose()},0)}},[e,T]),null};return{JourneyProvider:({views:e,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T=!1,children:v})=>{let y=t;return(0,S.jsxs)(u.Provider,{value:e,children:[v,(0,S.jsx)(a,{runtimeMachine:y,onStart:n,onComplete:o,onTerminate:s,onError:l,disposeOnUnmount:T})]})},StepRenderer:({fallback:e=null})=>{let n=r(T=>T.currentStepId),s=d("StepRenderer")[n];if(!s)return(0,S.jsx)(S.Fragment,{children:e});let l=s;return(0,S.jsx)(c.default.Fragment,{children:(0,S.jsx)(l,{})},n)}}};var p=k(require("react"),1),Q=typeof window>"u"?p.default.useEffect:p.default.useLayoutEffect,H=t=>{let r=()=>{let e=t,n=p.default.useCallback(()=>e.getSnapshot(),[e]),o=p.default.useCallback(s=>e.subscribe(s),[e]);return p.default.useSyncExternalStore(o,n,n)},u=()=>{let e=r(),n=t;return p.default.useMemo(()=>n.getComputed(),[n,e])},d=(e,n)=>{let o=t,s=n??Object.is,l=p.default.useRef(null),T=p.default.useCallback(()=>{let y=o.getSnapshot(),i=l.current;if(i&&Object.is(i.machine,o)&&Object.is(i.selector,e)&&Object.is(i.isEqual,s)&&Object.is(i.snapshot,y))return i.selected;let f=e(y);return i&&Object.is(i.machine,o)&&Object.is(i.selector,e)&&Object.is(i.isEqual,s)&&s(i.selected,f)?(l.current={machine:o,snapshot:y,selected:i.selected,selector:e,isEqual:s},i.selected):(l.current={machine:o,snapshot:y,selected:f,selector:e,isEqual:s},f)},[o,s,e]),v=p.default.useCallback(y=>o.subscribeSelector(e,()=>{y()},s),[o,s,e]);return p.default.useSyncExternalStore(v,T,T)},a=e=>{let n=t,o=p.default.useRef(e);o.current=e,Q(()=>n.subscribeEvent(s=>{o.current(s)}),[n])};return{useJourneySnapshot:r,useJourneyComputed:u,useJourneySelector:d,useJourneyApi:()=>{let e=t;return p.default.useMemo(()=>({start:e.start,send:e.send,goToNextStep:e.goToNextStep,goToStepById:e.goToStepById,terminateJourney:e.terminateJourney,completeJourney:e.completeJourney,goToPreviousStep:e.goToPreviousStep,goToLastVisitedStep:e.goToLastVisitedStep,clearStepError:e.clearStepError,updateContext:e.updateContext,getStepMeta:e.getStepMeta,resetJourney:()=>e.resetJourney()}),[e])},useJourneyEvent:a,useJourneyStepLifecycle:(e,n)=>{a(o=>{o.type==="step.enter"&&o.stepId===e?n.onEnter?.({context:t.getSnapshot().context}):o.type==="step.exit"&&o.stepId===e&&n.onLeave?.({context:t.getSnapshot().context})})}}};var b=(t,r)=>{let d=(0,F.createJourneyMachine)(t,r),a=H(d),P=j(d,a.useJourneySelector);return{machine:d,dispose:()=>d.dispose(),...a,...P}},q=(t,r)=>()=>b(t,r);0&&(module.exports={createJourney,createJourneyFactory});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|