@frak-labs/components 1.0.4 → 1.0.5-beta.53162c2d

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.
@@ -1,4 +1,5 @@
1
- import { a as registerWebComponent, i as useClientReady, n as buildStyleContent, o as openWalletModal, t as usePlacement } from "./usePlacement-DzEuVg_u.js";
1
+ import { a as registerWebComponent, i as useClientReady, n as buildStyleContent, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
2
+ import { t as openEmbeddedWallet } from "./embeddedWallet-By3_p5Xc.js";
2
3
  import { t as useReward } from "./useReward-ClVShg45.js";
3
4
  import { useEffect, useMemo, useState } from "preact/hooks";
4
5
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
@@ -20,6 +21,21 @@ function GiftIcon(props) {
20
21
  });
21
22
  }
22
23
  //#endregion
24
+ //#region src/utils/browser/safeVibrate.ts
25
+ /**
26
+ * Attempt to vibrate the device
27
+ */
28
+ function safeVibrate() {
29
+ if ("vibrate" in navigator) navigator.vibrate(10);
30
+ else console.log("Vibration not supported");
31
+ }
32
+ //#endregion
33
+ //#region src/components/ButtonWallet/utils.ts
34
+ function openWalletModal(targetInteraction, placement) {
35
+ safeVibrate();
36
+ openEmbeddedWallet(targetInteraction, placement);
37
+ }
38
+ //#endregion
23
39
  //#region src/components/ButtonWallet/ButtonWallet.tsx
24
40
  const componentCss = `
25
41
  .button {
@@ -0,0 +1,18 @@
1
+ import { displayEmbeddedWallet } from "@frak-labs/core-sdk/actions";
2
+ //#region src/actions/embeddedWallet.ts
3
+ async function openEmbeddedWallet(targetInteraction, placement) {
4
+ if (!window.FrakSetup?.client) {
5
+ console.error("Frak client not found");
6
+ return;
7
+ }
8
+ const modalWalletConfig = window.FrakSetup?.modalWalletConfig ?? {};
9
+ await displayEmbeddedWallet(window.FrakSetup.client, targetInteraction ? {
10
+ ...modalWalletConfig,
11
+ metadata: {
12
+ ...modalWalletConfig.metadata,
13
+ targetInteraction
14
+ }
15
+ } : modalWalletConfig, placement);
16
+ }
17
+ //#endregion
18
+ export { openEmbeddedWallet as t };
package/dist/openInApp.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as registerWebComponent, i as useClientReady, t as usePlacement } from "./usePlacement-DzEuVg_u.js";
2
- import { t as useLightDomStyles } from "./useLightDomStyles-DVe5UDg6.js";
1
+ import { a as registerWebComponent, i as useClientReady, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
2
+ import { t as useLightDomStyles } from "./useLightDomStyles-C8giLInY.js";
3
3
  import { DEEP_LINK_SCHEME, isMobile, trackEvent, triggerDeepLinkWithFallback } from "@frak-labs/core-sdk";
4
4
  import { useMemo } from "preact/hooks";
5
5
  import { jsx } from "preact/jsx-runtime";
@@ -1,7 +1,6 @@
1
- import { a as registerWebComponent, i as useClientReady, t as usePlacement } from "./usePlacement-DzEuVg_u.js";
2
- import { t as openSharingPage } from "./sharingPage-D6fQEXV9.js";
1
+ import { a as registerWebComponent, i as useClientReady, o as sanitizeProductList, s as openSharingPage, t as usePlacement } from "./usePlacement-5kbU3BKj.js";
3
2
  import { t as useGlobalComponents } from "./useGlobalComponents-mSs9unyN.js";
4
- import { t as useLightDomStyles } from "./useLightDomStyles-DVe5UDg6.js";
3
+ import { t as useLightDomStyles } from "./useLightDomStyles-C8giLInY.js";
5
4
  import { n as formatEstimatedReward, t as applyRewardPlaceholder } from "./formatReward-Cf2KpA3x.js";
6
5
  import { i as LogoFrakWithName, n as cssSource$2, t as GiftIcon } from "./GiftIcon-BIp9FTJs.js";
7
6
  import { trackEvent } from "@frak-labs/core-sdk";
@@ -112,67 +111,6 @@ var imageWrapper = "PostPurchase_imageWrapper__5fv5lh9";
112
111
  var message = "PostPurchase_message__5fv5lh5";
113
112
  const cssSource = cssSource$1;
114
113
  //#endregion
115
- //#region src/components/PostPurchase/products.ts
116
- /**
117
- * Whether `value` is a syntactically valid URL with an `http(s):` scheme.
118
- *
119
- * Used to gate `imageUrl` / `link` fields coming from the public `products`
120
- * prop — the listener-side sharing-page builder calls `new URL(...)` on the
121
- * incoming product link, and a `javascript:` URL would be a XSS sink in any
122
- * consumer that binds the value to an `href`.
123
- */
124
- function isHttpUrl(value) {
125
- try {
126
- const parsed = new URL(value);
127
- return parsed.protocol === "http:" || parsed.protocol === "https:";
128
- } catch {
129
- return false;
130
- }
131
- }
132
- /**
133
- * Coerce a raw `products` prop value into a candidate array suitable for
134
- * per-item normalisation, or null when it cannot be reduced to one.
135
- *
136
- * Surfaces that set the prop via the JS property (`el.products = [...]`)
137
- * deliver a real array; surfaces that bind it as an HTML attribute
138
- * (WP / Magento server-render) deliver a JSON-stringified array. Anything
139
- * else (truthy non-array non-string, JSON parse failure, JSON that decodes
140
- * to a non-array) is treated as "no products" so the share still works
141
- * without the product card section.
142
- */
143
- function coerceProductCandidates(products) {
144
- if (!products) return null;
145
- if (Array.isArray(products)) return products;
146
- if (typeof products !== "string") return null;
147
- try {
148
- const parsed = JSON.parse(products);
149
- return Array.isArray(parsed) ? parsed : null;
150
- } catch {
151
- return null;
152
- }
153
- }
154
- /**
155
- * Normalise one untrusted candidate into a {@link SharingPageProduct}, or
156
- * return null when the candidate has no usable title.
157
- *
158
- * The `products` prop is a public API boundary (merchants can set it
159
- * server-side via WP/Magento or imperatively from arbitrary JS). Each entry
160
- * is validated structurally so a malformed `link` reaching `new URL(...)`
161
- * downstream would not crash the sharing-page builder, and so a
162
- * `javascript:` URL cannot slip through as `imageUrl` / `link`.
163
- */
164
- function normalizeProductCandidate(candidate) {
165
- if (!candidate || typeof candidate !== "object") return null;
166
- const item = candidate;
167
- const title = typeof item.title === "string" ? item.title.trim() : "";
168
- if (title === "") return null;
169
- const entry = { title };
170
- if (typeof item.imageUrl === "string" && isHttpUrl(item.imageUrl)) entry.imageUrl = item.imageUrl;
171
- if (typeof item.link === "string" && isHttpUrl(item.link)) entry.link = item.link;
172
- if (typeof item.utmContent === "string" && item.utmContent !== "") entry.utmContent = item.utmContent;
173
- return entry;
174
- }
175
- //#endregion
176
114
  //#region src/components/PostPurchase/PostPurchase.tsx
177
115
  /**
178
116
  * Given referral status and merchant info, compute the display variant
@@ -303,16 +241,7 @@ function PostPurchase({ customerId, orderId, token, sharingUrl, merchantId, plac
303
241
  placementId,
304
242
  context?.reward
305
243
  ]);
306
- const parsedProducts = useMemo(() => {
307
- const candidates = coerceProductCandidates(products);
308
- if (!candidates) return void 0;
309
- const sanitized = [];
310
- for (const candidate of candidates) {
311
- const entry = normalizeProductCandidate(candidate);
312
- if (entry) sanitized.push(entry);
313
- }
314
- return sanitized.length > 0 ? sanitized : void 0;
315
- }, [products]);
244
+ const parsedProducts = useMemo(() => sanitizeProductList(products), [products]);
316
245
  const handleClick = useCallback(() => {
317
246
  if (!resolvedVariant) return;
318
247
  trackEvent(window.FrakSetup?.client, "post_purchase_clicked", {
@@ -1,4 +1,4 @@
1
- import { r as lightDomBaseCss } from "./usePlacement-DzEuVg_u.js";
1
+ import { r as lightDomBaseCss } from "./usePlacement-5kbU3BKj.js";
2
2
  import { useEffect } from "preact/hooks";
3
3
  //#region src/styles/styleManager.ts
4
4
  function ensureStyle(id, css) {
@@ -1,38 +1,126 @@
1
1
  import register from "preact-custom-element";
2
2
  import * as coreSdkIndex from "@frak-labs/core-sdk";
3
- import { sdkConfigStore, setupClient, trackEvent, withCache } from "@frak-labs/core-sdk";
3
+ import { decompressJsonFromB64, sdkConfigStore, setupClient, trackEvent, withCache } from "@frak-labs/core-sdk";
4
4
  import * as coreSdkActions from "@frak-labs/core-sdk/actions";
5
- import { displayEmbeddedWallet } from "@frak-labs/core-sdk/actions";
5
+ import { displaySharingPage } from "@frak-labs/core-sdk/actions";
6
6
  import { useEffect, useMemo, useState } from "preact/hooks";
7
- //#region src/actions/embeddedWallet.ts
8
- async function openEmbeddedWallet(targetInteraction, placement) {
7
+ //#region src/actions/sharingPage.ts
8
+ async function openSharingPage(targetInteraction, placement, options) {
9
9
  if (!window.FrakSetup?.client) {
10
10
  console.error("Frak client not found");
11
11
  return;
12
12
  }
13
- const modalWalletConfig = window.FrakSetup?.modalWalletConfig ?? {};
14
- await displayEmbeddedWallet(window.FrakSetup.client, targetInteraction ? {
15
- ...modalWalletConfig,
16
- metadata: {
17
- ...modalWalletConfig.metadata,
18
- targetInteraction
19
- }
20
- } : modalWalletConfig, placement);
13
+ await displaySharingPage(window.FrakSetup.client, {
14
+ ...options?.link && { link: options.link },
15
+ ...options?.products?.length && { products: options.products },
16
+ ...targetInteraction && { metadata: { targetInteraction } }
17
+ }, placement);
21
18
  }
22
19
  //#endregion
23
- //#region src/utils/browser/safeVibrate.ts
20
+ //#region src/utils/sharingPageProducts.ts
24
21
  /**
25
- * Attempt to vibrate the device
22
+ * Whether `value` is a syntactically valid URL with an `http(s):` scheme.
23
+ *
24
+ * Used to gate `imageUrl` / `link` fields coming from untrusted inputs (the
25
+ * public `products` prop on `<frak-post-purchase>`, decoded query params for
26
+ * Klaviyo / email share links, etc.) — the listener-side sharing-page builder
27
+ * calls `new URL(...)` on the incoming product link, and a `javascript:` URL
28
+ * would be a XSS sink in any consumer that binds the value to an `href`.
26
29
  */
27
- function safeVibrate() {
28
- if ("vibrate" in navigator) navigator.vibrate(10);
29
- else console.log("Vibration not supported");
30
+ function isHttpUrl(value) {
31
+ try {
32
+ const parsed = new URL(value);
33
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
34
+ } catch {
35
+ return false;
36
+ }
30
37
  }
31
- //#endregion
32
- //#region src/components/ButtonWallet/utils.ts
33
- function openWalletModal(targetInteraction, placement) {
34
- safeVibrate();
35
- openEmbeddedWallet(targetInteraction, placement);
38
+ /**
39
+ * Coerce a raw `products` value into a candidate array suitable for
40
+ * per-item normalisation, or null when it cannot be reduced to one.
41
+ *
42
+ * Accepts:
43
+ * - Real arrays (JS-property surface, decompressed query payloads).
44
+ * - JSON-stringified arrays (HTML-attribute surface — WP / Magento
45
+ * server-render delivers attribute values as raw strings).
46
+ *
47
+ * Anything else (non-array non-string, JSON parse failure, JSON that
48
+ * decodes to a non-array) is treated as "no products" so the share still
49
+ * works without the product card section.
50
+ */
51
+ function coerceProductCandidates(products) {
52
+ if (!products) return null;
53
+ if (Array.isArray(products)) return products;
54
+ if (typeof products !== "string") return null;
55
+ try {
56
+ const parsed = JSON.parse(products);
57
+ return Array.isArray(parsed) ? parsed : null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+ /**
63
+ * Normalise one untrusted candidate into a {@link SharingPageProduct}, or
64
+ * return null when the candidate has no usable title.
65
+ *
66
+ * The `products` payload is a public API boundary — merchants can set it
67
+ * server-side via WP / Magento, imperatively from arbitrary JS, or via
68
+ * email-template query params built by Klaviyo. Each entry is validated
69
+ * structurally so a malformed `link` reaching `new URL(...)` downstream
70
+ * would not crash the sharing-page builder, and so a `javascript:` URL
71
+ * cannot slip through as `imageUrl` / `link`.
72
+ */
73
+ function normalizeProductCandidate(candidate) {
74
+ if (!candidate || typeof candidate !== "object") return null;
75
+ const item = candidate;
76
+ const title = typeof item.title === "string" ? item.title.trim() : "";
77
+ if (title === "") return null;
78
+ const entry = { title };
79
+ if (typeof item.imageUrl === "string" && isHttpUrl(item.imageUrl)) entry.imageUrl = item.imageUrl;
80
+ if (typeof item.link === "string" && isHttpUrl(item.link)) entry.link = item.link;
81
+ if (typeof item.utmContent === "string" && item.utmContent !== "") entry.utmContent = item.utmContent;
82
+ return entry;
83
+ }
84
+ /**
85
+ * Pipe `coerceProductCandidates` + `normalizeProductCandidate` over an
86
+ * untrusted value and return a non-empty {@link SharingPageProduct}[] or
87
+ * `undefined` when nothing usable came out.
88
+ *
89
+ * The undefined sentinel is what `openSharingPage` / `displaySharingPage`
90
+ * expect when the caller has no products to show — the sharing page just
91
+ * skips the product card section.
92
+ */
93
+ function sanitizeProductList(input) {
94
+ const candidates = coerceProductCandidates(input);
95
+ if (!candidates) return void 0;
96
+ const sanitized = [];
97
+ for (const candidate of candidates) {
98
+ const entry = normalizeProductCandidate(candidate);
99
+ if (entry) sanitized.push(entry);
100
+ }
101
+ return sanitized.length > 0 ? sanitized : void 0;
102
+ }
103
+ /**
104
+ * Decode a `products` URL query param produced by
105
+ * `compressJsonToB64(productsArray)` — the encoding Klaviyo (and any
106
+ * other email tool) uses when embedding the product list of an order
107
+ * confirmation into a Frak share CTA.
108
+ *
109
+ * The result is run through `sanitizeProductList` so every link / image
110
+ * URL is structurally validated before reaching `new URL(...)` downstream.
111
+ * Malformed / tampered payloads degrade gracefully to `undefined` — the
112
+ * share still works, just without the product card section.
113
+ */
114
+ function decodeProductsParam(value) {
115
+ if (!value) return void 0;
116
+ let decoded;
117
+ try {
118
+ decoded = decompressJsonFromB64(value);
119
+ } catch {
120
+ return;
121
+ }
122
+ if (decoded === null) return void 0;
123
+ return sanitizeProductList(decoded);
36
124
  }
37
125
  //#endregion
38
126
  //#region src/bootstrap/clientReady.ts
@@ -97,15 +185,41 @@ async function doInit() {
97
185
  handleActionQueryParam();
98
186
  }
99
187
  /**
100
- * Check the query param contain params for an auto opening of the frak modal
188
+ * Check the query param for an auto-opening of the Frak sharing page.
189
+ *
190
+ * Supported params (all optional except `frakAction`):
191
+ * - `frakAction=share` triggers the auto-open.
192
+ * - `link` overrides the URL the sharing page generates outbound shares for.
193
+ * When omitted, the listener falls back to the merchant domain.
194
+ * - `products` is a base64-encoded compressed JSON payload of
195
+ * `SharingPageProduct[]` — produced by `compressJsonToB64(productsArray)`
196
+ * on the sender side (e.g. a Klaviyo email template). Used by
197
+ * post-purchase emails to surface the items the customer just bought as
198
+ * product cards on the sharing page.
199
+ * - `placement` lets the caller scope backend-driven CSS / config to a
200
+ * specific placement (mirrors the prop on the components).
201
+ *
202
+ * The four params are stripped from the URL via `history.replaceState` as
203
+ * soon as they are read, so refreshes / shares of the current URL do not
204
+ * re-trigger the auto-open. Matches the `fmt` (merge token) and `sso`
205
+ * cleanup patterns elsewhere in the SDK.
101
206
  */
102
207
  function handleActionQueryParam() {
103
- const frakAction = new URLSearchParams(window.location.search).get("frakAction");
104
- if (!frakAction) return;
105
- if (frakAction === "share") {
106
- console.log("[Frak SDK] Auto open query param found");
107
- openWalletModal();
108
- }
208
+ const url = new URL(window.location.href);
209
+ if (url.searchParams.get("frakAction") !== "share") return;
210
+ console.log("[Frak SDK] Auto open share via query param");
211
+ const link = url.searchParams.get("link") ?? void 0;
212
+ const placement = url.searchParams.get("placement") ?? void 0;
213
+ const products = decodeProductsParam(url.searchParams.get("products"));
214
+ url.searchParams.delete("frakAction");
215
+ url.searchParams.delete("link");
216
+ url.searchParams.delete("placement");
217
+ url.searchParams.delete("products");
218
+ window.history.replaceState({}, "", url.toString());
219
+ openSharingPage(void 0, placement, {
220
+ link,
221
+ products
222
+ });
109
223
  }
110
224
  //#endregion
111
225
  //#region src/utils/browser/onDocumentReady.ts
@@ -250,4 +364,4 @@ function usePlacement(placementId) {
250
364
  return useMemo(() => placementId ? getPlacement(placementId) : void 0, [placementId, configVersion]);
251
365
  }
252
366
  //#endregion
253
- export { registerWebComponent as a, useClientReady as i, buildStyleContent as n, openWalletModal as o, lightDomBaseCss as r, openEmbeddedWallet as s, usePlacement as t };
367
+ export { registerWebComponent as a, useClientReady as i, buildStyleContent as n, sanitizeProductList as o, lightDomBaseCss as r, openSharingPage as s, usePlacement as t };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "url": "https://twitter.com/QNivelais"
12
12
  }
13
13
  ],
14
- "version": "1.0.4",
14
+ "version": "1.0.5-beta.53162c2d",
15
15
  "description": "Frak Wallet components, helping any person to interact with the Frak wallet.",
16
16
  "repository": {
17
17
  "url": "https://github.com/frak-id/wallet",
@@ -86,8 +86,8 @@
86
86
  "publish": "echo 'Publishing components...'"
87
87
  },
88
88
  "dependencies": {
89
- "@frak-labs/core-sdk": "1.1.0",
90
- "@frak-labs/frame-connector": "0.2.0",
89
+ "@frak-labs/core-sdk": "1.1.0-beta.53162c2d",
90
+ "@frak-labs/frame-connector": "0.2.0-beta.53162c2d",
91
91
  "preact": "^10.29.0",
92
92
  "preact-custom-element": "^4.6.0",
93
93
  "@frak-labs/design-system": "0.0.0"
@@ -1,178 +0,0 @@
1
- import{T as e,b as t,c as n,d as r,u as i,v as a}from"./loader.js";import{a as o,c as s,d as c,i as l,l as u,o as d,s as f,t as ee,u as p}from"./usePlacement.BgMXY5CX.js";import{a as m,i as h,n as g,r as te,t as _}from"./GiftIcon.eRNTGQ_r.js";import{t as v}from"./useGlobalComponents.TG9kIYSc.js";import{t as y}from"./useLightDomStyles.tjNBKcOr.js";import{t as b}from"./useReward.B530suzR.js";var x=`inAppBanner_body__1ibpiy75`,S=`inAppBanner_closeButton__1ibpiy78`,C=`inAppBanner_container__1ibpiy71`,w=`inAppBanner_cta__1ibpiy77`,T=`inAppBanner_description__1ibpiy76`,E=`inAppBanner_header__1ibpiy72`,D=`inAppBanner_iconWrapper__1ibpiy73`,O=`inAppBanner_title__1ibpiy74`;function k({title:e,description:t,cta:n,dismissLabel:r,onAction:i,onDismiss:a,className:o,classNames:s}){return p(`div`,{className:`${C}${o?` ${o}`:``}`,role:`alert`,children:[p(`div`,{className:E,children:[p(`span`,{className:`${D}${s?.icon?` ${s.icon}`:``}`,children:p(g,{width:20,height:20})}),p(`p`,{className:`${O}${s?.title?` ${s.title}`:``}`,children:e})]}),p(`div`,{className:x,children:[p(`p`,{className:`${T}${s?.description?` ${s.description}`:``}`,children:t}),p(`button`,{type:`button`,className:`${w}${s?.cta?` ${s.cta}`:``}`,onClick:i,children:[n,p(h,{width:14,height:14})]})]}),p(`button`,{type:`button`,className:`${S}${s?.close?` ${s.close}`:``}`,onClick:a,"aria-label":r,children:p(m,{width:16,height:16})})]})}var A=`Banner_frakLogo__1gnumzia`,j=`Banner_iconSvg__1gnumzi2`,M=`Banner_referral__1gnumzi3 reset_base__1831jhd0 Banner_rootBase__1gnumzi1`,N=`Banner_referralBody__1gnumzi6`,P=`Banner_referralCta__1gnumzi9 sharedBaseCss_buttonReset__7cswil0`,ne=`Banner_referralDescription__1gnumzi8 reset_base__1831jhd0`,F=`Banner_referralIconWrapper__1gnumzi4`,I=`Banner_referralImage__1gnumzi5`,L=`Banner_referralTitle__1gnumzi7 reset_base__1831jhd0`;function R({placement:c,classname:m=``,interaction:h,referralTitle:g,referralDescription:x,referralCta:S,inappTitle:C,inappDescription:w,inappCta:T,imageUrl:E,preview:D,previewMode:O}){let R=!!D,z=O===`inapp`?`inapp`:`referral`,B=ee(c),{shouldRender:V,isHidden:H,isClientReady:U}=l();y(`frak-banner`,c,B?.components?.banner?.css,`@keyframes inAppBanner_fadeIn__1ibpiy70 {
2
- from {
3
- opacity: 0;
4
- transform: translateY(-4px);
5
- }
6
- to {
7
- opacity: 1;
8
- transform: translateY(0);
9
- }
10
- }
11
- .inAppBanner_container__1ibpiy71 {
12
- position: fixed;
13
- top: max(8px, env(safe-area-inset-top));
14
- left: 16px;
15
- right: 16px;
16
- z-index: 1000;
17
- display: flex;
18
- flex-direction: column;
19
- gap: 4px;
20
- padding: 12px 16px;
21
- padding-right: 32px;
22
- border-radius: 12px;
23
- background-color: #000000CC;
24
- backdrop-filter: blur(12px);
25
- -webkit-backdrop-filter: blur(12px);
26
- color: #ffffff;
27
- animation: inAppBanner_fadeIn__1ibpiy70 300ms ease-out;
28
- }
29
- .inAppBanner_header__1ibpiy72 {
30
- display: flex;
31
- align-items: center;
32
- gap: 8px;
33
- }
34
- .inAppBanner_iconWrapper__1ibpiy73 {
35
- flex-shrink: 0;
36
- width: 20px;
37
- height: 20px;
38
- display: flex;
39
- align-items: center;
40
- justify-content: center;
41
- color: #ffffff;
42
- }
43
- .inAppBanner_title__1ibpiy74 {
44
- margin: 0;
45
- padding: 0;
46
- font-size: 16px;
47
- font-weight: 500;
48
- line-height: 26px;
49
- color: var(--text-onAction__pbq4ak6);
50
- }
51
- .inAppBanner_body__1ibpiy75 {
52
- display: flex;
53
- flex-wrap: wrap;
54
- align-items: baseline;
55
- gap: 0 4px;
56
- }
57
- .inAppBanner_description__1ibpiy76 {
58
- margin: 0;
59
- padding: 0;
60
- font-size: 14px;
61
- color: var(--text-onAction__pbq4ak6);
62
- line-height: 22px;
63
- opacity: 0.96;
64
- }
65
- .inAppBanner_cta__1ibpiy77 {
66
- all: unset;
67
- display: inline-flex;
68
- align-items: center;
69
- gap: 4px;
70
- color: #2BB2FF;
71
- font-size: 14px;
72
- font-weight: 600;
73
- text-decoration: underline;
74
- text-underline-offset: 2px;
75
- cursor: pointer;
76
- }
77
- .inAppBanner_cta__1ibpiy77:focus-visible {
78
- outline: 2px solid #2BB2FF;
79
- outline-offset: 2px;
80
- border-radius: 4px;
81
- }
82
- .inAppBanner_closeButton__1ibpiy78 {
83
- all: unset;
84
- position: absolute;
85
- top: 8px;
86
- right: 8px;
87
- width: 28px;
88
- height: 28px;
89
- display: flex;
90
- align-items: center;
91
- justify-content: center;
92
- border-radius: 9999px;
93
- color: rgba(255, 255, 255, 0.6);
94
- cursor: pointer;
95
- }
96
- .inAppBanner_closeButton__1ibpiy78:focus-visible {
97
- outline: 2px solid #ffffff;
98
- outline-offset: 2px;
99
- }@keyframes Banner_fadeIn__1gnumzi0 {
100
- from {
101
- opacity: 0;
102
- transform: translateY(-4px);
103
- }
104
- to {
105
- opacity: 1;
106
- transform: translateY(0);
107
- }
108
- }
109
- .Banner_rootBase__1gnumzi1 {
110
- position: relative;
111
- display: flex;
112
- animation: Banner_fadeIn__1gnumzi0 300ms ease-out;
113
- }
114
- .Banner_iconSvg__1gnumzi2 {
115
- width: 100%;
116
- height: 100%;
117
- }
118
- .Banner_referral__1gnumzi3 {
119
- flex-direction: row;
120
- align-items: center;
121
- gap: 16px;
122
- padding: 16px;
123
- background-color: #ffffff;
124
- color: var(--text-primary__pbq4ak0);
125
- border: 1px solid var(--border-default__pbq4akv);
126
- border-radius: 12px;
127
- }
128
- .Banner_referralIconWrapper__1gnumzi4 {
129
- flex-shrink: 0;
130
- align-self: flex-start;
131
- display: flex;
132
- align-items: center;
133
- justify-content: center;
134
- width: 40px;
135
- height: 40px;
136
- overflow: hidden;
137
- }
138
- .Banner_referralImage__1gnumzi5 {
139
- max-width: 100%;
140
- max-height: 100%;
141
- width: auto;
142
- height: auto;
143
- object-fit: contain;
144
- display: block;
145
- }
146
- .Banner_referralBody__1gnumzi6 {
147
- flex: 1;
148
- min-width: 0;
149
- }
150
- .Banner_referralTitle__1gnumzi7 {
151
- font-size: 16px;
152
- font-weight: 600;
153
- color: var(--text-primary__pbq4ak0);
154
- line-height: 22px;
155
- }
156
- .Banner_referralDescription__1gnumzi8 {
157
- margin-bottom: 8px;
158
- font-size: 14px;
159
- color: #979797;
160
- line-height: 22px;
161
- }
162
- .Banner_referralCta__1gnumzi9 {
163
- display: inline-block;
164
- padding: 8px 16px;
165
- border: 1px solid #000000;
166
- border-radius: 9999px;
167
- color: var(--text-primary__pbq4ak0);
168
- font-size: 10px;
169
- font-weight: 700;
170
- line-height: 12px;
171
- text-transform: uppercase;
172
- }
173
- .Banner_frakLogo__1gnumzia {
174
- position: absolute;
175
- right: 16px;
176
- bottom: 12px;
177
- pointer-events: none;
178
- }`,e);let[W,G]=f(!1),[K,q]=f(()=>R?z:a?`inapp`:null),J=o(null);u(()=>{R&&q(z)},[R,z]);let{reward:Y}=b(K===`referral`&&U,h),[X,re]=f(null);u(()=>{let e=window.FrakSetup?.client;K!==`inapp`||R||!U||!e||n(e).then(e=>re(e)).catch(()=>{})},[K,R,U]),u(()=>{R||!K||W||J.current!==K&&U&&(t(window.FrakSetup?.client,`banner_impression`,{placement:c,variant:K,has_reward:K===`referral`?!!Y:void 0}),J.current=K)},[K,W,U,R,c]),u(()=>{if(R||K===`inapp`)return;let e=()=>q(`referral`);return window.addEventListener(i,e),()=>window.removeEventListener(i,e)},[R,K]);let Z=s(async()=>{if(R)return;if(t(window.FrakSetup?.client,`banner_resolved`,{placement:c,variant:K??`referral`,outcome:`clicked`}),K===`referral`){G(!0);return}let e=X;if(!e&&window.FrakSetup?.client)try{e=await n(window.FrakSetup?.client)}catch{}let i=window.location.href;if(e){let t=new URL(i);t.searchParams.set(`fmt`,e),i=t.toString()}r(i)},[R,K,X,c]),ie=s(()=>{R||(t(window.FrakSetup?.client,`banner_resolved`,{placement:c,variant:K??`referral`,outcome:`dismissed`}),G(!0))},[R,K,c]),ae=v(),Q=B?.components?.banner??ae?.banner,$=d(()=>{if(K===`referral`){let e=Y?`Earn ${Y} on purchases on this site`:`You've been referred!`;return{title:g??Q?.referralTitle??e,description:x??Q?.referralDescription??`Earn rewards after your purchase via the Frak partner app.`,cta:S??Q?.referralCta??`Got it`}}return{title:C??Q?.inappTitle??`Open in your browser`,description:w??Q?.inappDescription??`For a better experience and to earn your rewards, open this page in your default browser.`,cta:T??Q?.inappCta??`Open browser`}},[K,Y,Q,g,x,S,C,w,T]);if(!K||!R&&(!V||H||W))return null;let oe=[M,`frak-banner`,`frak-banner--${K}`,m].filter(Boolean).join(` `);return K===`inapp`?p(k,{title:$.title,description:$.description,cta:$.cta,dismissLabel:`Dismiss`,onAction:Z,onDismiss:ie,className:[`frak-banner`,`frak-banner--inapp`,m].filter(Boolean).join(` `),classNames:{icon:`frak-banner__icon`,title:`frak-banner__title`,description:`frak-banner__description`,cta:`frak-banner__cta`,close:`frak-banner__close`}}):p(`div`,{class:oe,role:`alert`,children:[p(`div`,{class:`${F} frak-banner__icon`,children:E?p(`img`,{src:E,alt:``,class:I}):p(_,{class:j})}),p(`div`,{class:`${N} frak-banner__text`,children:[p(`p`,{class:`${L} frak-banner__title`,children:$.title}),p(`p`,{class:`${ne} frak-banner__description`,children:$.description}),p(`button`,{type:`button`,class:`${P} frak-banner__cta`,onClick:Z,children:$.cta})]}),p(te,{class:`${A} frak-banner__logo`,width:42,height:24})]})}c(R,`frak-banner`,[`placement`,`classname`,`interaction`,`referralTitle`,`referralDescription`,`referralCta`,`inappTitle`,`inappDescription`,`inappCta`,`preview`,`previewMode`,`imageUrl`],{shadow:!1});export{R as Banner};
@@ -1 +0,0 @@
1
- import{b as e,i as t}from"./loader.js";import{c as n,d as r,i,o as a,t as o,u as s}from"./usePlacement.BgMXY5CX.js";import{t as c}from"./useGlobalComponents.TG9kIYSc.js";import{t as l}from"./useLightDomStyles.tjNBKcOr.js";import{t as u}from"./formatReward.B1ZyoceC.js";import{t as d}from"./useReward.B530suzR.js";import{t as f}from"./sharingPage.BYsqcN9O.js";function p({placement:r,text:p=`Share and earn!`,classname:m=``,useReward:h,noRewardText:g,targetInteraction:_,clickAction:v,preview:y}){let b=!!y,x=o(r),S=c(),C=x?.components?.buttonShare??S?.buttonShare;l(`frak-button-share`,r,C?.css);let w=a(()=>x?.targetInteraction===void 0?_:x.targetInteraction,[x?.targetInteraction,_]),T=C?.text??p,E=C?.noRewardText??g,D=a(()=>C?.useReward??h===!0,[C?.useReward,h]),O=a(()=>C?.clickAction??v??`sharing-page`,[C?.clickAction,v]),{shouldRender:k,isHidden:A,isClientReady:j}=i(),{reward:M}=d(D&&j,w),N=a(()=>D?M?T.includes(`{REWARD}`)?u(T,M):`${T} ${M}`:E??u(T,void 0):T,[D,T,E,M]),P=n(()=>{if(!b){if(e(window.FrakSetup.client,`share_button_clicked`,{placement:r,target_interaction:w,has_reward:!!M,click_action:O}),O===`embedded-wallet`){t(w,r);return}f(w,r)}},[b,O,w,r,M]);if(!b&&(!k||A))return null;let F=[`button`,`button__fadeIn`,m].filter(Boolean).join(` `);return s(`button`,{type:`button`,disabled:!b&&!j,class:F,onClick:P,children:N})}r(p,`frak-button-share`,[`text`,`placement`,`classname`,`clickAction`,`useReward`,`noRewardText`,`targetInteraction`,`preview`],{shadow:!1});export{p as ButtonShare};
@@ -1,40 +0,0 @@
1
- import{r as e}from"./loader.js";import{d as t,i as n,l as r,m as i,n as a,o,s,t as c,u as l}from"./usePlacement.BgMXY5CX.js";import{t as u}from"./useReward.B530suzR.js";function d(e){return l(`svg`,{fill:`none`,height:`1em`,viewBox:`0 0 28 28`,width:`1em`,xmlns:`http://www.w3.org/2000/svg`,...e,children:[l(`title`,{children:`Gift icon`}),l(`path`,{d:`m23.1427 13.9999v11.4285h-18.2857v-11.4285m9.1429 11.4285v-17.14282m0 0h-5.1429c-.75776 0-1.48448-.30102-2.0203-.83684s-.83684-1.26255-.83684-2.02031.30102-1.48448.83684-2.0203 1.26254-.83684 2.0203-.83684c4 0 5.1429 5.71429 5.1429 5.71429zm0 0h5.1428c.7578 0 1.4845-.30102 2.0203-.83684s.8369-1.26255.8369-2.02031-.3011-1.48448-.8369-2.0203-1.2625-.83684-2.0203-.83684c-4 0-5.1428 5.71429-5.1428 5.71429zm-11.42861 0h22.85711v5.71432h-22.85711z`,stroke:`#fff`,"stroke-linecap":`round`,"stroke-linejoin":`round`})]})}function f({placement:t,classname:f=``,useReward:p,targetInteraction:m}){let h=c(t),g=o(()=>h?.targetInteraction===void 0?m:h.targetInteraction,[h?.targetInteraction,m]),_=o(()=>p===!0,[p]),{shouldRender:v,isHidden:y,isClientReady:b}=n(),{reward:x}=u(_&&b,g),[S,C]=s(`right`);if(r(()=>{let e=h?.components?.buttonWallet?.position,t=window.FrakSetup?.modalWalletConfig?.metadata?.position;C(e??t??`right`)},[h?.components?.buttonWallet?.position]),!v||y)return null;let w=[`button`,`button__fadeIn`,S===`left`?`button__left`:`button__right`,f].filter(Boolean).join(` `);return l(i,{children:[l(`style`,{children:a(`
2
- .button {
3
- all: unset;
4
- position: fixed;
5
- bottom: 20px;
6
- z-index: 2000000;
7
- display: flex;
8
- justify-content: center;
9
- align-items: center;
10
- background-color: #3e557e;
11
- width: 45px;
12
- height: 45px;
13
- border-radius: 50%;
14
- cursor: pointer;
15
- text-align: center;
16
- font-size: 24px;
17
- }
18
-
19
- .button__left {
20
- left: 20px;
21
- }
22
-
23
- .button__right {
24
- right: 20px;
25
- }
26
-
27
- .reward {
28
- position: absolute;
29
- top: -4px;
30
- right: 27px;
31
- padding: 2px 3px;
32
- border-radius: 5px;
33
- background: #ff3f3f;
34
- font-size: 9px;
35
- color: #fff;
36
- font-weight: 600;
37
- white-space: nowrap;
38
- line-height: 9px;
39
- }
40
- `,h?.components?.buttonWallet?.css)}),l(`button`,{type:`button`,"aria-label":`Open wallet`,part:`button`,disabled:!b,class:w,onClick:()=>{e(g,t)},children:[l(d,{}),x&&l(`span`,{class:`reward`,children:x})]})]})}t(f,`frak-button-wallet`,[`placement`,`classname`,`useReward`,`targetInteraction`],{shadow:!0});export{f as ButtonWallet};