@revenuecat/purchases-ui-js 3.0.0 → 3.0.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.
@@ -342,13 +342,44 @@
342
342
  name="Wallet Button"
343
343
  args={{
344
344
  paywallData: pastaPaywallData,
345
- walletButtonRender: (element: HTMLElement, selectedPackageId) => {
345
+ walletButtonRender: (
346
+ element: HTMLElement,
347
+ { selectedPackageId, onReady },
348
+ ) => {
346
349
  const newDiv = document.createElement("div");
347
350
  newDiv.innerText = "Hi! I was injected from the walletButtonRender";
348
351
  newDiv.style.width = "100%";
349
352
  newDiv.style.textAlign = "center";
350
353
  newDiv.style.border = "1px solid black";
351
- element.append(newDiv);
354
+
355
+ setTimeout(() => {
356
+ element.append(newDiv);
357
+ onReady && onReady();
358
+ }, 3000);
359
+ return {};
360
+ },
361
+ }}
362
+ />
363
+
364
+ <Story
365
+ name="Wallet Button Dark"
366
+ args={{
367
+ paywallData: STACK_PAYWALL,
368
+ walletButtonRender: (
369
+ element: HTMLElement,
370
+ { selectedPackageId, onReady },
371
+ ) => {
372
+ const newDiv = document.createElement("div");
373
+ newDiv.innerText = "Hi! I was injected from the walletButtonRender";
374
+ newDiv.style.width = "100%";
375
+ newDiv.style.textAlign = "center";
376
+ newDiv.style.color = "white";
377
+ newDiv.style.border = "1px solid white";
378
+
379
+ setTimeout(() => {
380
+ element.append(newDiv);
381
+ onReady && onReady();
382
+ }, 3000);
352
383
  return {};
353
384
  },
354
385
  }}
@@ -42,7 +42,10 @@
42
42
  onError?: (error: unknown) => void;
43
43
  walletButtonRender?: (
44
44
  node: HTMLElement,
45
- selectedPackageId: string,
45
+ params: {
46
+ selectedPackageId: string;
47
+ onReady?: () => void;
48
+ },
46
49
  ) => {
47
50
  destroy?: () => void;
48
51
  update?: (selectedPackageId: string) => void;
@@ -16,7 +16,10 @@ interface Props {
16
16
  onNavigateToUrlClicked?: (url: string) => void;
17
17
  onActionTriggered?: (actionId: string) => void;
18
18
  onError?: (error: unknown) => void;
19
- walletButtonRender?: (node: HTMLElement, selectedPackageId: string) => {
19
+ walletButtonRender?: (node: HTMLElement, params: {
20
+ selectedPackageId: string;
21
+ onReady?: () => void;
22
+ }) => {
20
23
  destroy?: () => void;
21
24
  update?: (selectedPackageId: string) => void;
22
25
  };
@@ -7,12 +7,18 @@
7
7
  import {
8
8
  type CSS,
9
9
  css,
10
+ mapBorder,
11
+ mapBorderRadius,
12
+ mapShadow,
10
13
  mapSize,
11
14
  mapSpacing,
12
15
  px,
13
16
  } from "../../utils/base-utils";
14
17
  import { mapDimension } from "../stack/stack-utils";
15
18
  import type { StackProps } from "../../types/components/stack";
19
+ import { DEFAULT_SPACING } from "../../utils/constants";
20
+ import { getColorModeContext } from "../../stores/color-mode";
21
+ import { onMount } from "svelte";
16
22
 
17
23
  const props: PurchaseButtonProps = $props();
18
24
  const { stack } = props;
@@ -22,23 +28,49 @@
22
28
 
23
29
  const stackProps: StackProps & { style?: CSS } = { ...stack };
24
30
  const selectedState = getSelectedStateContext();
25
- const { size, dimension, spacing, margin } = $derived.by(() => {
26
- return {
27
- ...stackProps,
28
- ...getActiveStateProps($selectedState, stackProps.overrides),
29
- };
31
+ const { size, dimension, spacing, margin, border, shape, shadow } =
32
+ $derived.by(() => {
33
+ return {
34
+ ...stackProps,
35
+ ...getActiveStateProps($selectedState, stackProps.overrides),
36
+ };
37
+ });
38
+
39
+ const minDistanceBetweenPurchaseButtons = 10;
40
+ const maxWaitTimeBeforeClosingSkeleton = 3000;
41
+
42
+ const getColorMode = getColorModeContext();
43
+ const colorMode = $derived(getColorMode());
44
+
45
+ const stackLayoutRules = $derived({
46
+ ...stackProps.style,
47
+ display: "flex",
48
+ position: "relative",
49
+ width: mapSize(size.width),
50
+ height: mapSize(size.height),
51
+ ...mapDimension(dimension),
52
+ gap: px(spacing),
53
+ margin: mapSpacing({
54
+ ...(margin
55
+ ? {
56
+ ...margin,
57
+ bottom: Math.max(margin.bottom, minDistanceBetweenPurchaseButtons),
58
+ }
59
+ : {
60
+ ...DEFAULT_SPACING,
61
+ bottom: minDistanceBetweenPurchaseButtons,
62
+ }),
63
+ }),
30
64
  });
31
65
 
32
- const stackStyle = $derived(
66
+ const stackStyle = $derived(css(stackLayoutRules));
67
+
68
+ const loaderStyle = $derived(
33
69
  css({
34
- ...stackProps.style,
35
- display: "flex",
36
- position: "relative",
37
- width: mapSize(size.width),
38
- height: mapSize(size.height),
39
- ...mapDimension(dimension),
40
- gap: px(spacing),
41
- margin: mapSpacing(margin),
70
+ ...stackLayoutRules,
71
+ border: mapBorder(colorMode, border),
72
+ "border-radius": mapBorderRadius(shape),
73
+ "box-shadow": mapShadow(colorMode, shadow),
42
74
  }),
43
75
  );
44
76
 
@@ -46,17 +78,83 @@
46
78
  const actionId = props.triggers?.on_purchase_press;
47
79
  onPurchase(actionId);
48
80
  };
81
+
82
+ let shouldShowWalletSkeleton = $state(!!walletButtonRender);
83
+ const onWalletButtonReady = () => {
84
+ shouldShowWalletSkeleton = false;
85
+ };
86
+
87
+ onMount(() => {
88
+ setTimeout(() => {
89
+ shouldShowWalletSkeleton = false;
90
+ }, maxWaitTimeBeforeClosingSkeleton);
91
+ });
49
92
  </script>
50
93
 
51
- {#if walletButtonRender}
52
- {#if $selectedPackageId}
53
- <div style={stackStyle}>
54
- <div
55
- style="flex-grow: 1"
56
- use:walletButtonRender={$selectedPackageId}
57
- ></div>
58
- </div>
59
- {/if}
94
+ {#if walletButtonRender && $selectedPackageId}
95
+ <div style={stackStyle}>
96
+ <div
97
+ style="flex-grow: 1; width:100%;"
98
+ use:walletButtonRender={{
99
+ selectedPackageId: $selectedPackageId,
100
+ onReady: onWalletButtonReady,
101
+ }}
102
+ ></div>
103
+ </div>
104
+ {/if}
105
+
106
+ {#if shouldShowWalletSkeleton}
107
+ <div class="wallet-skeleton" style={loaderStyle} aria-hidden="true">
108
+ &nbsp;
109
+ </div>
110
+ {:else}
111
+ <Stack {...stack} {onclick} />
60
112
  {/if}
61
113
 
62
- <Stack {...stack} {onclick} />
114
+ <style>
115
+ .wallet-skeleton {
116
+ position: relative;
117
+ overflow: hidden;
118
+ border-radius: 9999px;
119
+ background-color: rgba(128, 128, 128, 0.16);
120
+ backdrop-filter: blur(18px);
121
+ min-height: 48px;
122
+ content: " ";
123
+ flex-grow: 1;
124
+ width: 100%;
125
+ }
126
+
127
+ .wallet-skeleton::before {
128
+ content: "";
129
+ position: absolute;
130
+ inset: 0;
131
+ background: linear-gradient(
132
+ 135deg,
133
+ rgba(255, 255, 255, 0.2),
134
+ rgba(255, 255, 255, 0.01)
135
+ );
136
+ opacity: 0.9;
137
+ mix-blend-mode: screen;
138
+ }
139
+
140
+ .wallet-skeleton::after {
141
+ content: "";
142
+ position: absolute;
143
+ inset: 0;
144
+ transform: translateX(-100%);
145
+ background: linear-gradient(
146
+ 120deg,
147
+ transparent 0%,
148
+ rgba(255, 255, 255, 0.6) 20%,
149
+ transparent 40%
150
+ );
151
+ opacity: 0.8;
152
+ animation: wallet-skeleton-shimmer 1.4s ease-in-out infinite;
153
+ }
154
+
155
+ @keyframes wallet-skeleton-shimmer {
156
+ 100% {
157
+ transform: translateX(100%);
158
+ }
159
+ }
160
+ </style>
@@ -7,7 +7,10 @@ type PaywallContext = Readonly<{
7
7
  variablesPerPackage: Readable<Record<string, VariableDictionary> | undefined>;
8
8
  infoPerPackage: Readable<Record<string, PackageInfo> | undefined>;
9
9
  onPurchase: (actionId?: string) => void;
10
- walletButtonRender?: (node: HTMLElement, selectedPackageId: string) => {
10
+ walletButtonRender?: (node: HTMLElement, params: {
11
+ selectedPackageId: string;
12
+ onReady?: () => void;
13
+ }) => {
11
14
  destroy?: () => void;
12
15
  update?: (selectedPackageId: string) => void;
13
16
  };
@@ -1,5 +1,8 @@
1
1
  import type { DecoratorFunction, Renderer } from "storybook/internal/csf";
2
- export declare function paywallDecorator<TRenderer extends Renderer, TArgs>(walletButtonRender?: (node: HTMLElement, selectedPackageId: string) => {
2
+ export declare function paywallDecorator<TRenderer extends Renderer, TArgs>(walletButtonRender?: (node: HTMLElement, params: {
3
+ selectedPackageId: string;
4
+ onReady?: () => void;
5
+ }) => {
3
6
  destroy?: () => void;
4
7
  update?: (selectedPackageId: string) => void;
5
8
  }): DecoratorFunction<TRenderer, TArgs>;
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.0.0",
5
+ "version": "3.0.1",
6
6
  "author": {
7
7
  "name": "RevenueCat, Inc."
8
8
  },