@revenuecat/purchases-ui-js 3.0.0 → 3.1.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.
- package/dist/components/paywall/Paywall.stories.svelte +33 -2
- package/dist/components/paywall/Paywall.svelte +4 -1
- package/dist/components/paywall/Paywall.svelte.d.ts +4 -1
- package/dist/components/purchase-button/PurchaseButton.svelte +122 -24
- package/dist/components/workflows/Screen.stories.svelte +31 -0
- package/dist/components/workflows/Screen.stories.svelte.d.ts +19 -0
- package/dist/components/workflows/Screen.svelte +52 -0
- package/dist/components/workflows/Screen.svelte.d.ts +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/stores/paywall.d.ts +4 -1
- package/dist/stories/paywall-decorator.d.ts +4 -1
- package/dist/types/workflow.d.ts +15 -0
- package/dist/types/workflow.js +1 -0
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -342,13 +342,44 @@
|
|
|
342
342
|
name="Wallet Button"
|
|
343
343
|
args={{
|
|
344
344
|
paywallData: pastaPaywallData,
|
|
345
|
-
walletButtonRender: (
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
...
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
{
|
|
53
|
-
<div
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
+
|
|
109
|
+
</div>
|
|
110
|
+
{:else}
|
|
111
|
+
<Stack {...stack} {onclick} />
|
|
60
112
|
{/if}
|
|
61
113
|
|
|
62
|
-
<
|
|
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>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
|
|
4
|
+
import Screen from "./Screen.svelte";
|
|
5
|
+
import { paywallData, uiConfigData } from "../../stories/fixtures";
|
|
6
|
+
import type { WorkflowScreen } from "../../types/workflow";
|
|
7
|
+
|
|
8
|
+
const defaultScreen: WorkflowScreen = {
|
|
9
|
+
...paywallData,
|
|
10
|
+
asset_base_url: "https://assets.pawwalls.com",
|
|
11
|
+
config: {},
|
|
12
|
+
localized_strings: {},
|
|
13
|
+
localized_strings_by_tier: {},
|
|
14
|
+
name: "Demo Screen",
|
|
15
|
+
offering_id: "demo_offering",
|
|
16
|
+
revision: 1,
|
|
17
|
+
template_name: "stack",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const { Story } = defineMeta({
|
|
21
|
+
title: "Components/Screen",
|
|
22
|
+
component: Screen,
|
|
23
|
+
args: {
|
|
24
|
+
paywallComponents: defaultScreen,
|
|
25
|
+
selectedLocale: defaultScreen.default_locale,
|
|
26
|
+
uiConfig: uiConfigData,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<Story name="Default" />
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Screen from "./Screen.svelte";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Screen: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Screen = InstanceType<typeof Screen>;
|
|
19
|
+
export default Screen;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Paywall, {
|
|
3
|
+
type UIConfig,
|
|
4
|
+
} from "../paywall/Paywall.svelte";
|
|
5
|
+
import type { WorkflowScreen } from "../../types/workflow";
|
|
6
|
+
import { VARIABLES } from "../paywall/fixtures/variables";
|
|
7
|
+
interface Props {
|
|
8
|
+
paywallComponents: WorkflowScreen | null | undefined;
|
|
9
|
+
selectedLocale?: string;
|
|
10
|
+
uiConfig: UIConfig;
|
|
11
|
+
onActionTriggered?: (actionId: string) => void;
|
|
12
|
+
onPurchaseClicked?: (
|
|
13
|
+
packageId: string,
|
|
14
|
+
actionId: string,
|
|
15
|
+
) => void | Promise<void>;
|
|
16
|
+
containerId?: string;
|
|
17
|
+
}
|
|
18
|
+
const {
|
|
19
|
+
paywallComponents,
|
|
20
|
+
selectedLocale = "en_US",
|
|
21
|
+
uiConfig,
|
|
22
|
+
onActionTriggered,
|
|
23
|
+
onPurchaseClicked,
|
|
24
|
+
containerId = "screen-container",
|
|
25
|
+
}: Props = $props();
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div id={containerId} class="paywall-container">
|
|
29
|
+
{#if paywallComponents}
|
|
30
|
+
<Paywall
|
|
31
|
+
paywallData={paywallComponents}
|
|
32
|
+
{selectedLocale}
|
|
33
|
+
{uiConfig}
|
|
34
|
+
variablesPerPackage={VARIABLES}
|
|
35
|
+
onNavigateToUrlClicked={() => {}}
|
|
36
|
+
onVisitCustomerCenterClicked={() => {}}
|
|
37
|
+
onBackClicked={() => {}}
|
|
38
|
+
onRestorePurchasesClicked={() => {}}
|
|
39
|
+
onActionTriggered={(actionId: string) => {
|
|
40
|
+
onActionTriggered?.(actionId);
|
|
41
|
+
}}
|
|
42
|
+
{onPurchaseClicked}
|
|
43
|
+
onError={(error) => {
|
|
44
|
+
console.error("Paywall error:", error);
|
|
45
|
+
}}
|
|
46
|
+
/>
|
|
47
|
+
{:else}
|
|
48
|
+
<div>
|
|
49
|
+
<p>No paywall data provided</p>
|
|
50
|
+
</div>
|
|
51
|
+
{/if}
|
|
52
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type UIConfig } from "../paywall/Paywall.svelte";
|
|
2
|
+
import type { WorkflowScreen } from "../../types/workflow";
|
|
3
|
+
interface Props {
|
|
4
|
+
paywallComponents: WorkflowScreen | null | undefined;
|
|
5
|
+
selectedLocale?: string;
|
|
6
|
+
uiConfig: UIConfig;
|
|
7
|
+
onActionTriggered?: (actionId: string) => void;
|
|
8
|
+
onPurchaseClicked?: (packageId: string, actionId: string) => void | Promise<void>;
|
|
9
|
+
containerId?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const Screen: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type Screen = ReturnType<typeof Screen>;
|
|
13
|
+
export default Screen;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { default as PurchaseButton } from "./components/purchase-button/Purchase
|
|
|
11
11
|
export { default as Stack } from "./components/stack/Stack.svelte";
|
|
12
12
|
export { default as Text } from "./components/text/Text.svelte";
|
|
13
13
|
export { default as Timeline } from "./components/timeline/Timeline.svelte";
|
|
14
|
+
export { default as Screen } from "./components/workflows/Screen.svelte";
|
|
14
15
|
export { default as Video } from "./components/video/Video.svelte";
|
|
15
16
|
export * from "./types";
|
|
16
17
|
export { type PaywallData } from "./types/paywall";
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { default as PurchaseButton } from "./components/purchase-button/Purchase
|
|
|
12
12
|
export { default as Stack } from "./components/stack/Stack.svelte";
|
|
13
13
|
export { default as Text } from "./components/text/Text.svelte";
|
|
14
14
|
export { default as Timeline } from "./components/timeline/Timeline.svelte";
|
|
15
|
+
export { default as Screen } from "./components/workflows/Screen.svelte";
|
|
15
16
|
export { default as Video } from "./components/video/Video.svelte";
|
|
16
17
|
export * from "./types";
|
|
17
18
|
export {} from "./types/paywall";
|
package/dist/stores/paywall.d.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
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>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PaywallData } from "./paywall";
|
|
2
|
+
/**
|
|
3
|
+
* Represents a screen/paywall configuration in a workflow.
|
|
4
|
+
* Extends core PaywallData with workflow-specific metadata.
|
|
5
|
+
*/
|
|
6
|
+
export interface WorkflowScreen extends PaywallData {
|
|
7
|
+
asset_base_url: string;
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
localized_strings: Record<string, Record<string, string>>;
|
|
10
|
+
localized_strings_by_tier: Record<string, Record<string, string>>;
|
|
11
|
+
name: string;
|
|
12
|
+
offering_id: string | null;
|
|
13
|
+
revision: number;
|
|
14
|
+
template_name: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
CHANGED