@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
@@ -129,12 +129,10 @@ interface PauseOffer {
129
129
  type: 'pause';
130
130
  months: number;
131
131
  interval?: 'month' | 'week';
132
- datePicker?: boolean;
133
132
  }
134
133
  interface PlanChangeOffer {
135
134
  type: 'plan_change';
136
135
  plans: PlanOption[];
137
- currentPlanId?: string;
138
136
  }
139
137
  /**
140
138
  * Plan option in a `plan_change` offer — `DirectPrice` plus optional
@@ -181,13 +179,22 @@ interface OfferCopy {
181
179
  declineCta: string;
182
180
  }
183
181
  type AcceptedOffer = OfferConfig & {
184
- reasonId: string;
185
- decisionId?: string;
182
+ /** Survey reason that routed to this offer. Absent when the offer was
183
+ * declared as a standalone `OfferStep`. */
184
+ reasonId?: string;
185
+ /** Payload from custom offers — whatever your component passed to
186
+ * `onAccept(result)`. Built-in offer types do not populate this. */
186
187
  result?: Record<string, unknown>;
187
188
  };
188
189
  interface ReasonConfig {
189
190
  id: string;
190
191
  label: string;
192
+ /**
193
+ * When true, picking this reason reveals a text input below the reason list.
194
+ * The typed text lands on the session as `followupResponse`. `surveyChoiceId`
195
+ * still carries the reason's `id` and `surveyChoiceValue` still carries the
196
+ * static `label`, so analytics groupings stay stable.
197
+ */
191
198
  freeform?: boolean;
192
199
  offer?: OfferConfig;
193
200
  }
@@ -205,11 +212,12 @@ interface OfferStep {
205
212
  title?: string;
206
213
  description?: string;
207
214
  /**
208
- * Offer attached to this step. Set this for proactive save offers shown
209
- * outside a survey; the SDK also populates it automatically on synthetic
210
- * offer steps spawned from survey choices.
215
+ * Offer attached to this step. Set this to declare a standalone offer
216
+ * step (one that isn't routed from a survey reason). `copy` is optional —
217
+ * the SDK synthesizes default copy from the offer config when none is
218
+ * provided, the same way it does for survey-attached offers.
211
219
  */
212
- offer?: OfferDecision;
220
+ offer?: OfferConfig | OfferDecision;
213
221
  classNames?: OfferClassNames;
214
222
  }
215
223
  interface FeedbackStep {
@@ -227,6 +235,10 @@ interface ConfirmStep {
227
235
  guid?: string;
228
236
  title?: string;
229
237
  description?: string;
238
+ /** Optional bullet list of what the customer is giving up. Rendered between the description and the period-end notice. */
239
+ losses?: string[];
240
+ /** Heading above the loss list. Defaults to "You'll lose access to:". */
241
+ lossesLabel?: string;
230
242
  confirmLabel?: string;
231
243
  goBackLabel?: string;
232
244
  classNames?: ConfirmClassNames;
@@ -258,7 +270,7 @@ interface SurveyClassNames {
258
270
  reasonButton?: string;
259
271
  reasonButtonSelected?: string;
260
272
  reasonLabel?: string;
261
- freeformInput?: string;
273
+ followupInput?: string;
262
274
  continueButton?: string;
263
275
  }
264
276
  interface OfferClassNames {
@@ -289,6 +301,10 @@ interface ConfirmClassNames {
289
301
  root?: string;
290
302
  title?: string;
291
303
  description?: string;
304
+ lossList?: string;
305
+ lossLabel?: string;
306
+ lossItem?: string;
307
+ lossBullet?: string;
292
308
  confirmButton?: string;
293
309
  goBackButton?: string;
294
310
  periodEndNotice?: string;
@@ -306,18 +322,55 @@ interface StructuralClassNames {
306
322
  closeButton?: string;
307
323
  backButton?: string;
308
324
  }
325
+ /**
326
+ * Typed surface for `appearance.variables`. Every key maps to a `--ck-*`
327
+ * CSS custom property. Consumers who need a token not in this list can
328
+ * still set the underlying CSS variable directly — these are the ones
329
+ * exposed through the typed JS API.
330
+ */
309
331
  interface AppearanceVariables {
310
- colorPrimary: string;
311
- colorPrimaryHover: string;
312
332
  colorBackground: string;
333
+ colorSurface: string;
334
+ colorSurfaceMuted: string;
335
+ colorBorder: string;
336
+ colorBorderStrong: string;
313
337
  colorText: string;
314
338
  colorTextSecondary: string;
315
- colorBorder: string;
316
- colorDanger: string;
339
+ colorTextMuted: string;
340
+ colorPrimary: string;
341
+ colorPrimaryHover: string;
342
+ colorPrimarySoft: string;
317
343
  colorSuccess: string;
344
+ colorSuccessSoft: string;
345
+ colorDanger: string;
346
+ colorDangerHover: string;
347
+ colorDangerSoft: string;
318
348
  fontFamily: string;
349
+ fontFamilyMono: string;
350
+ /**
351
+ * Display face used by step titles and other visual headlines. Defaults
352
+ * to `fontFamily`. Set this when your brand uses a separate display face
353
+ * (Tiempos, Canela, etc.) for headings.
354
+ */
355
+ fontFamilyDisplay: string;
319
356
  fontSize: string;
357
+ /** Weight applied to the step title. Default `'600'`. */
358
+ fontWeightDisplay: string;
359
+ /** Letter spacing applied to the step title. Default `'-0.015em'`. */
360
+ letterSpacingDisplay: string;
320
361
  borderRadius: string;
362
+ radiusSm: string;
363
+ radiusMd: string;
364
+ radiusLg: string;
365
+ radiusXl: string;
366
+ shadowModal: string;
367
+ shadowCard: string;
368
+ /**
369
+ * Color of the dim behind the modal. Defaults to a neutral translucent
370
+ * ink. Set to `color-mix(in srgb, var(--ck-color-primary) 40%, transparent)`
371
+ * to derive the overlay from your primary color, or any CSS color value.
372
+ */
373
+ overlayColor: string;
321
374
  }
322
375
  interface Appearance {
323
376
  /**
@@ -330,12 +383,14 @@ interface Appearance {
330
383
  interface CustomStepProps {
331
384
  step: CustomStepConfig;
332
385
  customer: DirectCustomer | null;
386
+ subscriptions: DirectSubscription[];
333
387
  onNext: (result?: Record<string, unknown>) => void;
334
388
  onBack: () => void;
335
389
  }
336
390
  interface CustomOfferProps {
337
391
  offer: OfferDecision;
338
392
  customer: DirectCustomer | null;
393
+ subscriptions: DirectSubscription[];
339
394
  onAccept: (result?: Record<string, unknown>) => Promise<void>;
340
395
  onDecline: () => void;
341
396
  isProcessing: boolean;
@@ -363,6 +418,7 @@ interface ModalProps {
363
418
  onClose: () => void;
364
419
  children: ReactNode;
365
420
  className?: string;
421
+ overlayClassName?: string;
366
422
  }
367
423
  interface CloseButtonProps {
368
424
  onClose: () => void;
@@ -375,9 +431,15 @@ interface BackButtonProps {
375
431
  interface SurveyStepProps {
376
432
  title: string;
377
433
  description?: string;
434
+ customer: DirectCustomer | null;
435
+ subscriptions: DirectSubscription[];
378
436
  reasons: ReasonConfig[];
379
437
  selectedReason: string | null;
380
438
  onSelectReason: (id: string) => void;
439
+ /** Free-text value when the selected reason has `freeform: true`. Lands on the session as `followupResponse`. */
440
+ followupResponse: string;
441
+ /** Set the follow-up response. The SDK forwards the value to the session. */
442
+ onFollowupResponseChange: (text: string) => void;
381
443
  onNext: () => void;
382
444
  classNames?: SurveyClassNames;
383
445
  components?: Partial<ComponentOverrides>;
@@ -385,6 +447,8 @@ interface SurveyStepProps {
385
447
  interface OfferStepProps {
386
448
  title?: string;
387
449
  description?: string;
450
+ customer: DirectCustomer | null;
451
+ subscriptions: DirectSubscription[];
388
452
  offer: OfferDecision;
389
453
  /**
390
454
  * Accept the offer. The optional `result` is included on the resulting
@@ -405,6 +469,8 @@ interface OfferStepProps {
405
469
  interface FeedbackStepProps {
406
470
  title: string;
407
471
  description?: string;
472
+ customer: DirectCustomer | null;
473
+ subscriptions: DirectSubscription[];
408
474
  placeholder?: string;
409
475
  required: boolean;
410
476
  minLength: number;
@@ -416,9 +482,12 @@ interface FeedbackStepProps {
416
482
  interface ConfirmStepProps {
417
483
  title: string;
418
484
  description?: string;
485
+ customer: DirectCustomer | null;
486
+ subscriptions: DirectSubscription[];
487
+ losses?: string[];
488
+ lossesLabel?: string;
419
489
  confirmLabel: string;
420
490
  goBackLabel: string;
421
- periodEnd?: string;
422
491
  onConfirm: () => Promise<void>;
423
492
  onGoBack: () => void;
424
493
  isProcessing: boolean;
@@ -429,6 +498,8 @@ interface SuccessStepProps {
429
498
  offer?: OfferDecision;
430
499
  title: string;
431
500
  description?: string;
501
+ customer: DirectCustomer | null;
502
+ subscriptions: DirectSubscription[];
432
503
  onClose: () => void;
433
504
  classNames?: SuccessClassNames;
434
505
  }
@@ -442,11 +513,13 @@ interface FlowState {
442
513
  step: string;
443
514
  currentStepId: string;
444
515
  selectedReason: string | null;
516
+ followupResponse: string;
445
517
  feedback: string;
446
518
  outcome: 'saved' | 'cancelled' | null;
447
519
  isProcessing: boolean;
448
520
  error: Error | null;
449
521
  customer: DirectCustomer | null;
522
+ subscriptions: DirectSubscription[];
450
523
  }
451
524
  interface FlowConfig extends FlowCallbacks {
452
525
  appId?: string;
@@ -505,12 +578,6 @@ interface CancelFlowProps extends FlowCallbacks {
505
578
  classNames?: StructuralClassNames;
506
579
  components?: Partial<ComponentOverrides>;
507
580
  customComponents?: CustomComponents;
508
- layout?: {
509
- desktop?: 'modal' | 'inline' | 'drawer';
510
- mobile?: 'sheet' | 'fullscreen' | 'inline';
511
- breakpoint?: number;
512
- };
513
- animation?: 'css' | 'framer' | 'none';
514
581
  }
515
582
 
516
583
  interface ResolvedStep {
@@ -529,6 +596,8 @@ interface ResolvedStep {
529
596
  placeholder?: string;
530
597
  required?: boolean;
531
598
  minLength?: number;
599
+ losses?: string[];
600
+ lossesLabel?: string;
532
601
  savedTitle?: string;
533
602
  savedDescription?: string;
534
603
  cancelledTitle?: string;
@@ -129,12 +129,10 @@ interface PauseOffer {
129
129
  type: 'pause';
130
130
  months: number;
131
131
  interval?: 'month' | 'week';
132
- datePicker?: boolean;
133
132
  }
134
133
  interface PlanChangeOffer {
135
134
  type: 'plan_change';
136
135
  plans: PlanOption[];
137
- currentPlanId?: string;
138
136
  }
139
137
  /**
140
138
  * Plan option in a `plan_change` offer — `DirectPrice` plus optional
@@ -181,13 +179,22 @@ interface OfferCopy {
181
179
  declineCta: string;
182
180
  }
183
181
  type AcceptedOffer = OfferConfig & {
184
- reasonId: string;
185
- decisionId?: string;
182
+ /** Survey reason that routed to this offer. Absent when the offer was
183
+ * declared as a standalone `OfferStep`. */
184
+ reasonId?: string;
185
+ /** Payload from custom offers — whatever your component passed to
186
+ * `onAccept(result)`. Built-in offer types do not populate this. */
186
187
  result?: Record<string, unknown>;
187
188
  };
188
189
  interface ReasonConfig {
189
190
  id: string;
190
191
  label: string;
192
+ /**
193
+ * When true, picking this reason reveals a text input below the reason list.
194
+ * The typed text lands on the session as `followupResponse`. `surveyChoiceId`
195
+ * still carries the reason's `id` and `surveyChoiceValue` still carries the
196
+ * static `label`, so analytics groupings stay stable.
197
+ */
191
198
  freeform?: boolean;
192
199
  offer?: OfferConfig;
193
200
  }
@@ -205,11 +212,12 @@ interface OfferStep {
205
212
  title?: string;
206
213
  description?: string;
207
214
  /**
208
- * Offer attached to this step. Set this for proactive save offers shown
209
- * outside a survey; the SDK also populates it automatically on synthetic
210
- * offer steps spawned from survey choices.
215
+ * Offer attached to this step. Set this to declare a standalone offer
216
+ * step (one that isn't routed from a survey reason). `copy` is optional —
217
+ * the SDK synthesizes default copy from the offer config when none is
218
+ * provided, the same way it does for survey-attached offers.
211
219
  */
212
- offer?: OfferDecision;
220
+ offer?: OfferConfig | OfferDecision;
213
221
  classNames?: OfferClassNames;
214
222
  }
215
223
  interface FeedbackStep {
@@ -227,6 +235,10 @@ interface ConfirmStep {
227
235
  guid?: string;
228
236
  title?: string;
229
237
  description?: string;
238
+ /** Optional bullet list of what the customer is giving up. Rendered between the description and the period-end notice. */
239
+ losses?: string[];
240
+ /** Heading above the loss list. Defaults to "You'll lose access to:". */
241
+ lossesLabel?: string;
230
242
  confirmLabel?: string;
231
243
  goBackLabel?: string;
232
244
  classNames?: ConfirmClassNames;
@@ -258,7 +270,7 @@ interface SurveyClassNames {
258
270
  reasonButton?: string;
259
271
  reasonButtonSelected?: string;
260
272
  reasonLabel?: string;
261
- freeformInput?: string;
273
+ followupInput?: string;
262
274
  continueButton?: string;
263
275
  }
264
276
  interface OfferClassNames {
@@ -289,6 +301,10 @@ interface ConfirmClassNames {
289
301
  root?: string;
290
302
  title?: string;
291
303
  description?: string;
304
+ lossList?: string;
305
+ lossLabel?: string;
306
+ lossItem?: string;
307
+ lossBullet?: string;
292
308
  confirmButton?: string;
293
309
  goBackButton?: string;
294
310
  periodEndNotice?: string;
@@ -306,18 +322,55 @@ interface StructuralClassNames {
306
322
  closeButton?: string;
307
323
  backButton?: string;
308
324
  }
325
+ /**
326
+ * Typed surface for `appearance.variables`. Every key maps to a `--ck-*`
327
+ * CSS custom property. Consumers who need a token not in this list can
328
+ * still set the underlying CSS variable directly — these are the ones
329
+ * exposed through the typed JS API.
330
+ */
309
331
  interface AppearanceVariables {
310
- colorPrimary: string;
311
- colorPrimaryHover: string;
312
332
  colorBackground: string;
333
+ colorSurface: string;
334
+ colorSurfaceMuted: string;
335
+ colorBorder: string;
336
+ colorBorderStrong: string;
313
337
  colorText: string;
314
338
  colorTextSecondary: string;
315
- colorBorder: string;
316
- colorDanger: string;
339
+ colorTextMuted: string;
340
+ colorPrimary: string;
341
+ colorPrimaryHover: string;
342
+ colorPrimarySoft: string;
317
343
  colorSuccess: string;
344
+ colorSuccessSoft: string;
345
+ colorDanger: string;
346
+ colorDangerHover: string;
347
+ colorDangerSoft: string;
318
348
  fontFamily: string;
349
+ fontFamilyMono: string;
350
+ /**
351
+ * Display face used by step titles and other visual headlines. Defaults
352
+ * to `fontFamily`. Set this when your brand uses a separate display face
353
+ * (Tiempos, Canela, etc.) for headings.
354
+ */
355
+ fontFamilyDisplay: string;
319
356
  fontSize: string;
357
+ /** Weight applied to the step title. Default `'600'`. */
358
+ fontWeightDisplay: string;
359
+ /** Letter spacing applied to the step title. Default `'-0.015em'`. */
360
+ letterSpacingDisplay: string;
320
361
  borderRadius: string;
362
+ radiusSm: string;
363
+ radiusMd: string;
364
+ radiusLg: string;
365
+ radiusXl: string;
366
+ shadowModal: string;
367
+ shadowCard: string;
368
+ /**
369
+ * Color of the dim behind the modal. Defaults to a neutral translucent
370
+ * ink. Set to `color-mix(in srgb, var(--ck-color-primary) 40%, transparent)`
371
+ * to derive the overlay from your primary color, or any CSS color value.
372
+ */
373
+ overlayColor: string;
321
374
  }
322
375
  interface Appearance {
323
376
  /**
@@ -330,12 +383,14 @@ interface Appearance {
330
383
  interface CustomStepProps {
331
384
  step: CustomStepConfig;
332
385
  customer: DirectCustomer | null;
386
+ subscriptions: DirectSubscription[];
333
387
  onNext: (result?: Record<string, unknown>) => void;
334
388
  onBack: () => void;
335
389
  }
336
390
  interface CustomOfferProps {
337
391
  offer: OfferDecision;
338
392
  customer: DirectCustomer | null;
393
+ subscriptions: DirectSubscription[];
339
394
  onAccept: (result?: Record<string, unknown>) => Promise<void>;
340
395
  onDecline: () => void;
341
396
  isProcessing: boolean;
@@ -363,6 +418,7 @@ interface ModalProps {
363
418
  onClose: () => void;
364
419
  children: ReactNode;
365
420
  className?: string;
421
+ overlayClassName?: string;
366
422
  }
367
423
  interface CloseButtonProps {
368
424
  onClose: () => void;
@@ -375,9 +431,15 @@ interface BackButtonProps {
375
431
  interface SurveyStepProps {
376
432
  title: string;
377
433
  description?: string;
434
+ customer: DirectCustomer | null;
435
+ subscriptions: DirectSubscription[];
378
436
  reasons: ReasonConfig[];
379
437
  selectedReason: string | null;
380
438
  onSelectReason: (id: string) => void;
439
+ /** Free-text value when the selected reason has `freeform: true`. Lands on the session as `followupResponse`. */
440
+ followupResponse: string;
441
+ /** Set the follow-up response. The SDK forwards the value to the session. */
442
+ onFollowupResponseChange: (text: string) => void;
381
443
  onNext: () => void;
382
444
  classNames?: SurveyClassNames;
383
445
  components?: Partial<ComponentOverrides>;
@@ -385,6 +447,8 @@ interface SurveyStepProps {
385
447
  interface OfferStepProps {
386
448
  title?: string;
387
449
  description?: string;
450
+ customer: DirectCustomer | null;
451
+ subscriptions: DirectSubscription[];
388
452
  offer: OfferDecision;
389
453
  /**
390
454
  * Accept the offer. The optional `result` is included on the resulting
@@ -405,6 +469,8 @@ interface OfferStepProps {
405
469
  interface FeedbackStepProps {
406
470
  title: string;
407
471
  description?: string;
472
+ customer: DirectCustomer | null;
473
+ subscriptions: DirectSubscription[];
408
474
  placeholder?: string;
409
475
  required: boolean;
410
476
  minLength: number;
@@ -416,9 +482,12 @@ interface FeedbackStepProps {
416
482
  interface ConfirmStepProps {
417
483
  title: string;
418
484
  description?: string;
485
+ customer: DirectCustomer | null;
486
+ subscriptions: DirectSubscription[];
487
+ losses?: string[];
488
+ lossesLabel?: string;
419
489
  confirmLabel: string;
420
490
  goBackLabel: string;
421
- periodEnd?: string;
422
491
  onConfirm: () => Promise<void>;
423
492
  onGoBack: () => void;
424
493
  isProcessing: boolean;
@@ -429,6 +498,8 @@ interface SuccessStepProps {
429
498
  offer?: OfferDecision;
430
499
  title: string;
431
500
  description?: string;
501
+ customer: DirectCustomer | null;
502
+ subscriptions: DirectSubscription[];
432
503
  onClose: () => void;
433
504
  classNames?: SuccessClassNames;
434
505
  }
@@ -442,11 +513,13 @@ interface FlowState {
442
513
  step: string;
443
514
  currentStepId: string;
444
515
  selectedReason: string | null;
516
+ followupResponse: string;
445
517
  feedback: string;
446
518
  outcome: 'saved' | 'cancelled' | null;
447
519
  isProcessing: boolean;
448
520
  error: Error | null;
449
521
  customer: DirectCustomer | null;
522
+ subscriptions: DirectSubscription[];
450
523
  }
451
524
  interface FlowConfig extends FlowCallbacks {
452
525
  appId?: string;
@@ -505,12 +578,6 @@ interface CancelFlowProps extends FlowCallbacks {
505
578
  classNames?: StructuralClassNames;
506
579
  components?: Partial<ComponentOverrides>;
507
580
  customComponents?: CustomComponents;
508
- layout?: {
509
- desktop?: 'modal' | 'inline' | 'drawer';
510
- mobile?: 'sheet' | 'fullscreen' | 'inline';
511
- breakpoint?: number;
512
- };
513
- animation?: 'css' | 'framer' | 'none';
514
581
  }
515
582
 
516
583
  interface ResolvedStep {
@@ -529,6 +596,8 @@ interface ResolvedStep {
529
596
  placeholder?: string;
530
597
  required?: boolean;
531
598
  minLength?: number;
599
+ losses?: string[];
600
+ lossesLabel?: string;
532
601
  savedTitle?: string;
533
602
  savedDescription?: string;
534
603
  cancelledTitle?: string;