@schematichq/schematic-components 2.2.0 → 2.2.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 CHANGED
@@ -14,8 +14,60 @@ pnpm add @schematichq/schematic-components
14
14
 
15
15
  ## Usage
16
16
 
17
+ Import components and functions and compose them into your project.
18
+
19
+ ```js
20
+ import { EmbedProvider, SchematicEmbed, useEmbed } from '@schematichq/schematic-components';
21
+ ```
22
+
17
23
  See the [Schematic documentation](https://docs.schematichq.com/components/set-up) for a full guide on how to set up and use Schematic components.
18
24
 
25
+ ## Advanced Checkout Usage
26
+
27
+ We provide a function `initializeWithPlan` as an alternate entrypoint into a
28
+ checkout flow. It's suitable for click handlers, and must be extracted from
29
+ the library's embedded context.
30
+
31
+ ```ts
32
+ const { initializeWithPlan } = useEmbed();
33
+ ```
34
+
35
+ This function allows developers to create their own button that
36
+
37
+ * Pre-selects a Plan
38
+ * Pre-selects Add-ons (if available)
39
+ * Skips and hides plan selection stages
40
+
41
+ The `initializeWithPlan` function can be called with a Schematic plan ID, or
42
+ with a more powerful `BypassConfig` object.
43
+
44
+ Providing a plan ID as a string will preselect that plan and skip the plan
45
+ selection stage.
46
+
47
+ ```ts
48
+ initializeWithPlan('plan_VBXv4bHjSf3');
49
+ ```
50
+
51
+ Passing a config object allows pre-selecting Add-ons as well as hiding
52
+ specific stages.
53
+
54
+ ```ts
55
+ const config = {
56
+ planId: 'plan_VBXv4bHjSf3', // pre-select a Plan
57
+ addOnIds: ['plan_AWv7bPjSx2'], // pre-select 1 or more Add-ons
58
+ skipped: {
59
+ planStage: true, // if true, skip Plan selection
60
+ addOnStage: true // if true, skip Add-on selection
61
+ }
62
+ hideSkipped: true // if true, hide skipped stages from breadcrumb navigation
63
+ };
64
+
65
+ initializeWithPlan(config);
66
+ ```
67
+
68
+ The Plans and Add-ons available to the checkout flows must be live in your
69
+ Schematic account [Catalog configuration](https://docs.schematichq.com/catalog/overview).
70
+
19
71
  ## License
20
72
 
21
73
  MIT
@@ -8315,12 +8315,29 @@ var reducer = (state, action) => {
8315
8315
  };
8316
8316
  }
8317
8317
  case "SET_PLANID_BYPASS": {
8318
+ const isStringFormat = typeof action.config === "string";
8319
+ const config = isStringFormat ? { planId: action.config, hideSkipped: false } : action.config;
8320
+ let bypassPlanSelection;
8321
+ let bypassAddOnSelection;
8322
+ if (config.skipped !== void 0) {
8323
+ bypassPlanSelection = config.skipped.planStage ?? false;
8324
+ bypassAddOnSelection = config.skipped.addOnStage ?? false;
8325
+ } else if (isStringFormat) {
8326
+ bypassPlanSelection = true;
8327
+ bypassAddOnSelection = false;
8328
+ } else {
8329
+ bypassPlanSelection = false;
8330
+ bypassAddOnSelection = false;
8331
+ }
8318
8332
  return {
8319
8333
  ...state,
8320
8334
  layout: "checkout",
8321
8335
  checkoutState: {
8322
- planId: action.planId,
8323
- bypassPlanSelection: true
8336
+ ...config.planId && { planId: config.planId },
8337
+ bypassPlanSelection,
8338
+ bypassAddOnSelection,
8339
+ ...config.addOnIds && { addOnIds: config.addOnIds },
8340
+ hideSkippedStages: config.hideSkipped ?? false
8324
8341
  }
8325
8342
  };
8326
8343
  }
@@ -8330,7 +8347,7 @@ var reducer = (state, action) => {
8330
8347
  // src/context/EmbedProvider.tsx
8331
8348
  var import_jsx_runtime2 = require("react/jsx-runtime");
8332
8349
  var getCustomHeaders = (sessionId) => ({
8333
- "X-Schematic-Components-Version": "2.2.0",
8350
+ "X-Schematic-Components-Version": "2.2.1",
8334
8351
  "X-Schematic-Session-ID": sessionId
8335
8352
  });
8336
8353
  var EmbedProvider = ({
@@ -8622,8 +8639,8 @@ var EmbedProvider = ({
8622
8639
  const setCheckoutState = (0, import_react4.useCallback)((state2) => {
8623
8640
  dispatch({ type: "SET_CHECKOUT_STATE", state: state2 });
8624
8641
  }, []);
8625
- const initializeWithPlan = (0, import_react4.useCallback)((planId) => {
8626
- dispatch({ type: "SET_PLANID_BYPASS", planId });
8642
+ const initializeWithPlan = (0, import_react4.useCallback)((config) => {
8643
+ dispatch({ type: "SET_PLANID_BYPASS", config });
8627
8644
  }, []);
8628
8645
  (0, import_react4.useEffect)(() => {
8629
8646
  const element = document.getElementById(
@@ -11843,7 +11860,7 @@ var Checkout = ({
11843
11860
  if (!isPaymentMethodRequired) {
11844
11861
  return null;
11845
11862
  }
11846
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Flex, { $position: "relative", $flexDirection: "column", $gap: "1.5rem", children: [
11863
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Flex, { $flexDirection: "column", $gap: "1.5rem", children: [
11847
11864
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
11848
11865
  PaymentMethodDetails,
11849
11866
  {
@@ -12818,20 +12835,13 @@ var CheckoutDialog = ({ top = 0 }) => {
12818
12835
  );
12819
12836
  const [isLoading, setIsLoading] = (0, import_react23.useState)(false);
12820
12837
  const [error, setError] = (0, import_react23.useState)();
12821
- const {
12822
- currentPlanId,
12823
- currentEntitlements,
12824
- showPeriodToggle,
12825
- trialPaymentMethodRequired
12826
- } = (0, import_react23.useMemo)(() => {
12838
+ const { currentEntitlements, showPeriodToggle, trialPaymentMethodRequired } = (0, import_react23.useMemo)(() => {
12827
12839
  return {
12828
- currentPlanId: data?.company?.plan?.id,
12829
12840
  currentEntitlements: data?.featureUsage ? data.featureUsage.features : [],
12830
12841
  showPeriodToggle: data?.showPeriodToggle ?? true,
12831
12842
  trialPaymentMethodRequired: data?.trialPaymentMethodRequired === true
12832
12843
  };
12833
12844
  }, [
12834
- data?.company?.plan?.id,
12835
12845
  data?.featureUsage,
12836
12846
  data?.showPeriodToggle,
12837
12847
  data?.trialPaymentMethodRequired
@@ -12859,8 +12869,12 @@ var CheckoutDialog = ({ top = 0 }) => {
12859
12869
  const [addOns, setAddOns] = (0, import_react23.useState)(() => {
12860
12870
  return availableAddOns.map((addOn) => ({
12861
12871
  ...addOn,
12862
- isSelected: typeof checkoutState?.addOnId !== "undefined" ? addOn.id === checkoutState.addOnId : (data?.company?.addOns || []).some(
12863
- (currentAddOn) => addOn.id === currentAddOn.id
12872
+ isSelected: (
12873
+ // Check if bypassed with specific add-on IDs
12874
+ checkoutState?.addOnIds?.includes(addOn.id) || // Check if single add-on ID provided
12875
+ (typeof checkoutState?.addOnId !== "undefined" ? addOn.id === checkoutState.addOnId : (data?.company?.addOns || []).some(
12876
+ (currentAddOn) => addOn.id === currentAddOn.id
12877
+ ))
12864
12878
  )
12865
12879
  }));
12866
12880
  });
@@ -12880,19 +12894,47 @@ var CheckoutDialog = ({ top = 0 }) => {
12880
12894
  )
12881
12895
  );
12882
12896
  const [addOnUsageBasedEntitlements, setAddOnUsageBasedEntitlements] = (0, import_react23.useState)(() => {
12883
- return (data?.company?.addOns || []).flatMap((currentAddOn) => {
12884
- const availableAddOn = availableAddOns.find(
12885
- (available) => available.id === currentAddOn.id
12886
- );
12887
- if (!availableAddOn) return [];
12888
- return availableAddOn.entitlements.reduce(
12889
- createActiveUsageBasedEntitlementsReducer(
12890
- currentEntitlements,
12891
- planPeriod
12892
- ),
12893
- []
12897
+ const currentAddOnEntitlements = (data?.company?.addOns || []).flatMap(
12898
+ (currentAddOn) => {
12899
+ const availableAddOn = availableAddOns.find(
12900
+ (available) => available.id === currentAddOn.id
12901
+ );
12902
+ if (!availableAddOn) return [];
12903
+ return availableAddOn.entitlements.reduce(
12904
+ createActiveUsageBasedEntitlementsReducer(
12905
+ currentEntitlements,
12906
+ planPeriod
12907
+ ),
12908
+ []
12909
+ );
12910
+ }
12911
+ );
12912
+ const bypassAddOnEntitlements = (checkoutState?.addOnIds || []).flatMap(
12913
+ (addOnId) => {
12914
+ const availableAddOn = availableAddOns.find(
12915
+ (available) => available.id === addOnId
12916
+ );
12917
+ if (!availableAddOn) return [];
12918
+ return availableAddOn.entitlements.filter(
12919
+ (entitlement) => entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */
12920
+ ).map((entitlement) => ({
12921
+ ...entitlement,
12922
+ allocation: entitlement.valueNumeric || 0,
12923
+ usage: 0,
12924
+ quantity: 1
12925
+ }));
12926
+ }
12927
+ );
12928
+ const allEntitlements = [...currentAddOnEntitlements];
12929
+ for (const bypassEnt of bypassAddOnEntitlements) {
12930
+ const exists = currentAddOnEntitlements.some(
12931
+ (current) => current.featureId === bypassEnt.featureId
12894
12932
  );
12895
- });
12933
+ if (!exists) {
12934
+ allEntitlements.push(bypassEnt);
12935
+ }
12936
+ }
12937
+ return allEntitlements;
12896
12938
  });
12897
12939
  const payInAdvanceEntitlements = (0, import_react23.useMemo)(
12898
12940
  () => usageBasedEntitlements.filter(
@@ -12981,6 +13023,10 @@ var CheckoutDialog = ({ top = 0 }) => {
12981
13023
  isPaymentMethodRequired
12982
13024
  ]);
12983
13025
  const [hasSkippedInitialPlan, setHasSkippedInitialPlan] = (0, import_react23.useState)(false);
13026
+ const [hasSkippedInitialAddOns, setHasSkippedInitialAddOns] = (0, import_react23.useState)(false);
13027
+ const [isBypassLoading, setIsBypassLoading] = (0, import_react23.useState)(
13028
+ () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection
13029
+ );
12984
13030
  const [checkoutStage, setCheckoutStage] = (0, import_react23.useState)(() => {
12985
13031
  if (checkoutState?.addOnId) {
12986
13032
  return "addons";
@@ -12994,24 +13040,35 @@ var CheckoutDialog = ({ top = 0 }) => {
12994
13040
  if (checkoutState?.credits) {
12995
13041
  return "credits";
12996
13042
  }
12997
- if (typeof checkoutState?.planId !== "undefined" && checkoutState.planId !== currentPlanId || checkoutState?.bypassPlanSelection) {
13043
+ if (checkoutState?.bypassPlanSelection) {
12998
13044
  return checkoutStages.some((stage) => stage.id === "usage") ? "usage" : checkoutStages.some((stage) => stage.id === "addons") ? "addons" : checkoutStages.some((stage) => stage.id === "addonsUsage") ? "addonsUsage" : checkoutStages.some((stage) => stage.id === "credits") ? "credits" : checkoutStages.some((stage) => stage.id === "checkout") ? "checkout" : checkoutStages[0]?.id || "plan";
12999
13045
  }
13000
13046
  return "plan";
13001
13047
  });
13002
13048
  (0, import_react23.useEffect)(() => {
13003
13049
  if (checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan) {
13004
- const nextStage = checkoutStages.find((stage) => stage.id !== "plan");
13050
+ const currentIndex = checkoutStages.findIndex((s2) => s2.id === "plan");
13051
+ const nextStage = checkoutStages[currentIndex + 1];
13005
13052
  if (nextStage) {
13006
13053
  setHasSkippedInitialPlan(true);
13007
13054
  setCheckoutStage(nextStage.id);
13008
13055
  }
13009
13056
  }
13057
+ if (checkoutState?.bypassAddOnSelection && checkoutStage === "addons" && !hasSkippedInitialAddOns) {
13058
+ const currentIndex = checkoutStages.findIndex((s2) => s2.id === "addons");
13059
+ const nextStage = checkoutStages[currentIndex + 1];
13060
+ if (nextStage) {
13061
+ setHasSkippedInitialAddOns(true);
13062
+ setCheckoutStage(nextStage.id);
13063
+ }
13064
+ }
13010
13065
  }, [
13011
13066
  checkoutStages,
13012
13067
  checkoutState?.bypassPlanSelection,
13068
+ checkoutState?.bypassAddOnSelection,
13013
13069
  checkoutStage,
13014
- hasSkippedInitialPlan
13070
+ hasSkippedInitialPlan,
13071
+ hasSkippedInitialAddOns
13015
13072
  ]);
13016
13073
  const handlePreviewCheckout = (0, import_react23.useCallback)(
13017
13074
  async (updates) => {
@@ -13122,6 +13179,9 @@ var CheckoutDialog = ({ top = 0 }) => {
13122
13179
  setError(msg);
13123
13180
  } finally {
13124
13181
  setIsLoading(false);
13182
+ if (isBypassLoading) {
13183
+ setIsBypassLoading(false);
13184
+ }
13125
13185
  }
13126
13186
  },
13127
13187
  [
@@ -13134,7 +13194,8 @@ var CheckoutDialog = ({ top = 0 }) => {
13134
13194
  addOns,
13135
13195
  creditBundles,
13136
13196
  shouldTrial,
13137
- promoCode
13197
+ promoCode,
13198
+ isBypassLoading
13138
13199
  ]
13139
13200
  );
13140
13201
  const selectPlan = (0, import_react23.useCallback)(
@@ -13281,34 +13342,29 @@ var CheckoutDialog = ({ top = 0 }) => {
13281
13342
  },
13282
13343
  [handlePreviewCheckout]
13283
13344
  );
13345
+ const hasInitializedPlan = (0, import_react23.useRef)(false);
13284
13346
  (0, import_react23.useEffect)(() => {
13285
- if (selectedPlan) {
13347
+ if (!hasInitializedPlan.current && selectedPlan) {
13348
+ hasInitializedPlan.current = true;
13286
13349
  selectPlan({ plan: selectedPlan, period: currentPeriod });
13287
13350
  }
13288
- }, []);
13351
+ }, [selectedPlan, currentPeriod, selectPlan]);
13289
13352
  (0, import_react23.useEffect)(() => {
13290
13353
  if (checkoutState?.planId) {
13291
13354
  const plan = availablePlans.find(
13292
13355
  (plan2) => plan2.id === checkoutState.planId
13293
13356
  );
13294
- setSelectedPlan(plan);
13295
- }
13296
- }, [availablePlans, checkoutState?.planId]);
13297
- (0, import_react23.useEffect)(() => {
13298
- if (checkoutState?.addOnId) {
13299
- const checkoutStateAddOn = availableAddOns.find(
13300
- (addOn) => addOn.id === checkoutState.addOnId
13301
- );
13302
- setAddOns(
13303
- (prev2) => prev2.map((addOn) => ({
13304
- ...addOn,
13305
- ...addOn.id === checkoutStateAddOn?.id && {
13306
- isSelected: true
13307
- }
13308
- }))
13309
- );
13357
+ if (plan && plan.id !== selectedPlan?.id) {
13358
+ selectPlan({ plan, period: currentPeriod });
13359
+ }
13310
13360
  }
13311
- }, [availableAddOns, checkoutState?.addOnId]);
13361
+ }, [
13362
+ availablePlans,
13363
+ checkoutState?.planId,
13364
+ currentPeriod,
13365
+ selectPlan,
13366
+ selectedPlan?.id
13367
+ ]);
13312
13368
  (0, import_react23.useEffect)(() => {
13313
13369
  setAddOns((prevAddOns) => {
13314
13370
  return availableAddOns.filter((availAddOn) => {
@@ -13350,7 +13406,21 @@ var CheckoutDialog = ({ top = 0 }) => {
13350
13406
  const activeCheckoutStage = checkoutStages.find(
13351
13407
  (stage) => stage.id === checkoutStage
13352
13408
  );
13353
- const shouldShowBypassOverlay = checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan;
13409
+ const visibleStages = (0, import_react23.useMemo)(() => {
13410
+ if (!checkoutState?.hideSkippedStages) {
13411
+ return checkoutStages;
13412
+ }
13413
+ return checkoutStages.filter((stage) => {
13414
+ if (stage.id === "plan" && checkoutState.bypassPlanSelection) {
13415
+ return false;
13416
+ }
13417
+ if (stage.id === "addons" && checkoutState.bypassAddOnSelection) {
13418
+ return false;
13419
+ }
13420
+ return true;
13421
+ });
13422
+ }, [checkoutStages, checkoutState]);
13423
+ const shouldShowBypassOverlay = isBypassLoading || checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan || checkoutState?.bypassAddOnSelection && checkoutStage === "addons" && !hasSkippedInitialAddOns;
13354
13424
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Modal2, { ref: modalRef, size: "lg", top, children: [
13355
13425
  shouldShowBypassOverlay && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13356
13426
  Flex,
@@ -13384,12 +13454,12 @@ var CheckoutDialog = ({ top = 0 }) => {
13384
13454
  $gap: "1rem"
13385
13455
  }
13386
13456
  },
13387
- children: checkoutStages.map((stage, index, stages) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13457
+ children: visibleStages.map((stage, index, stages) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
13388
13458
  Navigation,
13389
13459
  {
13390
13460
  name: stage.name,
13391
13461
  index,
13392
- activeIndex: checkoutStages.findIndex(
13462
+ activeIndex: visibleStages.findIndex(
13393
13463
  (s2) => s2.id === checkoutStage
13394
13464
  ),
13395
13465
  isLast: index === stages.length - 1,
@@ -15792,7 +15862,7 @@ var registerWrapper = function registerWrapper2(stripe, startTime) {
15792
15862
  }
15793
15863
  stripe._registerWrapper({
15794
15864
  name: "stripe-js",
15795
- version: "8.3.0",
15865
+ version: "8.4.0",
15796
15866
  startTime
15797
15867
  });
15798
15868
  };
@@ -15867,7 +15937,7 @@ var initStripe = function initStripe2(maybeStripe, args, startTime) {
15867
15937
  var version = runtimeVersionToUrlVersion(maybeStripe.version);
15868
15938
  var expectedVersion = RELEASE_TRAIN;
15869
15939
  if (isTestKey && version !== expectedVersion) {
15870
- console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("8.3.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
15940
+ console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("8.4.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
15871
15941
  }
15872
15942
  var stripe = maybeStripe.apply(void 0, args);
15873
15943
  registerWrapper(stripe, startTime);
@@ -16061,7 +16131,7 @@ var PaymentMethodDetails = ({
16061
16131
  showPaymentForm,
16062
16132
  initializePaymentMethod
16063
16133
  ]);
16064
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
16134
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Flex, { $position: "relative", $flexDirection: "column", $gap: "1.5rem", children: [
16065
16135
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
16066
16136
  Flex,
16067
16137
  {
@@ -1869,6 +1869,89 @@ export declare type ButtonSize = "sm" | "md" | "lg";
1869
1869
 
1870
1870
  export declare type ButtonVariant = "filled" | "outline" | "ghost" | "text";
1871
1871
 
1872
+ /**
1873
+ * Configuration for controlling checkout stage flow and pre-selection.
1874
+ *
1875
+ * ## Three Behavior Modes
1876
+ *
1877
+ * ### 1. Pre-Selection Mode (object without `skipped`)
1878
+ * When you provide planId/addOnIds without explicit skip config, stages are
1879
+ * shown with values pre-selected for user review.
1880
+ *
1881
+ * @example
1882
+ * // Pre-select plan, show plan stage for review
1883
+ * initializeWithPlan({ planId: 'plan_xyz' })
1884
+ *
1885
+ * @example
1886
+ * // Pre-select plan and add-ons, show both stages for review
1887
+ * initializeWithPlan({
1888
+ * planId: 'plan_xyz',
1889
+ * addOnIds: ['addon_1', 'addon_2']
1890
+ * })
1891
+ *
1892
+ * ### 2. Explicit Skip Mode (object with `skipped`)
1893
+ * With explicit skip configuration, you control exactly which stages to skip.
1894
+ * You can skip stages without pre-selecting, or pre-select and skip together.
1895
+ *
1896
+ * @example
1897
+ * // Skip plan stage without pre-selecting (user chooses plan)
1898
+ * initializeWithPlan({
1899
+ * skipped: { planStage: true }
1900
+ * })
1901
+ *
1902
+ * @example
1903
+ * // Pre-select plan AND skip plan stage (go directly to add-ons)
1904
+ * initializeWithPlan({
1905
+ * planId: 'plan_xyz',
1906
+ * skipped: { planStage: true }
1907
+ * })
1908
+ *
1909
+ * @example
1910
+ * // Pre-select plan but show it, skip add-ons stage
1911
+ * initializeWithPlan({
1912
+ * planId: 'plan_xyz',
1913
+ * skipped: { planStage: false, addOnStage: true }
1914
+ * })
1915
+ *
1916
+ * @example
1917
+ * // Skip both stages, go straight to checkout
1918
+ * initializeWithPlan({
1919
+ * planId: 'plan_xyz',
1920
+ * addOnIds: ['addon_1'],
1921
+ * skipped: { planStage: true, addOnStage: true }
1922
+ * })
1923
+ *
1924
+ * ### 3. Legacy String Format
1925
+ * Backwards compatible mode: pre-selects plan and skips plan stage.
1926
+ *
1927
+ * @example
1928
+ * initializeWithPlan('plan_xyz')
1929
+ * // Equivalent to: { planId: 'plan_xyz', skipped: { planStage: true } }
1930
+ */
1931
+ export declare interface BypassConfig {
1932
+ /**
1933
+ * Plan ID to pre-select.
1934
+ * Optional - you can skip stages without pre-selecting a plan.
1935
+ */
1936
+ planId?: string;
1937
+ /**
1938
+ * Add-on IDs to pre-select.
1939
+ * Optional - you can skip stages without pre-selecting add-ons.
1940
+ */
1941
+ addOnIds?: string[];
1942
+ /**
1943
+ * Explicit skip configuration for stages.
1944
+ * - If not provided: stages are shown with pre-selected values (review mode)
1945
+ * - If provided: you control exactly which stages to skip
1946
+ */
1947
+ skipped?: CheckoutStageSkipConfig;
1948
+ /**
1949
+ * Hide skipped stages from breadcrumb navigation.
1950
+ * Default: false (skipped stages still appear in breadcrumbs)
1951
+ */
1952
+ hideSkipped?: boolean;
1953
+ }
1954
+
1872
1955
  export declare const Card: ForwardRefExoticComponent<CardProps & RefAttributes<HTMLDivElement | null>>;
1873
1956
 
1874
1957
  export declare const cardBoxShadow = "0px 1px 20px 0px #1018280F, 0px 1px 3px 0px #1018281A";
@@ -2118,6 +2201,49 @@ export declare interface CheckoutStage {
2118
2201
  description?: string;
2119
2202
  }
2120
2203
 
2204
+ /**
2205
+ * Explicit configuration for skipping checkout stages.
2206
+ *
2207
+ * This configuration is independent of pre-selection (planId/addOnIds).
2208
+ * You have full control to:
2209
+ * - Skip stages without pre-selecting values
2210
+ * - Pre-select values without skipping stages
2211
+ * - Pre-select AND skip stages
2212
+ * - Any combination that suits your checkout flow
2213
+ *
2214
+ * @example
2215
+ * // Skip both stages (go directly to checkout/payment)
2216
+ * { planStage: true, addOnStage: true }
2217
+ *
2218
+ * @example
2219
+ * // Skip only plan stage (show add-ons)
2220
+ * { planStage: true, addOnStage: false }
2221
+ *
2222
+ * @example
2223
+ * // Show plan stage, skip add-ons stage
2224
+ * { planStage: false, addOnStage: true }
2225
+ *
2226
+ * @example
2227
+ * // Show both stages (same as not providing skipped config)
2228
+ * { planStage: false, addOnStage: false }
2229
+ */
2230
+ export declare interface CheckoutStageSkipConfig {
2231
+ /**
2232
+ * Skip the plan selection stage.
2233
+ * - true: Skip directly to next stage
2234
+ * - false: Show plan stage (user can review/change selection)
2235
+ * - undefined: Defaults to false (show stage)
2236
+ */
2237
+ planStage?: boolean;
2238
+ /**
2239
+ * Skip the add-on selection stage.
2240
+ * - true: Skip directly to next stage
2241
+ * - false: Show add-on stage (user can review/change selection)
2242
+ * - undefined: Defaults to false (show stage)
2243
+ */
2244
+ addOnStage?: boolean;
2245
+ }
2246
+
2121
2247
  export declare type CheckoutState = {
2122
2248
  period?: string;
2123
2249
  planId?: string | null;
@@ -2126,6 +2252,9 @@ export declare type CheckoutState = {
2126
2252
  addOnUsage?: boolean;
2127
2253
  credits?: boolean;
2128
2254
  bypassPlanSelection?: boolean;
2255
+ bypassAddOnSelection?: boolean;
2256
+ addOnIds?: string[];
2257
+ hideSkippedStages?: boolean;
2129
2258
  };
2130
2259
 
2131
2260
  /**
@@ -4100,7 +4229,7 @@ export declare interface EmbedContextProps extends EmbedState {
4100
4229
  setError: (error: Error) => void;
4101
4230
  setLayout: (layout: EmbedLayout) => void;
4102
4231
  setCheckoutState: (state: CheckoutState) => void;
4103
- initializeWithPlan: (planId: string) => void;
4232
+ initializeWithPlan: (config: string | BypassConfig) => void;
4104
4233
  setData: (data: HydrateDataWithCompanyContext) => void;
4105
4234
  updateSettings: (settings: DeepPartial<EmbedSettings>, options?: {
4106
4235
  update?: boolean;
@@ -8255,12 +8255,29 @@ var reducer = (state, action) => {
8255
8255
  };
8256
8256
  }
8257
8257
  case "SET_PLANID_BYPASS": {
8258
+ const isStringFormat = typeof action.config === "string";
8259
+ const config = isStringFormat ? { planId: action.config, hideSkipped: false } : action.config;
8260
+ let bypassPlanSelection;
8261
+ let bypassAddOnSelection;
8262
+ if (config.skipped !== void 0) {
8263
+ bypassPlanSelection = config.skipped.planStage ?? false;
8264
+ bypassAddOnSelection = config.skipped.addOnStage ?? false;
8265
+ } else if (isStringFormat) {
8266
+ bypassPlanSelection = true;
8267
+ bypassAddOnSelection = false;
8268
+ } else {
8269
+ bypassPlanSelection = false;
8270
+ bypassAddOnSelection = false;
8271
+ }
8258
8272
  return {
8259
8273
  ...state,
8260
8274
  layout: "checkout",
8261
8275
  checkoutState: {
8262
- planId: action.planId,
8263
- bypassPlanSelection: true
8276
+ ...config.planId && { planId: config.planId },
8277
+ bypassPlanSelection,
8278
+ bypassAddOnSelection,
8279
+ ...config.addOnIds && { addOnIds: config.addOnIds },
8280
+ hideSkippedStages: config.hideSkipped ?? false
8264
8281
  }
8265
8282
  };
8266
8283
  }
@@ -8270,7 +8287,7 @@ var reducer = (state, action) => {
8270
8287
  // src/context/EmbedProvider.tsx
8271
8288
  import { jsx, jsxs } from "react/jsx-runtime";
8272
8289
  var getCustomHeaders = (sessionId) => ({
8273
- "X-Schematic-Components-Version": "2.2.0",
8290
+ "X-Schematic-Components-Version": "2.2.1",
8274
8291
  "X-Schematic-Session-ID": sessionId
8275
8292
  });
8276
8293
  var EmbedProvider = ({
@@ -8562,8 +8579,8 @@ var EmbedProvider = ({
8562
8579
  const setCheckoutState = useCallback2((state2) => {
8563
8580
  dispatch({ type: "SET_CHECKOUT_STATE", state: state2 });
8564
8581
  }, []);
8565
- const initializeWithPlan = useCallback2((planId) => {
8566
- dispatch({ type: "SET_PLANID_BYPASS", planId });
8582
+ const initializeWithPlan = useCallback2((config) => {
8583
+ dispatch({ type: "SET_PLANID_BYPASS", config });
8567
8584
  }, []);
8568
8585
  useEffect(() => {
8569
8586
  const element = document.getElementById(
@@ -11803,7 +11820,7 @@ var Checkout = ({
11803
11820
  if (!isPaymentMethodRequired) {
11804
11821
  return null;
11805
11822
  }
11806
- return /* @__PURE__ */ jsxs11(Flex, { $position: "relative", $flexDirection: "column", $gap: "1.5rem", children: [
11823
+ return /* @__PURE__ */ jsxs11(Flex, { $flexDirection: "column", $gap: "1.5rem", children: [
11807
11824
  /* @__PURE__ */ jsx17(
11808
11825
  PaymentMethodDetails,
11809
11826
  {
@@ -12778,20 +12795,13 @@ var CheckoutDialog = ({ top = 0 }) => {
12778
12795
  );
12779
12796
  const [isLoading, setIsLoading] = useState10(false);
12780
12797
  const [error, setError] = useState10();
12781
- const {
12782
- currentPlanId,
12783
- currentEntitlements,
12784
- showPeriodToggle,
12785
- trialPaymentMethodRequired
12786
- } = useMemo8(() => {
12798
+ const { currentEntitlements, showPeriodToggle, trialPaymentMethodRequired } = useMemo8(() => {
12787
12799
  return {
12788
- currentPlanId: data?.company?.plan?.id,
12789
12800
  currentEntitlements: data?.featureUsage ? data.featureUsage.features : [],
12790
12801
  showPeriodToggle: data?.showPeriodToggle ?? true,
12791
12802
  trialPaymentMethodRequired: data?.trialPaymentMethodRequired === true
12792
12803
  };
12793
12804
  }, [
12794
- data?.company?.plan?.id,
12795
12805
  data?.featureUsage,
12796
12806
  data?.showPeriodToggle,
12797
12807
  data?.trialPaymentMethodRequired
@@ -12819,8 +12829,12 @@ var CheckoutDialog = ({ top = 0 }) => {
12819
12829
  const [addOns, setAddOns] = useState10(() => {
12820
12830
  return availableAddOns.map((addOn) => ({
12821
12831
  ...addOn,
12822
- isSelected: typeof checkoutState?.addOnId !== "undefined" ? addOn.id === checkoutState.addOnId : (data?.company?.addOns || []).some(
12823
- (currentAddOn) => addOn.id === currentAddOn.id
12832
+ isSelected: (
12833
+ // Check if bypassed with specific add-on IDs
12834
+ checkoutState?.addOnIds?.includes(addOn.id) || // Check if single add-on ID provided
12835
+ (typeof checkoutState?.addOnId !== "undefined" ? addOn.id === checkoutState.addOnId : (data?.company?.addOns || []).some(
12836
+ (currentAddOn) => addOn.id === currentAddOn.id
12837
+ ))
12824
12838
  )
12825
12839
  }));
12826
12840
  });
@@ -12840,19 +12854,47 @@ var CheckoutDialog = ({ top = 0 }) => {
12840
12854
  )
12841
12855
  );
12842
12856
  const [addOnUsageBasedEntitlements, setAddOnUsageBasedEntitlements] = useState10(() => {
12843
- return (data?.company?.addOns || []).flatMap((currentAddOn) => {
12844
- const availableAddOn = availableAddOns.find(
12845
- (available) => available.id === currentAddOn.id
12846
- );
12847
- if (!availableAddOn) return [];
12848
- return availableAddOn.entitlements.reduce(
12849
- createActiveUsageBasedEntitlementsReducer(
12850
- currentEntitlements,
12851
- planPeriod
12852
- ),
12853
- []
12857
+ const currentAddOnEntitlements = (data?.company?.addOns || []).flatMap(
12858
+ (currentAddOn) => {
12859
+ const availableAddOn = availableAddOns.find(
12860
+ (available) => available.id === currentAddOn.id
12861
+ );
12862
+ if (!availableAddOn) return [];
12863
+ return availableAddOn.entitlements.reduce(
12864
+ createActiveUsageBasedEntitlementsReducer(
12865
+ currentEntitlements,
12866
+ planPeriod
12867
+ ),
12868
+ []
12869
+ );
12870
+ }
12871
+ );
12872
+ const bypassAddOnEntitlements = (checkoutState?.addOnIds || []).flatMap(
12873
+ (addOnId) => {
12874
+ const availableAddOn = availableAddOns.find(
12875
+ (available) => available.id === addOnId
12876
+ );
12877
+ if (!availableAddOn) return [];
12878
+ return availableAddOn.entitlements.filter(
12879
+ (entitlement) => entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */
12880
+ ).map((entitlement) => ({
12881
+ ...entitlement,
12882
+ allocation: entitlement.valueNumeric || 0,
12883
+ usage: 0,
12884
+ quantity: 1
12885
+ }));
12886
+ }
12887
+ );
12888
+ const allEntitlements = [...currentAddOnEntitlements];
12889
+ for (const bypassEnt of bypassAddOnEntitlements) {
12890
+ const exists = currentAddOnEntitlements.some(
12891
+ (current) => current.featureId === bypassEnt.featureId
12854
12892
  );
12855
- });
12893
+ if (!exists) {
12894
+ allEntitlements.push(bypassEnt);
12895
+ }
12896
+ }
12897
+ return allEntitlements;
12856
12898
  });
12857
12899
  const payInAdvanceEntitlements = useMemo8(
12858
12900
  () => usageBasedEntitlements.filter(
@@ -12941,6 +12983,10 @@ var CheckoutDialog = ({ top = 0 }) => {
12941
12983
  isPaymentMethodRequired
12942
12984
  ]);
12943
12985
  const [hasSkippedInitialPlan, setHasSkippedInitialPlan] = useState10(false);
12986
+ const [hasSkippedInitialAddOns, setHasSkippedInitialAddOns] = useState10(false);
12987
+ const [isBypassLoading, setIsBypassLoading] = useState10(
12988
+ () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection
12989
+ );
12944
12990
  const [checkoutStage, setCheckoutStage] = useState10(() => {
12945
12991
  if (checkoutState?.addOnId) {
12946
12992
  return "addons";
@@ -12954,24 +13000,35 @@ var CheckoutDialog = ({ top = 0 }) => {
12954
13000
  if (checkoutState?.credits) {
12955
13001
  return "credits";
12956
13002
  }
12957
- if (typeof checkoutState?.planId !== "undefined" && checkoutState.planId !== currentPlanId || checkoutState?.bypassPlanSelection) {
13003
+ if (checkoutState?.bypassPlanSelection) {
12958
13004
  return checkoutStages.some((stage) => stage.id === "usage") ? "usage" : checkoutStages.some((stage) => stage.id === "addons") ? "addons" : checkoutStages.some((stage) => stage.id === "addonsUsage") ? "addonsUsage" : checkoutStages.some((stage) => stage.id === "credits") ? "credits" : checkoutStages.some((stage) => stage.id === "checkout") ? "checkout" : checkoutStages[0]?.id || "plan";
12959
13005
  }
12960
13006
  return "plan";
12961
13007
  });
12962
13008
  useEffect5(() => {
12963
13009
  if (checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan) {
12964
- const nextStage = checkoutStages.find((stage) => stage.id !== "plan");
13010
+ const currentIndex = checkoutStages.findIndex((s2) => s2.id === "plan");
13011
+ const nextStage = checkoutStages[currentIndex + 1];
12965
13012
  if (nextStage) {
12966
13013
  setHasSkippedInitialPlan(true);
12967
13014
  setCheckoutStage(nextStage.id);
12968
13015
  }
12969
13016
  }
13017
+ if (checkoutState?.bypassAddOnSelection && checkoutStage === "addons" && !hasSkippedInitialAddOns) {
13018
+ const currentIndex = checkoutStages.findIndex((s2) => s2.id === "addons");
13019
+ const nextStage = checkoutStages[currentIndex + 1];
13020
+ if (nextStage) {
13021
+ setHasSkippedInitialAddOns(true);
13022
+ setCheckoutStage(nextStage.id);
13023
+ }
13024
+ }
12970
13025
  }, [
12971
13026
  checkoutStages,
12972
13027
  checkoutState?.bypassPlanSelection,
13028
+ checkoutState?.bypassAddOnSelection,
12973
13029
  checkoutStage,
12974
- hasSkippedInitialPlan
13030
+ hasSkippedInitialPlan,
13031
+ hasSkippedInitialAddOns
12975
13032
  ]);
12976
13033
  const handlePreviewCheckout = useCallback9(
12977
13034
  async (updates) => {
@@ -13082,6 +13139,9 @@ var CheckoutDialog = ({ top = 0 }) => {
13082
13139
  setError(msg);
13083
13140
  } finally {
13084
13141
  setIsLoading(false);
13142
+ if (isBypassLoading) {
13143
+ setIsBypassLoading(false);
13144
+ }
13085
13145
  }
13086
13146
  },
13087
13147
  [
@@ -13094,7 +13154,8 @@ var CheckoutDialog = ({ top = 0 }) => {
13094
13154
  addOns,
13095
13155
  creditBundles,
13096
13156
  shouldTrial,
13097
- promoCode
13157
+ promoCode,
13158
+ isBypassLoading
13098
13159
  ]
13099
13160
  );
13100
13161
  const selectPlan = useCallback9(
@@ -13241,34 +13302,29 @@ var CheckoutDialog = ({ top = 0 }) => {
13241
13302
  },
13242
13303
  [handlePreviewCheckout]
13243
13304
  );
13305
+ const hasInitializedPlan = useRef6(false);
13244
13306
  useEffect5(() => {
13245
- if (selectedPlan) {
13307
+ if (!hasInitializedPlan.current && selectedPlan) {
13308
+ hasInitializedPlan.current = true;
13246
13309
  selectPlan({ plan: selectedPlan, period: currentPeriod });
13247
13310
  }
13248
- }, []);
13311
+ }, [selectedPlan, currentPeriod, selectPlan]);
13249
13312
  useEffect5(() => {
13250
13313
  if (checkoutState?.planId) {
13251
13314
  const plan = availablePlans.find(
13252
13315
  (plan2) => plan2.id === checkoutState.planId
13253
13316
  );
13254
- setSelectedPlan(plan);
13255
- }
13256
- }, [availablePlans, checkoutState?.planId]);
13257
- useEffect5(() => {
13258
- if (checkoutState?.addOnId) {
13259
- const checkoutStateAddOn = availableAddOns.find(
13260
- (addOn) => addOn.id === checkoutState.addOnId
13261
- );
13262
- setAddOns(
13263
- (prev2) => prev2.map((addOn) => ({
13264
- ...addOn,
13265
- ...addOn.id === checkoutStateAddOn?.id && {
13266
- isSelected: true
13267
- }
13268
- }))
13269
- );
13317
+ if (plan && plan.id !== selectedPlan?.id) {
13318
+ selectPlan({ plan, period: currentPeriod });
13319
+ }
13270
13320
  }
13271
- }, [availableAddOns, checkoutState?.addOnId]);
13321
+ }, [
13322
+ availablePlans,
13323
+ checkoutState?.planId,
13324
+ currentPeriod,
13325
+ selectPlan,
13326
+ selectedPlan?.id
13327
+ ]);
13272
13328
  useEffect5(() => {
13273
13329
  setAddOns((prevAddOns) => {
13274
13330
  return availableAddOns.filter((availAddOn) => {
@@ -13310,7 +13366,21 @@ var CheckoutDialog = ({ top = 0 }) => {
13310
13366
  const activeCheckoutStage = checkoutStages.find(
13311
13367
  (stage) => stage.id === checkoutStage
13312
13368
  );
13313
- const shouldShowBypassOverlay = checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan;
13369
+ const visibleStages = useMemo8(() => {
13370
+ if (!checkoutState?.hideSkippedStages) {
13371
+ return checkoutStages;
13372
+ }
13373
+ return checkoutStages.filter((stage) => {
13374
+ if (stage.id === "plan" && checkoutState.bypassPlanSelection) {
13375
+ return false;
13376
+ }
13377
+ if (stage.id === "addons" && checkoutState.bypassAddOnSelection) {
13378
+ return false;
13379
+ }
13380
+ return true;
13381
+ });
13382
+ }, [checkoutStages, checkoutState]);
13383
+ const shouldShowBypassOverlay = isBypassLoading || checkoutState?.bypassPlanSelection && checkoutStage === "plan" && !hasSkippedInitialPlan || checkoutState?.bypassAddOnSelection && checkoutStage === "addons" && !hasSkippedInitialAddOns;
13314
13384
  return /* @__PURE__ */ jsxs16(Modal2, { ref: modalRef, size: "lg", top, children: [
13315
13385
  shouldShowBypassOverlay && /* @__PURE__ */ jsx22(
13316
13386
  Flex,
@@ -13344,12 +13414,12 @@ var CheckoutDialog = ({ top = 0 }) => {
13344
13414
  $gap: "1rem"
13345
13415
  }
13346
13416
  },
13347
- children: checkoutStages.map((stage, index, stages) => /* @__PURE__ */ jsx22(
13417
+ children: visibleStages.map((stage, index, stages) => /* @__PURE__ */ jsx22(
13348
13418
  Navigation,
13349
13419
  {
13350
13420
  name: stage.name,
13351
13421
  index,
13352
- activeIndex: checkoutStages.findIndex(
13422
+ activeIndex: visibleStages.findIndex(
13353
13423
  (s2) => s2.id === checkoutStage
13354
13424
  ),
13355
13425
  isLast: index === stages.length - 1,
@@ -15757,7 +15827,7 @@ var registerWrapper = function registerWrapper2(stripe, startTime) {
15757
15827
  }
15758
15828
  stripe._registerWrapper({
15759
15829
  name: "stripe-js",
15760
- version: "8.3.0",
15830
+ version: "8.4.0",
15761
15831
  startTime
15762
15832
  });
15763
15833
  };
@@ -15832,7 +15902,7 @@ var initStripe = function initStripe2(maybeStripe, args, startTime) {
15832
15902
  var version = runtimeVersionToUrlVersion(maybeStripe.version);
15833
15903
  var expectedVersion = RELEASE_TRAIN;
15834
15904
  if (isTestKey && version !== expectedVersion) {
15835
- console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("8.3.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
15905
+ console.warn("Stripe.js@".concat(version, " was loaded on the page, but @stripe/stripe-js@").concat("8.4.0", " expected Stripe.js@").concat(expectedVersion, ". This may result in unexpected behavior. For more information, see https://docs.stripe.com/sdks/stripejs-versioning"));
15836
15906
  }
15837
15907
  var stripe = maybeStripe.apply(void 0, args);
15838
15908
  registerWrapper(stripe, startTime);
@@ -15871,7 +15941,7 @@ var loadStripe = function loadStripe2() {
15871
15941
  // src/components/elements/payment-method/PaymentMethodDetails.tsx
15872
15942
  import { useCallback as useCallback12, useEffect as useEffect7, useMemo as useMemo20, useState as useState17 } from "react";
15873
15943
  import { useTranslation as useTranslation26 } from "react-i18next";
15874
- import { Fragment as Fragment17, jsx as jsx42, jsxs as jsxs31 } from "react/jsx-runtime";
15944
+ import { jsx as jsx42, jsxs as jsxs31 } from "react/jsx-runtime";
15875
15945
  var resolveDesignProps6 = () => {
15876
15946
  return {
15877
15947
  header: {
@@ -16026,7 +16096,7 @@ var PaymentMethodDetails = ({
16026
16096
  showPaymentForm,
16027
16097
  initializePaymentMethod
16028
16098
  ]);
16029
- return /* @__PURE__ */ jsxs31(Fragment17, { children: [
16099
+ return /* @__PURE__ */ jsxs31(Flex, { $position: "relative", $flexDirection: "column", $gap: "1.5rem", children: [
16030
16100
  /* @__PURE__ */ jsx42(
16031
16101
  Flex,
16032
16102
  {
@@ -16197,9 +16267,9 @@ var AddOn = ({ addOn, currency, layout }) => {
16197
16267
  };
16198
16268
 
16199
16269
  // src/components/elements/plan-manager/UsageDetails.tsx
16200
- import { Fragment as Fragment18, useMemo as useMemo21 } from "react";
16270
+ import { Fragment as Fragment17, useMemo as useMemo21 } from "react";
16201
16271
  import { useTranslation as useTranslation27 } from "react-i18next";
16202
- import { Fragment as Fragment19, jsx as jsx44, jsxs as jsxs33 } from "react/jsx-runtime";
16272
+ import { Fragment as Fragment18, jsx as jsx44, jsxs as jsxs33 } from "react/jsx-runtime";
16203
16273
  var UsageDetails2 = ({
16204
16274
  entitlement,
16205
16275
  period,
@@ -16222,9 +16292,9 @@ var UsageDetails2 = ({
16222
16292
  let index = 0;
16223
16293
  if (entitlement.priceBehavior === "overage" /* Overage */) {
16224
16294
  acc.push(
16225
- amount > 0 ? /* @__PURE__ */ jsx44(Fragment18, { children: t2("X additional", {
16295
+ amount > 0 ? /* @__PURE__ */ jsx44(Fragment17, { children: t2("X additional", {
16226
16296
  amount
16227
- }) }, index) : /* @__PURE__ */ jsxs33(Fragment18, { children: [
16297
+ }) }, index) : /* @__PURE__ */ jsxs33(Fragment17, { children: [
16228
16298
  t2("Additional"),
16229
16299
  ": "
16230
16300
  ] }, index)
@@ -16235,16 +16305,16 @@ var UsageDetails2 = ({
16235
16305
  if (entitlement.priceBehavior !== "tier" /* Tiered */ && entitlement.feature && typeof price === "number" && !amount) {
16236
16306
  const packageSize = billingPrice?.packageSize ?? 1;
16237
16307
  acc.push(
16238
- /* @__PURE__ */ jsxs33(Fragment18, { children: [
16308
+ /* @__PURE__ */ jsxs33(Fragment17, { children: [
16239
16309
  formatCurrency(price, billingPrice?.currency),
16240
16310
  /* @__PURE__ */ jsxs33("sub", { children: [
16241
16311
  "/",
16242
- packageSize > 1 && /* @__PURE__ */ jsxs33(Fragment19, { children: [
16312
+ packageSize > 1 && /* @__PURE__ */ jsxs33(Fragment18, { children: [
16243
16313
  packageSize,
16244
16314
  " "
16245
16315
  ] }),
16246
16316
  getFeatureName(entitlement.feature, packageSize),
16247
- entitlement.feature.featureType === "trait" /* Trait */ && /* @__PURE__ */ jsxs33(Fragment19, { children: [
16317
+ entitlement.feature.featureType === "trait" /* Trait */ && /* @__PURE__ */ jsxs33(Fragment18, { children: [
16248
16318
  "/",
16249
16319
  shortenPeriod(period)
16250
16320
  ] })
@@ -16256,7 +16326,7 @@ var UsageDetails2 = ({
16256
16326
  if (showCredits && entitlement.priceBehavior === "credit_burndown" /* Credit */ && entitlement.planEntitlement?.consumptionRate && entitlement.planEntitlement?.valueCredit) {
16257
16327
  const creditAmount = entitlement.planEntitlement.consumptionRate * amount;
16258
16328
  acc.push(
16259
- creditAmount > 0 ? /* @__PURE__ */ jsxs33(Fragment18, { children: [
16329
+ creditAmount > 0 ? /* @__PURE__ */ jsxs33(Fragment17, { children: [
16260
16330
  creditAmount,
16261
16331
  " ",
16262
16332
  getFeatureName(
@@ -16265,7 +16335,7 @@ var UsageDetails2 = ({
16265
16335
  ),
16266
16336
  " ",
16267
16337
  t2("used")
16268
- ] }, index) : /* @__PURE__ */ jsxs33(Fragment18, { children: [
16338
+ ] }, index) : /* @__PURE__ */ jsxs33(Fragment17, { children: [
16269
16339
  entitlement.planEntitlement.consumptionRate,
16270
16340
  " ",
16271
16341
  getFeatureName(
@@ -16294,7 +16364,7 @@ var UsageDetails2 = ({
16294
16364
  $flexWrap: "wrap",
16295
16365
  $gap: "0.5rem",
16296
16366
  children: [
16297
- /* @__PURE__ */ jsx44(Text, { display: layout.addOns.fontStyle, children: typeof quantity === "number" && quantity > 0 ? /* @__PURE__ */ jsxs33(Fragment19, { children: [
16367
+ /* @__PURE__ */ jsx44(Text, { display: layout.addOns.fontStyle, children: typeof quantity === "number" && quantity > 0 ? /* @__PURE__ */ jsxs33(Fragment18, { children: [
16298
16368
  quantity,
16299
16369
  " ",
16300
16370
  entitlement.feature.name
@@ -16334,7 +16404,7 @@ var UsageDetails2 = ({
16334
16404
  };
16335
16405
 
16336
16406
  // src/components/elements/plan-manager/PlanManager.tsx
16337
- import { Fragment as Fragment20, jsx as jsx45, jsxs as jsxs34 } from "react/jsx-runtime";
16407
+ import { Fragment as Fragment19, jsx as jsx45, jsxs as jsxs34 } from "react/jsx-runtime";
16338
16408
  var resolveDesignProps7 = (props) => {
16339
16409
  return {
16340
16410
  header: {
@@ -16455,7 +16525,7 @@ var PlanManager = forwardRef14(({ children, className, portal, ...rest }, ref) =
16455
16525
  const isUsageBasedPlan2 = isFreePlan2 && usageBasedEntitlements.length > 0;
16456
16526
  return { isFreePlan: isFreePlan2, isUsageBasedPlan: isUsageBasedPlan2 };
16457
16527
  }, [currentPlan, usageBasedEntitlements]);
16458
- return /* @__PURE__ */ jsxs34(Fragment20, { children: [
16528
+ return /* @__PURE__ */ jsxs34(Fragment19, { children: [
16459
16529
  isTrialSubscription && !willSubscriptionCancel ? /* @__PURE__ */ jsxs34(
16460
16530
  Notice,
16461
16531
  {
@@ -16616,7 +16686,7 @@ var PlanManager = forwardRef14(({ children, className, portal, ...rest }, ref) =
16616
16686
  " ",
16617
16687
  getFeatureName(group, group.quantity),
16618
16688
  " ",
16619
- subscriptionInterval && /* @__PURE__ */ jsxs34(Fragment20, { children: [
16689
+ subscriptionInterval && /* @__PURE__ */ jsxs34(Fragment19, { children: [
16620
16690
  t2("per"),
16621
16691
  " ",
16622
16692
  t2(subscriptionInterval)
@@ -16647,7 +16717,7 @@ var PlanManager = forwardRef14(({ children, className, portal, ...rest }, ref) =
16647
16717
  typeof planCreditGrant.billingCreditAutoTopupThresholdPercent === "number" ? t2("Auto-topup enabled at X%", {
16648
16718
  threshold: planCreditGrant.billingCreditAutoTopupThresholdPercent
16649
16719
  }) : t2("Auto-topup enabled"),
16650
- planCreditGrant.billingCreditAutoTopupAmount && /* @__PURE__ */ jsxs34(Fragment20, { children: [
16720
+ planCreditGrant.billingCreditAutoTopupAmount && /* @__PURE__ */ jsxs34(Fragment19, { children: [
16651
16721
  " ",
16652
16722
  "(+",
16653
16723
  planCreditGrant.billingCreditAutoTopupAmount,
@@ -16787,7 +16857,7 @@ PlanManager.displayName = "PlanManager";
16787
16857
 
16788
16858
  // src/components/elements/pricing-table/PricingTable.tsx
16789
16859
  import {
16790
- Fragment as Fragment24,
16860
+ Fragment as Fragment23,
16791
16861
  forwardRef as forwardRef15,
16792
16862
  useCallback as useCallback13,
16793
16863
  useEffect as useEffect8,
@@ -16798,7 +16868,7 @@ import { useTranslation as useTranslation32 } from "react-i18next";
16798
16868
  // src/components/elements/pricing-table/AddOn.tsx
16799
16869
  import { useMemo as useMemo23 } from "react";
16800
16870
  import { useTranslation as useTranslation29 } from "react-i18next";
16801
- import { Fragment as Fragment21, jsx as jsx46, jsxs as jsxs35 } from "react/jsx-runtime";
16871
+ import { Fragment as Fragment20, jsx as jsx46, jsxs as jsxs35 } from "react/jsx-runtime";
16802
16872
  function renderMeteredEntitlementPricing2({
16803
16873
  priceBehavior,
16804
16874
  softLimit,
@@ -16810,7 +16880,7 @@ function renderMeteredEntitlementPricing2({
16810
16880
  isTiered
16811
16881
  }) {
16812
16882
  if (priceBehavior === "overage" /* Overage */ && softLimit) {
16813
- return /* @__PURE__ */ jsxs35(Fragment21, { children: [
16883
+ return /* @__PURE__ */ jsxs35(Fragment20, { children: [
16814
16884
  "Additional: ",
16815
16885
  formatCurrency(price, currency),
16816
16886
  "/",
@@ -16821,10 +16891,10 @@ function renderMeteredEntitlementPricing2({
16821
16891
  ] });
16822
16892
  }
16823
16893
  if (priceBehavior === "pay_as_you_go" /* PayAsYouGo */ || priceBehavior === "pay_in_advance" /* PayInAdvance */) {
16824
- return /* @__PURE__ */ jsxs35(Fragment21, { children: [
16894
+ return /* @__PURE__ */ jsxs35(Fragment20, { children: [
16825
16895
  formatCurrency(price, currency),
16826
16896
  "/",
16827
- packageSize > 1 && /* @__PURE__ */ jsxs35(Fragment21, { children: [
16897
+ packageSize > 1 && /* @__PURE__ */ jsxs35(Fragment20, { children: [
16828
16898
  packageSize,
16829
16899
  " "
16830
16900
  ] }),
@@ -16835,7 +16905,7 @@ function renderMeteredEntitlementPricing2({
16835
16905
  ] });
16836
16906
  }
16837
16907
  if (isTiered) {
16838
- return /* @__PURE__ */ jsx46(Fragment21, { children: "Tier-based pricing" });
16908
+ return /* @__PURE__ */ jsx46(Fragment20, { children: "Tier-based pricing" });
16839
16909
  }
16840
16910
  return null;
16841
16911
  }
@@ -16922,7 +16992,7 @@ var AddOn2 = ({ addOn, sharedProps, selectedPeriod }) => {
16922
16992
  {
16923
16993
  "data-testid": "sch-addon-price",
16924
16994
  display: layout.plans.name.fontStyle,
16925
- children: shouldShowUsageBased2(addOnPrice ?? 0, displayableEntitlements) ? t2("Usage-based") : /* @__PURE__ */ jsxs35(Fragment21, { children: [
16995
+ children: shouldShowUsageBased2(addOnPrice ?? 0, displayableEntitlements) ? t2("Usage-based") : /* @__PURE__ */ jsxs35(Fragment20, { children: [
16926
16996
  formatCurrency(addOnPrice ?? 0, addOnCurrency),
16927
16997
  /* @__PURE__ */ jsxs35("sub", { children: [
16928
16998
  "/",
@@ -17086,7 +17156,7 @@ import { useTranslation as useTranslation31 } from "react-i18next";
17086
17156
 
17087
17157
  // src/components/elements/pricing-table/Entitlement.tsx
17088
17158
  import { useTranslation as useTranslation30 } from "react-i18next";
17089
- import { Fragment as Fragment22, jsx as jsx47, jsxs as jsxs36 } from "react/jsx-runtime";
17159
+ import { Fragment as Fragment21, jsx as jsx47, jsxs as jsxs36 } from "react/jsx-runtime";
17090
17160
  var Entitlement = ({
17091
17161
  entitlement,
17092
17162
  sharedProps,
@@ -17123,17 +17193,17 @@ var Entitlement = ({
17123
17193
  ),
17124
17194
  entitlement.feature?.name && /* @__PURE__ */ jsxs36(Flex, { $flexDirection: "column", $gap: "0.5rem", children: [
17125
17195
  /* @__PURE__ */ jsxs36(Flex, { $flexDirection: "column", $justifyContent: "center", $flexGrow: 1, children: [
17126
- /* @__PURE__ */ jsx47(Text, { children: typeof entitlementPrice === "number" && (entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */ || entitlement.priceBehavior === "pay_as_you_go" /* PayAsYouGo */) ? /* @__PURE__ */ jsxs36(Fragment22, { children: [
17196
+ /* @__PURE__ */ jsx47(Text, { children: typeof entitlementPrice === "number" && (entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */ || entitlement.priceBehavior === "pay_as_you_go" /* PayAsYouGo */) ? /* @__PURE__ */ jsxs36(Fragment21, { children: [
17127
17197
  formatCurrency(entitlementPrice, entitlementCurrency),
17128
17198
  " ",
17129
17199
  t2("per"),
17130
17200
  " ",
17131
- entitlementPackageSize > 1 && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17201
+ entitlementPackageSize > 1 && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17132
17202
  formatNumber(entitlementPackageSize),
17133
17203
  " "
17134
17204
  ] }),
17135
17205
  getFeatureName(entitlement.feature, entitlementPackageSize),
17136
- entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */ && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17206
+ entitlement.priceBehavior === "pay_in_advance" /* PayInAdvance */ && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17137
17207
  " ",
17138
17208
  t2("per"),
17139
17209
  " ",
@@ -17145,7 +17215,7 @@ var Entitlement = ({
17145
17215
  entitlement,
17146
17216
  period: selectedPeriod
17147
17217
  }
17148
- ) : showCredits && entitlement.priceBehavior === "credit_burndown" /* Credit */ && entitlement.valueCredit && entitlement.consumptionRate ? /* @__PURE__ */ jsxs36(Fragment22, { children: [
17218
+ ) : showCredits && entitlement.priceBehavior === "credit_burndown" /* Credit */ && entitlement.valueCredit && entitlement.consumptionRate ? /* @__PURE__ */ jsxs36(Fragment21, { children: [
17149
17219
  formatNumber(entitlement.consumptionRate),
17150
17220
  " ",
17151
17221
  getFeatureName(
@@ -17156,7 +17226,7 @@ var Entitlement = ({
17156
17226
  t2("per"),
17157
17227
  " ",
17158
17228
  getFeatureName(entitlement.feature, 1)
17159
- ] }) : entitlement.priceBehavior === "credit_burndown" /* Credit */ && creditBasedEntitlementLimit ? /* @__PURE__ */ jsx47(Fragment22, { children: creditBasedEntitlementLimit?.period ? t2("Up to X units per period", {
17229
+ ] }) : entitlement.priceBehavior === "credit_burndown" /* Credit */ && creditBasedEntitlementLimit ? /* @__PURE__ */ jsx47(Fragment21, { children: creditBasedEntitlementLimit?.period ? t2("Up to X units per period", {
17160
17230
  amount: formatNumber(creditBasedEntitlementLimit.limit),
17161
17231
  units: getFeatureName(
17162
17232
  entitlement.feature,
@@ -17169,17 +17239,17 @@ var Entitlement = ({
17169
17239
  entitlement.feature,
17170
17240
  creditBasedEntitlementLimit.limit
17171
17241
  )
17172
- }) }) : entitlement.valueType === "numeric" /* Numeric */ || entitlement.valueType === "unlimited" /* Unlimited */ || entitlement.valueType === "trait" /* Trait */ ? /* @__PURE__ */ jsxs36(Fragment22, { children: [
17242
+ }) }) : entitlement.valueType === "numeric" /* Numeric */ || entitlement.valueType === "unlimited" /* Unlimited */ || entitlement.valueType === "trait" /* Trait */ ? /* @__PURE__ */ jsxs36(Fragment21, { children: [
17173
17243
  entitlement.valueType === "unlimited" /* Unlimited */ && !entitlement.priceBehavior ? t2("Unlimited", {
17174
17244
  item: getFeatureName(entitlement.feature)
17175
- }) : /* @__PURE__ */ jsxs36(Fragment22, { children: [
17176
- typeof limit === "number" && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17245
+ }) : /* @__PURE__ */ jsxs36(Fragment21, { children: [
17246
+ typeof limit === "number" && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17177
17247
  formatNumber(limit),
17178
17248
  " "
17179
17249
  ] }),
17180
17250
  getFeatureName(entitlement.feature, limit)
17181
17251
  ] }),
17182
- metricPeriodName && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17252
+ metricPeriodName && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17183
17253
  " ",
17184
17254
  t2("per"),
17185
17255
  " ",
@@ -17197,12 +17267,12 @@ var Entitlement = ({
17197
17267
  " ",
17198
17268
  formatCurrency(entitlementPrice, entitlementCurrency),
17199
17269
  "/",
17200
- entitlementPackageSize > 1 && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17270
+ entitlementPackageSize > 1 && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17201
17271
  formatNumber(entitlementPackageSize),
17202
17272
  " "
17203
17273
  ] }),
17204
17274
  getFeatureName(entitlement.feature, entitlementPackageSize),
17205
- entitlement.feature.featureType === "trait" /* Trait */ && /* @__PURE__ */ jsxs36(Fragment22, { children: [
17275
+ entitlement.feature.featureType === "trait" /* Trait */ && /* @__PURE__ */ jsxs36(Fragment21, { children: [
17206
17276
  "/",
17207
17277
  shortenPeriod(selectedPeriod)
17208
17278
  ] })
@@ -17249,7 +17319,7 @@ var Entitlement = ({
17249
17319
  };
17250
17320
 
17251
17321
  // src/components/elements/pricing-table/Plan.tsx
17252
- import { Fragment as Fragment23, jsx as jsx48, jsxs as jsxs37 } from "react/jsx-runtime";
17322
+ import { Fragment as Fragment22, jsx as jsx48, jsxs as jsxs37 } from "react/jsx-runtime";
17253
17323
  var Plan2 = ({
17254
17324
  plan,
17255
17325
  index,
@@ -17382,7 +17452,7 @@ var Plan2 = ({
17382
17452
  credit.quantity,
17383
17453
  " ",
17384
17454
  getFeatureName(credit, credit.quantity),
17385
- credit.period && /* @__PURE__ */ jsxs37(Fragment23, { children: [
17455
+ credit.period && /* @__PURE__ */ jsxs37(Fragment22, { children: [
17386
17456
  " ",
17387
17457
  t2("per"),
17388
17458
  " ",
@@ -17549,7 +17619,7 @@ var Plan2 = ({
17549
17619
  };
17550
17620
 
17551
17621
  // src/components/elements/pricing-table/PricingTable.tsx
17552
- import { Fragment as Fragment25, jsx as jsx49, jsxs as jsxs38 } from "react/jsx-runtime";
17622
+ import { Fragment as Fragment24, jsx as jsx49, jsxs as jsxs38 } from "react/jsx-runtime";
17553
17623
  var resolveDesignProps8 = (props) => {
17554
17624
  return {
17555
17625
  showPeriodToggle: props.showPeriodToggle ?? true,
@@ -17665,7 +17735,7 @@ var PricingTable = forwardRef15(({ className, ...rest }, ref) => {
17665
17735
  rest.callToActionUrl,
17666
17736
  rest.callToActionTarget
17667
17737
  );
17668
- const Wrapper = typeof data?.component === "undefined" ? Container : Fragment24;
17738
+ const Wrapper = typeof data?.component === "undefined" ? Container : Fragment23;
17669
17739
  return /* @__PURE__ */ jsx49(Wrapper, { children: /* @__PURE__ */ jsxs38(
17670
17740
  FussyChild,
17671
17741
  {
@@ -17741,7 +17811,7 @@ var PricingTable = forwardRef15(({ className, ...rest }, ref) => {
17741
17811
  }
17742
17812
  )
17743
17813
  ] }),
17744
- /* @__PURE__ */ jsx49(Box, { children: props.addOns.isVisible && addOns.length > 0 && /* @__PURE__ */ jsxs38(Fragment25, { children: [
17814
+ /* @__PURE__ */ jsx49(Box, { children: props.addOns.isVisible && addOns.length > 0 && /* @__PURE__ */ jsxs38(Fragment24, { children: [
17745
17815
  props.header.isVisible && /* @__PURE__ */ jsx49(
17746
17816
  Flex,
17747
17817
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-components",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "main": "dist/schematic-components.cjs.js",
5
5
  "module": "dist/schematic-components.esm.js",
6
6
  "types": "dist/schematic-components.d.ts",
@@ -27,13 +27,14 @@
27
27
  "format": "prettier --write \"src/**/*.{ts,tsx}\"",
28
28
  "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --fix",
29
29
  "openapi": "./generate_openapi.sh -c ./src/api/config_checkoutexternal.yml && ./generate_openapi.sh -c ./src/api/config_componentspublic.yml",
30
- "test": "yarn node --experimental-vm-modules $(yarn bin jest)",
30
+ "test": "./test.sh",
31
+ "test:watch": "vitest",
31
32
  "tsc": "npx tsc",
32
33
  "test:demo": "../scripts/test-components.sh"
33
34
  },
34
35
  "dependencies": {
35
36
  "@schematichq/schematic-icons": "^0.5.2",
36
- "@stripe/stripe-js": "^8.3.0",
37
+ "@stripe/stripe-js": "^8.4.0",
37
38
  "lodash": "^4.17.21",
38
39
  "pako": "^2.1.0",
39
40
  "styled-components": "^6.1.19",
@@ -43,41 +44,36 @@
43
44
  "@eslint/js": "^9.39.1",
44
45
  "@eslint/json": "^0.14.0",
45
46
  "@eslint/markdown": "^7.5.1",
46
- "@jest/globals": "^30.2.0",
47
- "@microsoft/api-extractor": "^7.54.0",
47
+ "@microsoft/api-extractor": "^7.55.0",
48
48
  "@openapitools/openapi-generator-cli": "^2.25.0",
49
49
  "@stripe/react-stripe-js": "^5.3.0",
50
- "@swc/core": "^1.15.1",
51
- "@swc/jest": "^0.2.39",
52
- "@swc/plugin-styled-components": "^11.0.0",
50
+ "@swc/core": "^1.15.2",
53
51
  "@testing-library/dom": "^10.4.1",
54
52
  "@testing-library/jest-dom": "^6.9.1",
55
53
  "@testing-library/react": "^16.3.0",
56
- "@types/jest": "^30.0.0",
57
54
  "@types/lodash": "^4.17.20",
58
55
  "@types/pako": "^2.0.4",
59
- "@types/react": "^19.2.2",
60
- "@types/react-dom": "^19.2.2",
56
+ "@types/react": "^19.2.5",
57
+ "@types/react-dom": "^19.2.3",
58
+ "@vitest/browser": "^4.0.10",
61
59
  "esbuild": "^0.27.0",
62
60
  "eslint": "^9.39.1",
63
61
  "eslint-import-resolver-typescript": "^4.4.4",
64
62
  "eslint-plugin-import": "^2.32.0",
65
- "eslint-plugin-jest": "^29.1.0",
66
63
  "eslint-plugin-react": "^7.37.5",
67
- "eslint-plugin-react-hooks": "^7.0.0",
64
+ "eslint-plugin-react-hooks": "^7.0.1",
68
65
  "globals": "^16.5.0",
69
- "i18next": "^25.6.1",
70
- "jest": "^30.2.0",
71
- "jest-environment-jsdom": "^30.2.0",
72
- "jest-fixed-jsdom": "^0.0.10",
73
- "jest-styled-components": "^7.2.0",
74
- "msw": "2.11.6",
66
+ "happy-dom": "^20.0.10",
67
+ "i18next": "^25.6.2",
68
+ "jsdom": "^27.2.0",
69
+ "msw": "^2.12.2",
75
70
  "prettier": "^3.6.2",
76
71
  "react": "^19.2.0",
77
72
  "react-dom": "^19.2.0",
78
- "react-i18next": "^16.2.4",
73
+ "react-i18next": "^16.3.3",
79
74
  "typescript": "^5.9.3",
80
- "typescript-eslint": "^8.46.4"
75
+ "typescript-eslint": "^8.47.0",
76
+ "vitest": "^4.0.10"
81
77
  },
82
78
  "peerDependencies": {
83
79
  "@stripe/react-stripe-js": ">=3",