@revenuecat/purchases-ui-js 0.0.15 → 0.0.17

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.
Files changed (51) hide show
  1. package/dist/components/button/Button.svelte.d.ts +4 -2
  2. package/dist/components/button/ButtonNode.stories.svelte +2 -4
  3. package/dist/components/button/ButtonNode.svelte.d.ts +1 -0
  4. package/dist/components/footer/Footer.stories.svelte +46 -156
  5. package/dist/components/footer/Footer.stories.svelte.d.ts +1 -2
  6. package/dist/components/footer/Footer.svelte +9 -0
  7. package/dist/components/footer/Footer.svelte.d.ts +1 -0
  8. package/dist/components/image/Image.stories.svelte +9 -7
  9. package/dist/components/image/Image.svelte +18 -3
  10. package/dist/components/image/Image.svelte.d.ts +1 -0
  11. package/dist/components/image/image-utils.js +5 -4
  12. package/dist/components/package/Package.stories.svelte +0 -2
  13. package/dist/components/package/Package.svelte.d.ts +1 -0
  14. package/dist/components/paywall/Node.svelte +8 -1
  15. package/dist/components/paywall/Node.svelte.d.ts +4 -2
  16. package/dist/components/paywall/Paywall.stories.svelte +79 -15
  17. package/dist/components/paywall/Paywall.svelte +41 -22
  18. package/dist/components/paywall/Paywall.svelte.d.ts +4 -0
  19. package/dist/components/purchase-button/PurchaseButton.stories.svelte +0 -2
  20. package/dist/components/purchase-button/PurchaseButton.svelte.d.ts +1 -0
  21. package/dist/components/stack/Stack.stories.svelte +0 -2
  22. package/dist/components/stack/Stack.svelte +3 -0
  23. package/dist/components/stack/Stack.svelte.d.ts +1 -0
  24. package/dist/components/stack/stack-utils.js +3 -3
  25. package/dist/components/text/Text.svelte.d.ts +4 -2
  26. package/dist/components/text/TextNode.stories.svelte +1 -2
  27. package/dist/components/text/TextNode.svelte +5 -12
  28. package/dist/components/text/TextNode.svelte.d.ts +1 -0
  29. package/dist/components/text/text-utils.d.ts +5 -2
  30. package/dist/components/text/text-utils.js +9 -9
  31. package/dist/components/timeline/Timeline.stories.svelte +640 -0
  32. package/dist/components/timeline/Timeline.stories.svelte.d.ts +19 -0
  33. package/dist/components/timeline/Timeline.svelte +40 -0
  34. package/dist/components/timeline/Timeline.svelte.d.ts +4 -0
  35. package/dist/components/timeline/TimelineItem.svelte +100 -0
  36. package/dist/components/timeline/TimelineItem.svelte.d.ts +4 -0
  37. package/dist/components/timeline/timeline-utils.d.ts +25 -0
  38. package/dist/components/timeline/timeline-utils.js +93 -0
  39. package/dist/data/entities.d.ts +62 -21
  40. package/dist/data/state.d.ts +2 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.js +1 -0
  43. package/dist/stories/fixtures.d.ts +5 -0
  44. package/dist/stories/fixtures.js +4716 -33
  45. package/dist/stories/meta-templates.d.ts +0 -1
  46. package/dist/stories/meta-templates.js +0 -5
  47. package/dist/types.d.ts +12 -4
  48. package/dist/types.js +7 -0
  49. package/dist/utils/style-utils.d.ts +36 -4
  50. package/dist/utils/style-utils.js +82 -13
  51. package/package.json +27 -25
@@ -7,7 +7,6 @@ export declare const fontWeightStoryMeta: InputType;
7
7
  export declare const fontSizeStoryMeta: InputType;
8
8
  export declare const textStyleStoryMeta: InputType;
9
9
  export declare const horizontalAlignmentStoryMeta: InputType;
10
- export declare const colorModeStoryMeta: InputType;
11
10
  export declare const shadowStoryMeta: InputType;
12
11
  export declare const borderStoryMeta: InputType;
13
12
  export declare const sizeStoryMeta: InputType;
@@ -85,11 +85,6 @@ export const horizontalAlignmentStoryMeta = {
85
85
  options: ["center", "start", "end"],
86
86
  description: "Text horizontal alignment",
87
87
  };
88
- export const colorModeStoryMeta = {
89
- control: { type: "select" },
90
- options: ["light", "dark"],
91
- description: "Color mode",
92
- };
93
88
  export const shadowStoryMeta = {
94
89
  control: {
95
90
  type: "object",
package/dist/types.d.ts CHANGED
@@ -3,7 +3,7 @@ export type ColorStop = {
3
3
  color: string;
4
4
  percent: number;
5
5
  };
6
- type Color = {
6
+ export type Color = {
7
7
  type: "hex" | "alias" | "linear" | "radial";
8
8
  value?: string;
9
9
  degrees?: number;
@@ -48,7 +48,11 @@ export declare enum FontSizes {
48
48
  heading_xl = "26px",
49
49
  heading_xxl = "32px"
50
50
  }
51
- export type TextAlignment = "center" | "start" | "end";
51
+ export declare enum TextAlignments {
52
+ leading = "start",
53
+ center = "center",
54
+ trailing = "end"
55
+ }
52
56
  export type SizeType = {
53
57
  width: Size;
54
58
  height: Size;
@@ -63,10 +67,13 @@ type RelativeSize = {
63
67
  type: FitTypes;
64
68
  };
65
69
  export type ShapeType = RectangleShape | PillShape;
66
- type RectangleShape = {
70
+ export type RectangleShape = {
67
71
  type: "rectangle";
68
72
  corners: CornerRadiusType;
69
73
  };
74
+ export type CircleShape = {
75
+ type: "circle";
76
+ };
70
77
  type PillShape = {
71
78
  type: "pill";
72
79
  };
@@ -111,7 +118,8 @@ export type ShadowType = {
111
118
  };
112
119
  export declare enum StackDirection {
113
120
  vertical = "column",
114
- horizontal = "row"
121
+ horizontal = "row",
122
+ zlayer = "zstack"
115
123
  }
116
124
  export declare enum StackAlignment {
117
125
  top = "flex-start",
package/dist/types.js CHANGED
@@ -37,10 +37,17 @@ export var FontSizes;
37
37
  FontSizes["heading_xl"] = "26px";
38
38
  FontSizes["heading_xxl"] = "32px";
39
39
  })(FontSizes || (FontSizes = {}));
40
+ export var TextAlignments;
41
+ (function (TextAlignments) {
42
+ TextAlignments["leading"] = "start";
43
+ TextAlignments["center"] = "center";
44
+ TextAlignments["trailing"] = "end";
45
+ })(TextAlignments || (TextAlignments = {}));
40
46
  export var StackDirection;
41
47
  (function (StackDirection) {
42
48
  StackDirection["vertical"] = "column";
43
49
  StackDirection["horizontal"] = "row";
50
+ StackDirection["zlayer"] = "zstack";
44
51
  })(StackDirection || (StackDirection = {}));
45
52
  export var StackAlignment;
46
53
  (function (StackAlignment) {
@@ -1,5 +1,6 @@
1
1
  import type { ComponentLocalizations, ComponentState, ImageMaskShapeType, PaywallData, TextNodeProps } from "../data/entities.js";
2
- import { type BorderType, type ColorMode, type ColorType, type DimensionType, FontSizeTags, type ShadowType, type ShapeType, type SizeType, type Spacing } from "../types.js";
2
+ import { type VariableDictionary } from "./variable-utils.js";
3
+ import { type BorderType, type ColorMode, type ColorType, type CornerRadiusType, type DimensionType, FontSizeTags, type ShadowType, type ShapeType, type SizeType, type Spacing } from "../types.js";
3
4
  export type TextComponentTags = "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
4
5
  /**
5
6
  * Maps font size to appropriate HTML heading tag
@@ -17,6 +18,19 @@ export declare function getColor({ colorMap, colorMode, fallback, }: {
17
18
  colorMode?: ColorMode;
18
19
  fallback?: string;
19
20
  }): string;
21
+ /**
22
+ * Generates CSS border style string
23
+ * @param border - Border configuration object
24
+ * @param colorMode - Color mode (light/dark)
25
+ * @returns CSS border style string
26
+ */
27
+ export declare function getBorderStyle(border?: BorderType, colorMode?: ColorMode): string;
28
+ /**
29
+ * Generates CSS border radius style for corners
30
+ * @param corners - Corner radius configuration
31
+ * @returns CSS border radius string
32
+ */
33
+ export declare function getCornerRadiusStyle(corners: CornerRadiusType): string;
20
34
  /**
21
35
  * Generates comprehensive component styles including spacing, colors, borders and shadows
22
36
  * @param params - Component style configuration object
@@ -51,7 +65,7 @@ export declare function getComponentStyles({ backgroundColor, border, margin, pa
51
65
  * @param size - Size configuration object
52
66
  * @returns CSS style object with size properties
53
67
  */
54
- export declare function getSizeStyle(size: SizeType): {
68
+ export declare function getSizeStyle(size: SizeType, isZStack?: boolean): {
55
69
  "--width": string;
56
70
  "--height": string;
57
71
  "--flex": string;
@@ -83,6 +97,9 @@ export declare function getDimensionStyle(dimension: DimensionType): {
83
97
  "--direction": string;
84
98
  "--alignment": string;
85
99
  "--distribution": string;
100
+ "--position": string;
101
+ "--inset": string;
102
+ "--transform": string;
86
103
  };
87
104
  /**
88
105
  * Generates text-related styles
@@ -90,7 +107,7 @@ export declare function getDimensionStyle(dimension: DimensionType): {
90
107
  * @param colorMode - The currently selected ColorMode (dark/light)
91
108
  * @returns CSS style object with text formatting properties
92
109
  */
93
- export declare function getTextStyles(props: TextNodeProps, colorMode?: ColorMode): any;
110
+ export declare function getTextStyles(props: TextNodeProps, colorMode?: ColorMode): Record<string, unknown>;
94
111
  /**
95
112
  * Converts a style object to a CSS string
96
113
  * @param styles - Object containing CSS properties and values
@@ -108,10 +125,25 @@ export declare function stringifyStyles(styles: Record<string, string | number>)
108
125
  * @returns The label in the preferred or fallback locale, or undefined.
109
126
  */
110
127
  export declare function getLabelById(label_id: string, locale: string, fallbackLocale: string, labels: ComponentLocalizations): string | undefined;
128
+ /**
129
+ * Gets a label by ID and replaces any variables in it with values from the dictionary
130
+ * @param text_lid - The ID of the text label to retrieve
131
+ * @param purchaseState - Object containing locale and defaultLocale
132
+ * @param labels - ComponentLocalizations containing the labels
133
+ * @param variableDictionary - Dictionary of variables to replace in the label text
134
+ * @returns The label with variables replaced, or undefined if label not found
135
+ */
136
+ export declare function getLabelAndReplaceVariables({ text_lid, locale, defaultLocale, labels, variableDictionary, }: {
137
+ text_lid?: string;
138
+ locale: string;
139
+ defaultLocale: string;
140
+ labels: ComponentLocalizations;
141
+ variableDictionary?: VariableDictionary;
142
+ }): string | undefined;
111
143
  /**
112
144
  * Given an instance of PaywallData, returns the id of the first package marked as `is_selected_by_default` if any.
113
145
  * @param paywallData
114
146
  * @returns the id of the first package marked as `is_selected_by_default` or undefined
115
147
  */
116
148
  export declare function findSelectedPackageId(paywallData: PaywallData): string | undefined;
117
- export declare const getActiveStateProps: <T>(overrides?: Record<"states", Record<string, T>>, componentState?: ComponentState) => T;
149
+ export declare const getActiveStateProps: <T>(overrides?: Record<string, T>, componentState?: ComponentState) => T;
@@ -1,4 +1,5 @@
1
- import { FontSizes, FontSizeTags, FontWeights, StackAlignment, StackDirection, StackDistribution, } from "../types.js";
1
+ import { replaceVariables, } from "./variable-utils.js";
2
+ import { FontSizes, FontSizeTags, FontWeights, StackAlignment, StackDirection, StackDistribution, TextAlignments, } from "../types.js";
2
3
  /**
3
4
  * Generates CSS spacing styles for margin or padding
4
5
  * @param spacing - The spacing object containing top, trailing, bottom, and leading values
@@ -47,8 +48,9 @@ export function getColor({ colorMap, colorMode = "light", fallback = "FFFFFF", }
47
48
  .map((point) => `${point.color} ${point.percent}%`)
48
49
  .join(", ");
49
50
  return `radial-gradient(${colorPoints})`;
51
+ default:
52
+ return fallback;
50
53
  }
51
- return fallback;
52
54
  }
53
55
  /**
54
56
  * Generates CSS border style string
@@ -56,7 +58,9 @@ export function getColor({ colorMap, colorMode = "light", fallback = "FFFFFF", }
56
58
  * @param colorMode - Color mode (light/dark)
57
59
  * @returns CSS border style string
58
60
  */
59
- function getBorderStyle(border, colorMode = "light") {
61
+ export function getBorderStyle(border, colorMode = "light") {
62
+ if (!border)
63
+ return "";
60
64
  const color = getColor({ colorMap: border.color, colorMode });
61
65
  return `${border.width}px solid ${color}`;
62
66
  }
@@ -65,7 +69,7 @@ function getBorderStyle(border, colorMode = "light") {
65
69
  * @param corners - Corner radius configuration
66
70
  * @returns CSS border radius string
67
71
  */
68
- function getCornerRadiusStyle(corners) {
72
+ export function getCornerRadiusStyle(corners) {
69
73
  return `${corners.top_leading}px ${corners.top_trailing}px ${corners.bottom_trailing}px ${corners.bottom_leading}px`;
70
74
  }
71
75
  /**
@@ -129,12 +133,12 @@ export function getComponentStyles({ backgroundColor, border, margin, padding, t
129
133
  * @param size - Size configuration object
130
134
  * @returns CSS style object with size properties
131
135
  */
132
- export function getSizeStyle(size) {
136
+ export function getSizeStyle(size, isZStack = false) {
133
137
  function getSizeValue(size) {
134
138
  if (size.type === "fixed") {
135
139
  return `${size.value}px`;
136
140
  }
137
- if (size.type === "fit") {
141
+ if (size.type === "fit" || isZStack) {
138
142
  return "fit-content";
139
143
  }
140
144
  if (size.type === "fill") {
@@ -172,7 +176,7 @@ export function getGradientStyle(colorMode, gradientColors) {
172
176
  * @returns CSS style object with mask properties
173
177
  */
174
178
  export const getMaskStyle = (maskShape) => {
175
- let maskStyles = {
179
+ const maskStyles = {
176
180
  "--corner-radius": "0px",
177
181
  "--clip-path": "none",
178
182
  };
@@ -192,6 +196,47 @@ export const getMaskStyle = (maskShape) => {
192
196
  }
193
197
  return maskStyles;
194
198
  };
199
+ function getInsetStyles(dimension) {
200
+ const defaultStyles = {
201
+ "--inset": "initial",
202
+ "--transform": "initial",
203
+ };
204
+ switch (dimension.alignment) {
205
+ case "top_leading":
206
+ defaultStyles["--inset"] = "0 auto auto 0";
207
+ break;
208
+ case "top":
209
+ defaultStyles["--inset"] = "0 50%";
210
+ defaultStyles["--transform"] = "translate(-50%, 0)";
211
+ break;
212
+ case "top_trailing":
213
+ defaultStyles["--inset"] = "0 0 auto auto";
214
+ break;
215
+ case "leading":
216
+ defaultStyles["--inset"] = "50% 0 50% 0";
217
+ defaultStyles["--transform"] = "translate(0, -50%)";
218
+ break;
219
+ case "center":
220
+ defaultStyles["--inset"] = "50% 50% 50% 50%";
221
+ defaultStyles["--transform"] = "translate(-50%, -50%)";
222
+ break;
223
+ case "trailing":
224
+ defaultStyles["--inset"] = "50% 0 50% auto";
225
+ defaultStyles["--transform"] = "translate(0, -50%)";
226
+ break;
227
+ case "bottom_leading":
228
+ defaultStyles["--inset"] = "auto auto 0 0";
229
+ break;
230
+ case "bottom":
231
+ defaultStyles["--inset"] = "auto 50% 0 50%";
232
+ defaultStyles["--transform"] = "translate(-50%, 0)";
233
+ break;
234
+ case "bottom_trailing":
235
+ defaultStyles["--inset"] = "auto 0 0 auto";
236
+ break;
237
+ }
238
+ return defaultStyles;
239
+ }
195
240
  /**
196
241
  * Generates dimension-related styles for stack components
197
242
  * @param dimension - Dimension configuration object
@@ -202,9 +247,14 @@ export function getDimensionStyle(dimension) {
202
247
  "--direction": "initial",
203
248
  "--alignment": "initial",
204
249
  "--distribution": "initial",
250
+ "--position": "relative",
251
+ "--inset": "unset",
252
+ "--transform": "unset",
205
253
  };
206
254
  if (dimension.type === "zlayer") {
207
- // TODO: Review with Monetization team
255
+ styles["--position"] = "absolute";
256
+ const insetStyles = getInsetStyles(dimension);
257
+ Object.assign(styles, insetStyles);
208
258
  }
209
259
  else {
210
260
  styles["--direction"] = StackDirection[dimension.type];
@@ -231,7 +281,8 @@ export function getTextStyles(props, colorMode = "light") {
231
281
  "--background-clip": "initial",
232
282
  "--text-fill-color": "initial",
233
283
  };
234
- styles["--text-align"] = horizontal_alignment;
284
+ styles["--text-align"] =
285
+ TextAlignments[horizontal_alignment] || TextAlignments.leading;
235
286
  styles["--font-weight"] = FontWeights[font_weight] || FontWeights.regular;
236
287
  styles["--font-size"] = FontSizes[font_size] || FontSizes.body_m;
237
288
  styles["--font-family"] = font_name || "sans-serif";
@@ -264,12 +315,30 @@ export function stringifyStyles(styles) {
264
315
  * @returns The label in the preferred or fallback locale, or undefined.
265
316
  */
266
317
  export function getLabelById(label_id, locale, fallbackLocale, labels) {
267
- const fallback = (labels[fallbackLocale] || {})[label_id];
318
+ const fallback = labels[fallbackLocale]?.[label_id];
268
319
  if (!(labels[locale] || {})[label_id]) {
269
320
  return fallback;
270
321
  }
271
322
  return labels[locale][label_id];
272
323
  }
324
+ /**
325
+ * Gets a label by ID and replaces any variables in it with values from the dictionary
326
+ * @param text_lid - The ID of the text label to retrieve
327
+ * @param purchaseState - Object containing locale and defaultLocale
328
+ * @param labels - ComponentLocalizations containing the labels
329
+ * @param variableDictionary - Dictionary of variables to replace in the label text
330
+ * @returns The label with variables replaced, or undefined if label not found
331
+ */
332
+ export function getLabelAndReplaceVariables({ text_lid, locale, defaultLocale, labels, variableDictionary, }) {
333
+ if (!text_lid)
334
+ return "";
335
+ const label = getLabelById(text_lid, locale, defaultLocale, labels);
336
+ const parsedLabel = replaceVariables({
337
+ value: label,
338
+ variableDictionary,
339
+ });
340
+ return parsedLabel;
341
+ }
273
342
  /**
274
343
  * Given an instance of PaywallData, returns the id of the first package marked as `is_selected_by_default` if any.
275
344
  * @param paywallData
@@ -281,8 +350,8 @@ export function findSelectedPackageId(paywallData) {
281
350
  node.is_selected_by_default) {
282
351
  return node;
283
352
  }
284
- if (node.components) {
285
- for (let c of node.components) {
353
+ if (node.components && Array.isArray(node.components)) {
354
+ for (const c of node.components) {
286
355
  const pkg = traverseNode(c);
287
356
  if (pkg) {
288
357
  return pkg;
@@ -309,7 +378,7 @@ export const getActiveStateProps = (overrides, componentState) => {
309
378
  const activeStateKeys = getComponentActiveStateKeys(componentState);
310
379
  const activeStateProps = activeStateKeys.reduce((props, key) => {
311
380
  if (overrides) {
312
- const styles = overrides.states[key];
381
+ const styles = overrides[key] || {};
313
382
  return { ...props, ...styles };
314
383
  }
315
384
  return props;
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": "0.0.15",
5
+ "version": "0.0.17",
6
6
  "author": {
7
7
  "name": "RevenueCat, Inc."
8
8
  },
@@ -36,7 +36,8 @@
36
36
  "chromatic": "chromatic",
37
37
  "format": "prettier --write .",
38
38
  "typecheck": "tsc --noEmit",
39
- "test": "vitest"
39
+ "test": "vitest",
40
+ "lint": "eslint --config eslint.config.js src/**/*"
40
41
  },
41
42
  "files": [
42
43
  "dist",
@@ -57,39 +58,40 @@
57
58
  }
58
59
  },
59
60
  "peerDependencies": {
60
- "svelte": "^5.0.0"
61
+ "svelte": "^5.3.0"
61
62
  },
62
63
  "devDependencies": {
63
- "@chromatic-com/storybook": "^1.9.0",
64
+ "@chromatic-com/storybook": "^3.2.2",
64
65
  "@eslint/js": "^9.16.0",
65
- "@storybook/addon-essentials": "^8.3.6",
66
- "@storybook/addon-interactions": "^8.3.6",
67
- "@storybook/addon-links": "^8.3.6",
68
- "@storybook/addon-svelte-csf": "^5.0.0-next.9",
69
- "@storybook/blocks": "^8.3.6",
70
- "@storybook/svelte": "^8.3.6",
71
- "@storybook/sveltekit": "^8.3.6",
72
- "@storybook/test": "^8.3.6",
66
+ "@storybook/addon-essentials": "^8.4.7",
67
+ "@storybook/addon-interactions": "^8.4.7",
68
+ "@storybook/addon-links": "^8.4.7",
69
+ "@storybook/addon-svelte-csf": "^5.0.0-next.14",
70
+ "@storybook/blocks": "^8.4.7",
71
+ "@storybook/svelte": "^8.4.7",
72
+ "@storybook/sveltekit": "^8.4.7",
73
+ "@storybook/test": "^8.4.7",
73
74
  "@sveltejs/adapter-node": "^5.2.9",
74
- "@sveltejs/kit": "^2.0.0",
75
- "@sveltejs/package": "^2.0.0",
76
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
75
+ "@sveltejs/kit": "^2.9.0",
76
+ "@sveltejs/package": "^2.3.7",
77
+ "@sveltejs/vite-plugin-svelte": "^5.0.2",
77
78
  "@typescript-eslint/parser": "^8.17.0",
78
- "chromatic": "^11.16.1",
79
+ "chromatic": "^11.20.0",
79
80
  "eslint": "^9.16.0",
80
81
  "eslint-plugin-svelte": "^2.46.1",
81
82
  "globals": "^15.13.0",
82
- "husky": "^9.1.6",
83
+ "husky": "^9.1.7",
83
84
  "lint-staged": "^15.2.10",
84
- "prettier": "^3.3.3",
85
- "prettier-plugin-svelte": "^3.2.7",
86
- "publint": "^0.2.0",
87
- "storybook": "^8.3.6",
88
- "svelte": "^5.0.0",
89
- "svelte-check": "^4.0.0",
90
- "typescript": "^5.0.0",
85
+ "prettier": "^3.4.2",
86
+ "prettier-plugin-svelte": "^3.3.2",
87
+ "publint": "^0.2.12",
88
+ "storybook": "^8.4.7",
89
+ "svelte": "^5.9.1",
90
+ "svelte-check": "^4.1.1",
91
+ "typescript": "^5.7.2",
91
92
  "typescript-eslint": "^8.17.0",
92
- "vite": "^5.0.11"
93
+ "vite": "^6.0.3",
94
+ "vitest": "^2.1.8"
93
95
  },
94
96
  "lint-staged": {
95
97
  "**/*": [