@frak-labs/components 0.0.23 → 0.0.24-beta.d13d0e5d

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 +1,109 @@
1
- import e from"preact-custom-element";import{formatAmount as t,getCurrencyAmountKey as n,setupClient as o,trackEvent as r}from"@frak-labs/core-sdk";import{displayEmbeddedWallet as i,getProductInformation as a,modalBuilder as l,referralInteraction as u}from"@frak-labs/core-sdk/actions";import{jsx as c,jsxs as _}from"preact/jsx-runtime";import{useCallback as s,useEffect as f,useMemo as d,useState as p}from"preact/hooks";import{cx as v}from"class-variance-authority";import{Component as m,Fragment as h,createElement as w,options as k,toChildArray as y}from"preact";import*as g from"@frak-labs/core-sdk/bundle";function b(){if(!window.FrakSetup?.client)return void console.error("Frak client not found");"vibrate"in navigator?navigator.vibrate(10):console.log("Vibration not supported"),i(window.FrakSetup.client,window.FrakSetup?.modalWalletConfig??{})}let S="frakClientReady";function F(e,t){if(window.FrakSetup?.client&&"add"===e)return void t();("add"===e?window.addEventListener:window.removeEventListener)(S,t,!1)}async function C(e){console.log("referral",await u(e,{modalConfig:window.FrakSetup?.modalWalletConfig}))}async function P(){if(window.FrakSetup.core=g,!(window.frakSetupInProgress?(console.log("[Frak SDK] Initialization already in progress"),!1):window.FrakSetup?.client?(console.log("[Frak SDK] Client already initialized"),!1):!!window.FrakSetup?.config||(console.error("[Frak SDK] Configuration not found. Please ensure window.FrakSetup.config is set."),!1)))return;if(console.log("[Frak SDK] Starting initialization"),window.frakSetupInProgress=!0,!window.FrakSetup.config){console.error("[Frak SDK] Configuration not found"),window.frakSetupInProgress=!1;return}let e=await o({config:window.FrakSetup.config});if(!e){console.error("[Frak SDK] Failed to create client"),window.frakSetupInProgress=!1;return}window.FrakSetup.client=e,console.log("[Frak SDK] Client initialized successfully");let t=new CustomEvent(S);window.dispatchEvent(t),window.modalBuilderSteps=l(e,window.FrakSetup?.modalConfig??{}),C(e),window.frakSetupInProgress=!1,function(){let e=new URLSearchParams(window.location.search).get("frakAction");e&&"share"===e&&(console.log("[Frak SDK] Auto open query param found"),b())}()}async function E({targetInteraction:e}){let o=window.FrakSetup?.client;if(!o)return void console.warn("Frak client not ready yet");let{maxReferrer:r,rewards:i}=await a(o);if(!r)return;let l=n(o.config.metadata?.currency),u=Math.round(r[l]);if(e){let t=i.filter(t=>t.interactionTypeKey===e).map(e=>e.referrer[l]).reduce((e,t)=>t>e?t:e,0);t>0&&(u=Math.round(t))}return t(u,o.config.metadata?.currency)}let O={button:"button-aPZnsb",button__left:"button__left-fQJUnK",button__right:"button__right-TkFFFK",reward:"reward-w5dm3K"};function x(e,t){for(var n in e)if("__source"!==n&&!(n in t))return!0;for(var o in t)if("__source"!==o&&e[o]!==t[o])return!0;return!1}function D(e,t){this.props=e,this.context=t}(D.prototype=new m).isPureReactComponent=!0,D.prototype.shouldComponentUpdate=function(e,t){return x(this.props,e)||x(this.state,t)};var K=k.__b;k.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),K&&K(e)},"undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.forward_ref");var R=k.__e;k.__e=function(e,t,n,o){if(e.then){for(var r,i=t;i=i.__;)if((r=i.__c)&&r.__c)return null==t.__e&&(t.__e=n.__e,t.__k=n.__k),r.__c(e,t)}R(e,t,n,o)};var L=k.unmount;function U(){this.__u=0,this.o=null,this.__b=null}function N(e){var t=e.__.__c;return t&&t.__a&&t.__a(e)}function V(){this.i=null,this.l=null}k.unmount=function(e){var t=e.__c;t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),L&&L(e)},(U.prototype=new m).__c=function(e,t){var n=t.__c,o=this;null==o.o&&(o.o=[]),o.o.push(n);var r=N(o.__v),i=!1,a=function(){i||(i=!0,n.__R=null,r?r(l):l())};n.__R=a;var l=function(){if(!--o.__u){if(o.state.__a){var e,t=o.state.__a;o.__v.__k[0]=function e(t,n,o){return t&&o&&(t.__v=null,t.__k=t.__k&&t.__k.map(function(t){return e(t,n,o)}),t.__c&&t.__c.__P===n&&(t.__e&&o.appendChild(t.__e),t.__c.__e=!0,t.__c.__P=o)),t}(t,t.__c.__P,t.__c.__O)}for(o.setState({__a:o.__b=null});e=o.o.pop();)e.forceUpdate()}};o.__u++||32&t.__u||o.setState({__a:o.__b=o.__v.__k[0]}),e.then(a,a)},U.prototype.componentWillUnmount=function(){this.o=[]},U.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var n=document.createElement("div"),o=this.__v.__k[0].__c;this.__v.__k[0]=function e(t,n,o){return t&&(t.__c&&t.__c.__H&&(t.__c.__H.__.forEach(function(e){"function"==typeof e.__c&&e.__c()}),t.__c.__H=null),null!=(t=function(e,t){for(var n in t)e[n]=t[n];return e}({},t)).__c&&(t.__c.__P===o&&(t.__c.__P=n),t.__c.__e=!0,t.__c=null),t.__k=t.__k&&t.__k.map(function(t){return e(t,n,o)})),t}(this.__b,n,o.__O=o.__P)}this.__b=null}var r=t.__a&&w(h,null,e.fallback);return r&&(r.__u&=-33),[w(h,null,t.__a?null:e.children),r]};var W=function(e,t,n){if(++n[1]===n[0]&&e.l.delete(t),e.props.revealOrder&&("t"!==e.props.revealOrder[0]||!e.l.size))for(n=e.i;n;){for(;n.length>3;)n.pop()();if(n[1]<n[0])break;e.i=n=n[2]}};(V.prototype=new m).__a=function(e){var t=this,n=N(t.__v),o=t.l.get(e);return o[0]++,function(r){var i=function(){t.props.revealOrder?(o.push(r),W(t,e,o)):r()};n?n(i):i()}},V.prototype.render=function(e){this.i=null,this.l=new Map;var t=y(e.children);e.revealOrder&&"b"===e.revealOrder[0]&&t.reverse();for(var n=t.length;n--;)this.l.set(t[n],this.i=[1,0,this.i]);return e.children},V.prototype.componentDidUpdate=V.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(t,n){W(e,n,t)})};var A="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,M=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,z=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,H=/[A-Z0-9]/g,I="undefined"!=typeof document;m.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(m.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var j=k.event;function B(){}function T(){return this.cancelBubble}function Z(){return this.defaultPrevented}k.event=function(e){return j&&(e=j(e)),e.persist=B,e.isPropagationStopped=T,e.isDefaultPrevented=Z,e.nativeEvent=e};var $={enumerable:!1,configurable:!0,get:function(){return this.class}},q=k.vnode;k.vnode=function(e){"string"==typeof e.type&&function(e){var t=e.props,n=e.type,o={},r=-1===n.indexOf("-");for(var i in t){var a=t[i];if(!("value"===i&&"defaultValue"in t&&null==a||I&&"children"===i&&"noscript"===n||"class"===i||"className"===i)){var l,u=i.toLowerCase();"defaultValue"===i&&"value"in t&&null==t.value?i="value":"download"===i&&!0===a?a="":"translate"===u&&"no"===a?a=!1:"o"===u[0]&&"n"===u[1]?"ondoubleclick"===u?i="ondblclick":"onchange"!==u||"input"!==n&&"textarea"!==n||(l=t.type,("undefined"!=typeof Symbol&&"symbol"==typeof Symbol()?/fil|che|rad/:/fil|che|ra/).test(l))?"onfocus"===u?i="onfocusin":"onblur"===u?i="onfocusout":z.test(i)&&(i=u):u=i="oninput":r&&M.test(i)?i=i.replace(H,"-$&").toLowerCase():null===a&&(a=void 0),"oninput"===u&&o[i=u]&&(i="oninputCapture"),o[i]=a}}"select"==n&&o.multiple&&Array.isArray(o.value)&&(o.value=y(t.children).forEach(function(e){e.props.selected=-1!=o.value.indexOf(e.props.value)})),"select"==n&&null!=o.defaultValue&&(o.value=y(t.children).forEach(function(e){e.props.selected=o.multiple?-1!=o.defaultValue.indexOf(e.props.value):o.defaultValue==e.props.value})),t.class&&!t.className?(o.class=t.class,Object.defineProperty(o,"className",$)):(t.className&&!t.class||t.class&&t.className)&&(o.class=o.className=t.className),e.props=o}(e),e.$$typeof=A,q&&q(e)};var J=k.__r;k.__r=function(e){J&&J(e),e.__c};var Q=k.diffed;k.diffed=function(e){Q&&Q(e);var t=e.props,n=e.__e;null!=n&&"textarea"===e.type&&"value"in t&&t.value!==n.value&&(n.value=null==t.value?"":t.value)};let G=e=>c("svg",{xmlns:"http://www.w3.org/2000/svg",width:"1em",height:"1em",fill:"none",viewBox:"0 0 28 28",...e,children:c("path",{stroke:"#fff",strokeLinecap:"round",strokeLinejoin:"round",d:"M23.143 14v11.428H4.857V14M14 25.428V8.286m0 0H8.857a2.857 2.857 0 0 1 0-5.715c4 0 5.143 5.715 5.143 5.715m0 0h5.143a2.857 2.857 0 1 0 0-5.715c-4 0-5.143 5.715-5.143 5.715m-11.429 0h22.857V14H2.571z"})});function X({classname:e="",useReward:t,targetInteraction:n}){let o=d(()=>void 0!==t,[t]),{isClientReady:i}=function(){let[e,t]=p(!0),n=s(()=>{t(!1)},[]);return f(()=>(F("add",n),()=>F("remove",n)),[n]),{isClientReady:!e}}(),{reward:a}=function(e,t){let[n,o]=p(void 0);return f(()=>{e&&E({targetInteraction:t}).then(e=>{e&&o(e)})},[e,t]),{reward:n}}(o&&i,n),[l,u]=p("right");return f(()=>{u(window.FrakSetup?.modalWalletConfig?.metadata?.position??"right")},[]),_("button",{type:"button","aria-label":"Open wallet",class:v(O.button,"left"===l?O.button__left:O.button__right,e,"override"),disabled:!i,onClick:()=>{r(window.FrakSetup.client,"wallet_button_clicked"),b()},children:[c(G,{}),a&&c("span",{className:O.reward,children:a})]})}!function(t,n,o=[],r={shadow:!1}){"undefined"!=typeof window&&("complete"===document.readyState||"interactive"===document.readyState?setTimeout(P,1):document.addEventListener?document.addEventListener("DOMContentLoaded",P):document.attachEvent("onreadystatechange",()=>{"complete"===document.readyState&&P()}),customElements.get(n)||e(t,n,o,r))}(X,"frak-button-wallet",[],{shadow:!1});export{X as ButtonWallet};
1
+ import { i as openWalletModal, n as registerWebComponent, t as useClientReady } from "./useClientReady-iCtUeDsc.js";
2
+ import { t as useReward } from "./useReward-DAkT-7wT.js";
3
+ import { trackEvent } from "@frak-labs/core-sdk";
4
+ import { cx } from "class-variance-authority";
5
+ import { useEffect, useMemo, useState } from "preact/hooks";
6
+ import { jsx, jsxs } from "preact/jsx-runtime";
7
+
8
+ //#region src/components/ButtonWallet/assets/GiftIcon.tsx
9
+ function GiftIcon(props) {
10
+ return /* @__PURE__ */ jsxs("svg", {
11
+ fill: "none",
12
+ height: "1em",
13
+ viewBox: "0 0 28 28",
14
+ width: "1em",
15
+ xmlns: "http://www.w3.org/2000/svg",
16
+ ...props,
17
+ children: [/* @__PURE__ */ jsx("title", { children: "Gift icon" }), /* @__PURE__ */ jsx("path", {
18
+ 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",
19
+ stroke: "#fff",
20
+ "stroke-linecap": "round",
21
+ "stroke-linejoin": "round"
22
+ })]
23
+ });
24
+ }
25
+
26
+ //#endregion
27
+ //#region src/components/ButtonWallet/ButtonWallet.module.css?css_module
28
+ const classes = {
29
+ "button__right": "Kl62ia_button__right",
30
+ "button__left": "Kl62ia_button__left",
31
+ "button": "Kl62ia_button",
32
+ "reward": "Kl62ia_reward"
33
+ };
34
+ const _button__right0 = classes["button__right"];
35
+ const _button__left0 = classes["button__left"];
36
+ const _button0 = classes["button"];
37
+ const _reward0 = classes["reward"];
38
+
39
+ //#endregion
40
+ //#region src/components/ButtonWallet/ButtonWallet.tsx
41
+ /**
42
+ * Button to open wallet modal
43
+ *
44
+ * @param args
45
+ * @returns The wallet button with `<button>` tag
46
+ *
47
+ * @group components
48
+ *
49
+ * @example
50
+ * Basic usage:
51
+ * ```html
52
+ * <frak-button-wallet></frak-button-wallet>
53
+ * ```
54
+ *
55
+ * @example
56
+ * Using a custom class:
57
+ * ```html
58
+ * <frak-button-wallet classname="button button-primary"></frak-button-wallet>
59
+ * ```
60
+ *
61
+ * @example
62
+ * Using reward information:
63
+ * ```html
64
+ * <frak-button-wallet use-reward></frak-button-wallet>
65
+ * ```
66
+ *
67
+ * @example
68
+ * Using reward information for specific reward:
69
+ * ```html
70
+ * <frak-button-wallet use-reward target-interaction="custom.customerMeeting"></frak-button-wallet>
71
+ * ```
72
+ *
73
+ * @see {@link @frak-labs/core-sdk!actions.modalBuilder | `modalBuilder()`} for more info about the modal display
74
+ * @see {@link @frak-labs/core-sdk!actions.getProductInformation | `getProductInformation()`} for more info about the estimated reward fetching
75
+ */
76
+ function ButtonWallet({ classname = "", useReward: rawUseReward, targetInteraction }) {
77
+ const shouldUseReward = useMemo(() => rawUseReward !== void 0, [rawUseReward]);
78
+ const { isClientReady } = useClientReady();
79
+ const { reward } = useReward(shouldUseReward && isClientReady, targetInteraction);
80
+ const [position, setPosition] = useState("right");
81
+ /**
82
+ * Setup the position of the button
83
+ */
84
+ useEffect(() => {
85
+ const position = window.FrakSetup?.modalWalletConfig?.metadata?.position;
86
+ setPosition(position ?? "right");
87
+ }, []);
88
+ return /* @__PURE__ */ jsxs("button", {
89
+ type: "button",
90
+ "aria-label": "Open wallet",
91
+ class: cx(classes.button, position === "left" ? classes.button__left : classes.button__right, classname, "override"),
92
+ disabled: !isClientReady,
93
+ onClick: () => {
94
+ trackEvent(window.FrakSetup.client, "wallet_button_clicked");
95
+ openWalletModal();
96
+ },
97
+ children: [/* @__PURE__ */ jsx(GiftIcon, {}), reward && /* @__PURE__ */ jsx("span", {
98
+ className: classes.reward,
99
+ children: reward
100
+ })]
101
+ });
102
+ }
103
+
104
+ //#endregion
105
+ //#region src/components/ButtonWallet/index.ts
106
+ registerWebComponent(ButtonWallet, "frak-button-wallet", [], { shadow: false });
107
+
108
+ //#endregion
109
+ export { ButtonWallet };
@@ -0,0 +1 @@
1
+ .XYfqGq_button{justify-content:center;align-items:center;gap:10px;display:flex}
@@ -0,0 +1,56 @@
1
+ import * as preact from "preact";
2
+
3
+ //#region src/components/OpenInAppButton/types.d.ts
4
+ type OpenInAppButtonProps = {
5
+ /**
6
+ * Text to display on the button
7
+ * @defaultValue `"Open in App"`
8
+ */
9
+ text?: string;
10
+ /**
11
+ * Classname to apply to the button
12
+ */
13
+ classname?: string;
14
+ };
15
+ //#endregion
16
+ //#region src/components/OpenInAppButton/OpenInAppButton.d.ts
17
+ /**
18
+ * Button to open the Frak Wallet mobile app via deep link
19
+ *
20
+ * @param args
21
+ * @returns The open in app button with `<button>` tag (only renders on mobile devices)
22
+ *
23
+ * @group components
24
+ *
25
+ * @example
26
+ * Basic usage:
27
+ * ```html
28
+ * <frak-open-in-app></frak-open-in-app>
29
+ * ```
30
+ *
31
+ * @example
32
+ * Using a custom text:
33
+ * ```html
34
+ * <frak-open-in-app text="Get the App"></frak-open-in-app>
35
+ * ```
36
+ *
37
+ * @example
38
+ * With login action:
39
+ * ```html
40
+ * <frak-open-in-app classname="button button-primary"></frak-open-in-app>
41
+ * ```
42
+ */
43
+ declare function OpenInAppButton({
44
+ text,
45
+ classname
46
+ }: OpenInAppButtonProps): preact.JSX.Element | null;
47
+ //#endregion
48
+ //#region src/components/OpenInAppButton/index.d.ts
49
+ interface OpenInAppButtonElement extends HTMLElement, OpenInAppButtonProps {}
50
+ declare global {
51
+ interface HTMLElementTagNameMap {
52
+ "frak-open-in-app": OpenInAppButtonElement;
53
+ }
54
+ }
55
+ //#endregion
56
+ export { OpenInAppButton, OpenInAppButtonElement };
@@ -0,0 +1,110 @@
1
+ import { n as registerWebComponent, t as useClientReady } from "./useClientReady-iCtUeDsc.js";
2
+ import { t as Spinner } from "./Spinner-J7chVm6X.js";
3
+ import { DEEP_LINK_SCHEME, trackEvent, triggerDeepLinkWithFallback } from "@frak-labs/core-sdk";
4
+ import { cx } from "class-variance-authority";
5
+ import { useMemo } from "preact/hooks";
6
+ import { jsx, jsxs } from "preact/jsx-runtime";
7
+
8
+ //#region src/utils/isMobile.ts
9
+ /**
10
+ * Check if the current device is a mobile device
11
+ * Uses UA regex + iPad desktop mode heuristic (maxTouchPoints)
12
+ *
13
+ * iPadOS 13+ sends a Macintosh UA in desktop mode, so the regex alone
14
+ * misses it. The maxTouchPoints check catches iPads reporting as Mac.
15
+ *
16
+ * @returns True if the device is mobile (iOS, Android, iPadOS, etc.)
17
+ */
18
+ function isMobile() {
19
+ if (typeof navigator === "undefined") return false;
20
+ if (/iPhone|iPad|iPod|Android|webOS|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) return true;
21
+ if (/Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints > 1) return true;
22
+ return false;
23
+ }
24
+
25
+ //#endregion
26
+ //#region src/hooks/useIsMobile.ts
27
+ function useIsMobile() {
28
+ return { isMobile: useMemo(() => isMobile(), []) };
29
+ }
30
+
31
+ //#endregion
32
+ //#region src/utils/openInApp.ts
33
+ const DEFAULT_PATH = "wallet";
34
+ /**
35
+ * Open the Frak Wallet mobile app via deep link with fallback detection.
36
+ *
37
+ * Uses visibility-based detection to determine if the app opened.
38
+ * If the app is not installed (page stays visible after 2.5s),
39
+ * tracks an "app_not_installed" event.
40
+ *
41
+ * @param path - Path to open in the app (default: "wallet")
42
+ */
43
+ function openFrakWalletApp(path = DEFAULT_PATH) {
44
+ const client = window.FrakSetup?.client;
45
+ if (client) trackEvent(client, "open_in_app_clicked");
46
+ triggerDeepLinkWithFallback(`${DEEP_LINK_SCHEME}${path}`, { onFallback: () => {
47
+ if (client) trackEvent(client, "app_not_installed");
48
+ } });
49
+ }
50
+
51
+ //#endregion
52
+ //#region src/components/OpenInAppButton/OpenInAppButton.module.css?css_module
53
+ const classes = { "button": "XYfqGq_button" };
54
+ const _button0 = classes["button"];
55
+
56
+ //#endregion
57
+ //#region src/components/OpenInAppButton/OpenInAppButton.tsx
58
+ /**
59
+ * Button to open the Frak Wallet mobile app via deep link
60
+ *
61
+ * @param args
62
+ * @returns The open in app button with `<button>` tag (only renders on mobile devices)
63
+ *
64
+ * @group components
65
+ *
66
+ * @example
67
+ * Basic usage:
68
+ * ```html
69
+ * <frak-open-in-app></frak-open-in-app>
70
+ * ```
71
+ *
72
+ * @example
73
+ * Using a custom text:
74
+ * ```html
75
+ * <frak-open-in-app text="Get the App"></frak-open-in-app>
76
+ * ```
77
+ *
78
+ * @example
79
+ * With login action:
80
+ * ```html
81
+ * <frak-open-in-app classname="button button-primary"></frak-open-in-app>
82
+ * ```
83
+ */
84
+ function OpenInAppButton({ text = "Open in App", classname = "" }) {
85
+ const { isClientReady } = useClientReady();
86
+ const { isMobile } = useIsMobile();
87
+ if (!isMobile) return null;
88
+ const handleClick = () => {
89
+ openFrakWalletApp();
90
+ };
91
+ return /* @__PURE__ */ jsxs("button", {
92
+ type: "button",
93
+ "aria-label": "Open in Frak Wallet app",
94
+ className: cx(classes.button, classname, "override"),
95
+ disabled: !isClientReady,
96
+ onClick: handleClick,
97
+ children: [
98
+ !isClientReady && /* @__PURE__ */ jsx(Spinner, {}),
99
+ " ",
100
+ text
101
+ ]
102
+ });
103
+ }
104
+
105
+ //#endregion
106
+ //#region src/components/OpenInAppButton/index.ts
107
+ registerWebComponent(OpenInAppButton, "frak-open-in-app", ["text"], { shadow: false });
108
+
109
+ //#endregion
110
+ export { OpenInAppButton };
@@ -0,0 +1,197 @@
1
+ import register from "preact-custom-element";
2
+ import { setupClient } from "@frak-labs/core-sdk";
3
+ import * as coreSdk from "@frak-labs/core-sdk/bundle";
4
+ import { displayEmbeddedWallet, modalBuilder, referralInteraction } from "@frak-labs/core-sdk/actions";
5
+ import { useCallback, useEffect, useState } from "preact/hooks";
6
+
7
+ //#region ../../packages/ui/utils/onDocumentReady.ts
8
+ /**
9
+ * When the document is ready, run the callback
10
+ * @param callback
11
+ */
12
+ function onDocumentReady(callback) {
13
+ if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(callback, 1);
14
+ else if (document.addEventListener) document.addEventListener("DOMContentLoaded", callback);
15
+ else document.attachEvent("onreadystatechange", () => {
16
+ if (document.readyState === "complete") callback();
17
+ });
18
+ }
19
+
20
+ //#endregion
21
+ //#region src/utils/safeVibrate.ts
22
+ /**
23
+ * Attempt to vibrate the device
24
+ */
25
+ function safeVibrate() {
26
+ if ("vibrate" in navigator) navigator.vibrate(10);
27
+ else console.log("Vibration not supported");
28
+ }
29
+
30
+ //#endregion
31
+ //#region src/components/ButtonWallet/utils.ts
32
+ /**
33
+ * Open the wallet modal
34
+ *
35
+ * @description
36
+ * This function will open the wallet modal with the configuration provided in the `window.FrakSetup.modalWalletConfig` object.
37
+ */
38
+ function openWalletModal() {
39
+ if (!window.FrakSetup?.client) {
40
+ console.error("Frak client not found");
41
+ return;
42
+ }
43
+ safeVibrate();
44
+ displayEmbeddedWallet(window.FrakSetup.client, window.FrakSetup?.modalWalletConfig ?? {});
45
+ }
46
+
47
+ //#endregion
48
+ //#region src/utils/clientReady.ts
49
+ const CUSTOM_EVENT_NAME = "frakClientReady";
50
+ /**
51
+ * Dispatch a custom event when the Frak client is ready
52
+ */
53
+ function dispatchClientReadyEvent() {
54
+ const event = new CustomEvent(CUSTOM_EVENT_NAME);
55
+ window.dispatchEvent(event);
56
+ }
57
+ /**
58
+ * Add or remove an event listener for when the Frak client is ready
59
+ * @param action
60
+ * @param callback
61
+ */
62
+ function onClientReady(action, callback) {
63
+ if (window.FrakSetup?.client && action === "add") {
64
+ callback();
65
+ return;
66
+ }
67
+ (action === "add" ? window.addEventListener : window.removeEventListener)(CUSTOM_EVENT_NAME, callback, false);
68
+ }
69
+
70
+ //#endregion
71
+ //#region src/utils/setup.ts
72
+ /**
73
+ * Setup the modal config
74
+ * @param client
75
+ */
76
+ function setupModalConfig(client) {
77
+ window.modalBuilderSteps = modalBuilder(client, window.FrakSetup?.modalConfig ?? {});
78
+ }
79
+ /**
80
+ * Setup the referral
81
+ * @param client
82
+ */
83
+ async function setupReferral(client) {
84
+ const referral = await referralInteraction(client, { modalConfig: window.FrakSetup?.modalWalletConfig });
85
+ console.log("referral", referral);
86
+ }
87
+ /**
88
+ * Return the modal builder steps
89
+ */
90
+ function getModalBuilderSteps() {
91
+ if (!window.modalBuilderSteps) throw new Error("modalBuilderSteps not found");
92
+ return window.modalBuilderSteps;
93
+ }
94
+
95
+ //#endregion
96
+ //#region src/utils/initFrakSdk.ts
97
+ /**
98
+ * Initializes the Frak SDK client and sets up necessary configurations.
99
+ * This function handles the one-time setup of the Frak client and related features.
100
+ *
101
+ * @returns {Promise<void>}
102
+ */
103
+ async function initFrakSdk() {
104
+ window.FrakSetup.core = coreSdk;
105
+ if (!preChecks()) return;
106
+ console.log("[Frak SDK] Starting initialization");
107
+ if (!window.FrakSetup.config) {
108
+ console.error("[Frak SDK] Configuration not found");
109
+ window.frakSetupInProgress = false;
110
+ return;
111
+ }
112
+ const client = await setupClient({ config: window.FrakSetup.config });
113
+ if (!client) {
114
+ console.error("[Frak SDK] Failed to create client");
115
+ window.frakSetupInProgress = false;
116
+ return;
117
+ }
118
+ window.FrakSetup.client = client;
119
+ console.log("[Frak SDK] Client initialized successfully");
120
+ dispatchClientReadyEvent();
121
+ setupModalConfig(client);
122
+ setupReferral(client);
123
+ window.frakSetupInProgress = false;
124
+ handleActionQueryParam();
125
+ }
126
+ /**
127
+ * Pre-checks for the Frak SDK initialization
128
+ * Sets frakSetupInProgress flag atomically to prevent race conditions
129
+ */
130
+ function preChecks() {
131
+ if (window.frakSetupInProgress) {
132
+ console.log("[Frak SDK] Initialization already in progress");
133
+ return false;
134
+ }
135
+ window.frakSetupInProgress = true;
136
+ if (window.FrakSetup?.client) {
137
+ console.log("[Frak SDK] Client already initialized");
138
+ window.frakSetupInProgress = false;
139
+ return false;
140
+ }
141
+ if (!window.FrakSetup?.config) {
142
+ console.error("[Frak SDK] Configuration not found. Please ensure window.FrakSetup.config is set.");
143
+ window.frakSetupInProgress = false;
144
+ return false;
145
+ }
146
+ return true;
147
+ }
148
+ /**
149
+ * Check the query param contain params for an auto opening of the frak modal
150
+ */
151
+ function handleActionQueryParam() {
152
+ const frakAction = new URLSearchParams(window.location.search).get("frakAction");
153
+ if (!frakAction) return;
154
+ if (frakAction === "share") {
155
+ console.log("[Frak SDK] Auto open query param found");
156
+ openWalletModal();
157
+ }
158
+ }
159
+
160
+ //#endregion
161
+ //#region src/utils/registerWebComponent.ts
162
+ /**
163
+ * Registers a Preact component as a custom web component
164
+ *
165
+ * @param component - The Preact component to register
166
+ * @param tagName - The custom element tag name (e.g., "frak-button-wallet")
167
+ * @param observedAttributes - Array of attribute names to observe for changes
168
+ * @param options - Registration options (e.g., { shadow: false })
169
+ */
170
+ function registerWebComponent(component, tagName, observedAttributes = [], options = { shadow: false }) {
171
+ if (typeof window !== "undefined") {
172
+ onDocumentReady(initFrakSdk);
173
+ if (!customElements.get(tagName)) register(component, tagName, observedAttributes, options);
174
+ }
175
+ }
176
+
177
+ //#endregion
178
+ //#region src/hooks/useClientReady.ts
179
+ /**
180
+ * Hook to manage client readiness state for the wallet button
181
+ * Handles subscription to client ready events and manages readiness state
182
+ * @returns Object containing the readiness state of the client
183
+ */
184
+ function useClientReady() {
185
+ const [disabled, setDisabled] = useState(true);
186
+ const handleClientReady = useCallback(() => {
187
+ setDisabled(false);
188
+ }, []);
189
+ useEffect(() => {
190
+ onClientReady("add", handleClientReady);
191
+ return () => onClientReady("remove", handleClientReady);
192
+ }, [handleClientReady]);
193
+ return { isClientReady: !disabled };
194
+ }
195
+
196
+ //#endregion
197
+ export { openWalletModal as i, registerWebComponent as n, getModalBuilderSteps as r, useClientReady as t };
@@ -0,0 +1,48 @@
1
+ import { formatAmount, getCurrencyAmountKey } from "@frak-labs/core-sdk";
2
+ import { getMerchantInformation } from "@frak-labs/core-sdk/actions";
3
+ import { useEffect, useState } from "preact/hooks";
4
+
5
+ //#region src/utils/getCurrentReward.ts
6
+ function getFixedFiatAmount(estimated, key) {
7
+ if (!estimated || estimated.payoutType !== "fixed") return 0;
8
+ return estimated.amount[key];
9
+ }
10
+ function getMaxFixedReferrerReward(rewards, key) {
11
+ return rewards.reduce((max, reward) => Math.max(max, getFixedFiatAmount(reward.referrer, key)), 0);
12
+ }
13
+ async function getCurrentReward({ targetInteraction }) {
14
+ const client = window.FrakSetup?.client;
15
+ if (!client) {
16
+ console.warn("Frak client not ready yet");
17
+ return;
18
+ }
19
+ const { rewards } = await getMerchantInformation(client);
20
+ const currencyAmountKey = getCurrencyAmountKey(client.config.metadata?.currency);
21
+ const maxReward = getMaxFixedReferrerReward(targetInteraction ? rewards.filter((r) => r.interactionTypeKey === targetInteraction) : rewards, currencyAmountKey);
22
+ if (maxReward <= 0) return;
23
+ return formatAmount(Math.round(maxReward), client.config.metadata?.currency);
24
+ }
25
+
26
+ //#endregion
27
+ //#region src/hooks/useReward.ts
28
+ /**
29
+ * Hook to fetch and format the current reward value for a given interaction
30
+ * @param shouldUseReward - Flag to determine if reward should be fetched
31
+ * @param targetInteraction - Optional interaction type to get specific reward for
32
+ * @param currency - The currency to use for the reward (default is "eur")
33
+ * @returns Object containing the formatted reward value in euros
34
+ */
35
+ function useReward(shouldUseReward, targetInteraction) {
36
+ const [reward, setReward] = useState(void 0);
37
+ useEffect(() => {
38
+ if (!shouldUseReward) return;
39
+ getCurrentReward({ targetInteraction }).then((reward) => {
40
+ if (!reward) return;
41
+ setReward(reward);
42
+ });
43
+ }, [shouldUseReward, targetInteraction]);
44
+ return { reward };
45
+ }
46
+
47
+ //#endregion
48
+ export { useReward as t };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "url": "https://twitter.com/QNivelais"
12
12
  }
13
13
  ],
14
- "version": "0.0.23",
14
+ "version": "0.0.24-beta.d13d0e5d",
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",
@@ -40,34 +40,68 @@
40
40
  ],
41
41
  "main": "./cdn/components.js",
42
42
  "browser": "./cdn/components.js",
43
+ "exports": {
44
+ "./buttonWallet": {
45
+ "development": "./src/components/ButtonWallet/index.ts",
46
+ "import": "./dist/buttonWallet.js",
47
+ "types": "./dist/buttonWallet.d.ts"
48
+ },
49
+ "./buttonShare": {
50
+ "development": "./src/components/ButtonShare/index.ts",
51
+ "import": "./dist/buttonShare.js",
52
+ "types": "./dist/buttonShare.d.ts"
53
+ },
54
+ "./openInApp": {
55
+ "development": "./src/components/OpenInAppButton/index.ts",
56
+ "import": "./dist/openInApp.js",
57
+ "types": "./dist/openInApp.d.ts"
58
+ },
59
+ "./cdn": {
60
+ "import": "./cdn/components.js"
61
+ },
62
+ "./dist/*": "./dist/*"
63
+ },
43
64
  "scripts": {
44
65
  "lint": "biome lint .",
45
66
  "format:check": "biome check .",
46
67
  "format": "biome check --write .",
47
68
  "clean": "rimraf cdn dist",
48
- "build": "rslib build",
49
- "build:watch": "rslib build --watch",
69
+ "build": "tsdown",
70
+ "build:watch": "tsdown --watch",
50
71
  "typecheck": "tsc --noEmit",
72
+ "test": "vitest",
73
+ "test:ui": "vitest --ui",
74
+ "test:coverage": "vitest --coverage",
51
75
  "prepublish": "bun run lint && bun run build",
52
76
  "publish": "echo 'Publishing components...'"
53
77
  },
54
78
  "dependencies": {
55
- "@frak-labs/frame-connector": "0.1.0",
56
- "@frak-labs/core-sdk": "0.1.0",
79
+ "@frak-labs/frame-connector": "0.1.0-beta.d13d0e5d",
80
+ "@frak-labs/core-sdk": "0.1.1-beta.d13d0e5d",
57
81
  "class-variance-authority": "^0.7.1",
58
- "preact": "^10.26.9",
59
- "preact-custom-element": "^4.3.0"
82
+ "preact": "^10.28.3",
83
+ "preact-custom-element": "^4.6.0"
60
84
  },
61
85
  "devDependencies": {
62
- "@rsbuild/plugin-preact": "^1.4.0",
63
- "@rsbuild/plugin-svgr": "^1.2.0",
64
- "@rslib/core": "^0.9.2",
65
- "@types/node": "^24",
86
+ "@bosh-code/tsdown-plugin-inject-css": "^2.0.0",
87
+ "@frak-labs/dev-tooling": "0.0.0",
88
+ "@frak-labs/test-foundation": "0.1.0",
89
+ "@frak-labs/ui": "0.0.0",
90
+ "@preact/preset-vite": "^2.10.3",
91
+ "@rolldown/plugin-node-polyfills": "^1.0.3",
92
+ "@testing-library/jest-dom": "^6.9.1",
93
+ "@testing-library/preact": "^3.2.4",
94
+ "@testing-library/user-event": "^14.6.1",
95
+ "@types/jsdom": "^27.0.0",
96
+ "@types/node": "^24.10.13",
66
97
  "@types/preact-custom-element": "^4.0.4",
98
+ "@vitest/coverage-v8": "^4.0.18",
99
+ "@vitest/ui": "^4.0.18",
100
+ "jsdom": "^28.0.0",
101
+ "tsdown": "^0.20.3",
67
102
  "typescript": "^5",
68
- "@frak-labs/dev-tooling": "0.0.0"
69
- },
70
- "browserslist": [
71
- "extends @frak-labs/browserslist-config"
72
- ]
103
+ "unplugin-lightningcss": "^0.4.5",
104
+ "vite-tsconfig-paths": "^6.1.0",
105
+ "vitest": "^4.0.18"
106
+ }
73
107
  }