@revenuecat/purchases-ui-js 2.0.1 → 2.0.3

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 (138) hide show
  1. package/dist/components/button/ButtonNode.stories.svelte +66 -108
  2. package/dist/components/button/ButtonNode.svelte +3 -31
  3. package/dist/components/footer/Footer.stories.svelte +112 -106
  4. package/dist/components/footer/Footer.svelte +10 -6
  5. package/dist/components/icon/Icon.stories.svelte +100 -0
  6. package/dist/components/icon/Icon.stories.svelte.d.ts +19 -0
  7. package/dist/components/icon/Icon.svelte +73 -0
  8. package/dist/components/icon/Icon.svelte.d.ts +4 -0
  9. package/dist/components/image/ClipPath.svelte +49 -0
  10. package/dist/components/image/ClipPath.svelte.d.ts +9 -0
  11. package/dist/components/image/Image.stories.svelte +83 -199
  12. package/dist/components/image/Image.svelte +152 -137
  13. package/dist/components/image/Image.svelte.d.ts +1 -1
  14. package/dist/components/image/Overlay.svelte +36 -0
  15. package/dist/components/image/Overlay.svelte.d.ts +8 -0
  16. package/dist/components/package/Package.stories.svelte +12 -27
  17. package/dist/components/package/Package.svelte +10 -44
  18. package/dist/components/paywall/Node.svelte +45 -43
  19. package/dist/components/paywall/Node.svelte.d.ts +10 -12
  20. package/dist/components/paywall/Paywall.stories.svelte +36 -140
  21. package/dist/components/paywall/Paywall.svelte +38 -20
  22. package/dist/components/paywall/Paywall.svelte.d.ts +3 -2
  23. package/dist/components/paywall/fixtures/override-paywall.d.ts +2 -0
  24. package/dist/components/paywall/fixtures/override-paywall.js +1310 -0
  25. package/dist/components/paywall/fixtures/stack-paywall.d.ts +2 -0
  26. package/dist/components/paywall/fixtures/stack-paywall.js +5223 -0
  27. package/dist/components/paywall/fixtures/variables.d.ts +261 -0
  28. package/dist/components/paywall/fixtures/variables.js +262 -0
  29. package/dist/components/purchase-button/PurchaseButton.stories.svelte +10 -29
  30. package/dist/components/purchase-button/PurchaseButton.svelte +2 -34
  31. package/dist/components/stack/Stack.stories.svelte +2364 -1020
  32. package/dist/components/stack/Stack.svelte +108 -151
  33. package/dist/components/stack/Stack.svelte.d.ts +6 -2
  34. package/dist/components/stack/stack-utils.d.ts +10 -30
  35. package/dist/components/stack/stack-utils.js +77 -257
  36. package/dist/components/text/Text.svelte +3 -37
  37. package/dist/components/text/Text.svelte.d.ts +1 -2
  38. package/dist/components/text/TextNode.stories.svelte +10 -48
  39. package/dist/components/text/TextNode.svelte +25 -37
  40. package/dist/components/text/TextNode.svelte.d.ts +1 -1
  41. package/dist/components/text/text-utils.d.ts +4 -9
  42. package/dist/components/text/text-utils.js +32 -117
  43. package/dist/components/timeline/Timeline.stories.svelte +640 -256
  44. package/dist/components/timeline/Timeline.svelte +42 -30
  45. package/dist/components/timeline/Timeline.svelte.d.ts +1 -1
  46. package/dist/components/timeline/TimelineItem.svelte +80 -112
  47. package/dist/components/timeline/TimelineItem.svelte.d.ts +6 -2
  48. package/dist/components/timeline/timeline-utils.d.ts +24 -6
  49. package/dist/components/timeline/timeline-utils.js +21 -114
  50. package/dist/data/entities.d.ts +23 -169
  51. package/dist/index.d.ts +11 -10
  52. package/dist/index.js +11 -10
  53. package/dist/stores/color-mode.d.ts +1 -1
  54. package/dist/stores/localization.d.ts +1 -1
  55. package/dist/stores/localization.js +3 -2
  56. package/dist/stores/paywall.d.ts +7 -3
  57. package/dist/stores/selected.d.ts +5 -0
  58. package/dist/stores/selected.js +12 -0
  59. package/dist/stores/variables.d.ts +2 -3
  60. package/dist/stores/variables.js +0 -1
  61. package/dist/stories/component-decorator.d.ts +2 -0
  62. package/dist/stories/component-decorator.js +12 -0
  63. package/dist/stories/fixtures.d.ts +6 -4
  64. package/dist/stories/fixtures.js +6241 -5485
  65. package/dist/stories/localization-decorator.js +1 -1
  66. package/dist/stories/paywall-decorator.js +8 -1
  67. package/dist/stories/variables-decorator.d.ts +1 -1
  68. package/dist/stories/viewport-decorator.d.ts +2 -0
  69. package/dist/stories/viewport-decorator.js +8 -0
  70. package/dist/stories/viewport-wrapper.svelte +53 -0
  71. package/dist/stories/viewport-wrapper.svelte.d.ts +10 -0
  72. package/dist/stories/with-layout.d.ts +2 -10
  73. package/dist/stories/with-layout.js +3 -5
  74. package/dist/stories/with-layout.svelte +3 -3
  75. package/dist/types/alignment.d.ts +5 -3
  76. package/dist/types/background.d.ts +6 -5
  77. package/dist/types/base.d.ts +7 -0
  78. package/dist/types/colors.d.ts +4 -4
  79. package/dist/types/component.d.ts +10 -0
  80. package/dist/types/component.js +1 -0
  81. package/dist/types/components/button.d.ts +5 -2
  82. package/dist/types/components/footer.d.ts +3 -2
  83. package/dist/types/components/icon.d.ts +28 -0
  84. package/dist/types/components/icon.js +1 -0
  85. package/dist/types/components/image.d.ts +20 -0
  86. package/dist/types/components/image.js +1 -0
  87. package/dist/types/components/package.d.ts +3 -2
  88. package/dist/types/components/purchase-button.d.ts +3 -2
  89. package/dist/types/components/stack.d.ts +32 -0
  90. package/dist/types/components/stack.js +1 -0
  91. package/dist/types/components/text.d.ts +20 -0
  92. package/dist/types/components/text.js +1 -0
  93. package/dist/types/components/timeline.d.ts +35 -0
  94. package/dist/types/components/timeline.js +1 -0
  95. package/dist/types/localization.d.ts +2 -1
  96. package/dist/types/media.d.ts +4 -3
  97. package/dist/types/overrides.d.ts +48 -0
  98. package/dist/types/overrides.js +1 -0
  99. package/dist/types/variables.d.ts +13 -0
  100. package/dist/types/variables.js +10 -0
  101. package/dist/types.d.ts +17 -9
  102. package/dist/ui/atoms/typography.stories.svelte +3 -29
  103. package/dist/ui/atoms/typography.stories.svelte.d.ts +1 -1
  104. package/dist/ui/layout/main-block.svelte +2 -2
  105. package/dist/ui/molecules/button.stories.svelte +5 -10
  106. package/dist/ui/molecules/button.svelte +1 -1
  107. package/dist/ui/theme/colors.d.ts +0 -6
  108. package/dist/ui/theme/colors.js +1 -1
  109. package/dist/ui/theme/text.d.ts +3 -4
  110. package/dist/ui/theme/theme.d.ts +2 -2
  111. package/dist/ui/theme/theme.js +2 -2
  112. package/dist/ui/theme/utils.d.ts +2 -12
  113. package/dist/ui/theme/utils.js +5 -5
  114. package/dist/utils/background-utils.d.ts +4 -0
  115. package/dist/utils/background-utils.js +39 -0
  116. package/dist/utils/base-utils.d.ts +18 -0
  117. package/dist/utils/base-utils.js +124 -0
  118. package/dist/utils/constants.d.ts +2 -2
  119. package/dist/utils/constants.js +6 -1
  120. package/dist/utils/font-utils.d.ts +4 -0
  121. package/dist/utils/font-utils.js +47 -0
  122. package/dist/utils/style-utils.d.ts +7 -120
  123. package/dist/utils/style-utils.js +35 -314
  124. package/dist/utils/variable-utils.d.ts +1 -22
  125. package/dist/utils/variable-utils.js +28 -24
  126. package/dist/web-components/index.css +1 -1
  127. package/dist/web-components/index.js +1415 -987
  128. package/package.json +34 -24
  129. package/dist/components/button/button-utils.d.ts +0 -2
  130. package/dist/components/button/button-utils.js +0 -19
  131. package/dist/components/image/image-utils.d.ts +0 -19
  132. package/dist/components/image/image-utils.js +0 -33
  133. package/dist/components/purchase-button/purchase-button-utils.d.ts +0 -2
  134. package/dist/components/purchase-button/purchase-button-utils.js +0 -20
  135. package/dist/data/state.d.ts +0 -4
  136. package/dist/stories/meta-templates.d.ts +0 -12
  137. package/dist/stories/meta-templates.js +0 -155
  138. /package/dist/{data/state.js → types/base.js} +0 -0
@@ -1,36 +1,7 @@
1
- import { DEFAULT_COLOR_MODE, DEFAULT_TEXT_COLOR, } from "./constants.js";
2
- import { FontSizes, FontSizeTags, FontWeights, StackAlignment, StackDirection, StackDistribution, TextAlignments, } from "../types.js";
3
- /**
4
- * Generates CSS spacing styles for margin or padding
5
- * @param spacing - The spacing object containing top, trailing, bottom, and leading values
6
- * @param spacingKey - The type of spacing ('margin' or 'padding')
7
- * @returns CSS style object with logical properties for spacing
8
- */
9
- function getSpacingStyle(spacing, spacingKey) {
10
- const styles = {
11
- [`--${spacingKey}-block-start`]: "0px",
12
- [`--${spacingKey}-inline-end`]: "0px",
13
- [`--${spacingKey}-block-end`]: "0px",
14
- [`--${spacingKey}-inline-start`]: "0px",
15
- };
16
- if (!spacing || !spacingKey)
17
- return styles;
18
- Object.assign(styles, {
19
- [`--${spacingKey}-block-start`]: `${spacing.top ?? 0}px`,
20
- [`--${spacingKey}-inline-end`]: `${spacing.trailing ?? 0}px`,
21
- [`--${spacingKey}-block-end`]: `${spacing.bottom ?? 0}px`,
22
- [`--${spacingKey}-inline-start`]: `${spacing.leading ?? 0}px`,
23
- });
24
- return styles;
25
- }
26
- /**
27
- * Maps font size to appropriate HTML heading tag
28
- * @param fontSize - Key from FontSizeTags enum
29
- * @returns Corresponding HTML heading tag
30
- */
31
- export function getTextComponentTag(fontSize) {
32
- return FontSizeTags[fontSize];
33
- }
1
+ import { getPaywallContext } from "../stores/paywall.js";
2
+ import { DEFAULT_COLOR_MODE } from "./constants.js";
3
+ import { FontSizes, FontWeights, TextAlignments, } from "../types.js";
4
+ import { getScopedFontFamily, isFontRCFMManaged } from "./font-utils.js";
34
5
  /**
35
6
  * Gets color value based on color mode with fallback
36
7
  * @param params - Object containing color map, mode and fallback color
@@ -59,198 +30,6 @@ export function getColor({ colorMap, colorMode = DEFAULT_COLOR_MODE, fallback =
59
30
  return fallback;
60
31
  }
61
32
  }
62
- /**
63
- * Generates CSS border style string
64
- * @param border - Border configuration object
65
- * @param colorMode - Color mode (light/dark)
66
- * @returns CSS border style string
67
- */
68
- export function getBorderStyle(border, colorMode = DEFAULT_COLOR_MODE) {
69
- if (!border)
70
- return "";
71
- const color = getColor({ colorMap: border.color, colorMode });
72
- return `${border.width}px solid ${color}`;
73
- }
74
- /**
75
- * Generates CSS border radius style for corners
76
- * @param corners - Corner radius configuration
77
- * @returns CSS border radius string
78
- */
79
- export function getCornerRadiusStyle(corners) {
80
- return {
81
- "--border-start-start-radius": `${corners.top_leading}px`,
82
- "--border-start-end-radius": `${corners.top_trailing}px`,
83
- "--border-end-start-radius": `${corners.bottom_leading}px`,
84
- "--border-end-end-radius": `${corners.bottom_trailing}px`,
85
- };
86
- }
87
- /**
88
- * Generates comprehensive component styles including spacing, colors, borders and shadows
89
- * @param params - Component style configuration object
90
- * @returns CSS style object with component styles
91
- */
92
- export function getComponentStyles({ background_color, border, margin, padding, color, colorMode = DEFAULT_COLOR_MODE, shape, shadow, }) {
93
- const stylesObject = {
94
- "--margin-block-start": "0px",
95
- "--margin-inline-end": "0px",
96
- "--margin-block-end": "0px",
97
- "--margin-inline-start": "0px",
98
- "--padding-block-start": "0px",
99
- "--padding-inline-end": "0px",
100
- "--padding-block-end": "0px",
101
- "--padding-inline-start": "0px",
102
- "--background": "initial",
103
- "--text-color": "initial",
104
- "--border": "none",
105
- "--border-end-start-radius": "0px",
106
- "--border-end-end-radius": "0px",
107
- "--border-start-start-radius": "0px",
108
- "--border-start-end-radius": "0px",
109
- "--shadow": "none",
110
- };
111
- if (padding) {
112
- Object.assign(stylesObject, getSpacingStyle(padding, "padding"));
113
- }
114
- if (margin) {
115
- Object.assign(stylesObject, getSpacingStyle(margin, "margin"));
116
- }
117
- if (background_color) {
118
- stylesObject["--background"] = getColor({
119
- colorMap: background_color,
120
- colorMode,
121
- fallback: "transparent",
122
- });
123
- }
124
- if (color) {
125
- stylesObject["--text-color"] = getColor({
126
- colorMap: color,
127
- colorMode,
128
- fallback: DEFAULT_TEXT_COLOR,
129
- });
130
- }
131
- if (border) {
132
- stylesObject["--border"] = getBorderStyle(border, colorMode);
133
- }
134
- if (shape?.type === "rectangle" && shape.corners) {
135
- Object.assign(stylesObject, getCornerRadiusStyle(shape.corners));
136
- }
137
- if (shape?.type === "pill") {
138
- Object.assign(stylesObject, getCornerRadiusStyle({
139
- bottom_leading: 9999,
140
- bottom_trailing: 9999,
141
- top_leading: 9999,
142
- top_trailing: 9999,
143
- }));
144
- }
145
- if (shadow) {
146
- stylesObject["--shadow"] = `${shadow.x}px ${shadow.y}px ${shadow.radius}px
147
- ${getColor({ colorMap: shadow.color, colorMode, fallback: DEFAULT_TEXT_COLOR })}`;
148
- }
149
- return stylesObject;
150
- }
151
- function getSizeValue(size) {
152
- if (size.type === "fixed") {
153
- return `${size.value}px`;
154
- }
155
- if (size.type === "fit") {
156
- return "fit-content";
157
- }
158
- if (size.type === "fill") {
159
- const userAgent = navigator.userAgent;
160
- const isFirefox = userAgent.match(/firefox|fxios/i);
161
- return isFirefox ? "-moz-available" : "-webkit-fill-available";
162
- }
163
- return "initial";
164
- }
165
- /**
166
- * Generates size-related CSS styles for components
167
- * @param size - Size configuration object
168
- * @returns CSS style object with size properties
169
- */
170
- export function getSizeStyle(size) {
171
- const styles = {
172
- "--width": "initial",
173
- "--height": "initial",
174
- "--flex": "initial",
175
- };
176
- const width = getSizeValue(size.width);
177
- const height = getSizeValue(size.height);
178
- const isGrow = size.width.type === "fill" || size.height.type === "fill";
179
- Object.assign(styles, {
180
- "--width": width,
181
- "--height": height,
182
- "--flex": isGrow ? "initial" : "0 1 auto",
183
- });
184
- return styles;
185
- }
186
- export function getInsetStyles(dimension) {
187
- const defaultStyles = {
188
- "--inset": "initial",
189
- "--transform": "initial",
190
- };
191
- switch (dimension.alignment) {
192
- case "top_leading":
193
- defaultStyles["--inset"] = "0 auto auto 0";
194
- break;
195
- case "top":
196
- defaultStyles["--inset"] = "auto auto auto 50%";
197
- defaultStyles["--transform"] = "translate(-50%, 0)";
198
- break;
199
- case "top_trailing":
200
- defaultStyles["--inset"] = "0 0 auto auto";
201
- break;
202
- case "leading":
203
- defaultStyles["--inset"] = "50% 0 50% 0";
204
- defaultStyles["--transform"] = "translate(0, -50%)";
205
- break;
206
- case "center":
207
- defaultStyles["--inset"] = "50% auto auto 50%";
208
- defaultStyles["--transform"] = "translate(-50%, -50%)";
209
- break;
210
- case "trailing":
211
- defaultStyles["--inset"] = "50% 0 50% auto";
212
- defaultStyles["--transform"] = "translate(0, -50%)";
213
- break;
214
- case "bottom_leading":
215
- defaultStyles["--inset"] = "auto auto 0 0";
216
- break;
217
- case "bottom":
218
- defaultStyles["--inset"] = "auto 50% 0 auto";
219
- defaultStyles["--transform"] = "translate(50%, 0)";
220
- break;
221
- case "bottom_trailing":
222
- defaultStyles["--inset"] = "auto 0 0 auto";
223
- break;
224
- }
225
- return defaultStyles;
226
- }
227
- /**
228
- * Generates dimension-related styles for stack components
229
- * @param dimension - Dimension configuration object
230
- * @returns CSS style object with flex layout properties
231
- */
232
- export function getDimensionStyle(dimension) {
233
- const styles = {
234
- "--direction": "initial",
235
- "--alignment": "initial",
236
- "--distribution": "initial",
237
- "--position": "relative",
238
- "--inset": "initial",
239
- "--transform": "initial",
240
- };
241
- if (dimension.type !== "zlayer") {
242
- Object.assign(styles, {
243
- "--direction": StackDirection[dimension.type],
244
- "--alignment": StackAlignment[dimension.alignment],
245
- });
246
- if (dimension.distribution) {
247
- Object.assign(styles, {
248
- "--distribution": StackDistribution[dimension.distribution],
249
- });
250
- }
251
- }
252
- return styles;
253
- }
254
33
  /**
255
34
  * Generates text-related styles
256
35
  * @param props - Text component properties
@@ -258,7 +37,12 @@ export function getDimensionStyle(dimension) {
258
37
  * @returns CSS style object with text formatting properties
259
38
  */
260
39
  export function getTextStyles(props) {
261
- const { font_size, horizontal_alignment, font_weight, font_name } = props;
40
+ const { font_size, horizontal_alignment, font_weight, font_name, font_weight_int, } = props;
41
+ const paywall = getPaywallContext();
42
+ const uiConfig = paywall.uiConfig;
43
+ const { fonts } = uiConfig.app;
44
+ const font = fonts[font_name ?? ""];
45
+ const fontFamily = font?.web?.family;
262
46
  const styles = {
263
47
  "--text-align": "initial",
264
48
  "--font-weight": "initial",
@@ -270,9 +54,13 @@ export function getTextStyles(props) {
270
54
  };
271
55
  Object.assign(styles, {
272
56
  "--text-align": TextAlignments[horizontal_alignment] || TextAlignments.leading,
273
- "--font-weight": FontWeights[font_weight] || FontWeights.regular,
274
- "--font-size": FontSizes[font_size] || FontSizes.body_m,
275
- "--font-family": font_name || "sans-serif",
57
+ "--font-weight": font_weight_int ?? FontWeights[font_weight] ?? FontWeights.regular,
58
+ "--font-size": Number.isInteger(Number(font_size))
59
+ ? `${font_size}px`
60
+ : FontSizes[font_size] || FontSizes.body_m,
61
+ "--font-family": isFontRCFMManaged(font_name ?? "")
62
+ ? getScopedFontFamily(fontFamily ?? "")
63
+ : "sans-serif",
276
64
  });
277
65
  return styles;
278
66
  }
@@ -293,54 +81,39 @@ export function stringifyStyles(styles) {
293
81
  */
294
82
  export function findSelectedPackageId(paywallData) {
295
83
  const traverseNode = (node) => {
296
- if (node.type === "package" &&
297
- node.is_selected_by_default) {
84
+ if (node.type === "package" && node.is_selected_by_default) {
298
85
  return node;
299
86
  }
300
- if (node.components && Array.isArray(node.components)) {
301
- for (const c of node.components) {
302
- const pkg = traverseNode(c);
303
- if (pkg) {
87
+ if ("components" in node && Array.isArray(node.components)) {
88
+ for (const component of node.components) {
89
+ const pkg = traverseNode(component);
90
+ if (pkg !== undefined) {
304
91
  return pkg;
305
92
  }
306
93
  }
307
94
  }
308
- if (node.stack !== undefined) {
95
+ if ("stack" in node) {
309
96
  const pkg = traverseNode(node.stack);
310
- if (pkg) {
97
+ if (pkg !== undefined) {
311
98
  return pkg;
312
99
  }
313
100
  }
314
101
  return undefined;
315
102
  };
316
- const p = traverseNode(paywallData.components_config.base.stack);
317
- if (p === undefined) {
318
- return undefined;
103
+ for (const component of paywallData.components_config.base.stack.components) {
104
+ const pkg = traverseNode(component);
105
+ if (pkg !== undefined) {
106
+ return pkg?.package_id;
107
+ }
319
108
  }
320
- return p.package_id;
109
+ return undefined;
321
110
  }
322
- export const getActiveStateProps = (overrides, componentState) => {
323
- if (!componentState)
111
+ export const getActiveStateProps = (selectedState, overrides) => {
112
+ if (!selectedState) {
324
113
  return {};
325
- const activeStateKeys = getComponentActiveStateKeys(componentState);
326
- const activeStateProps = activeStateKeys.reduce((props, key) => {
327
- if (overrides) {
328
- const styles = overrides?.states?.[key] || {};
329
- return { ...props, ...styles };
330
- }
331
- return props;
332
- }, {});
333
- return activeStateProps;
334
- };
335
- const getComponentActiveStateKeys = (componentState) => {
336
- if (!componentState)
337
- return [];
338
- const stateKeys = Object.entries(componentState).reduce((activeStates, [stateKey, stateValue]) => {
339
- if (stateValue)
340
- activeStates.push(stateKey);
341
- return activeStates;
342
- }, []);
343
- return stateKeys;
114
+ }
115
+ const override = overrides?.find((override) => override.conditions.find((condition) => condition.type === "selected"));
116
+ return override?.properties ?? {};
344
117
  };
345
118
  export function prefixObject(object, prefix) {
346
119
  if (!object)
@@ -353,55 +126,3 @@ export function prefixObject(object, prefix) {
353
126
  return acc;
354
127
  }, {});
355
128
  }
356
- export function getMaskPath(props) {
357
- const { mask_shape: maskShape, imageAspectRatio } = props;
358
- let maskPath = "";
359
- if (maskShape?.type === "concave") {
360
- maskPath = `M 0 0
361
- H 100
362
- V ${imageAspectRatio * 100}
363
- Q 50 ${imageAspectRatio * 80} 0 ${imageAspectRatio * 100}
364
- Z`;
365
- }
366
- else if (maskShape?.type === "convex") {
367
- maskPath = `M 0 0
368
- H 100
369
- V ${imageAspectRatio * 80}
370
- Q 50 ${imageAspectRatio * 120} 0 ${imageAspectRatio * 80}
371
- Z`;
372
- }
373
- else {
374
- maskPath = `M 0 0 H 100 V ${imageAspectRatio * 100} H 0 Z`;
375
- }
376
- return maskPath;
377
- }
378
- /**
379
- * Generates mask styles for images
380
- * @param maskShape - Shape configuration for image mask
381
- * @returns CSS style object with mask properties
382
- */
383
- export const getMaskStyle = (maskShape) => {
384
- const maskStyles = {
385
- "--border-end-start-radius": "0px",
386
- "--border-end-end-radius": "0px",
387
- "--border-start-start-radius": "0px",
388
- "--border-start-end-radius": "0px",
389
- };
390
- if (maskShape?.corners) {
391
- Object.assign(maskStyles, getCornerRadiusStyle(maskShape.corners));
392
- }
393
- return maskStyles;
394
- };
395
- export function getLinearGradientAngle(colorMode, props) {
396
- const { color_overlay: colorOverlay } = props;
397
- if (colorOverlay?.[colorMode]?.type !== "linear") {
398
- return { x1: "0%", y1: "0%", x2: "0%", y2: "0%" };
399
- }
400
- const defaultColor = colorOverlay?.[DEFAULT_COLOR_MODE];
401
- const angle = defaultColor?.type === "linear" ? defaultColor.degrees : 0;
402
- const x1 = "50%";
403
- const y1 = "0%";
404
- const x2 = `${Math.round(50 + Math.sin(((angle + 90) * Math.PI) / 90) * 50)}%`;
405
- const y2 = `${Math.round(50 - Math.cos(((angle + 90) * Math.PI) / 90) * 50)}%`;
406
- return { x1, y1, x2, y2 };
407
- }
@@ -1,23 +1,2 @@
1
- export declare const VARIABLE_NAMES: string[];
2
- export type VariableDictionary = {
3
- product_name: string | number | undefined;
4
- price: string | number | undefined;
5
- price_per_period: string | number | undefined;
6
- price_per_period_full: string | number | undefined;
7
- total_price_and_per_month: string | number | undefined;
8
- total_price_and_per_month_full: string | number | undefined;
9
- sub_price_per_month: string | number | undefined;
10
- sub_price_per_week: string | number | undefined;
11
- sub_duration: string | number | undefined;
12
- sub_duration_in_months: string | number | undefined;
13
- sub_period: string | number | undefined;
14
- sub_period_length: string | number | undefined;
15
- sub_period_abbreviated: string | number | undefined;
16
- sub_offer_duration: string | number | undefined;
17
- sub_offer_duration_2: string | number | undefined;
18
- sub_offer_price: string | number | undefined;
19
- sub_offer_price_2: string | number | undefined;
20
- sub_relative_discount: string | number | undefined;
21
- [key: string]: string | number | undefined;
22
- };
1
+ import type { VariableDictionary } from "../types/variables";
23
2
  export declare function replaceVariables(input?: string, variables?: VariableDictionary): string | undefined;
@@ -1,29 +1,33 @@
1
- export const VARIABLE_NAMES = [
2
- "product_name",
3
- "price",
4
- "price_per_period",
5
- "price_per_period_full",
6
- "total_price_and_per_month",
7
- "total_price_and_per_month_full",
8
- "sub_price_per_month",
9
- "sub_price_per_week",
10
- "sub_duration",
11
- "sub_duration_in_months",
12
- "sub_period",
13
- "sub_period_length",
14
- "sub_period_abbreviated",
15
- "sub_offer_duration",
16
- "sub_offer_duration_2",
17
- "sub_offer_price",
18
- "sub_offer_price_2",
19
- "sub_relative_discount",
20
- ];
1
+ function capitalize(value) {
2
+ return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
3
+ }
4
+ const VARIABLE_MODIFIERS = {
5
+ uppercase: (value) => String(value ?? "").toUpperCase(),
6
+ lowercase: (value) => String(value ?? "").toLowerCase(),
7
+ capitalize: (value) => {
8
+ return String(value ?? "").replaceAll(/(\p{Letter}+)/giu, capitalize);
9
+ },
10
+ };
11
+ function parseTemplate(template, variables) {
12
+ // Match {{ product.variable | helper1 | helper2:arg1,arg2 }} patterns
13
+ const templateRegex = /\{\{\s*([a-z0-9._-]+)(?:\s*\|\s*([^}]*))?\s*\}\}/gi;
14
+ return template.replace(templateRegex, (match, namePart, modifierPart) => {
15
+ const variableName = namePart?.trim();
16
+ const variable = variableName && variables[variableName];
17
+ if (variable === undefined) {
18
+ return "N/A";
19
+ }
20
+ const modifierName = modifierPart?.trim();
21
+ if (modifierName === undefined) {
22
+ return variable;
23
+ }
24
+ const modifier = VARIABLE_MODIFIERS[modifierName];
25
+ return modifier ? modifier(variable) : variable;
26
+ });
27
+ }
21
28
  export function replaceVariables(input = "", variables) {
22
29
  if (variables === undefined) {
23
30
  return input;
24
31
  }
25
- return VARIABLE_NAMES.reduce((result, variableName) => {
26
- const currentVariableReplaced = result.replaceAll(`{{ ${variableName} }}`, variables[variableName]?.toString() || "N/A");
27
- return currentVariableReplaced;
28
- }, input);
32
+ return parseTemplate(input, variables);
29
33
  }
@@ -1 +1 @@
1
- .rcb-processing.svelte-2j2b59{width:var(--width, 12px);aspect-ratio:1;border-radius:50%;animation:svelte-2j2b59-l5 1.5s infinite linear}@keyframes svelte-2j2b59-l5{0%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}25%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff;background:#fff2}50%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff}75%{box-shadow:var(--shadow-offset) 0 #fff,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}to{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}}.rcb-typography-heading-2xl.svelte-byrjto{font:var(--rc-text-heading2xl-mobile)}.rcb-typography-heading-xl.svelte-byrjto{font:var(--rc-text-headingXl-mobile)}.rcb-typography-heading-lg.svelte-byrjto{font:var(--rc-text-headingLg-mobile)}.rcb-typography-heading-md.svelte-byrjto{font:var(--rc-text-headingMd-mobile)}.rcb-typography-body-base.svelte-byrjto{font:var(--rc-text-bodyBase-mobile)}.rcb-typography-body-small.svelte-byrjto{font:var(--rc-text-bodySmall-mobile)}.rcb-typography-label-button.svelte-byrjto{font:var(--rc-text-labelButton-mobile)}.rcb-typography-label-default.svelte-byrjto{font:var(--rc-text-labelDefault-mobile)}.rcb-typography-caption-default.svelte-byrjto{font:var(--rc-text-captionDefault-mobile)}.rcb-typography-caption-link.svelte-byrjto{font:var(--rc-text-captionLink-mobile)}@container layout-query-container (width >= 768px){.rcb-typography-heading-2xl.svelte-byrjto{font:var(--rc-text-heading2xl-desktop)}.rcb-typography-heading-xl.svelte-byrjto{font:var(--rc-text-headingXl-desktop)}.rcb-typography-heading-lg.svelte-byrjto{font:var(--rc-text-headingLg-desktop)}.rcb-typography-heading-md.svelte-byrjto{font:var(--rc-text-headingMd-desktop)}.rcb-typography-body-base.svelte-byrjto{font:var(--rc-text-bodyBase-desktop)}.rcb-typography-body-small.svelte-byrjto{font:var(--rc-text-bodySmall-desktop)}.rcb-typography-label-button.svelte-byrjto{font:var(--rc-text-labelButton-desktop)}.rcb-typography-label-default.svelte-byrjto{font:var(--rc-text-labelDefault-desktop)}.rcb-typography-caption-default.svelte-byrjto{font:var(--rc-text-captionDefault-desktop)}.rcb-typography-caption-link.svelte-byrjto{font:var(--rc-text-captionLink-desktop)}}button.svelte-td7xvm{border:none;border-radius:var(--rc-shape-input-button-border-radius);cursor:pointer;height:var(--rc-spacing-inputHeight-mobile);color:var(--rc-color-grey-text-dark);background-color:var(--rc-color-grey-ui-dark);display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-tap-highlight-color:transparent;transition:background-color .15s ease-in-out;-webkit-user-select:none;user-select:none}@container layout-query-container (width >= 768px){button.svelte-td7xvm{height:var(--rc-spacing-inputHeight-desktop)}}button.svelte-td7xvm:focus-visible{outline:2px solid var(--rc-color-focus)}button.intent-primary.svelte-td7xvm{background-color:var(--rc-color-primary);color:var(--rc-color-primary-text)}button.svelte-td7xvm:disabled{color:var(--rc-color-grey-text-light);background-color:var(--rc-color-grey-ui-dark);outline:none}button.intent-primary.svelte-td7xvm:not(:disabled):hover{background-color:var(--rc-color-primary-hover)}button.intent-primary.svelte-td7xvm:not(:disabled):active,button.svelte-td7xvm:active{background-color:var(--rc-color-primary-pressed);outline:none}button.intent-primary.svelte-td7xvm:disabled{color:var(--rc-color-grey-text-light);background-color:var(--rc-color-grey-ui-dark)}
1
+ .rcb-typography-heading-2xl.svelte-jt3g5k{font:var(--rc-text-heading2xl-mobile)}.rcb-typography-heading-xl.svelte-jt3g5k{font:var(--rc-text-headingXl-mobile)}.rcb-typography-heading-lg.svelte-jt3g5k{font:var(--rc-text-headingLg-mobile)}.rcb-typography-heading-md.svelte-jt3g5k{font:var(--rc-text-headingMd-mobile)}.rcb-typography-body-base.svelte-jt3g5k{font:var(--rc-text-bodyBase-mobile)}.rcb-typography-body-small.svelte-jt3g5k{font:var(--rc-text-bodySmall-mobile)}.rcb-typography-label-button.svelte-jt3g5k{font:var(--rc-text-labelButton-mobile)}.rcb-typography-label-default.svelte-jt3g5k{font:var(--rc-text-labelDefault-mobile)}.rcb-typography-caption-default.svelte-jt3g5k{font:var(--rc-text-captionDefault-mobile)}.rcb-typography-caption-link.svelte-jt3g5k{font:var(--rc-text-captionLink-mobile)}@container layout-query-container (width >= 768px){.rcb-typography-heading-2xl.svelte-jt3g5k{font:var(--rc-text-heading2xl-desktop)}.rcb-typography-heading-xl.svelte-jt3g5k{font:var(--rc-text-headingXl-desktop)}.rcb-typography-heading-lg.svelte-jt3g5k{font:var(--rc-text-headingLg-desktop)}.rcb-typography-heading-md.svelte-jt3g5k{font:var(--rc-text-headingMd-desktop)}.rcb-typography-body-base.svelte-jt3g5k{font:var(--rc-text-bodyBase-desktop)}.rcb-typography-body-small.svelte-jt3g5k{font:var(--rc-text-bodySmall-desktop)}.rcb-typography-label-button.svelte-jt3g5k{font:var(--rc-text-labelButton-desktop)}.rcb-typography-label-default.svelte-jt3g5k{font:var(--rc-text-labelDefault-desktop)}.rcb-typography-caption-default.svelte-jt3g5k{font:var(--rc-text-captionDefault-desktop)}.rcb-typography-caption-link.svelte-jt3g5k{font:var(--rc-text-captionLink-desktop)}}.rcb-processing.svelte-1i80tfc{width:var(--width, 12px);aspect-ratio:1;border-radius:50%;animation:svelte-1i80tfc-l5 1.5s infinite linear}@keyframes svelte-1i80tfc-l5{0%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}25%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff;background:#fff2}50%{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff}75%{box-shadow:var(--shadow-offset) 0 #fff,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}to{box-shadow:var(--shadow-offset) 0 #fff2,calc(-1 * var(--shadow-offset)) 0 #fff2;background:#fff2}}button.svelte-hnboq0{border:none;border-radius:var(--rc-shape-input-button-border-radius);cursor:pointer;height:var(--rc-spacing-inputHeight-mobile);color:var(--rc-color-grey-text-dark);background-color:var(--rc-color-grey-ui-dark);display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-tap-highlight-color:transparent;transition:background-color .15s ease-in-out;-webkit-user-select:none;user-select:none}@container layout-query-container (width >= 768px){button.svelte-hnboq0{height:var(--rc-spacing-inputHeight-desktop)}}button.svelte-hnboq0:focus-visible{outline:2px solid var(--rc-color-focus)}button.intent-primary.svelte-hnboq0{background-color:var(--rc-color-primary);color:var(--rc-color-primary-text)}button.svelte-hnboq0:disabled{color:var(--rc-color-grey-text-light);background-color:var(--rc-color-grey-ui-dark);outline:none}button.intent-primary.svelte-hnboq0:not(:disabled):hover{background-color:var(--rc-color-primary-hover)}button.intent-primary.svelte-hnboq0:not(:disabled):active,button.svelte-hnboq0:active{background-color:var(--rc-color-primary-pressed);outline:none}button.intent-primary.svelte-hnboq0:disabled{color:var(--rc-color-grey-text-light);background-color:var(--rc-color-grey-ui-dark)}