@churnkey/react 0.1.2 → 0.3.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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-CPBEP4NW.cjs → chunk-2VQNWZWO.cjs} +35 -23
  3. package/dist/chunk-2VQNWZWO.cjs.map +1 -0
  4. package/dist/{chunk-XU7KDCXO.cjs → chunk-42SJA62X.cjs} +9 -7
  5. package/dist/chunk-42SJA62X.cjs.map +1 -0
  6. package/dist/{chunk-SIYJ4R4B.cjs → chunk-LVUDBCQ2.cjs} +57 -11
  7. package/dist/chunk-LVUDBCQ2.cjs.map +1 -0
  8. package/dist/{chunk-GCQ75J4G.js → chunk-SQ35G4LA.js} +55 -11
  9. package/dist/chunk-SQ35G4LA.js.map +1 -0
  10. package/dist/{chunk-IFVMM2LB.js → chunk-UNSSI6KX.js} +35 -23
  11. package/dist/chunk-UNSSI6KX.js.map +1 -0
  12. package/dist/{chunk-QTMZI5I2.js → chunk-YZERGV7F.js} +6 -4
  13. package/dist/chunk-YZERGV7F.js.map +1 -0
  14. package/dist/core.cjs +20 -12
  15. package/dist/core.d.cts +14 -3
  16. package/dist/core.d.ts +14 -3
  17. package/dist/core.js +2 -2
  18. package/dist/headless.cjs +3 -3
  19. package/dist/headless.d.cts +5 -1
  20. package/dist/headless.d.ts +5 -1
  21. package/dist/headless.js +2 -2
  22. package/dist/index.cjs +199 -189
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +7 -7
  25. package/dist/index.d.ts +7 -7
  26. package/dist/index.js +116 -114
  27. package/dist/index.js.map +1 -1
  28. package/dist/{step-graph-ChdI-VXV.d.ts → step-graph-ChlSCUGk.d.cts} +89 -20
  29. package/dist/{step-graph-ChdI-VXV.d.cts → step-graph-ChlSCUGk.d.ts} +89 -20
  30. package/dist/styles.css +173 -67
  31. package/package.json +1 -1
  32. package/dist/chunk-CPBEP4NW.cjs.map +0 -1
  33. package/dist/chunk-GCQ75J4G.js.map +0 -1
  34. package/dist/chunk-IFVMM2LB.js.map +0 -1
  35. package/dist/chunk-QTMZI5I2.js.map +0 -1
  36. package/dist/chunk-SIYJ4R4B.cjs.map +0 -1
  37. package/dist/chunk-XU7KDCXO.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { useCancelFlowMachine } from './chunk-QTMZI5I2.js';
2
- export { useCancelFlow } from './chunk-QTMZI5I2.js';
3
- import { cn, discountPhrase, formatShortDate, formatPriceFromMinor, formatMonthDay, appearanceToStyle, defaultTitles } from './chunk-GCQ75J4G.js';
4
- export { BUILT_IN_STEP_TYPES, appearanceToStyle, calculateDiscountedPrice, cn, defaultTitles, formatPrice } from './chunk-GCQ75J4G.js';
5
- export { AnalyticsClient, CancelFlowMachine, ChurnkeyApi, decodeSessionToken } from './chunk-IFVMM2LB.js';
6
- import { useState, useRef, useCallback, useEffect } from 'react';
1
+ import { useCancelFlowMachine } from './chunk-YZERGV7F.js';
2
+ export { useCancelFlow } from './chunk-YZERGV7F.js';
3
+ import { formatPeriodEnd, cn, discountPhrase, formatMonthDayLong, formatPriceFromMinor, formatMonthDay, appearanceToStyle, defaultTitles, BUILT_IN_OFFER_TYPES } from './chunk-SQ35G4LA.js';
4
+ export { BUILT_IN_OFFER_TYPES, BUILT_IN_STEP_TYPES, appearanceToStyle, calculateDiscountedPrice, cn, defaultTitles, formatPeriodEnd, formatPrice } from './chunk-SQ35G4LA.js';
5
+ export { AnalyticsClient, CancelFlowMachine, ChurnkeyApi, decodeSessionToken } from './chunk-UNSSI6KX.js';
6
+ import { useState, useRef, useEffect, useCallback } from 'react';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
8
8
 
9
9
  function RichText({ html, as = "p", className }) {
@@ -20,17 +20,28 @@ function RichText({ html, as = "p", className }) {
20
20
  function DefaultConfirm({
21
21
  title,
22
22
  description,
23
+ subscriptions,
24
+ losses,
25
+ lossesLabel,
23
26
  confirmLabel,
24
27
  goBackLabel,
25
- periodEnd,
26
28
  onConfirm,
27
29
  onGoBack,
28
30
  isProcessing,
29
31
  classNames
30
32
  }) {
33
+ const hasLosses = Array.isArray(losses) && losses.length > 0;
34
+ const periodEnd = formatPeriodEnd(subscriptions);
31
35
  return /* @__PURE__ */ jsxs("div", { className: cn("ck-step ck-step-confirm", classNames?.root), children: [
32
36
  /* @__PURE__ */ jsx("h2", { className: cn("ck-step-title", classNames?.title), children: title }),
33
37
  description && /* @__PURE__ */ jsx(RichText, { html: description, className: cn("ck-step-description", classNames?.description) }),
38
+ hasLosses && /* @__PURE__ */ jsxs("div", { className: cn("ck-loss-block", classNames?.lossList), children: [
39
+ /* @__PURE__ */ jsx("div", { className: cn("ck-loss-label", classNames?.lossLabel), children: lossesLabel ?? "You'll lose access to:" }),
40
+ /* @__PURE__ */ jsx("ul", { className: "ck-loss-list", children: losses.map((item) => /* @__PURE__ */ jsxs("li", { className: cn("ck-loss-item", classNames?.lossItem), children: [
41
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("ck-loss-bullet", classNames?.lossBullet), children: "\u25CF" }),
42
+ /* @__PURE__ */ jsx("span", { children: item })
43
+ ] }, item)) })
44
+ ] }),
34
45
  periodEnd && /* @__PURE__ */ jsxs("p", { className: cn("ck-period-end", classNames?.periodEndNotice), children: [
35
46
  "Your access continues until ",
36
47
  periodEnd,
@@ -194,86 +205,54 @@ function DefaultPauseOffer({
194
205
  }) {
195
206
  const o = offer;
196
207
  const max = Math.max(1, o.months);
197
- const [months, setMonths] = useState(Math.min(2, max));
208
+ const [months, setMonths] = useState(1);
198
209
  const headline = title ?? offer.copy.headline;
199
210
  const body = description ?? offer.copy.body;
200
- const options = Array.from({ length: max }, (_, i) => i + 1);
201
- const resumeAt = /* @__PURE__ */ new Date();
202
- resumeAt.setMonth(resumeAt.getMonth() + months);
203
- const resumeDate = formatShortDate(resumeAt);
211
+ const resume = /* @__PURE__ */ new Date();
212
+ resume.setMonth(resume.getMonth() + months);
213
+ const resumeDate = formatMonthDayLong(resume);
204
214
  return /* @__PURE__ */ jsxs("div", { className: cn("ck-step ck-step-offer", classNames?.root), children: [
205
215
  headline && /* @__PURE__ */ jsx("h2", { className: cn("ck-step-title", classNames?.title), children: headline }),
206
216
  body && /* @__PURE__ */ jsx(RichText, { html: body, className: cn("ck-step-description", classNames?.description) }),
207
- /* @__PURE__ */ jsxs("div", { className: cn("ck-offer-card", classNames?.card), children: [
208
- /* @__PURE__ */ jsxs("div", { className: "ck-offer-details ck-offer-pause", children: [
209
- /* @__PURE__ */ jsx("div", { className: "ck-pause-segments", style: { gridTemplateColumns: `repeat(${max}, 1fr)` }, children: options.map((m) => {
210
- const isSelected = m === months;
211
- return /* @__PURE__ */ jsxs(
212
- "button",
213
- {
214
- type: "button",
215
- onClick: () => setMonths(m),
216
- className: cn("ck-pause-segment", isSelected && "ck-pause-segment--selected"),
217
- children: [
218
- m,
219
- " ",
220
- m === 1 ? "month" : "months"
221
- ]
222
- },
223
- m
224
- );
225
- }) }),
226
- /* @__PURE__ */ jsxs("div", { className: "ck-pause-resume", children: [
227
- /* @__PURE__ */ jsxs("div", { children: [
228
- /* @__PURE__ */ jsx("div", { className: "ck-pause-resume-label", children: "Billing resumes" }),
229
- /* @__PURE__ */ jsx("div", { className: "ck-pause-resume-date", children: resumeDate })
230
- ] }),
231
- /* @__PURE__ */ jsx(CalendarIcon, {})
232
- ] })
233
- ] }),
234
- /* @__PURE__ */ jsx(
217
+ /* @__PURE__ */ jsxs("div", { className: cn("ck-offer-card ck-pause-card", classNames?.card), children: [
218
+ /* @__PURE__ */ jsx("div", { className: "ck-pause-eyebrow", children: "We'll see you back on" }),
219
+ /* @__PURE__ */ jsx("div", { className: "ck-pause-date", children: resumeDate }),
220
+ /* @__PURE__ */ jsx("div", { className: cn("ck-pause-chips", classNames?.pauseSlider), children: Array.from({ length: max }, (_, i) => i + 1).map((m) => /* @__PURE__ */ jsxs(
235
221
  "button",
236
222
  {
237
223
  type: "button",
238
- className: cn("ck-button ck-button-primary", classNames?.acceptButton),
239
- onClick: () => onAccept({ months }),
240
- disabled: isProcessing,
241
- children: isProcessing ? "Processing..." : offer.copy.cta
242
- }
243
- ),
244
- /* @__PURE__ */ jsx("button", { type: "button", className: cn("ck-button-link", classNames?.declineButton), onClick: onDecline, children: offer.copy.declineCta })
245
- ] })
224
+ onClick: () => setMonths(m),
225
+ className: cn("ck-pause-chip", m === months && "ck-pause-chip--selected"),
226
+ "aria-pressed": m === months,
227
+ children: [
228
+ m,
229
+ " ",
230
+ m === 1 ? "month" : "months"
231
+ ]
232
+ },
233
+ m
234
+ )) })
235
+ ] }),
236
+ /* @__PURE__ */ jsx(
237
+ "button",
238
+ {
239
+ type: "button",
240
+ className: cn("ck-button ck-button-primary", classNames?.acceptButton),
241
+ onClick: () => onAccept({ months }),
242
+ disabled: isProcessing,
243
+ children: isProcessing ? "Processing..." : offer.copy.cta
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx("button", { type: "button", className: cn("ck-button-link", classNames?.declineButton), onClick: onDecline, children: offer.copy.declineCta })
246
247
  ] });
247
248
  }
248
- function CalendarIcon() {
249
- return /* @__PURE__ */ jsxs(
250
- "svg",
251
- {
252
- className: "ck-pause-resume-icon",
253
- width: "18",
254
- height: "18",
255
- viewBox: "0 0 24 24",
256
- fill: "none",
257
- stroke: "currentColor",
258
- strokeWidth: "1.75",
259
- strokeLinecap: "round",
260
- strokeLinejoin: "round",
261
- "aria-hidden": "true",
262
- children: [
263
- /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "3" }),
264
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
265
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
266
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
267
- ]
268
- }
269
- );
270
- }
271
249
  function Checkmark({ color = "currentColor", size = 14 }) {
272
250
  return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 8.5L6.5 12L13 5", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) });
273
251
  }
274
252
  function DefaultPlanChangeOffer({
275
253
  title,
276
254
  description,
255
+ subscriptions,
277
256
  offer,
278
257
  onAccept,
279
258
  onDecline,
@@ -282,7 +261,9 @@ function DefaultPlanChangeOffer({
282
261
  }) {
283
262
  const o = offer;
284
263
  const plans = o.plans ?? [];
285
- const [selectedPlanId, setSelectedPlanId] = useState(plans[0]?.id ?? null);
264
+ const currentPlanId = subscriptions[0]?.items[0]?.price.id;
265
+ const initialPlanId = plans.find((p) => p.id !== currentPlanId)?.id ?? null;
266
+ const [selectedPlanId, setSelectedPlanId] = useState(initialPlanId);
286
267
  const selectedPlan = plans.find((p) => p.id === selectedPlanId) ?? null;
287
268
  const headline = title ?? offer.copy.headline;
288
269
  const body = description ?? offer.copy.body;
@@ -295,15 +276,24 @@ function DefaultPlanChangeOffer({
295
276
  const interval = plan.duration?.interval ?? "month";
296
277
  const currency = plan.amount.currency ?? "USD";
297
278
  const isSelected = plan.id === selectedPlanId;
279
+ const isCurrent = plan.id === currentPlanId;
298
280
  return /* @__PURE__ */ jsxs(
299
281
  "button",
300
282
  {
301
283
  type: "button",
302
284
  onClick: () => setSelectedPlanId(plan.id),
303
- className: cn("ck-plan-card", isSelected && "ck-plan-card--selected"),
285
+ disabled: isCurrent,
286
+ className: cn(
287
+ "ck-plan-card",
288
+ isSelected && "ck-plan-card--selected",
289
+ isCurrent && "ck-plan-card--current"
290
+ ),
304
291
  "aria-pressed": isSelected,
305
292
  children: [
306
- /* @__PURE__ */ jsx("div", { className: "ck-plan-name", children: plan.name ?? plan.id }),
293
+ /* @__PURE__ */ jsxs("div", { className: "ck-plan-name", children: [
294
+ plan.name ?? plan.id,
295
+ isCurrent && /* @__PURE__ */ jsx("span", { className: "ck-plan-current-badge", children: "Current" })
296
+ ] }),
307
297
  plan.tagline && /* @__PURE__ */ jsx("div", { className: "ck-plan-tagline", children: plan.tagline }),
308
298
  /* @__PURE__ */ jsxs("div", { className: "ck-plan-price-row", children: [
309
299
  /* @__PURE__ */ jsx("span", { className: "ck-plan-amount", children: formatPriceFromMinor(plan.amount.value, currency) }),
@@ -466,7 +456,6 @@ function DefaultReasonButton({ reason, index, isSelected, onSelect }) {
466
456
  type: "button",
467
457
  role: "radio",
468
458
  "aria-checked": isSelected,
469
- tabIndex: isSelected ? 0 : -1,
470
459
  onClick: () => onSelect(reason.id),
471
460
  className: cn("ck-reason-button", isSelected && "ck-reason-button--selected"),
472
461
  children: [
@@ -482,50 +471,37 @@ function DefaultSurvey({
482
471
  reasons,
483
472
  selectedReason,
484
473
  onSelectReason,
474
+ followupResponse,
475
+ onFollowupResponseChange,
485
476
  onNext,
486
477
  classNames,
487
478
  components
488
479
  }) {
489
480
  const ReasonButton = components?.ReasonButton ?? DefaultReasonButton;
490
- const listRef = useRef(null);
491
- const handleKeyDown = useCallback(
492
- (e) => {
493
- if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
494
- e.preventDefault();
495
- const currentIdx = reasons.findIndex((r) => r.id === selectedReason);
496
- let nextIdx;
497
- if (e.key === "ArrowDown") {
498
- nextIdx = currentIdx < reasons.length - 1 ? currentIdx + 1 : 0;
499
- } else {
500
- nextIdx = currentIdx > 0 ? currentIdx - 1 : reasons.length - 1;
501
- }
502
- onSelectReason(reasons[nextIdx].id);
503
- const buttons = listRef.current?.querySelectorAll('[role="radio"]');
504
- buttons?.[nextIdx]?.focus();
505
- },
506
- [reasons, selectedReason, onSelectReason]
507
- );
481
+ const selected = reasons.find((r) => r.id === selectedReason);
482
+ const showFollowup = selected?.freeform === true;
508
483
  return /* @__PURE__ */ jsxs("div", { className: cn("ck-step ck-step-survey", classNames?.root), children: [
509
484
  /* @__PURE__ */ jsx("h2", { className: cn("ck-step-title", classNames?.title), children: title }),
510
485
  description && /* @__PURE__ */ jsx(RichText, { html: description, className: cn("ck-step-description", classNames?.description) }),
511
- /* @__PURE__ */ jsx(
512
- "div",
486
+ /* @__PURE__ */ jsx("div", { className: cn("ck-reason-list", classNames?.reasonList), role: "radiogroup", "aria-label": title, children: reasons.map((reason, i) => /* @__PURE__ */ jsx(
487
+ ReasonButton,
513
488
  {
514
- ref: listRef,
515
- className: cn("ck-reason-list", classNames?.reasonList),
516
- role: "radiogroup",
517
- "aria-label": title,
518
- onKeyDown: handleKeyDown,
519
- children: reasons.map((reason, i) => /* @__PURE__ */ jsx(
520
- ReasonButton,
521
- {
522
- reason,
523
- index: i,
524
- isSelected: selectedReason === reason.id,
525
- onSelect: onSelectReason
526
- },
527
- reason.id
528
- ))
489
+ reason,
490
+ index: i,
491
+ isSelected: selectedReason === reason.id,
492
+ onSelect: onSelectReason
493
+ },
494
+ reason.id
495
+ )) }),
496
+ showFollowup && /* @__PURE__ */ jsx(
497
+ "textarea",
498
+ {
499
+ className: cn("ck-reason-followup", classNames?.followupInput),
500
+ placeholder: "Tell us more (optional)",
501
+ rows: 3,
502
+ value: followupResponse,
503
+ onChange: (e) => onFollowupResponseChange(e.target.value),
504
+ "aria-label": "Additional detail"
529
505
  }
530
506
  ),
531
507
  /* @__PURE__ */ jsx(
@@ -586,7 +562,7 @@ function trapFocus(container) {
586
562
  container.addEventListener("keydown", handleKeyDown);
587
563
  return () => container.removeEventListener("keydown", handleKeyDown);
588
564
  }
589
- function DefaultModal({ open, onClose, children, className }) {
565
+ function DefaultModal({ open, onClose, children, className, overlayClassName }) {
590
566
  const overlayRef = useRef(null);
591
567
  const modalRef = useRef(null);
592
568
  const previousFocusRef = useRef(null);
@@ -616,7 +592,7 @@ function DefaultModal({ open, onClose, children, className }) {
616
592
  "div",
617
593
  {
618
594
  ref: overlayRef,
619
- className: "ck-overlay",
595
+ className: cn("ck-overlay", overlayClassName),
620
596
  onClick: (e) => {
621
597
  if (e.target === overlayRef.current) onClose();
622
598
  },
@@ -696,7 +672,7 @@ function LoadStatus({
696
672
  const CloseButton = components?.CloseButton ?? DefaultCloseButton;
697
673
  const handleClose = onClose ?? (() => {
698
674
  });
699
- return /* @__PURE__ */ jsx("div", { className: "ck-cancel-flow", "data-color-scheme": scheme, style: appearanceStyle, children: /* @__PURE__ */ jsxs(Modal, { open: true, onClose: handleClose, className: classNames?.modal, children: [
675
+ return /* @__PURE__ */ jsx("div", { className: "ck-cancel-flow", "data-color-scheme": scheme, style: appearanceStyle, children: /* @__PURE__ */ jsxs(Modal, { open: true, onClose: handleClose, className: classNames?.modal, overlayClassName: classNames?.overlay, children: [
700
676
  /* @__PURE__ */ jsx(CloseButton, { onClose: handleClose, className: classNames?.closeButton }),
701
677
  /* @__PURE__ */ jsxs("div", { className: "ck-content", children: [
702
678
  isLoading && /* @__PURE__ */ jsxs("div", { className: "ck-loading", style: { padding: "32px", textAlign: "center" }, children: [
@@ -748,7 +724,7 @@ function FlowShell({ machine, state, appearance, classNames, components, customC
748
724
  const Modal = components?.Modal ?? DefaultModal;
749
725
  const CloseButton = components?.CloseButton ?? DefaultCloseButton;
750
726
  const BackButton = components?.BackButton ?? DefaultBackButton;
751
- return /* @__PURE__ */ jsx("div", { className: "ck-cancel-flow", "data-color-scheme": scheme, style: appearanceStyle, children: /* @__PURE__ */ jsxs(Modal, { open: true, onClose: machine.close, className: classNames?.modal, children: [
727
+ return /* @__PURE__ */ jsx("div", { className: "ck-cancel-flow", "data-color-scheme": scheme, style: appearanceStyle, children: /* @__PURE__ */ jsxs(Modal, { open: true, onClose: machine.close, className: classNames?.modal, overlayClassName: classNames?.overlay, children: [
752
728
  /* @__PURE__ */ jsx(CloseButton, { onClose: machine.close, className: classNames?.closeButton }),
753
729
  /* @__PURE__ */ jsxs("div", { className: "ck-content", children: [
754
730
  machine.canGoBack && /* @__PURE__ */ jsx(BackButton, { onBack: machine.back, className: classNames?.backButton }),
@@ -773,9 +749,13 @@ function StepRenderer({
773
749
  {
774
750
  title: config?.title ?? defaultTitles.survey,
775
751
  description: config?.description,
752
+ customer: state.customer,
753
+ subscriptions: state.subscriptions,
776
754
  reasons: machine.reasons,
777
755
  selectedReason: state.selectedReason,
778
756
  onSelectReason: machine.selectReason,
757
+ followupResponse: state.followupResponse,
758
+ onFollowupResponseChange: machine.setFollowupResponse,
779
759
  onNext: machine.next,
780
760
  classNames: config?.classNames,
781
761
  components
@@ -792,12 +772,16 @@ function StepRenderer({
792
772
  {
793
773
  offer,
794
774
  customer: state.customer,
775
+ subscriptions: state.subscriptions,
795
776
  onAccept: machine.accept,
796
777
  onDecline: machine.decline,
797
778
  isProcessing: state.isProcessing
798
779
  }
799
780
  );
800
781
  }
782
+ if (!BUILT_IN_OFFER_TYPES.includes(offer.type)) {
783
+ return /* @__PURE__ */ jsx(UnregisteredOfferFallback, { offerType: offer.type, onSkip: machine.decline });
784
+ }
801
785
  const Offer = components?.Offer ?? DefaultOffer;
802
786
  const config = stepConfig;
803
787
  return /* @__PURE__ */ jsx(
@@ -805,6 +789,8 @@ function StepRenderer({
805
789
  {
806
790
  title: config?.title,
807
791
  description: config?.description,
792
+ customer: state.customer,
793
+ subscriptions: state.subscriptions,
808
794
  offer,
809
795
  onAccept: machine.accept,
810
796
  onDecline: machine.decline,
@@ -822,6 +808,8 @@ function StepRenderer({
822
808
  {
823
809
  title: config?.title ?? defaultTitles.feedback,
824
810
  description: config?.description,
811
+ customer: state.customer,
812
+ subscriptions: state.subscriptions,
825
813
  placeholder: config?.placeholder,
826
814
  required: config?.required ?? false,
827
815
  minLength: config?.minLength ?? 0,
@@ -840,6 +828,10 @@ function StepRenderer({
840
828
  {
841
829
  title: config?.title ?? defaultTitles.confirm,
842
830
  description: config?.description,
831
+ customer: state.customer,
832
+ subscriptions: state.subscriptions,
833
+ losses: config?.losses,
834
+ lossesLabel: config?.lossesLabel,
843
835
  confirmLabel: config?.confirmLabel ?? "Cancel subscription",
844
836
  goBackLabel: config?.goBackLabel ?? "Go back",
845
837
  onConfirm: machine.cancel,
@@ -860,6 +852,8 @@ function StepRenderer({
860
852
  offer: machine.currentOffer ?? void 0,
861
853
  title: isSaved ? config?.savedTitle ?? "Welcome back!" : config?.cancelledTitle ?? "Subscription cancelled",
862
854
  description: isSaved ? config?.savedDescription ?? "Your offer has been applied." : config?.cancelledDescription ?? "We're sorry to see you go.",
855
+ customer: state.customer,
856
+ subscriptions: state.subscriptions,
863
857
  onClose: machine.close,
864
858
  classNames: config?.classNames
865
859
  }
@@ -881,6 +875,7 @@ function StepRenderer({
881
875
  data: config?.data
882
876
  },
883
877
  customer: state.customer,
878
+ subscriptions: state.subscriptions,
884
879
  onNext: machine.next,
885
880
  onBack: machine.back
886
881
  }
@@ -895,6 +890,13 @@ function UnregisteredStepFallback({ step, onSkip }) {
895
890
  }, [step, onSkip]);
896
891
  return null;
897
892
  }
893
+ function UnregisteredOfferFallback({ offerType, onSkip }) {
894
+ useEffect(() => {
895
+ console.warn(`[churnkey] No component registered for offer type "${offerType}". Skipping.`);
896
+ onSkip();
897
+ }, [offerType, onSkip]);
898
+ return null;
899
+ }
898
900
 
899
901
  export { CancelFlow, DefaultBackButton, DefaultCloseButton, DefaultConfirm, DefaultContactOffer, DefaultDiscountOffer, DefaultFeedback, DefaultModal, DefaultOffer, DefaultPauseOffer, DefaultPlanChangeOffer, DefaultReasonButton, DefaultRedirectOffer, DefaultSuccess, DefaultSurvey, DefaultTrialExtensionOffer };
900
902
  //# sourceMappingURL=index.js.map