@revenuecat/purchases-ui-js 3.9.1 → 3.9.3

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.
@@ -23,8 +23,11 @@
23
23
  // Reactive store for input satisfaction (defaults to true if no validation context)
24
24
  const inputSatisfied = validationContext?.isSatisfied ?? readable(true);
25
25
 
26
- // Button is disabled when it's a workflow (continue) action and inputs aren't satisfied
27
- const isDisabled = $derived(action.type === "workflow" && !$inputSatisfied);
26
+ // Button is disabled when it's a workflow (continue) or complete_workflow action and inputs aren't satisfied
27
+ const isDisabled = $derived(
28
+ (action.type === "workflow" || action.type === "complete_workflow") &&
29
+ !$inputSatisfied,
30
+ );
28
31
 
29
32
  const onclick = () => {
30
33
  if (isDisabled) return;
@@ -36,6 +39,8 @@
36
39
  switch (action.type) {
37
40
  case "workflow":
38
41
  return true;
42
+ case "complete_workflow":
43
+ return true;
39
44
  case "restore_purchases":
40
45
  return false;
41
46
  case "navigate_back":
@@ -50,7 +55,7 @@
50
55
  const style = $derived(
51
56
  isDisabled
52
57
  ? { opacity: "0.4", "pointer-events": "none", cursor: "not-allowed" }
53
- : {},
58
+ : undefined,
54
59
  );
55
60
  </script>
56
61
 
@@ -0,0 +1,164 @@
1
+ <script lang="ts">
2
+ import { getColorModeContext } from "../../stores/color-mode";
3
+ import { getHoverStateContext } from "../../stores/hover";
4
+ import { getLocalizationContext } from "../../stores/localization";
5
+ import { getPackageInfoContext } from "../../stores/packageInfo";
6
+ import { getPaywallContext } from "../../stores/paywall";
7
+ import { getSelectedStateContext } from "../../stores/selected";
8
+ import { getVariablesContext } from "../../stores/variables";
9
+ import { FontWeights, TextAlignments } from "../../types";
10
+ import type { InputTextProps } from "../../types/components/input-text";
11
+ import { mapBackground } from "../../utils/background-utils";
12
+ import {
13
+ css,
14
+ mapBorder,
15
+ mapBorderRadius,
16
+ mapShadow,
17
+ mapSize,
18
+ mapSpacing,
19
+ } from "../../utils/base-utils";
20
+ import {
21
+ getScopedFontFamily,
22
+ isFontRCFMManaged,
23
+ } from "../../utils/font-utils";
24
+ import {
25
+ evaluateVisibilityConditions,
26
+ getActiveStateProps,
27
+ getHoverStateProps,
28
+ } from "../../utils/style-utils";
29
+ import { replaceVariables } from "../../utils/variable-utils";
30
+ import type { HTMLInputAttributes } from "svelte/elements";
31
+ import { mapTextColor } from "../text/text-utils";
32
+
33
+ const props: InputTextProps = $props();
34
+
35
+ console.log("Hello");
36
+
37
+ const selectedState = getSelectedStateContext();
38
+ const hoverState = getHoverStateContext();
39
+ const {
40
+ placeholder_lid,
41
+ keyboard_type,
42
+ capitalize,
43
+ field_id,
44
+ required,
45
+ size,
46
+ padding,
47
+ margin,
48
+ border,
49
+ shape,
50
+ shadow,
51
+ font_name,
52
+ font_weight_int,
53
+ font_size,
54
+ horizontal_alignment,
55
+ color,
56
+ placeholder_font_name,
57
+ placeholder_font_weight_int,
58
+ placeholder_font_size,
59
+ placeholder_horizontal_alignment,
60
+ placeholder_color,
61
+ background_color,
62
+ } = $derived.by(() => {
63
+ return {
64
+ ...props,
65
+ ...getHoverStateProps($hoverState, props.overrides),
66
+ ...getActiveStateProps($selectedState, props.overrides),
67
+ };
68
+ });
69
+
70
+ const getColorMode = getColorModeContext();
71
+ const colorMode = $derived(getColorMode());
72
+ const { uiConfig, onInputChanged } = getPaywallContext();
73
+
74
+ const inputStyle = $derived.by(() => {
75
+ const font = uiConfig.app.fonts[font_name ?? ""];
76
+ const fontFamily = font?.web?.family;
77
+ const placeholderFont = uiConfig.app.fonts[placeholder_font_name ?? ""];
78
+ const placeholderFontFamily = placeholderFont?.web?.family;
79
+ const placeholderColor = mapTextColor(colorMode, placeholder_color);
80
+
81
+ return css({
82
+ display: props.visible === false ? "none" : "flex",
83
+ position: "relative",
84
+ width: mapSize(size.width),
85
+ height: mapSize(size.height),
86
+ margin: mapSpacing(margin),
87
+ padding: mapSpacing(padding),
88
+ ...mapBackground(colorMode, background_color, null),
89
+ border: mapBorder(colorMode, border),
90
+ "border-radius": mapBorderRadius(shape),
91
+ "box-shadow": mapShadow(colorMode, shadow),
92
+
93
+ ...mapTextColor(colorMode, color),
94
+ "text-align":
95
+ TextAlignments[horizontal_alignment] || TextAlignments.leading,
96
+ "font-weight": font_weight_int ?? FontWeights.regular,
97
+ "font-size": `${font_size}px`,
98
+ "font-family": isFontRCFMManaged(font_name ?? "")
99
+ ? getScopedFontFamily(fontFamily ?? "")
100
+ : "sans-serif",
101
+
102
+ "--placeholder-color": placeholderColor.color,
103
+ "--placeholder-background": placeholderColor.background,
104
+ "--placeholder-background-clip": placeholderColor["background-clip"],
105
+ "--placeholder-webkit-background-clip":
106
+ placeholderColor["-webkit-background-clip"],
107
+ "--placeholder-text-align":
108
+ TextAlignments[placeholder_horizontal_alignment] ||
109
+ TextAlignments.leading,
110
+ "--placeholder-font-weight":
111
+ placeholder_font_weight_int ?? FontWeights.regular,
112
+ "--placeholder-font-size": `${placeholder_font_size}px`,
113
+ "--placeholder-font-family": isFontRCFMManaged(
114
+ placeholder_font_name ?? "",
115
+ )
116
+ ? getScopedFontFamily(placeholderFontFamily ?? "")
117
+ : "sans-serif",
118
+ });
119
+ });
120
+
121
+ const variables = getVariablesContext();
122
+ const { getLocalizedString } = getLocalizationContext();
123
+ const placeholder = $derived(
124
+ replaceVariables(getLocalizedString(placeholder_lid), $variables),
125
+ );
126
+
127
+ const type = $derived.by((): HTMLInputAttributes["type"] => {
128
+ switch (props.keyboard_type) {
129
+ case "decimal":
130
+ case "numeric":
131
+ return "number";
132
+ case "email":
133
+ return "email";
134
+ case "tel":
135
+ return "tel";
136
+ case "text":
137
+ return "text";
138
+ }
139
+ });
140
+ </script>
141
+
142
+ <input
143
+ {type}
144
+ {placeholder}
145
+ {required}
146
+ inputmode={keyboard_type}
147
+ autocapitalize={capitalize}
148
+ style={inputStyle}
149
+ oninput={(event) => onInputChanged?.(field_id, event.currentTarget.value)}
150
+ />
151
+
152
+ <style>
153
+ input::placeholder {
154
+ color: var(--placeholder-color);
155
+ background: var(--placeholder-background);
156
+ background-clip: var(--placeholder-background-clip);
157
+ -webkit-background-clip: var(--placeholder-webkit-background-clip);
158
+
159
+ text-align: var(--placeholder-text-align);
160
+ font-weight: var(--placeholder-font-weight);
161
+ font-size: var(--placeholder-font-size);
162
+ font-family: var(--placeholder-font-family);
163
+ }
164
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { InputTextProps } from "../../types/components/input-text";
2
+ declare const InputText: import("svelte").Component<InputTextProps, {}, "">;
3
+ type InputText = ReturnType<typeof InputText>;
4
+ export default InputText;
@@ -10,6 +10,7 @@
10
10
  } from "../..";
11
11
  import ButtonNode from "../button/ButtonNode.svelte";
12
12
  import Countdown from "../countdown/Countdown.svelte";
13
+ import InputText from "../input-text/InputText.svelte";
13
14
  import InputMultipleChoice from "../options/InputMultipleChoice.svelte";
14
15
  import InputOption from "../options/InputOption.svelte";
15
16
  import InputSingleChoice from "../options/InputSingleChoice.svelte";
@@ -42,6 +43,7 @@
42
43
  input_multiple_choice: InputMultipleChoice,
43
44
  input_option: InputOption,
44
45
  input_single_choice: InputSingleChoice,
46
+ input_text: InputText,
45
47
  package: Package,
46
48
  purchase_button: PurchaseButton,
47
49
  redemption_button: RedemptionButton,
@@ -14,7 +14,10 @@
14
14
  type VariablesStore,
15
15
  } from "../../stores/variables";
16
16
  import type { ColorMode } from "../../types";
17
- import type { Action } from "../../types/components/button";
17
+ import type {
18
+ Action,
19
+ CompleteWorkflowNavigateArgs,
20
+ } from "../../types/components/button";
18
21
  import type { SheetProps } from "../../types/components/sheet";
19
22
  import type { PaywallData } from "../../types/paywall";
20
23
  import type { UIConfig } from "../../types/ui-config";
@@ -61,10 +64,18 @@
61
64
  onVisitCustomerCenterClicked?: () => void;
62
65
  onRestorePurchasesClicked?: () => void;
63
66
  onNavigateToUrlClicked?: (url: string) => void;
67
+ /**
68
+ * Called when a complete_workflow button is pressed. The URL is localized;
69
+ * the host merges `url_query_params` (e.g. `app_user_id`) if needed.
70
+ */
71
+ onCompleteWorkflowNavigate?: (
72
+ args: CompleteWorkflowNavigateArgs,
73
+ ) => void | Promise<void>;
64
74
  onActionTriggered?: (actionId: string) => void;
65
75
  onError?: (error: unknown) => void;
66
76
  hideBackButtons?: boolean;
67
77
  walletButtonRender?: WalletButtonRender;
78
+ onInputChanged?: (fieldId: string, value: string) => void;
68
79
  maxContentWidth?: string;
69
80
  initialInputSelections?: InitialInputSelections;
70
81
  /**
@@ -95,10 +106,12 @@
95
106
  onVisitCustomerCenterClicked,
96
107
  onRestorePurchasesClicked,
97
108
  onNavigateToUrlClicked,
109
+ onCompleteWorkflowNavigate,
98
110
  onActionTriggered,
99
111
  onError,
100
112
  uiConfig,
101
113
  walletButtonRender,
114
+ onInputChanged,
102
115
  hideBackButtons = false,
103
116
  maxContentWidth,
104
117
  initialInputSelections = {},
@@ -138,6 +151,18 @@
138
151
  onActionTriggered?.(actionId);
139
152
  }
140
153
  return;
154
+ case "complete_workflow": {
155
+ const baseUrl = getLocalizedString(action.url.url_lid);
156
+ if (!baseUrl) {
157
+ return;
158
+ }
159
+ void onCompleteWorkflowNavigate?.({
160
+ url: baseUrl,
161
+ method: action.url.method,
162
+ url_query_params: action.url_query_params,
163
+ });
164
+ return;
165
+ }
141
166
  case "navigate_back":
142
167
  onBackClicked?.();
143
168
  return;
@@ -183,6 +208,7 @@
183
208
  infoPerPackage: readable(infoPerPackage),
184
209
  onPurchase,
185
210
  onButtonAction,
211
+ onInputChanged,
186
212
  walletButtonRender,
187
213
  uiConfig,
188
214
  hideBackButtons,
@@ -1,5 +1,6 @@
1
1
  import { type InitialInputSelections } from "../../stores/inputValidation";
2
2
  import type { ColorMode } from "../../types";
3
+ import type { CompleteWorkflowNavigateArgs } from "../../types/components/button";
3
4
  import type { PaywallData } from "../../types/paywall";
4
5
  import type { UIConfig } from "../../types/ui-config";
5
6
  import { type CustomVariables, type PackageInfo, type VariableDictionary } from "../../types/variables";
@@ -27,10 +28,16 @@ interface Props {
27
28
  onVisitCustomerCenterClicked?: () => void;
28
29
  onRestorePurchasesClicked?: () => void;
29
30
  onNavigateToUrlClicked?: (url: string) => void;
31
+ /**
32
+ * Called when a complete_workflow button is pressed. The URL is localized;
33
+ * the host merges `url_query_params` (e.g. `app_user_id`) if needed.
34
+ */
35
+ onCompleteWorkflowNavigate?: (args: CompleteWorkflowNavigateArgs) => void | Promise<void>;
30
36
  onActionTriggered?: (actionId: string) => void;
31
37
  onError?: (error: unknown) => void;
32
38
  hideBackButtons?: boolean;
33
39
  walletButtonRender?: WalletButtonRender;
40
+ onInputChanged?: (fieldId: string, value: string) => void;
34
41
  maxContentWidth?: string;
35
42
  initialInputSelections?: InitialInputSelections;
36
43
  /**
@@ -14,6 +14,7 @@
14
14
  import {
15
15
  getActiveStateProps,
16
16
  getIntroOfferStateProps,
17
+ getPromoOfferStateProps,
17
18
  evaluateVisibilityConditions,
18
19
  } from "../../utils/style-utils";
19
20
  import { replaceVariables } from "../../utils/variable-utils";
@@ -32,21 +33,13 @@
32
33
  !!$packageInfo?.hasIntroOffer || !!$packageInfo?.hasTrial,
33
34
  props.overrides,
34
35
  ),
36
+ ...getPromoOfferStateProps(
37
+ !!$packageInfo?.hasPromoOffer,
38
+ props.overrides,
39
+ ),
35
40
  };
36
41
  });
37
42
 
38
- const isVisible = $derived(
39
- evaluateVisibilityConditions(
40
- {
41
- selectedPackageId: $selectedPackageId,
42
- packageInfo: $packageInfo,
43
- variables: $variables,
44
- },
45
- props.overrides,
46
- props.visible,
47
- ),
48
- );
49
-
50
43
  const getColorMode = getColorModeContext();
51
44
  const colorMode = $derived(getColorMode());
52
45
 
@@ -69,6 +62,18 @@
69
62
  replaceVariables(getLocalizedString(actualProps.text_lid), $variables),
70
63
  );
71
64
 
65
+ const isVisible = $derived(
66
+ evaluateVisibilityConditions(
67
+ {
68
+ selectedPackageId: $selectedPackageId,
69
+ packageInfo: $packageInfo,
70
+ variables: $variables ?? {},
71
+ },
72
+ props.overrides,
73
+ props.visible,
74
+ ),
75
+ );
76
+
72
77
  const markdownParsed = $derived(getHtmlFromMarkdown(label));
73
78
  </script>
74
79
 
@@ -1,11 +1,11 @@
1
1
  <script lang="ts">
2
2
  import Paywall from "../paywall/Paywall.svelte";
3
+ import type { CompleteWorkflowNavigateArgs } from "../../types/components/button";
3
4
  import type { InitialInputSelections } from "../../stores/inputValidation";
4
5
  import type { WorkflowScreen } from "../../types/workflow";
5
6
  import type { VariableDictionary } from "../../types/variables";
6
7
  import type { WalletButtonRender } from "../../types/wallet";
7
8
  import type { UIConfig } from "../../types/ui-config";
8
-
9
9
  interface Props {
10
10
  paywallComponents: WorkflowScreen | null | undefined;
11
11
  selectedLocale?: string;
@@ -21,9 +21,12 @@
21
21
  maxContentWidth?: string;
22
22
  variablesPerPackage?: Record<string, VariableDictionary>;
23
23
  initialInputSelections?: InitialInputSelections;
24
+ onInputChanged?: (fieldId: string, value: string) => void;
25
+ onCompleteWorkflowNavigate?: (
26
+ args: CompleteWorkflowNavigateArgs,
27
+ ) => void | Promise<void>;
24
28
  walletButtonRender?: WalletButtonRender;
25
29
  }
26
-
27
30
  const {
28
31
  paywallComponents,
29
32
  selectedLocale = "en_US",
@@ -36,6 +39,8 @@
36
39
  maxContentWidth,
37
40
  variablesPerPackage,
38
41
  initialInputSelections = {},
42
+ onInputChanged,
43
+ onCompleteWorkflowNavigate,
39
44
  walletButtonRender,
40
45
  }: Props = $props();
41
46
  </script>
@@ -53,6 +58,7 @@
53
58
  onNavigateToUrlClicked={(url: string) => {
54
59
  window.open(url, "_blank");
55
60
  }}
61
+ {onCompleteWorkflowNavigate}
56
62
  onVisitCustomerCenterClicked={() => {}}
57
63
  {onBackClicked}
58
64
  onRestorePurchasesClicked={() => {}}
@@ -60,6 +66,7 @@
60
66
  onActionTriggered?.(actionId);
61
67
  }}
62
68
  {onPurchaseClicked}
69
+ {onInputChanged}
63
70
  {walletButtonRender}
64
71
  onError={(error) => {
65
72
  console.error("Paywall error:", error);
@@ -1,3 +1,4 @@
1
+ import type { CompleteWorkflowNavigateArgs } from "../../types/components/button";
1
2
  import type { InitialInputSelections } from "../../stores/inputValidation";
2
3
  import type { WorkflowScreen } from "../../types/workflow";
3
4
  import type { VariableDictionary } from "../../types/variables";
@@ -15,6 +16,8 @@ interface Props {
15
16
  maxContentWidth?: string;
16
17
  variablesPerPackage?: Record<string, VariableDictionary>;
17
18
  initialInputSelections?: InitialInputSelections;
19
+ onInputChanged?: (fieldId: string, value: string) => void;
20
+ onCompleteWorkflowNavigate?: (args: CompleteWorkflowNavigateArgs) => void | Promise<void>;
18
21
  walletButtonRender?: WalletButtonRender;
19
22
  }
20
23
  declare const Screen: import("svelte").Component<Props, {}, "">;
package/dist/index.d.ts CHANGED
@@ -19,5 +19,6 @@ export { type InitialInputSelections } from "./stores/inputValidation";
19
19
  export { type UIConfig } from "./types/ui-config";
20
20
  export { type WalletButtonRender } from "./types/wallet";
21
21
  export { type CustomVariables, CustomVariableValue, type VariableDictionary, type PackageInfo, } from "./types/variables";
22
+ export type { CompleteWorkflowNavigateArgs, CompleteWorkflowUrlQueryParams, } from "./types/components/button";
22
23
  export * from "./ui/globals";
23
24
  export { default as Button } from "./ui/molecules/button.svelte";
@@ -16,6 +16,7 @@ type PaywallContext = Readonly<{
16
16
  baseVariables: Readable<VariableDictionary | undefined>;
17
17
  infoPerPackage: Readable<Record<string, PackageInfo> | undefined>;
18
18
  onPurchase: (actionId?: string) => void;
19
+ onInputChanged?: (fieldId: string, value: string) => void;
19
20
  walletButtonRender?: WalletButtonRender;
20
21
  onWalletButtonReady?: (walletButtonAvailable?: boolean) => void;
21
22
  onButtonAction: (action: Action, actionId?: string) => void;
@@ -4,6 +4,7 @@ import type { CountdownProps } from "./components/countdown";
4
4
  import type { FooterProps } from "./components/footer";
5
5
  import type { IconProps } from "./components/icon";
6
6
  import type { ImageProps } from "./components/image";
7
+ import type { InputTextProps } from "./components/input-text";
7
8
  import type { InputMultipleChoiceProps, InputOptionProps, InputSingleChoiceProps } from "./components/options";
8
9
  import type { PackageProps } from "./components/package";
9
10
  import type { PurchaseButtonProps } from "./components/purchase-button";
@@ -16,4 +17,4 @@ import type { VideoProps } from "./components/video";
16
17
  import type { WalletButtonProps } from "./components/wallet-button";
17
18
  import type { SkeletonLoaderProps } from "./components/skeleton-loader-props";
18
19
  import type { ExpressPurchaseButtonProps } from "./components/express-purchase-button-props";
19
- export type Component = ButtonProps | CarouselProps | CountdownProps | ExpressPurchaseButtonProps | FooterProps | IconProps | ImageProps | InputMultipleChoiceProps | InputOptionProps | InputSingleChoiceProps | PackageProps | PurchaseButtonProps | RedemptionButtonProps | SkeletonLoaderProps | StackProps | TabControlButtonProps | TabControlToggleProps | TabControlProps | TabsProps | TextNodeProps | TimelineProps | WalletButtonProps | VideoProps;
20
+ export type Component = ButtonProps | CarouselProps | CountdownProps | ExpressPurchaseButtonProps | FooterProps | IconProps | ImageProps | InputMultipleChoiceProps | InputOptionProps | InputSingleChoiceProps | InputTextProps | PackageProps | PurchaseButtonProps | RedemptionButtonProps | SkeletonLoaderProps | StackProps | TabControlButtonProps | TabControlToggleProps | TabControlProps | TabsProps | TextNodeProps | TimelineProps | WalletButtonProps | VideoProps;
@@ -34,7 +34,26 @@ interface NavigateToUrlAction {
34
34
  method: "deep_link" | "external_browser" | "in_app_browser";
35
35
  };
36
36
  }
37
- export type Action = WorkflowAction | RestorePurchasesAction | NavigateBackAction | NavigateToAction | NavigateToSheetAction | NavigateToWebPurchase | NavigateToUrlAction;
37
+ /** Optional query params for complete_workflow URLs (host merges values). */
38
+ export type CompleteWorkflowUrlQueryParams = {
39
+ app_user_id?: boolean;
40
+ };
41
+ /** Args passed to `onCompleteWorkflowNavigate` (host builds final URL if needed). */
42
+ export type CompleteWorkflowNavigateArgs = {
43
+ url: string;
44
+ method: "deep_link" | "external_browser" | "in_app_browser";
45
+ url_query_params?: CompleteWorkflowUrlQueryParams;
46
+ };
47
+ /** End the workflow and open a URL (optional query params, e.g. app user ID). */
48
+ interface CompleteWorkflowAction {
49
+ type: "complete_workflow";
50
+ url: {
51
+ url_lid: string;
52
+ method: "deep_link" | "external_browser" | "in_app_browser";
53
+ };
54
+ url_query_params?: CompleteWorkflowUrlQueryParams;
55
+ }
56
+ export type Action = WorkflowAction | RestorePurchasesAction | NavigateBackAction | NavigateToAction | NavigateToSheetAction | NavigateToWebPurchase | NavigateToUrlAction | CompleteWorkflowAction;
38
57
  export interface ButtonProps extends BaseComponent {
39
58
  type: "button";
40
59
  action: Action;
@@ -0,0 +1,33 @@
1
+ import type { BorderType, ShapeType, ShadowType, SizeType, Spacing, TextAlignments } from "..";
2
+ import type { BaseComponent } from "../base";
3
+ import type { ColorGradientScheme } from "../colors";
4
+ import type { Overrides } from "../overrides";
5
+ export type InputTextCapitalizeType = "none" | "sentences" | "words" | "characters";
6
+ export type InputTextKeyboardType = "decimal" | "email" | "numeric" | "tel" | "text" | "url";
7
+ export interface InputTextProps extends BaseComponent {
8
+ type: "input_text";
9
+ visible?: boolean | null;
10
+ placeholder_lid: string;
11
+ keyboard_type: InputTextKeyboardType;
12
+ capitalize: InputTextCapitalizeType;
13
+ field_id: string;
14
+ required: boolean;
15
+ size: SizeType;
16
+ padding: Spacing;
17
+ margin: Spacing;
18
+ border?: BorderType | null;
19
+ shape?: ShapeType | null;
20
+ shadow?: ShadowType | null;
21
+ font_name?: string | null;
22
+ font_weight_int?: number | null;
23
+ font_size: number;
24
+ horizontal_alignment: keyof typeof TextAlignments;
25
+ color: ColorGradientScheme;
26
+ placeholder_font_name?: string | null;
27
+ placeholder_font_weight_int?: number | null;
28
+ placeholder_font_size: number;
29
+ placeholder_horizontal_alignment: keyof typeof TextAlignments;
30
+ placeholder_color: ColorGradientScheme;
31
+ background_color?: ColorGradientScheme | null;
32
+ overrides?: Overrides<InputTextProps>;
33
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -11,6 +11,7 @@ export declare function findSelectedPackageId({ stack, sticky_footer, }: RootPay
11
11
  export declare const getActiveStateProps: <T extends Component>(selectedState: boolean, overrides?: Overrides<T>) => Partial<T>;
12
12
  export declare const getHoverStateProps: <T extends Component>(hoverState: boolean, overrides?: Overrides<T>) => Partial<T>;
13
13
  export declare const getIntroOfferStateProps: <T extends Component>(hasIntroOffer: boolean, overrides?: Overrides<T>) => Partial<T>;
14
+ export declare const getPromoOfferStateProps: <T extends Component>(hasPromoOffer: boolean, overrides?: Overrides<T>) => Partial<T>;
14
15
  export type VisibilityContext = {
15
16
  selectedPackageId: string | undefined;
16
17
  packageInfo: PackageInfo | undefined;
@@ -58,6 +58,13 @@ export const getIntroOfferStateProps = (hasIntroOffer, overrides) => {
58
58
  const override = overrides?.find((override) => override.conditions.find((condition) => condition.type === "intro_offer"));
59
59
  return override?.properties ?? {};
60
60
  };
61
+ export const getPromoOfferStateProps = (hasPromoOffer, overrides) => {
62
+ if (!hasPromoOffer) {
63
+ return {};
64
+ }
65
+ const override = overrides?.find((override) => override.conditions.find((condition) => condition.type === "promo_offer"));
66
+ return override?.properties ?? {};
67
+ };
61
68
  const CONDITION_ORDER = [
62
69
  RuleKey.IntroOfferCondition,
63
70
  RuleKey.PromoOfferCondition,