@revenuecat/purchases-ui-js 4.8.21 → 4.8.22
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/carousel/Carousel.svelte +3 -6
- package/dist/components/carousel/carousel-utils.d.ts +6 -0
- package/dist/components/carousel/carousel-utils.js +8 -0
- package/dist/components/paywall/Paywall.stories.svelte +14 -0
- package/dist/components/paywall/Paywall.svelte +2 -1
- package/dist/components/paywall/Sheet.svelte +19 -6
- package/dist/components/paywall/ViewportBackdrop.svelte +13 -1
- package/dist/components/paywall/ViewportBackdrop.svelte.d.ts +1 -0
- package/dist/components/paywall/fixtures/gradient-sheet-paywall.d.ts +2 -0
- package/dist/components/paywall/fixtures/gradient-sheet-paywall.js +68 -0
- package/dist/components/paywall/fixtures/sheet-close-button-paywall.d.ts +2 -0
- package/dist/components/paywall/fixtures/sheet-close-button-paywall.js +62 -0
- package/dist/components/workflows/Workflow.svelte +2 -1
- package/dist/stores/state.js +2 -2
- package/dist/utils/safe-area-background.js +1 -1
- package/dist/utils/style-utils.js +2 -2
- package/package.json +1 -1
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { onMount } from "svelte";
|
|
25
25
|
import {
|
|
26
26
|
clamp,
|
|
27
|
+
getDefaultPageIndex,
|
|
27
28
|
getSwipeTargetPage,
|
|
28
29
|
getTranslation,
|
|
29
30
|
mapPageAlignment,
|
|
@@ -132,10 +133,6 @@
|
|
|
132
133
|
let pageWidth = $derived(carouselWidth - pageOffset);
|
|
133
134
|
let gestureStartPage = $state<number | null>(null);
|
|
134
135
|
|
|
135
|
-
function getDefaultPageIndex() {
|
|
136
|
-
return pages.at(initial_page_index) !== undefined ? initial_page_index : 0;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
136
|
function normalizePageIndex(index: number) {
|
|
140
137
|
if (pages.length === 0) {
|
|
141
138
|
return 0;
|
|
@@ -199,7 +196,7 @@
|
|
|
199
196
|
}
|
|
200
197
|
|
|
201
198
|
onMount(() => {
|
|
202
|
-
const initialPage = getDefaultPageIndex();
|
|
199
|
+
const initialPage = getDefaultPageIndex(pages, initial_page_index);
|
|
203
200
|
currentPage = initialPage;
|
|
204
201
|
|
|
205
202
|
stopTransition();
|
|
@@ -265,7 +262,7 @@
|
|
|
265
262
|
destinationIndex: destinationPage,
|
|
266
263
|
originContextName: getPageContextName(gestureStartPage),
|
|
267
264
|
destinationContextName: getPageContextName(destinationPage),
|
|
268
|
-
defaultIndex: getDefaultPageIndex(),
|
|
265
|
+
defaultIndex: getDefaultPageIndex(pages, initial_page_index),
|
|
269
266
|
});
|
|
270
267
|
}
|
|
271
268
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { VerticalAlignment } from "../../types/alignment";
|
|
2
2
|
export declare function mapPageAlignment(alignment: VerticalAlignment): string;
|
|
3
3
|
export declare function clamp(value: number, min: number, max: number): number;
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the carousel's starting page. Out-of-range indexes (including a
|
|
6
|
+
* missing `pages[i]` hole) fall back to 0. Uses index access rather than
|
|
7
|
+
* `Array.prototype.at` so Chrome < 92 does not throw while mounting.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDefaultPageIndex<T>(pages: readonly T[], initialPageIndex: number): number;
|
|
4
10
|
/**
|
|
5
11
|
* Advance one page when the drag passed this fraction of a page's width,
|
|
6
12
|
* matching the iOS SDK carousel. A shorter drag snaps back to the page the
|
|
@@ -11,6 +11,14 @@ export function mapPageAlignment(alignment) {
|
|
|
11
11
|
export function clamp(value, min, max) {
|
|
12
12
|
return Math.max(min, Math.min(value, max));
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the carousel's starting page. Out-of-range indexes (including a
|
|
16
|
+
* missing `pages[i]` hole) fall back to 0. Uses index access rather than
|
|
17
|
+
* `Array.prototype.at` so Chrome < 92 does not throw while mounting.
|
|
18
|
+
*/
|
|
19
|
+
export function getDefaultPageIndex(pages, initialPageIndex) {
|
|
20
|
+
return pages[initialPageIndex] !== undefined ? initialPageIndex : 0;
|
|
21
|
+
}
|
|
14
22
|
/**
|
|
15
23
|
* Advance one page when the drag passed this fraction of a page's width,
|
|
16
24
|
* matching the iOS SDK carousel. A shorter drag snaps back to the page the
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
import { OVERRIDE_PAYWALL } from "./fixtures/override-paywall";
|
|
31
31
|
import { SHEET_PAYWALL } from "./fixtures/sheet-paywall";
|
|
32
32
|
import { SHEET_PAYWALL_VIDEO_STACKING } from "./fixtures/sheet-video-stacking-paywall";
|
|
33
|
+
import { GRADIENT_SHEET_PAYWALL } from "./fixtures/gradient-sheet-paywall";
|
|
33
34
|
import { STACK_PAYWALL } from "./fixtures/stack-paywall";
|
|
34
35
|
import { VARIABLES } from "./fixtures/variables";
|
|
35
36
|
import { CUSTOM_VARIABLES_PAYWALL } from "./fixtures/custom-variables-paywall";
|
|
@@ -167,6 +168,19 @@
|
|
|
167
168
|
}}
|
|
168
169
|
/>
|
|
169
170
|
|
|
171
|
+
<Story
|
|
172
|
+
name="Sheet — gradient background"
|
|
173
|
+
decorators={[viewportDecorator(500, 500, 0)]}
|
|
174
|
+
play={async ({ canvasElement }) => {
|
|
175
|
+
const button = canvasElement.querySelector("button");
|
|
176
|
+
button?.click();
|
|
177
|
+
await waitForAnimations();
|
|
178
|
+
}}
|
|
179
|
+
args={{
|
|
180
|
+
paywallData: GRADIENT_SHEET_PAYWALL,
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
|
|
170
184
|
<Story
|
|
171
185
|
name="Background - Color"
|
|
172
186
|
decorators={[viewportDecorator(500, 500, 0)]}
|
|
@@ -442,8 +442,9 @@
|
|
|
442
442
|
</script>
|
|
443
443
|
|
|
444
444
|
<svelte:boundary onerror={onError}>
|
|
445
|
+
<!-- Outside the root: filter/transform on `.blur` would clip the fixed backdrop to the paywall box. -->
|
|
446
|
+
<ViewportBackdrop model={viewportBackdropModel} blur={!!sheet} />
|
|
445
447
|
<div class={paywallClass} style={paywallStyle}>
|
|
446
|
-
<ViewportBackdrop model={viewportBackdropModel} />
|
|
447
448
|
{#if header}
|
|
448
449
|
<div
|
|
449
450
|
class="header-wrapper"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getColorModeContext } from "../../stores/color-mode";
|
|
3
3
|
import { useConditionContext } from "../../stores/condition-context.svelte";
|
|
4
|
-
import { getPaywallContext } from "../../stores/paywall";
|
|
4
|
+
import { getPaywallContext, setPaywallContext } from "../../stores/paywall";
|
|
5
5
|
import BackgroundVideoSurface from "./BackgroundVideoSurface.svelte";
|
|
6
6
|
import type { SheetProps } from "../../types/components/sheet";
|
|
7
7
|
import {
|
|
@@ -56,21 +56,34 @@
|
|
|
56
56
|
}),
|
|
57
57
|
);
|
|
58
58
|
|
|
59
|
-
const
|
|
59
|
+
const paywallContext = getPaywallContext();
|
|
60
|
+
const { onButtonAction } = paywallContext;
|
|
60
61
|
|
|
61
62
|
let sheet: HTMLDivElement | undefined;
|
|
62
63
|
let visible = $state(false);
|
|
63
64
|
|
|
65
|
+
const hideSheet = () => {
|
|
66
|
+
visible = false;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// navigate_back inside the sheet closes the sheet, not the paywall.
|
|
70
|
+
setPaywallContext({
|
|
71
|
+
...paywallContext,
|
|
72
|
+
onButtonAction: (action, actionId) => {
|
|
73
|
+
if (action.type === "navigate_back") {
|
|
74
|
+
hideSheet();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
onButtonAction(action, actionId);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
64
81
|
onMount(() => {
|
|
65
82
|
requestAnimationFrame(() => {
|
|
66
83
|
visible = true;
|
|
67
84
|
});
|
|
68
85
|
});
|
|
69
86
|
|
|
70
|
-
const hideSheet = () => {
|
|
71
|
-
visible = false;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
87
|
const ontransitionend = () => {
|
|
75
88
|
if (visible) {
|
|
76
89
|
return;
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
// through to the safe-area canvas. A position:fixed element that explicitly
|
|
7
7
|
// fills the viewport — including safe areas — is the only consistent paint
|
|
8
8
|
// surface for gradients and images on iOS Safari.
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
model,
|
|
11
|
+
blur = false,
|
|
12
|
+
}: { model: PaywallRootBackgroundModel; blur?: boolean } = $props();
|
|
10
13
|
|
|
11
14
|
const backdropStyle = $derived.by((): string => {
|
|
12
15
|
if (
|
|
@@ -46,6 +49,7 @@
|
|
|
46
49
|
{#if shouldRenderBackdrop}
|
|
47
50
|
<div
|
|
48
51
|
class="viewport-backdrop"
|
|
52
|
+
class:blurred={blur}
|
|
49
53
|
style={backdropStyle !== "" ? backdropStyle : undefined}
|
|
50
54
|
>
|
|
51
55
|
{#if model.kind === "video"}
|
|
@@ -77,6 +81,14 @@
|
|
|
77
81
|
pointer-events: none;
|
|
78
82
|
overflow: hidden;
|
|
79
83
|
isolation: isolate;
|
|
84
|
+
transition:
|
|
85
|
+
filter 0.1s ease-in-out,
|
|
86
|
+
transform 0.1s ease-in-out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.viewport-backdrop.blurred {
|
|
90
|
+
filter: blur(10px) brightness(0.8);
|
|
91
|
+
transform: scale(1.045);
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
.viewport-backdrop-overlay {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PaywallRootBackgroundModel } from "../../utils/background-utils";
|
|
2
2
|
type $$ComponentProps = {
|
|
3
3
|
model: PaywallRootBackgroundModel;
|
|
4
|
+
blur?: boolean;
|
|
4
5
|
};
|
|
5
6
|
declare const ViewportBackdrop: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
7
|
type ViewportBackdrop = ReturnType<typeof ViewportBackdrop>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createStack, createTextComponent } from "./helpers";
|
|
2
|
+
// Gradient background (painted by ViewportBackdrop) plus a button that opens a sheet.
|
|
3
|
+
export const GRADIENT_SHEET_PAYWALL = {
|
|
4
|
+
id: "gradient-sheet-paywall",
|
|
5
|
+
default_locale: "en_US",
|
|
6
|
+
components_localizations: {
|
|
7
|
+
en_US: { open_sheet: "Open sheet", sheet_title: "Sheet" },
|
|
8
|
+
},
|
|
9
|
+
components_config: {
|
|
10
|
+
base: {
|
|
11
|
+
background: {
|
|
12
|
+
type: "color",
|
|
13
|
+
value: {
|
|
14
|
+
light: {
|
|
15
|
+
type: "linear",
|
|
16
|
+
degrees: 45,
|
|
17
|
+
points: [
|
|
18
|
+
{ percent: 0, color: "#010101ff" },
|
|
19
|
+
{ percent: 100, color: "#f79e00ff" },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
stack: createStack({
|
|
25
|
+
id: "root",
|
|
26
|
+
name: "Root",
|
|
27
|
+
components: [
|
|
28
|
+
{
|
|
29
|
+
type: "button",
|
|
30
|
+
id: "open-sheet",
|
|
31
|
+
name: "open-sheet",
|
|
32
|
+
action: {
|
|
33
|
+
type: "navigate_to",
|
|
34
|
+
destination: "sheet",
|
|
35
|
+
sheet: {
|
|
36
|
+
type: "sheet",
|
|
37
|
+
id: "sheet",
|
|
38
|
+
name: "sheet",
|
|
39
|
+
size: { width: { type: "fill" }, height: { type: "fit" } },
|
|
40
|
+
background_blur: true,
|
|
41
|
+
stack: createStack({
|
|
42
|
+
id: "sheet-stack",
|
|
43
|
+
name: "Sheet",
|
|
44
|
+
components: [
|
|
45
|
+
createTextComponent({
|
|
46
|
+
id: "sheet-title",
|
|
47
|
+
textLid: "sheet_title",
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
stack: createStack({
|
|
54
|
+
id: "open-sheet-stack",
|
|
55
|
+
name: "open-sheet",
|
|
56
|
+
components: [
|
|
57
|
+
createTextComponent({
|
|
58
|
+
id: "open-sheet-text",
|
|
59
|
+
textLid: "open_sheet",
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createStack, createTextComponent } from "./helpers";
|
|
2
|
+
function button(id, textLid, action) {
|
|
3
|
+
return {
|
|
4
|
+
type: "button",
|
|
5
|
+
id,
|
|
6
|
+
name: id,
|
|
7
|
+
action,
|
|
8
|
+
stack: createStack({
|
|
9
|
+
id: `${id}-stack`,
|
|
10
|
+
name: id,
|
|
11
|
+
components: [createTextComponent({ id: `${id}-text`, textLid })],
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// Sheet whose close button uses navigate_back, as the builder configures it.
|
|
16
|
+
export const SHEET_CLOSE_BUTTON_PAYWALL = {
|
|
17
|
+
id: "sheet-close-button-paywall",
|
|
18
|
+
default_locale: "en_US",
|
|
19
|
+
components_localizations: {
|
|
20
|
+
en_US: {
|
|
21
|
+
open_sheet: "Included devices",
|
|
22
|
+
sheet_title: "Devices",
|
|
23
|
+
close_sheet: "Close",
|
|
24
|
+
close_paywall: "Dismiss paywall",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
components_config: {
|
|
28
|
+
base: {
|
|
29
|
+
stack: createStack({
|
|
30
|
+
id: "root",
|
|
31
|
+
name: "Root",
|
|
32
|
+
components: [
|
|
33
|
+
button("close-paywall", "close_paywall", { type: "navigate_back" }),
|
|
34
|
+
button("open-sheet", "open_sheet", {
|
|
35
|
+
type: "navigate_to",
|
|
36
|
+
destination: "sheet",
|
|
37
|
+
sheet: {
|
|
38
|
+
type: "sheet",
|
|
39
|
+
id: "devices-sheet",
|
|
40
|
+
name: "devices_sheet",
|
|
41
|
+
size: { width: { type: "fill" }, height: { type: "fit" } },
|
|
42
|
+
background_blur: true,
|
|
43
|
+
stack: createStack({
|
|
44
|
+
id: "sheet-stack",
|
|
45
|
+
name: "Sheet",
|
|
46
|
+
components: [
|
|
47
|
+
createTextComponent({
|
|
48
|
+
id: "sheet-title",
|
|
49
|
+
textLid: "sheet_title",
|
|
50
|
+
}),
|
|
51
|
+
button("close-sheet", "close_sheet", {
|
|
52
|
+
type: "navigate_back",
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -142,7 +142,8 @@
|
|
|
142
142
|
for (const [key, declaration] of Object.entries(
|
|
143
143
|
screen.state_declarations ?? {},
|
|
144
144
|
)) {
|
|
145
|
-
if (!Object.
|
|
145
|
+
if (!Object.prototype.hasOwnProperty.call(merged, key))
|
|
146
|
+
merged[key] = declaration;
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
return merged;
|
package/dist/stores/state.js
CHANGED
|
@@ -34,14 +34,14 @@ export class PaywallStateStore {
|
|
|
34
34
|
registerDeclarations(declarations) {
|
|
35
35
|
let changed = false;
|
|
36
36
|
for (const [key, declaration] of Object.entries(declarations)) {
|
|
37
|
-
if (Object.
|
|
37
|
+
if (Object.prototype.hasOwnProperty.call(this.#declaredDefaults, key))
|
|
38
38
|
continue;
|
|
39
39
|
const normalized = this.#normalizeForType(declaration.default, declaration.type);
|
|
40
40
|
if (normalized === undefined)
|
|
41
41
|
continue;
|
|
42
42
|
this.#declaredDefaults[key] = normalized;
|
|
43
43
|
this.#declaredTypes[key] = declaration.type;
|
|
44
|
-
if (!Object.
|
|
44
|
+
if (!Object.prototype.hasOwnProperty.call(this.#currentValues, key)) {
|
|
45
45
|
this.#currentValues[key] = normalized;
|
|
46
46
|
changed = true;
|
|
47
47
|
}
|
|
@@ -80,7 +80,7 @@ export function getSafeAreaFallbackColorHeadStyles(paywallData, hostFallbackColo
|
|
|
80
80
|
}
|
|
81
81
|
function colorAtPercent(sortedPoints, percent) {
|
|
82
82
|
const firstPoint = sortedPoints[0];
|
|
83
|
-
const lastPoint = sortedPoints.
|
|
83
|
+
const lastPoint = sortedPoints[sortedPoints.length - 1];
|
|
84
84
|
if (firstPoint == null || lastPoint == null) {
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
@@ -206,8 +206,8 @@ const conditionMatches = (condition, context) => {
|
|
|
206
206
|
if (condition.type === RuleKey.StateCondition) {
|
|
207
207
|
const stateValues = context.stateValues ?? {};
|
|
208
208
|
const stateDefaults = context.stateDefaults ?? {};
|
|
209
|
-
const hasCurrentValue = Object.
|
|
210
|
-
const hasDeclaredDefault = Object.
|
|
209
|
+
const hasCurrentValue = Object.prototype.hasOwnProperty.call(stateValues, condition.name);
|
|
210
|
+
const hasDeclaredDefault = Object.prototype.hasOwnProperty.call(stateDefaults, condition.name);
|
|
211
211
|
// Undeclared key (not in store, not declared): false for BOTH operators.
|
|
212
212
|
// This diverges from variable_condition (where != matches a missing variable):
|
|
213
213
|
// state keys are editor-managed, so an undeclared reference is always a bug,
|