@founderhq/journeys 0.3.61

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 ADDED
@@ -0,0 +1,172 @@
1
+ # @founderhq/journeys
2
+
3
+ `@founderhq/journeys` is a config-driven React runtime for interactive onboarding and questionnaire flows.
4
+
5
+ ## What It Includes
6
+
7
+ - journey runtime with forward/back navigation
8
+ - conditional routing between steps
9
+ - computed variables derived from prior answers
10
+ - block-based informational pages
11
+ - reusable styles shipped as `styles.css`
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pnpm add @founderhq/journeys
17
+ ```
18
+
19
+ ## Basic Usage
20
+
21
+ ```tsx
22
+ import { Journey } from "@founderhq/journeys";
23
+ import "@founderhq/journeys/styles.css";
24
+
25
+ export function Example({ config }: { config: import("@founderhq/journeys").JourneyConfig }) {
26
+ return <Journey config={config} storageKey="example-journey" />;
27
+ }
28
+ ```
29
+
30
+ You can also fetch a journey remotely by passing `apiKey` and `journeyId` instead of an inline config.
31
+
32
+ ## Injecting Runtime Data (`initialAnswers`)
33
+
34
+ Pass `initialAnswers` to seed the answer state at first render. Useful when journey config references runtime data via templates — e.g. live pricing plans from StoreKit, RevenueCat, or your own API:
35
+
36
+ ```tsx
37
+ <Journey
38
+ apiKey="fos_..."
39
+ journeyId="abc-123"
40
+ initialAnswers={{
41
+ pricingPlans: [
42
+ {
43
+ id: "pro_monthly",
44
+ name: "Pro",
45
+ price: { amount: 29, currency: "USD", period: "month", trial: { days: 7 } },
46
+ metadata: { stripePriceId: "price_xxx" },
47
+ },
48
+ ],
49
+ }}
50
+ onEvent={(event) => {
51
+ if (event.type === "purchase_intent") {
52
+ // event.plan.metadata.stripePriceId → kick off Stripe checkout
53
+ }
54
+ }}
55
+ />
56
+ ```
57
+
58
+ In the journey config, reference the injected value with a whole-value template:
59
+
60
+ ```ts
61
+ { type: "pricing_plans", props: { variable: "selectedPlan", plans: "${pricingPlans}" } }
62
+ ```
63
+
64
+ Keys declared in `computedVariables` are ignored in `initialAnswers`; computed values always come from their formulas.
65
+
66
+ ## Event Payloads
67
+
68
+ `onEvent` payloads keep user-provided answers and computed values separate:
69
+
70
+ ```ts
71
+ onEvent={(event) => {
72
+ // Raw/persisted answers only.
73
+ event.answers;
74
+
75
+ // Derived values from config.computedVariables.
76
+ event.computedVariables;
77
+ }}
78
+ ```
79
+
80
+ ## Pricing Plan Templates
81
+
82
+ When a user selects a plan, the block stores a flattened snapshot in `answers[variable]`. Templates anywhere downstream can reach into it with dotted paths:
83
+
84
+ ```
85
+ You're subscribing to ${selectedPlan.name} — ${selectedPlan.amount} ${selectedPlan.currency}/${selectedPlan.period}.
86
+ ${selectedPlan.trialDays} day free trial. Was ${selectedPlan.originalAmount}.
87
+ ```
88
+
89
+ Available paths: `id`, `name`, `amount`, `currency`, `period`, `originalAmount`, `perUnitLabel`, `display`, `trialDays`, `introOffer`, `description`, `badge`, `icon`, `features`, `metadata`.
90
+
91
+ Equality conditions on the variable continue to match the plan id (`{ op: "equals", value: "pro_monthly" }`).
92
+
93
+ ### Per-Plan Templates (`currentPlan`)
94
+
95
+ String fields anywhere inside a plan support templates, with `currentPlan` exposing this card's flattened plan fields (same shape as `selectedPlan`):
96
+
97
+ ```ts
98
+ {
99
+ id: "pro_monthly",
100
+ name: "Pro",
101
+ price: { amount: 29, currency: "USD", period: "month", trial: { days: 7 } },
102
+ badge: "${currentPlan.trialDays} Days Free",
103
+ subtext: "${currentPlan.trialDays} day free trial, then ${currentPlan.amount} ${currentPlan.currency}/${currentPlan.period}",
104
+ }
105
+ ```
106
+
107
+ `subtext` is rendered as a small line under the price. Trial and intro-offer lines are no longer auto-rendered — set `subtext` explicitly if you want them.
108
+
109
+ ## Optional Discount Codes
110
+
111
+ Discount codes are opened from a normal button action, so the Journey author controls whether the UI appears and where the trigger lives:
112
+
113
+ ```ts
114
+ {
115
+ type: "button",
116
+ props: {
117
+ label: "Have a coupon?",
118
+ action: {
119
+ type: "open_discount_code",
120
+ variable: "pricingDiscount",
121
+ planVariable: "selectedPlan",
122
+ },
123
+ },
124
+ }
125
+ ```
126
+
127
+ Pass `onDiscountCodeApply` to validate and reprice in the consumer app:
128
+
129
+ ```tsx
130
+ <Journey
131
+ config={config}
132
+ onDiscountCodeApply={async ({ code, plan }) => {
133
+ const result = await validateCoupon(code, plan?.id);
134
+ return result.valid
135
+ ? {
136
+ valid: true,
137
+ code,
138
+ planId: plan?.id,
139
+ message: "Discount applied",
140
+ pricing: {
141
+ total: result.total,
142
+ currency: result.currency,
143
+ originalAmount: result.originalTotal,
144
+ },
145
+ metadata: result.metadata,
146
+ }
147
+ : { valid: false, reason: result.reason };
148
+ }}
149
+ />
150
+ ```
151
+
152
+ Set `pricing_plans.props.discountVariable` to let cards replace the visible non-strike price from `pricing.display`, `pricing.amount`, or `pricing.total`. Set `purchase.action.discountVariable` to include the full applied discount answer in `purchase_intent`. Journeys never calculates billing amounts or provider rules; those belong in the consumer callback and `metadata`.
153
+
154
+ ## Config Shape
155
+
156
+ A journey config is centered around:
157
+
158
+ - `arcs`
159
+ Logical step groups and navigation order.
160
+ - `steps`
161
+ Individual screens such as `single_select`, `multi_select`, `input`, `slider`, and `info_page`.
162
+ - `computedVariables`
163
+ Derived values evaluated from the current answer set.
164
+
165
+ ## Development
166
+
167
+ ```bash
168
+ pnpm --filter @founderhq/journeys dev
169
+ pnpm --filter @founderhq/journeys build
170
+ ```
171
+
172
+ The build emits ESM, CJS, type declarations, and `dist/styles.css`.