@revenuecat/purchases-ui-js 0.0.17 → 0.0.19

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 (48) hide show
  1. package/dist/components/button/Button.svelte +0 -13
  2. package/dist/components/button/ButtonNode.stories.svelte +16 -9
  3. package/dist/components/button/ButtonNode.svelte +26 -1
  4. package/dist/components/button/button-utils.d.ts +2 -0
  5. package/dist/components/button/button-utils.js +19 -0
  6. package/dist/components/footer/Footer.stories.svelte +2 -0
  7. package/dist/components/footer/Footer.svelte +14 -8
  8. package/dist/components/image/Image.stories.svelte +6 -2
  9. package/dist/components/image/Image.svelte +20 -17
  10. package/dist/components/image/image-utils.d.ts +2 -12
  11. package/dist/components/image/image-utils.js +27 -10
  12. package/dist/components/package/Package.stories.svelte +5 -3
  13. package/dist/components/package/Package.svelte +15 -6
  14. package/dist/components/paywall/Node.svelte +75 -19
  15. package/dist/components/paywall/Node.svelte.d.ts +20 -2
  16. package/dist/components/paywall/Paywall.stories.svelte +80 -5
  17. package/dist/components/paywall/Paywall.svelte +74 -71
  18. package/dist/components/paywall/paywall-utils.d.ts +1 -1
  19. package/dist/components/paywall/paywall-utils.js +11 -9
  20. package/dist/components/purchase-button/PurchaseButton.stories.svelte +13 -6
  21. package/dist/components/purchase-button/PurchaseButton.svelte +24 -10
  22. package/dist/components/purchase-button/purchase-button-utils.d.ts +2 -0
  23. package/dist/components/purchase-button/purchase-button-utils.js +20 -0
  24. package/dist/components/stack/Stack.stories.svelte +1138 -4
  25. package/dist/components/stack/Stack.svelte +162 -45
  26. package/dist/components/stack/stack-utils.d.ts +24 -24
  27. package/dist/components/stack/stack-utils.js +245 -12
  28. package/dist/components/text/Text.svelte +24 -19
  29. package/dist/components/text/TextNode.stories.svelte +12 -11
  30. package/dist/components/text/TextNode.svelte +21 -24
  31. package/dist/components/text/text-utils.d.ts +9 -15
  32. package/dist/components/text/text-utils.js +123 -8
  33. package/dist/components/timeline/Timeline.svelte +10 -10
  34. package/dist/components/timeline/TimelineItem.svelte +45 -33
  35. package/dist/components/timeline/timeline-utils.d.ts +3 -20
  36. package/dist/components/timeline/timeline-utils.js +46 -11
  37. package/dist/data/entities.d.ts +41 -11
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.js +2 -2
  40. package/dist/stories/fixtures.d.ts +3 -1
  41. package/dist/stories/fixtures.js +7581 -3120
  42. package/dist/types.d.ts +4 -3
  43. package/dist/utils/style-utils.d.ts +72 -63
  44. package/dist/utils/style-utils.js +120 -102
  45. package/dist/utils/variable-utils.d.ts +27 -0
  46. package/dist/utils/variable-utils.js +37 -0
  47. package/package.json +3 -2
  48. package/dist/components/paywall/global-styles.css +0 -9
@@ -10,13 +10,13 @@
10
10
  paywallData,
11
11
  gradientPaywallData,
12
12
  variablesPastaPaywallData,
13
- stateTemplate,
14
13
  posterMakerTemplate,
15
14
  e2eTestTemplate,
16
15
  zStackTemplate,
17
16
  colorModeOverrideTemplate,
18
17
  errorPaywallData,
19
18
  paywallWithFooter,
19
+ fallbackPaywallData,
20
20
  } from "../../stories/fixtures";
21
21
  import { fn } from "@storybook/test";
22
22
  import type { VariableDictionary } from "../../utils/variable-utils";
@@ -144,7 +144,7 @@
144
144
  <Story
145
145
  name="Dynamic state style overrides"
146
146
  args={{
147
- paywallData: stateTemplate,
147
+ paywallData: e2eTestTemplate,
148
148
  onPurchaseClicked: fn(),
149
149
  onBackClicked: fn(),
150
150
  onNavigateToUrlClicked: fn(),
@@ -156,11 +156,11 @@
156
156
  name="Dynamic state style overrides with background image"
157
157
  args={{
158
158
  paywallData: {
159
- ...stateTemplate,
159
+ ...e2eTestTemplate,
160
160
  components_config: {
161
- ...stateTemplate.components_config,
161
+ ...e2eTestTemplate.components_config,
162
162
  base: {
163
- ...stateTemplate.components_config.base,
163
+ ...e2eTestTemplate.components_config.base,
164
164
  background: {
165
165
  type: "image",
166
166
  value: {
@@ -204,6 +204,68 @@
204
204
  onBackClicked: fn(),
205
205
  onNavigateToUrlClicked: fn(),
206
206
  onRestorePurchasesClicked: fn(),
207
+ variablesPerPackage: {
208
+ $rc_annual: {
209
+ product_name: "Yearly sub",
210
+ price: "$19.99",
211
+ price_per_period: "$19.99/1yr",
212
+ price_per_period_full: "$19.99/1year",
213
+ total_price_and_per_month: "$19.99/1yr($1.67/mo)",
214
+ total_price_and_per_month_full: "$19.99/1year($1.67/month)",
215
+ sub_price_per_month: "$1.67",
216
+ sub_price_per_week: "$0.42",
217
+ sub_duration: "1 year",
218
+ sub_duration_in_months: "12 months",
219
+ sub_period: "yearly",
220
+ sub_period_length: "year",
221
+ sub_period_abbreviated: "yr",
222
+ sub_relative_discount: "33% off",
223
+ sub_offer_duration: "undefined",
224
+ sub_offer_duration_2: "undefined",
225
+ sub_offer_price: "undefined",
226
+ sub_offer_price_2: "undefined",
227
+ },
228
+ $rc_monthly: {
229
+ product_name: "Monthly sub",
230
+ price: "$30.00",
231
+ price_per_period: "$30.00/1mo",
232
+ price_per_period_full: "$30.00/1month",
233
+ total_price_and_per_month: "$30.00",
234
+ total_price_and_per_month_full: "$30.00",
235
+ sub_price_per_month: "$30.00",
236
+ sub_price_per_week: "$30.00",
237
+ sub_duration: "1 month",
238
+ sub_duration_in_months: "1 month",
239
+ sub_period: "monthly",
240
+ sub_period_length: "month",
241
+ sub_period_abbreviated: "mo",
242
+ sub_relative_discount: "",
243
+ sub_offer_duration: "undefined",
244
+ sub_offer_duration_2: "undefined",
245
+ sub_offer_price: "undefined",
246
+ sub_offer_price_2: "undefined",
247
+ },
248
+ $rc_weekly: {
249
+ product_name: "Weekly no trial",
250
+ price: "$1.25",
251
+ price_per_period: "$1.25/1wk",
252
+ price_per_period_full: "$1.25/1week",
253
+ total_price_and_per_month: "$1.25/1wk($5.00/mo)",
254
+ total_price_and_per_month_full: "$1.25/1week($5.00/month)",
255
+ sub_price_per_month: "$5.00",
256
+ sub_price_per_week: "$1.25",
257
+ sub_duration: "1 week",
258
+ sub_duration_in_months: "1 week",
259
+ sub_period: "weekly",
260
+ sub_period_length: "week",
261
+ sub_period_abbreviated: "wk",
262
+ sub_relative_discount: "96% off",
263
+ sub_offer_duration: "undefined",
264
+ sub_offer_duration_2: "undefined",
265
+ sub_offer_price: "undefined",
266
+ sub_offer_price_2: "undefined",
267
+ },
268
+ },
207
269
  }}
208
270
  />
209
271
 
@@ -243,6 +305,19 @@
243
305
  }}
244
306
  />
245
307
 
308
+ <Story
309
+ name="Fallback Paywall"
310
+ args={{
311
+ paywallData: fallbackPaywallData,
312
+ onPurchaseClicked: fn(),
313
+ onBackClicked: fn(),
314
+ onNavigateToUrlClicked: fn(),
315
+ onRestorePurchasesClicked: fn(),
316
+ preferredColorMode: "dark",
317
+ onError: (error: unknown) => console.error(`Error - ${error}`),
318
+ }}
319
+ />
320
+
246
321
  <Story
247
322
  name="Sticky Footer"
248
323
  args={{
@@ -9,8 +9,11 @@
9
9
 
10
10
  import Node from "./Node.svelte";
11
11
  import type { PurchaseState } from "../../data/state";
12
- import { findSelectedPackageId, getLabelById } from "../../utils/style-utils";
13
- import { type VariableDictionary } from "../../utils/variable-utils";
12
+ import { findSelectedPackageId } from "../../utils/style-utils";
13
+ import {
14
+ getLabelById,
15
+ type VariableDictionary,
16
+ } from "../../utils/variable-utils";
14
17
  import {
15
18
  getBackgroundImageSource,
16
19
  getBackgroundStyles,
@@ -100,7 +103,6 @@
100
103
  }
101
104
  onPurchaseClicked?.(purchaseState.selectedPackageId);
102
105
  };
103
-
104
106
  const onAction = (action: SupportedActions, data?: Extra) => {
105
107
  switch (action.type) {
106
108
  case "select_package":
@@ -133,7 +135,7 @@
133
135
  </script>
134
136
 
135
137
  <svelte:boundary onerror={onError}>
136
- <div class="paywall">
138
+ <div class="rc-pw-paywall">
137
139
  <Node
138
140
  {onAction}
139
141
  nodeData={paywallData.components_config.base.stack}
@@ -150,107 +152,108 @@
150
152
  labels={paywallData.components_localizations}
151
153
  {purchaseState}
152
154
  {variableDictionary}
155
+ {onAction}
153
156
  />
154
157
  {/if}
155
158
  {#if paywallData.components_config.base.background?.type === "color"}
156
- <div class="paywall-background" style={backgroundStyles}></div>
159
+ <div class="rc-pw-paywall-background" style={backgroundStyles}></div>
157
160
  {:else if paywallData.components_config.base.background?.type === "image"}
158
- <div class="paywall-background image-container">
159
- <img class="image" src={backgroundImgSource} alt="" />
161
+ <div class="rc-pw-paywall-background rc-pw-image-container">
162
+ <img class="rc-pw-image" src={backgroundImgSource} alt="" />
160
163
  </div>
161
164
  {/if}
162
165
  </div>
163
166
  </svelte:boundary>
164
167
 
165
168
  <style>
166
- /* 1. Use a more-intuitive box-sizing model */
167
- *,
168
- *::before,
169
- *::after {
170
- box-sizing: border-box;
171
- margin: 0;
172
- }
173
-
174
- .paywall {
169
+ .rc-pw-paywall {
175
170
  position: relative;
171
+ display: block;
172
+ max-height: 100%;
176
173
  }
177
174
 
178
- .paywall-background {
175
+ .rc-pw-paywall-background {
179
176
  position: absolute;
180
177
  top: 0;
181
178
  left: 0;
182
179
  width: 100%;
183
180
  height: 100%;
184
- background: var(--background, none);
181
+ background: var(--paywall-background, none);
185
182
  z-index: -1;
186
183
  }
187
- .image-container {
184
+ .rc-pw-image-container {
188
185
  overflow: hidden;
189
186
  background: none;
190
187
  }
191
188
 
192
- .image {
189
+ .rc-pw-image {
193
190
  width: 100%;
194
191
  height: 100%;
195
192
  object-fit: cover;
196
193
  display: block;
197
194
  }
198
195
 
199
- body {
200
- /* 3. Add accessible line-height */
201
- line-height: 1.5;
202
- /* 4. Improve text rendering */
203
- -webkit-font-smoothing: antialiased;
204
- }
205
-
206
- /* 5. Improve media defaults */
207
- img,
208
- picture,
209
- video,
210
- canvas,
211
- svg {
212
- display: block;
213
- max-width: 100%;
214
- }
196
+ :global {
197
+ *,
198
+ *::before,
199
+ *::after {
200
+ box-sizing: border-box;
201
+ margin: 0;
202
+ padding: 0;
203
+ font-family: sans-serif;
204
+ }
205
+ body {
206
+ line-height: 1.5;
207
+ -webkit-font-smoothing: antialiased;
208
+ }
209
+ img,
210
+ picture,
211
+ video,
212
+ canvas,
213
+ svg {
214
+ display: block;
215
+ max-width: 100%;
216
+ }
215
217
 
216
- /* 6. Inherit fonts for form controls */
217
- input,
218
- button,
219
- textarea,
220
- select {
221
- font: inherit;
222
- }
218
+ input,
219
+ button,
220
+ textarea,
221
+ select {
222
+ font: inherit;
223
+ }
224
+ button {
225
+ border: none;
226
+ cursor: pointer;
227
+ background: transparent;
228
+ width: fit-content;
229
+ }
223
230
 
224
- /* 7. Avoid text overflows */
225
- p,
226
- h1,
227
- h2,
228
- h3,
229
- h4,
230
- h5,
231
- h6 {
232
- overflow-wrap: break-word;
233
- }
231
+ p,
232
+ h1,
233
+ h2,
234
+ h3,
235
+ h4,
236
+ h5,
237
+ h6 {
238
+ overflow-wrap: break-word;
239
+ }
234
240
 
235
- /* 8. Improve line wrapping */
236
- p {
237
- text-wrap: pretty;
238
- }
241
+ p {
242
+ text-wrap: pretty;
243
+ }
239
244
 
240
- h1,
241
- h2,
242
- h3,
243
- h4,
244
- h5,
245
- h6 {
246
- text-wrap: balance;
247
- }
245
+ h1,
246
+ h2,
247
+ h3,
248
+ h4,
249
+ h5,
250
+ h6 {
251
+ text-wrap: balance;
252
+ }
248
253
 
249
- /*
250
- 9. Create a root stacking context
251
- */
252
- #root,
253
- #__next {
254
- isolation: isolate;
254
+ #root,
255
+ #__next {
256
+ isolation: isolate;
257
+ }
255
258
  }
256
259
  </style>
@@ -3,5 +3,5 @@ import type { ColorMode } from "../../types";
3
3
  export declare function getBackgroundStyles({ background, colorMode, }: {
4
4
  background?: BaseNodeBackgroundType;
5
5
  colorMode: ColorMode;
6
- }): string | undefined;
6
+ }): string;
7
7
  export declare function getBackgroundImageSource(paywallData: PaywallData, colorMode: ColorMode): string;
@@ -1,15 +1,17 @@
1
- import { getColor } from "../../utils/style-utils";
1
+ import { getColor, prefixObject, stringifyStyles, } from "../../utils/style-utils";
2
2
  export function getBackgroundStyles({ background, colorMode, }) {
3
- if (!background)
4
- return "";
5
- if (background.type === "color") {
6
- const style = getColor({
7
- colorMap: background.value,
8
- colorMode,
9
- fallback: "transparent",
3
+ const styles = { "--background": "initial" };
4
+ if (background?.type === "color") {
5
+ Object.assign(styles, {
6
+ "--background": getColor({
7
+ colorMap: background.value,
8
+ colorMode,
9
+ fallback: "transparent",
10
+ }),
10
11
  });
11
- return `--background: ${style};`;
12
12
  }
13
+ const prefixedStyles = prefixObject(styles, "paywall");
14
+ return stringifyStyles(prefixedStyles);
13
15
  }
14
16
  export function getBackgroundImageSource(paywallData, colorMode) {
15
17
  if (paywallData.components_config.base?.background?.type !== "image")
@@ -1,6 +1,13 @@
1
1
  <script module lang="ts">
2
2
  import { defineMeta } from "@storybook/addon-svelte-csf";
3
3
  import PurchaseButton from "./PurchaseButton.svelte";
4
+ import type { PurchaseState } from "../../data/state";
5
+ import type { ColorMode, DimensionType } from "../../types";
6
+ import type { SupportedActions } from "../../data/entities";
7
+
8
+ const onAction = (action: SupportedActions) => {
9
+ alert(action.type);
10
+ };
4
11
 
5
12
  const { Story } = defineMeta({
6
13
  title: "Components/PurchaseButton",
@@ -25,7 +32,8 @@
25
32
  "6gpcQ4q6T8": "Continue",
26
33
  },
27
34
  };
28
- const purchaseState = {
35
+ const purchaseState: PurchaseState = {
36
+ colorMode: "light" as ColorMode,
29
37
  locale: "en_US",
30
38
  defaultLocale: "en_US",
31
39
  };
@@ -46,7 +54,6 @@
46
54
  value: "#a229f3",
47
55
  },
48
56
  },
49
- border: null,
50
57
  components: [
51
58
  {
52
59
  purchaseState,
@@ -92,10 +99,10 @@
92
99
  },
93
100
  ],
94
101
  dimension: {
95
- alignment: "leading",
102
+ alignment: "top",
96
103
  distribution: "space_between",
97
104
  type: "vertical",
98
- },
105
+ } as DimensionType,
99
106
  id: "pbvAUBvilP",
100
107
  margin: {
101
108
  bottom: 16,
@@ -122,17 +129,17 @@
122
129
  size: {
123
130
  height: {
124
131
  type: "fit",
125
- value: null,
126
132
  },
127
133
  width: {
128
134
  type: "fill",
129
- value: null,
130
135
  },
131
136
  },
132
137
  spacing: 8,
133
138
  type: "stack",
139
+ labels: labelsData,
134
140
  },
135
141
  labels: labelsData,
136
142
  type: "purchase_button",
143
+ onAction,
137
144
  }}
138
145
  />
@@ -2,6 +2,7 @@
2
2
  import type { PurchaseButtonProps } from "../../data/entities";
3
3
  import Stack from "../stack/Stack.svelte";
4
4
  import { Button } from "../../index";
5
+ import { getPurchaseButtonStyles } from "./purchase-button-utils";
5
6
 
6
7
  const {
7
8
  stack,
@@ -9,25 +10,38 @@
9
10
  onAction,
10
11
  purchaseState,
11
12
  variableDictionary,
13
+ zStackChildStyles,
14
+ ...restProps
12
15
  }: PurchaseButtonProps = $props();
13
16
  const handleClick = () => {
14
17
  onAction && onAction({ type: "purchase" });
15
18
  };
19
+
20
+ const buttonStyles = $derived(
21
+ getPurchaseButtonStyles({
22
+ stack,
23
+ labels,
24
+ onAction,
25
+ purchaseState,
26
+ variableDictionary,
27
+ zStackChildStyles,
28
+ ...restProps,
29
+ }),
30
+ );
16
31
  </script>
17
32
 
18
- <Button onclick={handleClick} class="purchase-button">
33
+ <Button
34
+ onclick={handleClick}
35
+ class="rc-pw-purchase-button"
36
+ style={buttonStyles}
37
+ >
19
38
  <Stack {...stack} {labels} {purchaseState} {variableDictionary} />
20
39
  </Button>
21
40
 
22
41
  <style>
23
- .purchase-button {
24
- border: none;
25
- cursor: pointer;
26
- background: transparent;
27
- padding: 0;
28
- width: 100%;
29
- display: flex;
30
- align-items: center;
31
- justify-content: center;
42
+ .rc-pw-purchase-button {
43
+ position: var(--purchase-button-position, relative);
44
+ inset: var(--purchase-button-inset, 0);
45
+ transform: var(--purchase-button-transform, initial);
32
46
  }
33
47
  </style>
@@ -0,0 +1,2 @@
1
+ import type { PurchaseButtonProps } from "../../data/entities";
2
+ export declare function getPurchaseButtonStyles({ stack, zStackChildStyles, }: PurchaseButtonProps): string;
@@ -0,0 +1,20 @@
1
+ import { prefixObject, stringifyStyles } from "../../utils/style-utils";
2
+ export function getPurchaseButtonStyles({ stack, zStackChildStyles, }) {
3
+ // Get the width of the inner stack to adjust to the outer button wrapper
4
+ const width = stack.size.width.type === "fill" ? "100%" : "fit-content";
5
+ // Prefix zStack child styles with purchase-button to prevent class overlap conflicts
6
+ const prefixedObject = prefixObject(zStackChildStyles || {}, "purchase-button");
7
+ // Define set of variables to be assigned to the purchase button
8
+ // Define width as an inline style
9
+ const assignedVariables = {
10
+ position: "var(--purchase-button-position, relative)",
11
+ inset: "var(--purchase-button-inset, 0)",
12
+ transform: "var(--purchase-button-transform, initial)",
13
+ width,
14
+ };
15
+ const purchaseButtonInlineStyles = stringifyStyles({
16
+ ...prefixedObject,
17
+ ...assignedVariables,
18
+ });
19
+ return purchaseButtonInlineStyles;
20
+ }