@founderhq/journeys 0.4.0 → 0.4.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.
@@ -323,7 +323,7 @@ declare type BlockPropsMap = {
323
323
  export { BlockPropsMap }
324
324
  export { BlockPropsMap as BlockPropsMap_alias_1 }
325
325
 
326
- export declare function BlockRenderer({ blocks, layout, answers, onNext, onBack, onGoToStep, scrollViewportRef, wrapInScrollViewport, }: BlockRendererProps): JSX.Element;
326
+ export declare function BlockRenderer({ blocks, layout, answers, onNext, onBack, onGoToStep, isLastStep, scrollViewportRef, wrapInScrollViewport, }: BlockRendererProps): JSX.Element;
327
327
 
328
328
  declare type BlockRendererProps = {
329
329
  blocks: BlockConfig[];
@@ -332,6 +332,7 @@ declare type BlockRendererProps = {
332
332
  onNext: () => void;
333
333
  onBack: () => void;
334
334
  onGoToStep?: (stepId: string) => void;
335
+ isLastStep?: boolean;
335
336
  scrollViewportRef?: Ref<HTMLDivElement>;
336
337
  wrapInScrollViewport?: boolean;
337
338
  };
@@ -355,6 +356,8 @@ declare type ButtonAction = {
355
356
  type: "link";
356
357
  url: string;
357
358
  external?: boolean;
359
+ /** Final-step links complete before navigating by default. Set false to opt out, or true to force this on non-final steps. */
360
+ completeBeforeNavigate?: boolean;
358
361
  } | {
359
362
  type: "purchase";
360
363
  planVariable?: string;
@@ -370,7 +373,7 @@ declare type ButtonAction = {
370
373
  export { ButtonAction }
371
374
  export { ButtonAction as ButtonAction_alias_1 }
372
375
 
373
- export declare function ButtonBlock({ label, action, variant, className, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, disabled, }: ButtonBlockComponentProps): JSX.Element;
376
+ export declare function ButtonBlock({ label, action, variant, className, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, disabled, isLastStep, }: ButtonBlockComponentProps): JSX.Element;
374
377
 
375
378
  declare type ButtonBlockComponentProps = ButtonBlockProps & {
376
379
  onNext?: () => void;
@@ -383,6 +386,7 @@ declare type ButtonBlockComponentProps = ButtonBlockProps & {
383
386
  onOpenDiscountCode?: () => void;
384
387
  /** Injected by BlockRenderer when sibling input blocks have unmet validation. */
385
388
  disabled?: boolean;
389
+ isLastStep?: boolean;
386
390
  };
387
391
 
388
392
  declare type ButtonBlockProps = {
@@ -572,13 +576,14 @@ declare type ColumnConfig = {
572
576
  export { ColumnConfig }
573
577
  export { ColumnConfig as ColumnConfig_alias_1 }
574
578
 
575
- export declare function ColumnsBlock({ columns, gap, responsive, className, answers, onNext, onBack, onGoToStep, }: ColumnsBlockComponentProps): JSX.Element;
579
+ export declare function ColumnsBlock({ columns, gap, responsive, className, answers, onNext, onBack, onGoToStep, isLastStep, }: ColumnsBlockComponentProps): JSX.Element;
576
580
 
577
581
  declare type ColumnsBlockComponentProps = ColumnsBlockProps & {
578
582
  answers?: JourneyAnswers;
579
583
  onNext?: () => void;
580
584
  onBack?: () => void;
581
585
  onGoToStep?: (stepId: string) => void;
586
+ isLastStep?: boolean;
582
587
  };
583
588
 
584
589
  declare type ColumnsBlockProps = {
@@ -979,7 +984,7 @@ declare type ImageBlockProps = {
979
984
  export { ImageBlockProps }
980
985
  export { ImageBlockProps as ImageBlockProps_alias_1 }
981
986
 
982
- export declare function InfoPageStep({ config, onNext }: StepComponentProps): JSX.Element | null;
987
+ export declare function InfoPageStep({ config, onNext, isLastStep, }: StepComponentProps): JSX.Element | null;
983
988
 
984
989
  export declare function Input({ className, type, ...props }: React_2.ComponentProps<"input">): React_2.JSX.Element;
985
990
 
@@ -1863,6 +1868,7 @@ declare type StepComponentProps = {
1863
1868
  answer: StepAnswer | undefined;
1864
1869
  onAnswer: (answer: StepAnswer) => void;
1865
1870
  onNext: () => void;
1871
+ isLastStep?: boolean;
1866
1872
  };
1867
1873
  export { StepComponentProps }
1868
1874
  export { StepComponentProps as StepComponentProps_alias_1 }
@@ -323,7 +323,7 @@ declare type BlockPropsMap = {
323
323
  export { BlockPropsMap }
324
324
  export { BlockPropsMap as BlockPropsMap_alias_1 }
325
325
 
326
- export declare function BlockRenderer({ blocks, layout, answers, onNext, onBack, onGoToStep, scrollViewportRef, wrapInScrollViewport, }: BlockRendererProps): JSX.Element;
326
+ export declare function BlockRenderer({ blocks, layout, answers, onNext, onBack, onGoToStep, isLastStep, scrollViewportRef, wrapInScrollViewport, }: BlockRendererProps): JSX.Element;
327
327
 
328
328
  declare type BlockRendererProps = {
329
329
  blocks: BlockConfig[];
@@ -332,6 +332,7 @@ declare type BlockRendererProps = {
332
332
  onNext: () => void;
333
333
  onBack: () => void;
334
334
  onGoToStep?: (stepId: string) => void;
335
+ isLastStep?: boolean;
335
336
  scrollViewportRef?: Ref<HTMLDivElement>;
336
337
  wrapInScrollViewport?: boolean;
337
338
  };
@@ -355,6 +356,8 @@ declare type ButtonAction = {
355
356
  type: "link";
356
357
  url: string;
357
358
  external?: boolean;
359
+ /** Final-step links complete before navigating by default. Set false to opt out, or true to force this on non-final steps. */
360
+ completeBeforeNavigate?: boolean;
358
361
  } | {
359
362
  type: "purchase";
360
363
  planVariable?: string;
@@ -370,7 +373,7 @@ declare type ButtonAction = {
370
373
  export { ButtonAction }
371
374
  export { ButtonAction as ButtonAction_alias_1 }
372
375
 
373
- export declare function ButtonBlock({ label, action, variant, className, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, disabled, }: ButtonBlockComponentProps): JSX.Element;
376
+ export declare function ButtonBlock({ label, action, variant, className, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, disabled, isLastStep, }: ButtonBlockComponentProps): JSX.Element;
374
377
 
375
378
  declare type ButtonBlockComponentProps = ButtonBlockProps & {
376
379
  onNext?: () => void;
@@ -383,6 +386,7 @@ declare type ButtonBlockComponentProps = ButtonBlockProps & {
383
386
  onOpenDiscountCode?: () => void;
384
387
  /** Injected by BlockRenderer when sibling input blocks have unmet validation. */
385
388
  disabled?: boolean;
389
+ isLastStep?: boolean;
386
390
  };
387
391
 
388
392
  declare type ButtonBlockProps = {
@@ -572,13 +576,14 @@ declare type ColumnConfig = {
572
576
  export { ColumnConfig }
573
577
  export { ColumnConfig as ColumnConfig_alias_1 }
574
578
 
575
- export declare function ColumnsBlock({ columns, gap, responsive, className, answers, onNext, onBack, onGoToStep, }: ColumnsBlockComponentProps): JSX.Element;
579
+ export declare function ColumnsBlock({ columns, gap, responsive, className, answers, onNext, onBack, onGoToStep, isLastStep, }: ColumnsBlockComponentProps): JSX.Element;
576
580
 
577
581
  declare type ColumnsBlockComponentProps = ColumnsBlockProps & {
578
582
  answers?: JourneyAnswers;
579
583
  onNext?: () => void;
580
584
  onBack?: () => void;
581
585
  onGoToStep?: (stepId: string) => void;
586
+ isLastStep?: boolean;
582
587
  };
583
588
 
584
589
  declare type ColumnsBlockProps = {
@@ -979,7 +984,7 @@ declare type ImageBlockProps = {
979
984
  export { ImageBlockProps }
980
985
  export { ImageBlockProps as ImageBlockProps_alias_1 }
981
986
 
982
- export declare function InfoPageStep({ config, onNext }: StepComponentProps): JSX.Element | null;
987
+ export declare function InfoPageStep({ config, onNext, isLastStep, }: StepComponentProps): JSX.Element | null;
983
988
 
984
989
  export declare function Input({ className, type, ...props }: React_2.ComponentProps<"input">): React_2.JSX.Element;
985
990
 
@@ -1863,6 +1868,7 @@ declare type StepComponentProps = {
1863
1868
  answer: StepAnswer | undefined;
1864
1869
  onAnswer: (answer: StepAnswer) => void;
1865
1870
  onNext: () => void;
1871
+ isLastStep?: boolean;
1866
1872
  };
1867
1873
  export { StepComponentProps }
1868
1874
  export { StepComponentProps as StepComponentProps_alias_1 }
package/dist/index.cjs CHANGED
@@ -2698,9 +2698,11 @@ function ButtonBlock({
2698
2698
  onGoToStep,
2699
2699
  onPurchase,
2700
2700
  onOpenDiscountCode,
2701
- disabled
2701
+ disabled,
2702
+ isLastStep
2702
2703
  }) {
2703
2704
  const handleClick = () => {
2705
+ var _a;
2704
2706
  if (!action) {
2705
2707
  onNext == null ? void 0 : onNext();
2706
2708
  return;
@@ -2720,6 +2722,9 @@ function ButtonBlock({
2720
2722
  }
2721
2723
  break;
2722
2724
  case "link":
2725
+ if ((_a = action.completeBeforeNavigate) != null ? _a : isLastStep) {
2726
+ onNext == null ? void 0 : onNext();
2727
+ }
2723
2728
  if (action.external) {
2724
2729
  window.open(action.url, "_blank", "noopener,noreferrer");
2725
2730
  } else {
@@ -4210,7 +4215,8 @@ function ColumnsBlock({
4210
4215
  answers,
4211
4216
  onNext,
4212
4217
  onBack,
4213
- onGoToStep
4218
+ onGoToStep,
4219
+ isLastStep
4214
4220
  }) {
4215
4221
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "jy-columns-container", children: /* @__PURE__ */ jsxRuntime.jsx(
4216
4222
  "div",
@@ -4236,6 +4242,7 @@ function ColumnsBlock({
4236
4242
  onBack: onBack != null ? onBack : (() => {
4237
4243
  }),
4238
4244
  onGoToStep,
4245
+ isLastStep,
4239
4246
  wrapInScrollViewport: false
4240
4247
  }
4241
4248
  )
@@ -7911,7 +7918,11 @@ function HiddenBlockSlot({ block }) {
7911
7918
  return /* @__PURE__ */ jsxRuntime.jsx(
7912
7919
  "div",
7913
7920
  {
7914
- className: cn(widthClass, resolvedMaxWidth ? "mx-auto" : void 0, block.className),
7921
+ className: cn(
7922
+ widthClass,
7923
+ resolvedMaxWidth ? "mx-auto" : void 0,
7924
+ block.className
7925
+ ),
7915
7926
  style: __spreadProps(__spreadValues(__spreadValues({}, resolvedMaxWidth ? { maxWidth: resolvedMaxWidth } : null), block.style), {
7916
7927
  visibility: "hidden"
7917
7928
  }),
@@ -8094,7 +8105,7 @@ function resolveAppliedDiscountForDialog(answers, discountVariable, planId) {
8094
8105
  if (!planId) return answer.planId ? void 0 : answer;
8095
8106
  return discountAppliesToPlan(answer, planId) ? answer : void 0;
8096
8107
  }
8097
- function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, inputsValid) {
8108
+ function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, inputsValid, isLastStep) {
8098
8109
  var _a, _b;
8099
8110
  const conditionMet = !block.condition || evaluateCondition(block.condition, answers);
8100
8111
  const hasExitAnim = ((_a = block.exitAnimation) == null ? void 0 : _a.preset) && block.exitAnimation.preset !== "none";
@@ -8121,8 +8132,9 @@ function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToS
8121
8132
  onGoToStep,
8122
8133
  onPurchase,
8123
8134
  onOpenDiscountCode,
8124
- disabled: buttonDisabledForValidity(resolvedProps, inputsValid)
8125
- }) : block.type === "columns" ? __spreadProps(__spreadValues({}, resolvedProps), { answers, onNext, onBack, onGoToStep }) : block.type === "gravity_bin" ? __spreadProps(__spreadValues({}, resolvedProps), { answers }) : resolvedProps;
8135
+ disabled: buttonDisabledForValidity(resolvedProps, inputsValid),
8136
+ isLastStep
8137
+ }) : block.type === "columns" ? __spreadProps(__spreadValues({}, resolvedProps), { answers, onNext, onBack, onGoToStep, isLastStep }) : block.type === "gravity_bin" ? __spreadProps(__spreadValues({}, resolvedProps), { answers }) : resolvedProps;
8126
8138
  const idx = visibleIndexRef.current;
8127
8139
  visibleIndexRef.current++;
8128
8140
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -8144,6 +8156,7 @@ function BlockRenderer({
8144
8156
  onNext,
8145
8157
  onBack,
8146
8158
  onGoToStep,
8159
+ isLastStep,
8147
8160
  scrollViewportRef,
8148
8161
  wrapInScrollViewport = true
8149
8162
  }) {
@@ -8229,7 +8242,8 @@ function BlockRenderer({
8229
8242
  onGoToStep,
8230
8243
  onPurchase,
8231
8244
  onOpenDiscountCode,
8232
- inputsValid
8245
+ inputsValid,
8246
+ isLastStep
8233
8247
  );
8234
8248
  };
8235
8249
  if (!wrapInScrollViewport && stickyBlocks.length === 0) {
@@ -8252,7 +8266,11 @@ function BlockRenderer({
8252
8266
  "div",
8253
8267
  {
8254
8268
  className: layoutClasses(layout),
8255
- style: { gap: `${gap}rem`, maxWidth: layout == null ? void 0 : layout.maxWidth, width: "100%" },
8269
+ style: {
8270
+ gap: `${gap}rem`,
8271
+ maxWidth: layout == null ? void 0 : layout.maxWidth,
8272
+ width: "100%"
8273
+ },
8256
8274
  children: contentBlocks.map((block, i) => renderOne(block, i))
8257
8275
  }
8258
8276
  )
@@ -8263,7 +8281,11 @@ function BlockRenderer({
8263
8281
  ) }) : null
8264
8282
  ] });
8265
8283
  }
8266
- function InfoPageStep({ config, onNext }) {
8284
+ function InfoPageStep({
8285
+ config,
8286
+ onNext,
8287
+ isLastStep
8288
+ }) {
8267
8289
  var _a;
8268
8290
  const { answers } = useJourneyState();
8269
8291
  const { goBack, goToStep } = useJourneyActions();
@@ -8271,9 +8293,7 @@ function InfoPageStep({ config, onNext }) {
8271
8293
  const sortedTimelineEvents = React.useMemo(
8272
8294
  () => {
8273
8295
  var _a2, _b;
8274
- return [...(_b = (_a2 = config.scrollTimeline) == null ? void 0 : _a2.events) != null ? _b : []].sort(
8275
- (a, b) => a.at - b.at
8276
- );
8296
+ return [...(_b = (_a2 = config.scrollTimeline) == null ? void 0 : _a2.events) != null ? _b : []].sort((a, b) => a.at - b.at);
8277
8297
  },
8278
8298
  [(_a = config.scrollTimeline) == null ? void 0 : _a.events]
8279
8299
  );
@@ -8453,6 +8473,7 @@ function InfoPageStep({ config, onNext }) {
8453
8473
  onNext,
8454
8474
  onBack: goBack,
8455
8475
  onGoToStep: goToStep,
8476
+ isLastStep,
8456
8477
  scrollViewportRef
8457
8478
  }
8458
8479
  );
@@ -9320,7 +9341,7 @@ var STEP_REGISTRY = {
9320
9341
  function StepRenderer({ config }) {
9321
9342
  var _a, _b;
9322
9343
  const { answers } = useJourneyState();
9323
- const { setAnswer, goNext } = useJourneyActions();
9344
+ const { setAnswer, goNext, isLastStep } = useJourneyActions();
9324
9345
  const resolvedConfig = React.useMemo(() => {
9325
9346
  var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9326
9347
  const hasTemplates = ((_a2 = config.preface) == null ? void 0 : _a2.includes("${")) || ((_b2 = config.question) == null ? void 0 : _b2.includes("${")) || ((_c = config.description) == null ? void 0 : _c.includes("${")) || ((_d = config.buttonText) == null ? void 0 : _d.includes("${")) || ((_e = config.footerText) == null ? void 0 : _e.includes("${")) || ((_g = (_f = config.swipeLabels) == null ? void 0 : _f.yes) == null ? void 0 : _g.includes("${")) || ((_i = (_h = config.swipeLabels) == null ? void 0 : _h.no) == null ? void 0 : _i.includes("${")) || ((_j = config.swipeCards) != null ? _j : []).some(
@@ -9373,7 +9394,8 @@ function StepRenderer({ config }) {
9373
9394
  }
9374
9395
  setAnswer(answerKey, answer);
9375
9396
  },
9376
- onNext: () => goNext()
9397
+ onNext: () => goNext(),
9398
+ isLastStep: isLastStep()
9377
9399
  }
9378
9400
  );
9379
9401
  }
@@ -9671,7 +9693,7 @@ function JourneyShell({ className, theme } = {}) {
9671
9693
  ] });
9672
9694
  }
9673
9695
  var JOURNEY_LIBRARY_NAME = "@founderhq/journeys";
9674
- var JOURNEY_LIBRARY_VERSION = "0.4.0";
9696
+ var JOURNEY_LIBRARY_VERSION = "0.4.1";
9675
9697
  function randomId(prefix) {
9676
9698
  const cryptoRef = globalThis.crypto;
9677
9699
  if (cryptoRef == null ? void 0 : cryptoRef.randomUUID) return `${prefix}_${cryptoRef.randomUUID()}`;
@@ -10060,7 +10082,9 @@ function useJourneyCapture(params) {
10060
10082
  });
10061
10083
  persistQueue();
10062
10084
  const batchSize = Math.max(1, (_b = capture.batchSize) != null ? _b : 10);
10063
- if (queueRef.current.length >= batchSize) void flush();
10085
+ if (event.type === "complete" || queueRef.current.length >= batchSize) {
10086
+ void flush();
10087
+ }
10064
10088
  },
10065
10089
  [ensureRuntime, flush, persistQueue]
10066
10090
  );
package/dist/index.js CHANGED
@@ -2673,9 +2673,11 @@ function ButtonBlock({
2673
2673
  onGoToStep,
2674
2674
  onPurchase,
2675
2675
  onOpenDiscountCode,
2676
- disabled
2676
+ disabled,
2677
+ isLastStep
2677
2678
  }) {
2678
2679
  const handleClick = () => {
2680
+ var _a;
2679
2681
  if (!action) {
2680
2682
  onNext == null ? void 0 : onNext();
2681
2683
  return;
@@ -2695,6 +2697,9 @@ function ButtonBlock({
2695
2697
  }
2696
2698
  break;
2697
2699
  case "link":
2700
+ if ((_a = action.completeBeforeNavigate) != null ? _a : isLastStep) {
2701
+ onNext == null ? void 0 : onNext();
2702
+ }
2698
2703
  if (action.external) {
2699
2704
  window.open(action.url, "_blank", "noopener,noreferrer");
2700
2705
  } else {
@@ -4185,7 +4190,8 @@ function ColumnsBlock({
4185
4190
  answers,
4186
4191
  onNext,
4187
4192
  onBack,
4188
- onGoToStep
4193
+ onGoToStep,
4194
+ isLastStep
4189
4195
  }) {
4190
4196
  return /* @__PURE__ */ jsx("div", { className: "jy-columns-container", children: /* @__PURE__ */ jsx(
4191
4197
  "div",
@@ -4211,6 +4217,7 @@ function ColumnsBlock({
4211
4217
  onBack: onBack != null ? onBack : (() => {
4212
4218
  }),
4213
4219
  onGoToStep,
4220
+ isLastStep,
4214
4221
  wrapInScrollViewport: false
4215
4222
  }
4216
4223
  )
@@ -7886,7 +7893,11 @@ function HiddenBlockSlot({ block }) {
7886
7893
  return /* @__PURE__ */ jsx(
7887
7894
  "div",
7888
7895
  {
7889
- className: cn(widthClass, resolvedMaxWidth ? "mx-auto" : void 0, block.className),
7896
+ className: cn(
7897
+ widthClass,
7898
+ resolvedMaxWidth ? "mx-auto" : void 0,
7899
+ block.className
7900
+ ),
7890
7901
  style: __spreadProps(__spreadValues(__spreadValues({}, resolvedMaxWidth ? { maxWidth: resolvedMaxWidth } : null), block.style), {
7891
7902
  visibility: "hidden"
7892
7903
  }),
@@ -8069,7 +8080,7 @@ function resolveAppliedDiscountForDialog(answers, discountVariable, planId) {
8069
8080
  if (!planId) return answer.planId ? void 0 : answer;
8070
8081
  return discountAppliesToPlan(answer, planId) ? answer : void 0;
8071
8082
  }
8072
- function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, inputsValid) {
8083
+ function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToStep, onPurchase, onOpenDiscountCode, inputsValid, isLastStep) {
8073
8084
  var _a, _b;
8074
8085
  const conditionMet = !block.condition || evaluateCondition(block.condition, answers);
8075
8086
  const hasExitAnim = ((_a = block.exitAnimation) == null ? void 0 : _a.preset) && block.exitAnimation.preset !== "none";
@@ -8096,8 +8107,9 @@ function renderBlock(block, i, visibleIndexRef, answers, onNext, onBack, onGoToS
8096
8107
  onGoToStep,
8097
8108
  onPurchase,
8098
8109
  onOpenDiscountCode,
8099
- disabled: buttonDisabledForValidity(resolvedProps, inputsValid)
8100
- }) : block.type === "columns" ? __spreadProps(__spreadValues({}, resolvedProps), { answers, onNext, onBack, onGoToStep }) : block.type === "gravity_bin" ? __spreadProps(__spreadValues({}, resolvedProps), { answers }) : resolvedProps;
8110
+ disabled: buttonDisabledForValidity(resolvedProps, inputsValid),
8111
+ isLastStep
8112
+ }) : block.type === "columns" ? __spreadProps(__spreadValues({}, resolvedProps), { answers, onNext, onBack, onGoToStep, isLastStep }) : block.type === "gravity_bin" ? __spreadProps(__spreadValues({}, resolvedProps), { answers }) : resolvedProps;
8101
8113
  const idx = visibleIndexRef.current;
8102
8114
  visibleIndexRef.current++;
8103
8115
  return /* @__PURE__ */ jsx(
@@ -8119,6 +8131,7 @@ function BlockRenderer({
8119
8131
  onNext,
8120
8132
  onBack,
8121
8133
  onGoToStep,
8134
+ isLastStep,
8122
8135
  scrollViewportRef,
8123
8136
  wrapInScrollViewport = true
8124
8137
  }) {
@@ -8204,7 +8217,8 @@ function BlockRenderer({
8204
8217
  onGoToStep,
8205
8218
  onPurchase,
8206
8219
  onOpenDiscountCode,
8207
- inputsValid
8220
+ inputsValid,
8221
+ isLastStep
8208
8222
  );
8209
8223
  };
8210
8224
  if (!wrapInScrollViewport && stickyBlocks.length === 0) {
@@ -8227,7 +8241,11 @@ function BlockRenderer({
8227
8241
  "div",
8228
8242
  {
8229
8243
  className: layoutClasses(layout),
8230
- style: { gap: `${gap}rem`, maxWidth: layout == null ? void 0 : layout.maxWidth, width: "100%" },
8244
+ style: {
8245
+ gap: `${gap}rem`,
8246
+ maxWidth: layout == null ? void 0 : layout.maxWidth,
8247
+ width: "100%"
8248
+ },
8231
8249
  children: contentBlocks.map((block, i) => renderOne(block, i))
8232
8250
  }
8233
8251
  )
@@ -8238,7 +8256,11 @@ function BlockRenderer({
8238
8256
  ) }) : null
8239
8257
  ] });
8240
8258
  }
8241
- function InfoPageStep({ config, onNext }) {
8259
+ function InfoPageStep({
8260
+ config,
8261
+ onNext,
8262
+ isLastStep
8263
+ }) {
8242
8264
  var _a;
8243
8265
  const { answers } = useJourneyState();
8244
8266
  const { goBack, goToStep } = useJourneyActions();
@@ -8246,9 +8268,7 @@ function InfoPageStep({ config, onNext }) {
8246
8268
  const sortedTimelineEvents = useMemo(
8247
8269
  () => {
8248
8270
  var _a2, _b;
8249
- return [...(_b = (_a2 = config.scrollTimeline) == null ? void 0 : _a2.events) != null ? _b : []].sort(
8250
- (a, b) => a.at - b.at
8251
- );
8271
+ return [...(_b = (_a2 = config.scrollTimeline) == null ? void 0 : _a2.events) != null ? _b : []].sort((a, b) => a.at - b.at);
8252
8272
  },
8253
8273
  [(_a = config.scrollTimeline) == null ? void 0 : _a.events]
8254
8274
  );
@@ -8428,6 +8448,7 @@ function InfoPageStep({ config, onNext }) {
8428
8448
  onNext,
8429
8449
  onBack: goBack,
8430
8450
  onGoToStep: goToStep,
8451
+ isLastStep,
8431
8452
  scrollViewportRef
8432
8453
  }
8433
8454
  );
@@ -9295,7 +9316,7 @@ var STEP_REGISTRY = {
9295
9316
  function StepRenderer({ config }) {
9296
9317
  var _a, _b;
9297
9318
  const { answers } = useJourneyState();
9298
- const { setAnswer, goNext } = useJourneyActions();
9319
+ const { setAnswer, goNext, isLastStep } = useJourneyActions();
9299
9320
  const resolvedConfig = useMemo(() => {
9300
9321
  var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9301
9322
  const hasTemplates = ((_a2 = config.preface) == null ? void 0 : _a2.includes("${")) || ((_b2 = config.question) == null ? void 0 : _b2.includes("${")) || ((_c = config.description) == null ? void 0 : _c.includes("${")) || ((_d = config.buttonText) == null ? void 0 : _d.includes("${")) || ((_e = config.footerText) == null ? void 0 : _e.includes("${")) || ((_g = (_f = config.swipeLabels) == null ? void 0 : _f.yes) == null ? void 0 : _g.includes("${")) || ((_i = (_h = config.swipeLabels) == null ? void 0 : _h.no) == null ? void 0 : _i.includes("${")) || ((_j = config.swipeCards) != null ? _j : []).some(
@@ -9348,7 +9369,8 @@ function StepRenderer({ config }) {
9348
9369
  }
9349
9370
  setAnswer(answerKey, answer);
9350
9371
  },
9351
- onNext: () => goNext()
9372
+ onNext: () => goNext(),
9373
+ isLastStep: isLastStep()
9352
9374
  }
9353
9375
  );
9354
9376
  }
@@ -9646,7 +9668,7 @@ function JourneyShell({ className, theme } = {}) {
9646
9668
  ] });
9647
9669
  }
9648
9670
  var JOURNEY_LIBRARY_NAME = "@founderhq/journeys";
9649
- var JOURNEY_LIBRARY_VERSION = "0.4.0";
9671
+ var JOURNEY_LIBRARY_VERSION = "0.4.1";
9650
9672
  function randomId(prefix) {
9651
9673
  const cryptoRef = globalThis.crypto;
9652
9674
  if (cryptoRef == null ? void 0 : cryptoRef.randomUUID) return `${prefix}_${cryptoRef.randomUUID()}`;
@@ -10035,7 +10057,9 @@ function useJourneyCapture(params) {
10035
10057
  });
10036
10058
  persistQueue();
10037
10059
  const batchSize = Math.max(1, (_b = capture.batchSize) != null ? _b : 10);
10038
- if (queueRef.current.length >= batchSize) void flush();
10060
+ if (event.type === "complete" || queueRef.current.length >= batchSize) {
10061
+ void flush();
10062
+ }
10039
10063
  },
10040
10064
  [ensureRuntime, flush, persistQueue]
10041
10065
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@founderhq/journeys",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Config-driven interactive journey/questionnaire engine for React",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",