@revenuecat/purchases-ui-js 4.12.5 → 4.14.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/image/Image.svelte +7 -2
- package/dist/components/loader-animation/LoaderAnimation.stories.svelte +1 -3
- package/dist/components/paywall/Paywall.svelte +7 -2
- package/dist/components/stack/Stack.stories.svelte +8 -8
- package/dist/components/text/text-utils.js +5 -0
- package/dist/components/video/Video.stories.svelte +29 -1
- package/dist/components/video/Video.svelte +16 -2
- package/dist/stores/localization.d.ts +5 -2
- package/dist/stores/localization.js +8 -6
- package/dist/stories/fixtures.js +2 -2
- package/dist/types/components/video.d.ts +1 -1
- package/dist/types/localization.d.ts +2 -1
- package/dist/types/paywall.d.ts +2 -1
- package/dist/utils/source-utils.d.ts +16 -0
- package/dist/utils/source-utils.js +19 -0
- package/dist/utils/style-utils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/image/image-utils.d.ts +0 -9
- package/dist/components/image/image-utils.js +0 -20
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
mapSpacing,
|
|
15
15
|
} from "../../utils/base-utils";
|
|
16
16
|
import { resolveOverrideProperties } from "../../utils/style-utils";
|
|
17
|
+
import { resolveLocalizedSource } from "../../utils/source-utils";
|
|
17
18
|
import ClipPath from "./ClipPath.svelte";
|
|
18
|
-
import { resolveImageSource } from "./image-utils";
|
|
19
19
|
import { viewBoxSize } from "./view-box-size";
|
|
20
20
|
import Overlay from "./Overlay.svelte";
|
|
21
21
|
|
|
@@ -45,7 +45,12 @@
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
const source = $derived(
|
|
48
|
-
|
|
48
|
+
resolveLocalizedSource(
|
|
49
|
+
props,
|
|
50
|
+
"override_source_lid",
|
|
51
|
+
conditionContext,
|
|
52
|
+
getLocalizedImage,
|
|
53
|
+
),
|
|
49
54
|
);
|
|
50
55
|
|
|
51
56
|
const getColorMode = getColorModeContext();
|
|
@@ -108,9 +108,7 @@
|
|
|
108
108
|
decorators={[staticLoaderDecorator(0.5)]}
|
|
109
109
|
template={linearClampTemplate}
|
|
110
110
|
play={async ({ canvasElement }) => {
|
|
111
|
-
const loader = canvasElement.querySelector(
|
|
112
|
-
".rc-loader-animation--linear",
|
|
113
|
-
);
|
|
111
|
+
const loader = canvasElement.querySelector(".rc-loader-animation--linear");
|
|
114
112
|
await expect(loader?.getBoundingClientRect().height).toBe(48);
|
|
115
113
|
}}
|
|
116
114
|
args={{
|
|
@@ -224,8 +224,12 @@
|
|
|
224
224
|
}),
|
|
225
225
|
);
|
|
226
226
|
|
|
227
|
-
const {
|
|
228
|
-
|
|
227
|
+
const {
|
|
228
|
+
default_locale,
|
|
229
|
+
components_config,
|
|
230
|
+
components_localizations,
|
|
231
|
+
components_video_localizations,
|
|
232
|
+
} = paywallData;
|
|
229
233
|
const { base } = components_config;
|
|
230
234
|
const defaultPackageId = findSelectedPackageId(base);
|
|
231
235
|
|
|
@@ -250,6 +254,7 @@
|
|
|
250
254
|
defaultLocale: default_locale,
|
|
251
255
|
selectedLocale,
|
|
252
256
|
localizations: components_localizations!,
|
|
257
|
+
videoLocalizations: components_video_localizations,
|
|
253
258
|
}));
|
|
254
259
|
|
|
255
260
|
const selectedPackageId = writable<string | undefined>(defaultPackageId);
|
|
@@ -353,14 +353,6 @@
|
|
|
353
353
|
}}
|
|
354
354
|
/>
|
|
355
355
|
|
|
356
|
-
<style>
|
|
357
|
-
.fill-clamp-layouts {
|
|
358
|
-
display: flex;
|
|
359
|
-
flex-wrap: wrap;
|
|
360
|
-
gap: 24px;
|
|
361
|
-
}
|
|
362
|
-
</style>
|
|
363
|
-
|
|
364
356
|
<Story
|
|
365
357
|
name="Z Layer"
|
|
366
358
|
args={{
|
|
@@ -3095,3 +3087,11 @@
|
|
|
3095
3087
|
},
|
|
3096
3088
|
}}
|
|
3097
3089
|
/>
|
|
3090
|
+
|
|
3091
|
+
<style>
|
|
3092
|
+
.fill-clamp-layouts {
|
|
3093
|
+
display: flex;
|
|
3094
|
+
flex-wrap: wrap;
|
|
3095
|
+
gap: 24px;
|
|
3096
|
+
}
|
|
3097
|
+
</style>
|
|
@@ -136,6 +136,11 @@ export function getHtmlFromMarkdown(text) {
|
|
|
136
136
|
bold: { regexp: /\*\*(.*?)\*\*/g, output: "<b>$1</b>" },
|
|
137
137
|
italic: { regexp: /\*(.*?)\*/g, output: "<i>$1</i>" },
|
|
138
138
|
strikethrough: { regexp: /~(.*?)~/g, output: "<s>$1</s>" },
|
|
139
|
+
// escapeHtml turned `<u>` tags into `<u>`, so we convert them back:
|
|
140
|
+
underline: { regexp: /<u>(.*?)<\/u>/g, output: "<u>$1</u>" },
|
|
141
|
+
// NOTE: Existing bug: the dashboard saves a literal "<" as `<` and
|
|
142
|
+
// escapeHtml escapes it again, so "Show your support <3" shows as
|
|
143
|
+
// "Show your support <3".
|
|
139
144
|
code: {
|
|
140
145
|
regexp: /`(.*?)`/g,
|
|
141
146
|
output: "<span style='font-family: monospace'>$1</span>",
|
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import Video from "./Video.svelte";
|
|
3
3
|
import { componentDecorator } from "../../stories/component-decorator";
|
|
4
|
+
import { localizationDecorator } from "../../stories/localization-decorator";
|
|
5
|
+
import type { VideoInfo } from "../../types/media";
|
|
4
6
|
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
5
7
|
|
|
8
|
+
const localizedVideo: VideoInfo = {
|
|
9
|
+
dark: null,
|
|
10
|
+
light: {
|
|
11
|
+
width: 1920,
|
|
12
|
+
height: 1080,
|
|
13
|
+
url: "https://videos.pexels.com/video-files/10288594/10288594-hd_1920_1080_25fps.mp4",
|
|
14
|
+
url_low_res:
|
|
15
|
+
"https://videos.pexels.com/video-files/10288594/10288594-hd_1920_1080_25fps.mp4",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
6
19
|
const { Story } = defineMeta({
|
|
7
20
|
title: "Components/Video",
|
|
8
21
|
component: Video,
|
|
9
|
-
decorators: [
|
|
22
|
+
decorators: [
|
|
23
|
+
componentDecorator(),
|
|
24
|
+
localizationDecorator({
|
|
25
|
+
defaultLocale: "en_US",
|
|
26
|
+
localizations: {},
|
|
27
|
+
videoLocalizations: { en_US: { localized_video: localizedVideo } },
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
10
30
|
parameters: {
|
|
11
31
|
chromatic: { disableSnapshot: true },
|
|
12
32
|
},
|
|
@@ -139,6 +159,14 @@
|
|
|
139
159
|
}}
|
|
140
160
|
/>
|
|
141
161
|
|
|
162
|
+
<Story
|
|
163
|
+
name="Localized Source"
|
|
164
|
+
args={{
|
|
165
|
+
source: null,
|
|
166
|
+
override_video_lid: "localized_video",
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
|
|
142
170
|
<Story
|
|
143
171
|
name="Overlay Radial Gradient"
|
|
144
172
|
args={{
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { untrack } from "svelte";
|
|
3
3
|
import { getColorModeContext } from "../../stores/color-mode";
|
|
4
4
|
import { useConditionContext } from "../../stores/condition-context.svelte";
|
|
5
|
+
import { getLocalizationContext } from "../../stores/localization";
|
|
5
6
|
import type { VideoProps } from "../../types/components/video";
|
|
6
7
|
import type { VideoFiles, ImageFiles } from "../../types/media";
|
|
7
8
|
import {
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
mapSpacing,
|
|
17
18
|
} from "../../utils/base-utils";
|
|
18
19
|
import { resolveOverrideProperties } from "../../utils/style-utils";
|
|
20
|
+
import { resolveLocalizedSource } from "../../utils/source-utils";
|
|
19
21
|
import {
|
|
20
22
|
applyInlineVideoPlaybackFlags,
|
|
21
23
|
subscribeDecorativeVideoAutoplayAttempts,
|
|
@@ -27,9 +29,12 @@
|
|
|
27
29
|
const props: VideoProps = $props();
|
|
28
30
|
|
|
29
31
|
const buildConditionContext = useConditionContext();
|
|
32
|
+
const { getLocalizedVideo } = getLocalizationContext();
|
|
33
|
+
|
|
34
|
+
const conditionContext = $derived(buildConditionContext());
|
|
35
|
+
|
|
30
36
|
const {
|
|
31
37
|
id,
|
|
32
|
-
source,
|
|
33
38
|
fallback_source,
|
|
34
39
|
size,
|
|
35
40
|
mask_shape,
|
|
@@ -47,10 +52,19 @@
|
|
|
47
52
|
} = $derived.by(() => {
|
|
48
53
|
return {
|
|
49
54
|
...props,
|
|
50
|
-
...resolveOverrideProperties(
|
|
55
|
+
...resolveOverrideProperties(conditionContext, props.overrides),
|
|
51
56
|
};
|
|
52
57
|
});
|
|
53
58
|
|
|
59
|
+
const source = $derived(
|
|
60
|
+
resolveLocalizedSource(
|
|
61
|
+
props,
|
|
62
|
+
"override_video_lid",
|
|
63
|
+
conditionContext,
|
|
64
|
+
getLocalizedVideo,
|
|
65
|
+
),
|
|
66
|
+
);
|
|
67
|
+
|
|
54
68
|
const getColorMode = getColorModeContext();
|
|
55
69
|
const colorMode = $derived(getColorMode());
|
|
56
70
|
const video: VideoFiles | null = $derived(
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import type { Localizations } from "../types/localization";
|
|
2
|
-
import type { ImageInfo } from "../types/media";
|
|
1
|
+
import type { Localizations, VideoLocalizations } from "../types/localization";
|
|
2
|
+
import type { ImageInfo, VideoInfo } from "../types/media";
|
|
3
3
|
type GetLocalizedString = (id?: string) => string | undefined;
|
|
4
4
|
export type GetLocalizedImage = (id?: string) => ImageInfo | undefined;
|
|
5
|
+
export type GetLocalizedVideo = (id?: string) => VideoInfo | undefined;
|
|
5
6
|
interface LocalizationContext {
|
|
6
7
|
getLocalizedString: GetLocalizedString;
|
|
7
8
|
getLocalizedImage: GetLocalizedImage;
|
|
9
|
+
getLocalizedVideo: GetLocalizedVideo;
|
|
8
10
|
}
|
|
9
11
|
export interface LocalizationContextProps {
|
|
10
12
|
defaultLocale: string;
|
|
11
13
|
selectedLocale?: string;
|
|
12
14
|
localizations: Localizations;
|
|
15
|
+
videoLocalizations?: VideoLocalizations;
|
|
13
16
|
}
|
|
14
17
|
export declare function setLocalizationContext(props: () => LocalizationContextProps): LocalizationContext;
|
|
15
18
|
export declare function getLocalizationContext(): LocalizationContext;
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import { getContext, setContext } from "svelte";
|
|
2
2
|
const key = Symbol("localization");
|
|
3
3
|
export function setLocalizationContext(props) {
|
|
4
|
-
const
|
|
4
|
+
const lookup = (table, id) => {
|
|
5
5
|
if (!id) {
|
|
6
6
|
return undefined;
|
|
7
7
|
}
|
|
8
|
-
const { selectedLocale, defaultLocale
|
|
8
|
+
const { selectedLocale, defaultLocale } = props();
|
|
9
9
|
const locale = selectedLocale ?? defaultLocale;
|
|
10
|
-
const selected =
|
|
11
|
-
const fallback =
|
|
10
|
+
const selected = table[locale]?.[id];
|
|
11
|
+
const fallback = table[defaultLocale]?.[id];
|
|
12
12
|
return selected ?? fallback;
|
|
13
13
|
};
|
|
14
14
|
const getLocalizedString = (id) => {
|
|
15
15
|
if (!id) {
|
|
16
16
|
return "";
|
|
17
17
|
}
|
|
18
|
-
const value =
|
|
18
|
+
const value = lookup(props().localizations, id);
|
|
19
19
|
return typeof value === "string" ? value : undefined;
|
|
20
20
|
};
|
|
21
21
|
const getLocalizedImage = (id) => {
|
|
22
|
-
const value =
|
|
22
|
+
const value = lookup(props().localizations, id);
|
|
23
23
|
return typeof value === "object" ? value : undefined;
|
|
24
24
|
};
|
|
25
|
+
const getLocalizedVideo = (id) => lookup(props().videoLocalizations ?? {}, id);
|
|
25
26
|
const context = {
|
|
26
27
|
getLocalizedString,
|
|
27
28
|
getLocalizedImage,
|
|
29
|
+
getLocalizedVideo,
|
|
28
30
|
};
|
|
29
31
|
setContext(key, context);
|
|
30
32
|
return context;
|
package/dist/stories/fixtures.js
CHANGED
|
@@ -5388,7 +5388,7 @@ export const fontsPaywallData = {
|
|
|
5388
5388
|
ptR0PssHwi: "Heading L",
|
|
5389
5389
|
wGpryncQ4j: "Semibold",
|
|
5390
5390
|
zZXnBwaz8X: "Heading S",
|
|
5391
|
-
uzD2rPJ68m: "**this is bold text**\\\n*this is italics*\\\n~this is strikethrough~\\\n`this is code`\\\n[this is a link](https://www.google.com)",
|
|
5391
|
+
uzD2rPJ68m: "**this is bold text**\\\n*this is italics*\\\n~this is strikethrough~\\\n<u>this is underlined</u>\\\n`this is code`\\\n[this is a link](https://www.google.com)",
|
|
5392
5392
|
},
|
|
5393
5393
|
},
|
|
5394
5394
|
created_at: "2024-11-08T21:39:13Z",
|
|
@@ -6443,7 +6443,7 @@ export const customFontsPaywallData = {
|
|
|
6443
6443
|
ptR0PssHwi: "Heading L",
|
|
6444
6444
|
wGpryncQ4j: "Semibold",
|
|
6445
6445
|
zZXnBwaz8X: "Heading S",
|
|
6446
|
-
uzD2rPJ68m: "**this is bold text**\\\n*this is italics*\\\n~this is strikethrough~\\\n`this is code`\\\n[this is a link](https://www.google.com)",
|
|
6446
|
+
uzD2rPJ68m: "**this is bold text**\\\n*this is italics*\\\n~this is strikethrough~\\\n<u>this is underlined</u>\\\n`this is code`\\\n[this is a link](https://www.google.com)",
|
|
6447
6447
|
},
|
|
6448
6448
|
},
|
|
6449
6449
|
created_at: "2024-11-08T21:39:13Z",
|
|
@@ -18,7 +18,7 @@ export interface VideoProps extends BaseComponent {
|
|
|
18
18
|
visible?: boolean | null;
|
|
19
19
|
source: VideoInfo | null;
|
|
20
20
|
fallback_source?: ImageInfo | null;
|
|
21
|
-
|
|
21
|
+
override_video_lid?: string | null;
|
|
22
22
|
size: SizeType;
|
|
23
23
|
mask_shape?: RectangleShape | CircleShape | ConcaveShape | ConvexShape | null;
|
|
24
24
|
fit_mode: FitMode;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ImageInfo } from "./media";
|
|
1
|
+
import type { ImageInfo, VideoInfo } from "./media";
|
|
2
2
|
export type LocalizationValue = string | ImageInfo;
|
|
3
3
|
type Localization = Partial<Record<string, LocalizationValue>>;
|
|
4
4
|
export type Localizations = Partial<Record<string, Localization>>;
|
|
5
|
+
export type VideoLocalizations = Partial<Record<string, Partial<Record<string, VideoInfo>>>>;
|
|
5
6
|
export {};
|
package/dist/types/paywall.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ColorScheme } from "./colors";
|
|
|
3
3
|
import type { FooterProps } from "./components/footer";
|
|
4
4
|
import type { HeaderProps } from "./components/header";
|
|
5
5
|
import type { StackProps } from "./components/stack";
|
|
6
|
-
import type { Localizations } from "./localization";
|
|
6
|
+
import type { Localizations, VideoLocalizations } from "./localization";
|
|
7
7
|
import type { StateDeclaration } from "./state";
|
|
8
8
|
export interface RootPaywall {
|
|
9
9
|
background?: Background;
|
|
@@ -29,6 +29,7 @@ export interface PaywallData {
|
|
|
29
29
|
default_locale: string;
|
|
30
30
|
components_config: ComponentConfig;
|
|
31
31
|
components_localizations: Localizations;
|
|
32
|
+
components_video_localizations?: VideoLocalizations;
|
|
32
33
|
/** Declared paywall-state keys (key → {type, default}). Absent on paywalls without state. */
|
|
33
34
|
state_declarations?: Record<string, StateDeclaration>;
|
|
34
35
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Overrides } from "../types/overrides";
|
|
2
|
+
import { type ConditionContext } from "./style-utils";
|
|
3
|
+
type LocalizedSourceFields<Source, LidKey extends string> = {
|
|
4
|
+
source?: Source;
|
|
5
|
+
} & Partial<Record<LidKey, string | null>>;
|
|
6
|
+
type LocalizedSourceProps<Source, LidKey extends string> = LocalizedSourceFields<Source, LidKey> & {
|
|
7
|
+
source: Source;
|
|
8
|
+
overrides?: Overrides<LocalizedSourceFields<Source, LidKey>>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the media source to render for a component, preferring a matching
|
|
12
|
+
* override but defaulting to the component's source. At each level, a
|
|
13
|
+
* localized source referenced by `lidKey` wins over the inline `source`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveLocalizedSource<Source, LidKey extends string>(props: LocalizedSourceProps<Source, LidKey>, lidKey: LidKey, context: ConditionContext, getLocalizedSource: (id?: string) => NonNullable<Source> | undefined): Source;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { filterMatchingOverrides, } from "./style-utils";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the media source to render for a component, preferring a matching
|
|
4
|
+
* override but defaulting to the component's source. At each level, a
|
|
5
|
+
* localized source referenced by `lidKey` wins over the inline `source`.
|
|
6
|
+
*/
|
|
7
|
+
export function resolveLocalizedSource(props, lidKey, context, getLocalizedSource) {
|
|
8
|
+
const resolve = (source, lid) => (lid ? (getLocalizedSource(lid) ?? source) : source);
|
|
9
|
+
let resolvedOverrideSource;
|
|
10
|
+
for (const override of filterMatchingOverrides(context, props.overrides)) {
|
|
11
|
+
const source = resolve(override.properties.source, override.properties[lidKey]);
|
|
12
|
+
if (source) {
|
|
13
|
+
resolvedOverrideSource = source;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return (resolvedOverrideSource ??
|
|
17
|
+
resolve(props.source, props[lidKey]) ??
|
|
18
|
+
props.source);
|
|
19
|
+
}
|
|
@@ -35,7 +35,7 @@ export type ConditionContext = {
|
|
|
35
35
|
* Returns the overrides (in array order) whose conditions all match (AND) the
|
|
36
36
|
* given context, without merging their properties.
|
|
37
37
|
*/
|
|
38
|
-
export declare const filterMatchingOverrides: <T
|
|
38
|
+
export declare const filterMatchingOverrides: <T>(context: ConditionContext, overrides?: Overrides<T>) => Overrides<T>;
|
|
39
39
|
/**
|
|
40
40
|
* Merges the properties of every override whose conditions all match (AND),
|
|
41
41
|
* applying them in override-array order (later overrides overwrite earlier ones).
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { ImageProps } from "../../types/components/image";
|
|
2
|
-
import type { ImageInfo } from "../../types/media";
|
|
3
|
-
import { type ConditionContext } from "../../utils/style-utils";
|
|
4
|
-
import type { GetLocalizedImage } from "../../stores/localization";
|
|
5
|
-
/**
|
|
6
|
-
* Resolves the ImageInfo to render for an image component, preferring
|
|
7
|
-
* a matching override but defaulting to the image source.
|
|
8
|
-
*/
|
|
9
|
-
export declare function resolveImageSource(props: ImageProps, context: ConditionContext, getLocalizedImage: GetLocalizedImage): ImageInfo;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { filterMatchingOverrides, } from "../../utils/style-utils";
|
|
2
|
-
/**
|
|
3
|
-
* Resolves the ImageInfo to render for an image component, preferring
|
|
4
|
-
* a matching override but defaulting to the image source.
|
|
5
|
-
*/
|
|
6
|
-
export function resolveImageSource(props, context, getLocalizedImage) {
|
|
7
|
-
const resolveLocalizedSource = (source, overrideSourceLid) => overrideSourceLid
|
|
8
|
-
? (getLocalizedImage(overrideSourceLid) ?? source)
|
|
9
|
-
: source;
|
|
10
|
-
let resolvedOverrideImage;
|
|
11
|
-
for (const override of filterMatchingOverrides(context, props.overrides)) {
|
|
12
|
-
const image = resolveLocalizedSource(override.properties.source, override.properties.override_source_lid);
|
|
13
|
-
if (image) {
|
|
14
|
-
resolvedOverrideImage = image;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return (resolvedOverrideImage ??
|
|
18
|
-
resolveLocalizedSource(props.source, props.override_source_lid) ??
|
|
19
|
-
props.source);
|
|
20
|
-
}
|