@revenuecat/purchases-ui-js 3.4.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,13 +57,13 @@
57
57
  overflow: "hidden",
58
58
  "background-color": mapColor(colorMode, color),
59
59
  "mask-image": `url(${webpUrl})`,
60
- "webkit-mask-image": `url(${webpUrl})`,
60
+ "-webkit-mask-image": `url(${webpUrl})`,
61
61
  "mask-size": "contain",
62
- "webkit-mask-size": "contain",
62
+ "-webkit-mask-size": "contain",
63
63
  "mask-position": "center",
64
- "webkit-mask-position": "center",
64
+ "-webkit-mask-position": "center",
65
65
  "mask-repeat": "no-repeat",
66
- "webkit-mask-repeat": "no-repeat",
66
+ "-webkit-mask-repeat": "no-repeat",
67
67
  }),
68
68
  );
69
69
  </script>
@@ -1,9 +1,19 @@
1
1
  <script lang="ts">
2
2
  import Node from "../paywall/Node.svelte";
3
+ import {
4
+ createInputChoiceContext,
5
+ setInputChoiceContext,
6
+ } from "../../stores/inputChoice";
3
7
  import type { InputMultipleChoiceProps } from "../../types/components/options";
4
8
 
5
9
  const props: InputMultipleChoiceProps = $props();
6
- const { stack } = props;
10
+ const { stack, field_id } = props;
11
+
12
+ const initialInputChoiceContext = createInputChoiceContext(
13
+ field_id,
14
+ "multiple",
15
+ );
16
+ setInputChoiceContext(initialInputChoiceContext);
7
17
  </script>
8
18
 
9
19
  <Node nodeData={stack} />
@@ -1,18 +1,45 @@
1
1
  <script lang="ts">
2
2
  import Stack from "../stack/Stack.svelte";
3
+ import { setHoverStateContext } from "../../stores/hover";
4
+ import { getInputChoiceContext } from "../../stores/inputChoice";
3
5
  import { getPaywallContext } from "../../stores/paywall";
6
+ import { setSelectedStateContext } from "../../stores/selected";
4
7
  import type { InputOptionProps } from "../../types/components/options";
8
+ import { derived, readable, writable } from "svelte/store";
5
9
 
6
10
  const props: InputOptionProps = $props();
7
- const { stack } = props;
11
+ const { stack, option_id } = props;
8
12
 
9
13
  const { onButtonAction } = getPaywallContext();
14
+ const inputChoiceContext = getInputChoiceContext();
15
+
16
+ // Derive selected state from context (similar to Package)
17
+ const isSelected = inputChoiceContext
18
+ ? derived(inputChoiceContext.selectedOptionIds, (ids) => ids.has(option_id))
19
+ : readable(false);
20
+ setSelectedStateContext(isSelected);
21
+
22
+ const isHovered = writable(false);
23
+ setHoverStateContext(isHovered);
24
+
25
+ const onmouseenter = () => isHovered.set(true);
26
+ const onmouseleave = () => isHovered.set(false);
10
27
 
11
28
  const onclick = () => {
12
29
  const actionId = props.triggers?.on_press;
13
30
  // Create a workflow action to pass up through the callback
14
31
  onButtonAction({ type: "workflow" }, actionId);
32
+ inputChoiceContext?.selectOption(option_id);
15
33
  };
16
34
  </script>
17
35
 
18
- <Stack {...stack} {onclick} />
36
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
37
+ <div class="option-wrapper" {onmouseenter} {onmouseleave}>
38
+ <Stack {...stack} {onclick} />
39
+ </div>
40
+
41
+ <style>
42
+ .option-wrapper {
43
+ display: contents;
44
+ }
45
+ </style>
@@ -1,9 +1,19 @@
1
1
  <script lang="ts">
2
2
  import Node from "../paywall/Node.svelte";
3
+ import {
4
+ createInputChoiceContext,
5
+ setInputChoiceContext,
6
+ } from "../../stores/inputChoice";
3
7
  import type { InputSingleChoiceProps } from "../../types/components/options";
4
8
 
5
9
  const props: InputSingleChoiceProps = $props();
6
- const { stack } = props;
10
+ const { stack, field_id } = props;
11
+
12
+ const initialInputChoiceContext = createInputChoiceContext(
13
+ field_id,
14
+ "single",
15
+ );
16
+ setInputChoiceContext(initialInputChoiceContext);
7
17
  </script>
8
18
 
9
19
  <Node nodeData={stack} />
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import Node from "../paywall/Node.svelte";
3
3
  import { getColorModeContext } from "../../stores/color-mode";
4
+ import { getHoverStateContext } from "../../stores/hover";
4
5
  import { getSelectedStateContext } from "../../stores/selected";
5
6
  import type { StackProps } from "../../types/components/stack";
6
7
  import { mapBackground } from "../../utils/background-utils";
@@ -14,7 +15,10 @@
14
15
  px,
15
16
  type CSS,
16
17
  } from "../../utils/base-utils";
17
- import { getActiveStateProps } from "../../utils/style-utils";
18
+ import {
19
+ getActiveStateProps,
20
+ getHoverStateProps,
21
+ } from "../../utils/style-utils";
18
22
  import type { Snippet } from "svelte";
19
23
  import { mapBadge, mapDimension, mapLayerAlignment } from "./stack-utils";
20
24
 
@@ -28,6 +32,7 @@
28
32
  const { onclick, children, style } = props;
29
33
 
30
34
  const selectedState = getSelectedStateContext();
35
+ const hoverState = getHoverStateContext();
31
36
  const {
32
37
  components,
33
38
  size,
@@ -44,6 +49,7 @@
44
49
  } = $derived.by(() => {
45
50
  return {
46
51
  ...props,
52
+ ...getHoverStateProps($hoverState, props.overrides),
47
53
  ...getActiveStateProps($selectedState, props.overrides),
48
54
  };
49
55
  });
@@ -4,7 +4,6 @@
4
4
  } from "../paywall/Paywall.svelte";
5
5
  import type { WorkflowScreen } from "../../types/workflow";
6
6
  import type { VariableDictionary } from "../../types/variables";
7
- import { VARIABLES } from "../paywall/fixtures/variables";
8
7
  interface Props {
9
8
  paywallComponents: WorkflowScreen | null | undefined;
10
9
  selectedLocale?: string;
@@ -15,8 +14,10 @@
15
14
  packageId: string,
16
15
  actionId: string,
17
16
  ) => void | Promise<void>;
17
+ onBackClicked?: () => void;
18
18
  containerId?: string;
19
19
  maxContentWidth?: string;
20
+ variablesPerPackage?: Record<string, VariableDictionary>;
20
21
  }
21
22
  const {
22
23
  paywallComponents,
@@ -25,8 +26,10 @@
25
26
  globalVariables = {},
26
27
  onActionTriggered,
27
28
  onPurchaseClicked,
29
+ onBackClicked,
28
30
  containerId = "screen-container",
29
31
  maxContentWidth,
32
+ variablesPerPackage,
30
33
  }: Props = $props();
31
34
  </script>
32
35
 
@@ -36,12 +39,12 @@
36
39
  paywallData={paywallComponents}
37
40
  {selectedLocale}
38
41
  {uiConfig}
39
- variablesPerPackage={VARIABLES}
42
+ {variablesPerPackage}
40
43
  {globalVariables}
41
44
  {maxContentWidth}
42
45
  onNavigateToUrlClicked={() => {}}
43
46
  onVisitCustomerCenterClicked={() => {}}
44
- onBackClicked={() => {}}
47
+ {onBackClicked}
45
48
  onRestorePurchasesClicked={() => {}}
46
49
  onActionTriggered={(actionId: string) => {
47
50
  onActionTriggered?.(actionId);
@@ -8,8 +8,10 @@ interface Props {
8
8
  globalVariables?: VariableDictionary;
9
9
  onActionTriggered?: (actionId: string) => void;
10
10
  onPurchaseClicked?: (packageId: string, actionId: string) => void | Promise<void>;
11
+ onBackClicked?: () => void;
11
12
  containerId?: string;
12
13
  maxContentWidth?: string;
14
+ variablesPerPackage?: Record<string, VariableDictionary>;
13
15
  }
14
16
  declare const Screen: import("svelte").Component<Props, {}, "">;
15
17
  type Screen = ReturnType<typeof Screen>;
@@ -0,0 +1,5 @@
1
+ import { type Readable } from "svelte/store";
2
+ type HoverContext = Readable<boolean>;
3
+ export declare function setHoverStateContext(context: HoverContext): void;
4
+ export declare function getHoverStateContext(): HoverContext;
5
+ export {};
@@ -0,0 +1,10 @@
1
+ import { getContext, setContext } from "svelte";
2
+ import { readable } from "svelte/store";
3
+ const key = Symbol("hover");
4
+ export function setHoverStateContext(context) {
5
+ setContext(key, context);
6
+ }
7
+ export function getHoverStateContext() {
8
+ const context = getContext(key);
9
+ return context ?? readable(false);
10
+ }
@@ -0,0 +1,12 @@
1
+ import { type Readable } from "svelte/store";
2
+ type SelectionMode = "single" | "multiple";
3
+ interface InputChoiceContext {
4
+ fieldId: string;
5
+ mode: SelectionMode;
6
+ selectedOptionIds: Readable<Set<string>>;
7
+ selectOption: (optionId: string) => void;
8
+ }
9
+ export declare function createInputChoiceContext(fieldId: string, mode: SelectionMode): InputChoiceContext;
10
+ export declare function setInputChoiceContext(context: InputChoiceContext): void;
11
+ export declare function getInputChoiceContext(): InputChoiceContext | undefined;
12
+ export {};
@@ -0,0 +1,37 @@
1
+ import { getContext, setContext } from "svelte";
2
+ import { writable } from "svelte/store";
3
+ const key = Symbol("inputChoice");
4
+ export function createInputChoiceContext(fieldId, mode) {
5
+ const selectedOptionIds = writable(new Set());
6
+ const selectOption = (optionId) => {
7
+ selectedOptionIds.update((current) => {
8
+ if (mode === "single") {
9
+ // Single select: replace with new selection
10
+ return new Set([optionId]);
11
+ }
12
+ else {
13
+ // Multiple select: toggle the option
14
+ const next = new Set(current);
15
+ if (next.has(optionId)) {
16
+ next.delete(optionId);
17
+ }
18
+ else {
19
+ next.add(optionId);
20
+ }
21
+ return next;
22
+ }
23
+ });
24
+ };
25
+ return {
26
+ fieldId,
27
+ mode,
28
+ selectedOptionIds,
29
+ selectOption,
30
+ };
31
+ }
32
+ export function setInputChoiceContext(context) {
33
+ setContext(key, context);
34
+ }
35
+ export function getInputChoiceContext() {
36
+ return getContext(key);
37
+ }
@@ -11,6 +11,9 @@ type MultipleIntroOffersCondition = {
11
11
  type SelectedCondition = {
12
12
  type: "selected";
13
13
  };
14
+ type HoverCondition = {
15
+ type: "hover";
16
+ };
14
17
  type ScreenSizeCondition = {
15
18
  type: "screen_size";
16
19
  operator: ArrayOperator;
@@ -34,7 +37,7 @@ type SelectedPackageCondition = {
34
37
  type PromoOfferCondition = {
35
38
  type: "promo_offer";
36
39
  };
37
- type OverrideCondition = IntroOfferCondition | MultipleIntroOffersCondition | SelectedCondition | ScreenSizeCondition | OrientationCondition | IntroductoryOfferCondition | SelectedPackageCondition | PromoOfferCondition;
40
+ type OverrideCondition = IntroOfferCondition | MultipleIntroOffersCondition | SelectedCondition | HoverCondition | ScreenSizeCondition | OrientationCondition | IntroductoryOfferCondition | SelectedPackageCondition | PromoOfferCondition;
38
41
  /**
39
42
  * The reserved properties of an override that should not be included in the override properties
40
43
  */
@@ -8,4 +8,5 @@ import type { RootPaywall } from "../types/paywall.js";
8
8
  */
9
9
  export declare function findSelectedPackageId({ stack, sticky_footer, }: RootPaywall): string | undefined;
10
10
  export declare const getActiveStateProps: <T extends Component>(selectedState: boolean, overrides?: Overrides<T>) => Partial<T>;
11
+ export declare const getHoverStateProps: <T extends Component>(hoverState: boolean, overrides?: Overrides<T>) => Partial<T>;
11
12
  export declare const getIntroOfferStateProps: <T extends Component>(hasIntroOffer: boolean, overrides?: Overrides<T>) => Partial<T>;
@@ -43,6 +43,13 @@ export const getActiveStateProps = (selectedState, overrides) => {
43
43
  const override = overrides?.find((override) => override.conditions.find((condition) => condition.type === "selected"));
44
44
  return override?.properties ?? {};
45
45
  };
46
+ export const getHoverStateProps = (hoverState, overrides) => {
47
+ if (!hoverState) {
48
+ return {};
49
+ }
50
+ const override = overrides?.find((override) => override.conditions.find((condition) => condition.type === "hover"));
51
+ return override?.properties ?? {};
52
+ };
46
53
  export const getIntroOfferStateProps = (hasIntroOffer, overrides) => {
47
54
  if (!hasIntroOffer) {
48
55
  return {};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@revenuecat/purchases-ui-js",
3
3
  "description": "Web components for Paywalls. Powered by RevenueCat",
4
4
  "private": false,
5
- "version": "3.4.1",
5
+ "version": "3.5.0",
6
6
  "author": {
7
7
  "name": "RevenueCat, Inc."
8
8
  },