@revenuecat/purchases-ui-js 3.11.2 → 3.11.4

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 (50) hide show
  1. package/dist/components/button/ButtonNode.stories.svelte +23 -0
  2. package/dist/components/button/ButtonNode.svelte +114 -2
  3. package/dist/components/button/ButtonNodeTestWrapper.svelte +10 -0
  4. package/dist/components/carousel/Carousel.stories.svelte +19 -0
  5. package/dist/components/carousel/Carousel.svelte +98 -52
  6. package/dist/components/carousel/PageControl.svelte +12 -11
  7. package/dist/components/countdown/Countdown.stories.svelte +101 -71
  8. package/dist/components/icon/Icon.stories.svelte +22 -0
  9. package/dist/components/icon/Icon.svelte +2 -2
  10. package/dist/components/image/Image.stories.svelte +19 -0
  11. package/dist/components/image/Image.svelte +8 -2
  12. package/dist/components/input-text/InputText.svelte +72 -32
  13. package/dist/components/options/InputMultipleChoice.stories.svelte +9 -3
  14. package/dist/components/options/InputOption.stories.svelte +13 -1
  15. package/dist/components/options/InputOption.svelte +1 -8
  16. package/dist/components/options/InputSingleChoice.stories.svelte +9 -3
  17. package/dist/components/package/Package.stories.svelte +7 -3
  18. package/dist/components/package/Package.svelte +25 -3
  19. package/dist/components/paywall/Paywall.svelte +86 -6
  20. package/dist/components/paywall/Paywall.svelte.d.ts +2 -0
  21. package/dist/components/purchase-button/PurchaseButton.stories.svelte +13 -1
  22. package/dist/components/purchase-button/PurchaseButton.svelte +62 -3
  23. package/dist/components/skeleton-loader/SkeletonLoader.svelte +18 -6
  24. package/dist/components/stack/Stack.stories.svelte +9 -3
  25. package/dist/components/stack/Stack.svelte +2 -2
  26. package/dist/components/tabs/TabControlButton.svelte +1 -1
  27. package/dist/components/tabs/TabControlToggle.svelte +1 -1
  28. package/dist/components/tabs/Tabs.stories.svelte +65 -3
  29. package/dist/components/tabs/Tabs.svelte +39 -12
  30. package/dist/components/tabs/tabs-context.d.ts +1 -1
  31. package/dist/components/text/TextNode.svelte +45 -2
  32. package/dist/components/video/Video.stories.svelte +9 -2
  33. package/dist/components/video/Video.svelte +8 -2
  34. package/dist/components/workflows/Screen.svelte +4 -0
  35. package/dist/components/workflows/Screen.svelte.d.ts +2 -0
  36. package/dist/stores/paywall.d.ts +4 -0
  37. package/dist/stories/paywall-decorator.js +2 -0
  38. package/dist/types/component.d.ts +2 -2
  39. package/dist/types/components/purchase-button.d.ts +24 -0
  40. package/dist/types/overrides.d.ts +8 -2
  41. package/dist/types/paywall-component-interaction.d.ts +50 -0
  42. package/dist/types/paywall-component-interaction.js +1 -0
  43. package/dist/types/variables.d.ts +1 -0
  44. package/dist/types.d.ts +3 -2
  45. package/dist/utils/background-utils.js +4 -1
  46. package/dist/utils/base-utils.d.ts +9 -1
  47. package/dist/utils/base-utils.js +34 -3
  48. package/dist/utils/style-utils.d.ts +4 -1
  49. package/dist/utils/style-utils.js +96 -27
  50. package/package.json +1 -1
@@ -98,3 +98,25 @@
98
98
  },
99
99
  }}
100
100
  />
101
+
102
+ <Story
103
+ name="Border"
104
+ args={{
105
+ icon_background: {
106
+ ...icon_background,
107
+ border: {
108
+ width: 10,
109
+ color: {
110
+ light: {
111
+ type: "linear",
112
+ degrees: 90,
113
+ points: [
114
+ { color: "#000000", percent: 0 },
115
+ { color: "#FF0000", percent: 100 },
116
+ ],
117
+ },
118
+ },
119
+ },
120
+ },
121
+ }}
122
+ />
@@ -40,7 +40,7 @@
40
40
  margin: mapSpacing(margin),
41
41
  padding: mapSpacing(padding),
42
42
  "background-color": mapColor(colorMode, background?.color),
43
- border: mapBorder(colorMode, background?.border),
43
+ ...mapBorder(colorMode, background?.border),
44
44
  "border-radius": mapBorderRadius(background?.shape),
45
45
  "box-shadow": mapShadow(colorMode, background?.shadow),
46
46
  flex: "0 0 auto",
@@ -68,6 +68,6 @@
68
68
  );
69
69
  </script>
70
70
 
71
- <div style={container}>
71
+ <div class="rc-gradient-border" style={container}>
72
72
  <div style={icon}></div>
73
73
  </div>
@@ -183,3 +183,22 @@
183
183
  },
184
184
  }}
185
185
  />
186
+
187
+ <Story
188
+ name="Border"
189
+ args={{
190
+ border: {
191
+ width: 10,
192
+ color: {
193
+ light: {
194
+ type: "linear",
195
+ degrees: 90,
196
+ points: [
197
+ { color: "#000000", percent: 0 },
198
+ { color: "#FF0000", percent: 100 },
199
+ ],
200
+ },
201
+ },
202
+ },
203
+ }}
204
+ />
@@ -132,6 +132,12 @@
132
132
  </g>
133
133
 
134
134
  <Overlay id={`${id}-overlay`} {overlay} />
135
+ {#if border && border.width > 0}
136
+ <Overlay
137
+ id={`${id}-border-color`}
138
+ overlay={mapColorMode(colorMode, border.color)}
139
+ />
140
+ {/if}
135
141
  </defs>
136
142
 
137
143
  {#if border && border.width > 0}
@@ -161,8 +167,8 @@
161
167
  <use
162
168
  href={`#${id}-border`}
163
169
  fill="none"
164
- stroke={mapColor(colorMode, border.color)}
165
- stroke-width={border.width}
170
+ stroke={`url(#${id}-border-color)`}
171
+ stroke-width={border.width * 2}
166
172
  />
167
173
  {/if}
168
174
  </g>
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
2
  import { getColorModeContext } from "../../stores/color-mode";
3
- import { getHoverStateContext } from "../../stores/hover";
4
3
  import { getLocalizationContext } from "../../stores/localization";
5
- import { getPackageInfoContext } from "../../stores/packageInfo";
6
4
  import { getPaywallContext } from "../../stores/paywall";
7
- import { getSelectedStateContext } from "../../stores/selected";
8
5
  import { getVariablesContext } from "../../stores/variables";
9
6
  import { FontWeights, TextAlignments } from "../../types";
10
- import type { InputTextProps } from "../../types/components/input-text";
7
+ import type {
8
+ InputTextKeyboardType,
9
+ InputTextProps,
10
+ } from "../../types/components/input-text";
11
11
  import { mapBackground } from "../../utils/background-utils";
12
12
  import {
13
13
  css,
@@ -22,20 +22,18 @@
22
22
  isFontRCFMManaged,
23
23
  } from "../../utils/font-utils";
24
24
  import {
25
- evaluateVisibilityConditions,
26
- getActiveStateProps,
27
- getHoverStateProps,
25
+ getErrorStateProps,
26
+ getFocusStateProps,
28
27
  } from "../../utils/style-utils";
29
28
  import { replaceVariables } from "../../utils/variable-utils";
30
- import type { HTMLInputAttributes } from "svelte/elements";
29
+ import type { FormEventHandler, HTMLInputAttributes } from "svelte/elements";
31
30
  import { mapTextColor } from "../text/text-utils";
32
31
 
33
32
  const props: InputTextProps = $props();
34
33
 
35
- console.log("Hello");
34
+ let focused = $state(false);
35
+ let error = $state(false);
36
36
 
37
- const selectedState = getSelectedStateContext();
38
- const hoverState = getHoverStateContext();
39
37
  const {
40
38
  placeholder_lid,
41
39
  keyboard_type,
@@ -62,15 +60,49 @@
62
60
  } = $derived.by(() => {
63
61
  return {
64
62
  ...props,
65
- ...getHoverStateProps($hoverState, props.overrides),
66
- ...getActiveStateProps($selectedState, props.overrides),
63
+ ...getFocusStateProps(focused, props.overrides),
64
+ ...getErrorStateProps(error, props.overrides),
67
65
  };
68
66
  });
69
67
 
68
+ function handleValueChange(input: HTMLInputElement) {
69
+ error = !input.validity.valid;
70
+ if (error) {
71
+ return;
72
+ }
73
+
74
+ const value = input.value.trim();
75
+ onInputChanged?.(field_id, value);
76
+ }
77
+
78
+ const oninput: FormEventHandler<HTMLInputElement> = (event) => {
79
+ if (error) {
80
+ handleValueChange(event.currentTarget);
81
+ }
82
+ };
83
+
84
+ const onblur: FormEventHandler<HTMLInputElement> = (event) => {
85
+ focused = false;
86
+ handleValueChange(event.currentTarget);
87
+ };
88
+
70
89
  const getColorMode = getColorModeContext();
71
90
  const colorMode = $derived(getColorMode());
72
91
  const { uiConfig, onInputChanged } = getPaywallContext();
73
92
 
93
+ const wrapperStyle = $derived(
94
+ css({
95
+ display: props.visible === false ? "none" : "flex",
96
+ width: mapSize(size.width),
97
+ height: mapSize(size.height),
98
+ margin: mapSpacing(margin),
99
+ ...mapBackground(colorMode, background_color, null),
100
+ ...mapBorder(colorMode, border),
101
+ "border-radius": mapBorderRadius(shape),
102
+ "box-shadow": mapShadow(colorMode, shadow),
103
+ }),
104
+ );
105
+
74
106
  const inputStyle = $derived.by(() => {
75
107
  const font = uiConfig.app.fonts[font_name ?? ""];
76
108
  const fontFamily = font?.web?.family;
@@ -79,17 +111,7 @@
79
111
  const placeholderColor = mapTextColor(colorMode, placeholder_color);
80
112
 
81
113
  return css({
82
- display: props.visible === false ? "none" : "flex",
83
- position: "relative",
84
- width: mapSize(size.width),
85
- height: mapSize(size.height),
86
- margin: mapSpacing(margin),
87
114
  padding: mapSpacing(padding),
88
- ...mapBackground(colorMode, background_color, null),
89
- border: mapBorder(colorMode, border),
90
- "border-radius": mapBorderRadius(shape),
91
- "box-shadow": mapShadow(colorMode, shadow),
92
-
93
115
  ...mapTextColor(colorMode, color),
94
116
  "text-align":
95
117
  TextAlignments[horizontal_alignment] || TextAlignments.leading,
@@ -135,21 +157,39 @@
135
157
  return "tel";
136
158
  case "text":
137
159
  return "text";
160
+ case "url":
161
+ return "url";
138
162
  }
139
163
  });
140
164
  </script>
141
165
 
142
- <input
143
- {type}
144
- {placeholder}
145
- {required}
146
- inputmode={keyboard_type}
147
- autocapitalize={capitalize}
148
- style={inputStyle}
149
- oninput={(event) => onInputChanged?.(field_id, event.currentTarget.value)}
150
- />
166
+ <div class="rc-gradient-border" style={wrapperStyle}>
167
+ <input
168
+ {type}
169
+ {placeholder}
170
+ {required}
171
+ inputmode={keyboard_type}
172
+ autocapitalize={capitalize}
173
+ style={inputStyle}
174
+ {oninput}
175
+ onfocus={() => (focused = true)}
176
+ {onblur}
177
+ />
178
+ </div>
151
179
 
152
180
  <style>
181
+ input {
182
+ width: 100%;
183
+ height: 100%;
184
+ border: none;
185
+ background: transparent;
186
+ border-radius: inherit;
187
+ }
188
+
189
+ input:focus-visible {
190
+ outline: none;
191
+ }
192
+
153
193
  input::placeholder {
154
194
  color: var(--placeholder-color);
155
195
  background: var(--placeholder-background);
@@ -72,10 +72,16 @@
72
72
  },
73
73
  background: null,
74
74
  border: {
75
- width: 1,
75
+ width: 10,
76
76
  color: {
77
- light: { type: "hex", value: "#E0E0E0" },
78
- dark: { type: "hex", value: "#404040" },
77
+ light: {
78
+ type: "linear",
79
+ degrees: 90,
80
+ points: [
81
+ { color: "#000000", percent: 0 },
82
+ { color: "#FF0000", percent: 100 },
83
+ ],
84
+ },
79
85
  },
80
86
  },
81
87
  shape: {
@@ -233,7 +233,19 @@
233
233
  light: { type: "hex", value: "#4A90E2" },
234
234
  },
235
235
  },
236
- border: null,
236
+ border: {
237
+ width: 10,
238
+ color: {
239
+ light: {
240
+ type: "linear",
241
+ degrees: 90,
242
+ points: [
243
+ { color: "#000000", percent: 0 },
244
+ { color: "#FF0000", percent: 100 },
245
+ ],
246
+ },
247
+ },
248
+ },
237
249
  shape: {
238
250
  type: "pill",
239
251
  },
@@ -10,7 +10,7 @@
10
10
  const props: InputOptionProps = $props();
11
11
  const { stack, option_id } = props;
12
12
 
13
- const { onButtonAction, onInputChanged } = getPaywallContext();
13
+ const { onButtonAction } = getPaywallContext();
14
14
  const inputChoiceContext = getInputChoiceContext();
15
15
 
16
16
  // Derive selected state from context (similar to Package)
@@ -41,13 +41,6 @@
41
41
  // Update selection state
42
42
  inputChoiceContext?.selectOption(option_id);
43
43
 
44
- // Notify host (e.g. workflows) so selections can be persisted when every option shares
45
- // the same workflow `on_press` id (e.g. `btn_*`); `onActionTriggered` alone is ambiguous.
46
- const fieldId = inputChoiceContext?.fieldId;
47
- if (fieldId) {
48
- onInputChanged?.(fieldId, option_id);
49
- }
50
-
51
44
  // Trigger navigation
52
45
  onButtonAction({ type: "workflow" }, actionId);
53
46
  };
@@ -72,10 +72,16 @@
72
72
  },
73
73
  background: null,
74
74
  border: {
75
- width: 1,
75
+ width: 10,
76
76
  color: {
77
- light: { type: "hex", value: "#E0E0E0" },
78
- dark: { type: "hex", value: "#404040" },
77
+ light: {
78
+ type: "linear",
79
+ degrees: 90,
80
+ points: [
81
+ { color: "#000000", percent: 0 },
82
+ { color: "#FF0000", percent: 100 },
83
+ ],
84
+ },
79
85
  },
80
86
  },
81
87
  shape: {
@@ -55,13 +55,17 @@
55
55
  },
56
56
  },
57
57
  border: {
58
+ width: 10,
58
59
  color: {
59
60
  light: {
60
- type: "hex",
61
- value: "#3b393f",
61
+ type: "linear",
62
+ degrees: 90,
63
+ points: [
64
+ { color: "#000000", percent: 0 },
65
+ { color: "#FF0000", percent: 100 },
66
+ ],
62
67
  },
63
68
  },
64
- width: 1,
65
69
  },
66
70
  components: [
67
71
  {
@@ -13,10 +13,14 @@
13
13
  getPackageInfoContext,
14
14
  setPackageInfoContext,
15
15
  } from "../../stores/packageInfo";
16
+ import type { PackageInfo, VariableDictionary } from "../../types/variables";
16
17
 
17
- const { stack, package_id, is_selected_by_default }: PackageProps = $props();
18
+ const { stack, package_id, is_selected_by_default, name }: PackageProps =
19
+ $props();
18
20
 
19
21
  const {
22
+ defaultPackageId,
23
+ emitComponentInteraction,
20
24
  selectedPackageId,
21
25
  variablesPerPackage,
22
26
  baseVariables,
@@ -40,7 +44,21 @@
40
44
  setSelectedStateContext(selectedStateStore);
41
45
 
42
46
  const onPackageClick = () => {
47
+ const originPackageId = $selectedPackageId;
48
+ if (originPackageId === package_id) {
49
+ return;
50
+ }
51
+
43
52
  $selectedPackageId = package_id;
53
+
54
+ emitComponentInteraction({
55
+ componentType: "package",
56
+ componentName: name,
57
+ componentValue: package_id,
58
+ originPackageIdentifier: originPackageId,
59
+ destinationPackageIdentifier: package_id,
60
+ defaultPackageIdentifier: defaultPackageId,
61
+ });
44
62
  };
45
63
 
46
64
  // Use $derived to make variables reactive to package_id changes
@@ -56,7 +74,9 @@
56
74
  ...packageVariables,
57
75
  };
58
76
  });
59
- const variablesStore = writable(computedVariables);
77
+ const variablesStore = writable<VariableDictionary | undefined>(
78
+ computedVariables,
79
+ );
60
80
  $effect(() => {
61
81
  variablesStore.set(computedVariables);
62
82
  });
@@ -67,7 +87,9 @@
67
87
  const computedPackageInfo = $derived(
68
88
  $infoPerPackage?.[package_id] ?? $fallbackPackageInfo,
69
89
  );
70
- const packageInfoStore = writable(computedPackageInfo);
90
+ const packageInfoStore = writable<PackageInfo | undefined>(
91
+ computedPackageInfo,
92
+ );
71
93
  $effect(() => {
72
94
  packageInfoStore.set(computedPackageInfo);
73
95
  });
@@ -19,6 +19,10 @@
19
19
  Action,
20
20
  CompleteWorkflowNavigateArgs,
21
21
  } from "../../types/components/button";
22
+ import type {
23
+ ComponentInteractionData,
24
+ OnComponentInteraction,
25
+ } from "../../types/paywall-component-interaction";
22
26
  import type { SheetProps } from "../../types/components/sheet";
23
27
  import type { PaywallData } from "../../types/paywall";
24
28
  import type { UIConfig } from "../../types/ui-config";
@@ -74,6 +78,7 @@
74
78
  args: CompleteWorkflowNavigateArgs,
75
79
  ) => void | Promise<void>;
76
80
  onActionTriggered?: (actionId: string) => void;
81
+ onComponentInteraction?: OnComponentInteraction;
77
82
  onError?: (error: unknown) => void;
78
83
  hideBackButtons?: boolean;
79
84
  walletButtonRender?: WalletButtonRender;
@@ -110,6 +115,7 @@
110
115
  onNavigateToUrlClicked,
111
116
  onCompleteWorkflowNavigate,
112
117
  onActionTriggered,
118
+ onComponentInteraction,
113
119
  onError,
114
120
  uiConfig,
115
121
  walletButtonRender,
@@ -126,6 +132,7 @@
126
132
  const { default_locale, components_config, components_localizations } =
127
133
  paywallData;
128
134
  const { base } = components_config;
135
+ const defaultPackageId = findSelectedPackageId(base);
129
136
 
130
137
  const { getLocalizedString } = setLocalizationContext(() => ({
131
138
  defaultLocale: default_locale,
@@ -133,10 +140,22 @@
133
140
  localizations: components_localizations!,
134
141
  }));
135
142
 
136
- const selectedPackageId = writable<string | undefined>(
137
- findSelectedPackageId(base),
138
- );
143
+ const selectedPackageId = writable<string | undefined>(defaultPackageId);
144
+
145
+ const normalizeComponentName = (name?: string) => {
146
+ if (name === undefined) {
147
+ return undefined;
148
+ }
139
149
 
150
+ return name.trim().length > 0 ? name : undefined;
151
+ };
152
+
153
+ const emitComponentInteraction = (data: ComponentInteractionData) => {
154
+ onComponentInteraction?.({
155
+ ...data,
156
+ componentName: normalizeComponentName(data.componentName),
157
+ });
158
+ };
140
159
  const onPurchase = (actionId?: string) => {
141
160
  const packageId = $selectedPackageId;
142
161
  if (packageId !== undefined) {
@@ -144,7 +163,10 @@
144
163
  }
145
164
  };
146
165
 
147
- let sheet = $state<SheetProps>();
166
+ let sheet = $state<{
167
+ props: SheetProps;
168
+ rootSelectedPackageIdentifier?: string;
169
+ }>();
148
170
 
149
171
  const onButtonAction = (action: Action, actionId?: string) => {
150
172
  switch (action.type) {
@@ -189,7 +211,26 @@
189
211
  }
190
212
  return;
191
213
  case "sheet":
192
- sheet = action.sheet ?? undefined;
214
+ if (action.sheet) {
215
+ sheet = {
216
+ props: action.sheet,
217
+ rootSelectedPackageIdentifier: $selectedPackageId,
218
+ };
219
+ } else {
220
+ if (sheet) {
221
+ const resultingPackageIdentifier =
222
+ sheet.rootSelectedPackageIdentifier;
223
+ emitComponentInteraction({
224
+ componentType: "package_selection_sheet",
225
+ componentName: sheet.props.name,
226
+ componentValue: "close",
227
+ currentPackageIdentifier: $selectedPackageId,
228
+ resultingPackageIdentifier,
229
+ });
230
+ selectedPackageId.set(resultingPackageIdentifier);
231
+ }
232
+ sheet = undefined;
233
+ }
193
234
  return;
194
235
  case "offer_code":
195
236
  case "web_paywall_link":
@@ -201,6 +242,7 @@
201
242
  const mergedCustomVars = mergeCustomVariables(customVariables, uiConfig);
202
243
 
203
244
  setPaywallContext({
245
+ defaultPackageId,
204
246
  selectedPackageId,
205
247
  variablesPerPackage: readable(variablesPerPackage),
206
248
  baseVariables: readable({
@@ -209,6 +251,8 @@
209
251
  }),
210
252
  infoPerPackage: readable(infoPerPackage),
211
253
  onPurchase,
254
+ emitComponentInteraction,
255
+ onNavigateToUrl: onNavigateToUrlClicked,
212
256
  onButtonAction,
213
257
  onInputChanged,
214
258
  walletButtonRender,
@@ -287,7 +331,7 @@
287
331
  </div>
288
332
 
289
333
  {#if sheet}
290
- <Sheet {...sheet} />
334
+ <Sheet {...sheet.props} />
291
335
  {/if}
292
336
  </svelte:boundary>
293
337
 
@@ -304,6 +348,18 @@
304
348
  transition-timing-function: ease-in-out;
305
349
  transform-origin: center;
306
350
 
351
+ &::before {
352
+ content: "";
353
+ position: absolute;
354
+ top: 0;
355
+ left: 0;
356
+ width: 100%;
357
+ height: 100%;
358
+ background: var(--overlay);
359
+ pointer-events: none;
360
+ z-index: 1;
361
+ }
362
+
307
363
  &:global(.blur) {
308
364
  filter: blur(10px) brightness(0.8);
309
365
  transform: scale(1.045);
@@ -317,6 +373,7 @@
317
373
  }
318
374
 
319
375
  .paywall-content {
376
+ z-index: 2;
320
377
  width: 100%;
321
378
  flex: 1;
322
379
  display: flex;
@@ -384,5 +441,28 @@
384
441
  .paywall h6 {
385
442
  text-wrap: balance;
386
443
  }
444
+
445
+ .paywall .rc-gradient-border {
446
+ position: relative;
447
+ }
448
+
449
+ .paywall .rc-gradient-border::after {
450
+ content: "";
451
+ display: var(--rc-border-display, none);
452
+ position: absolute;
453
+ inset: calc(-1 * var(--rc-border-width, 0px));
454
+ border-radius: inherit;
455
+ padding: var(--rc-border-width, 0px);
456
+ background: var(--rc-border-bg, transparent);
457
+ mask:
458
+ linear-gradient(#fff 0 0) content-box,
459
+ linear-gradient(#fff 0 0);
460
+ -webkit-mask:
461
+ linear-gradient(#fff 0 0) content-box,
462
+ linear-gradient(#fff 0 0);
463
+ mask-composite: exclude;
464
+ -webkit-mask-composite: xor;
465
+ pointer-events: none;
466
+ }
387
467
  }
388
468
  </style>
@@ -1,6 +1,7 @@
1
1
  import { type InitialInputSelections } from "../../stores/inputValidation";
2
2
  import type { ColorMode } from "../../types";
3
3
  import type { CompleteWorkflowNavigateArgs } from "../../types/components/button";
4
+ import type { OnComponentInteraction } from "../../types/paywall-component-interaction";
4
5
  import type { PaywallData } from "../../types/paywall";
5
6
  import type { UIConfig } from "../../types/ui-config";
6
7
  import { type CustomVariables, type PackageInfo, type VariableDictionary } from "../../types/variables";
@@ -34,6 +35,7 @@ interface Props {
34
35
  */
35
36
  onCompleteWorkflowNavigate?: (args: CompleteWorkflowNavigateArgs) => void | Promise<void>;
36
37
  onActionTriggered?: (actionId: string) => void;
38
+ onComponentInteraction?: OnComponentInteraction;
37
39
  onError?: (error: unknown) => void;
38
40
  hideBackButtons?: boolean;
39
41
  walletButtonRender?: WalletButtonRender;
@@ -108,7 +108,19 @@
108
108
  top: 16,
109
109
  trailing: 16,
110
110
  },
111
- border: null,
111
+ border: {
112
+ width: 10,
113
+ color: {
114
+ light: {
115
+ type: "linear",
116
+ degrees: 90,
117
+ points: [
118
+ { color: "#000000", percent: 0 },
119
+ { color: "#FF0000", percent: 100 },
120
+ ],
121
+ },
122
+ },
123
+ },
112
124
  shadow: null,
113
125
  shape: {
114
126
  corners: {