@txnlab/use-wallet-ui-react 1.2.1 → 1.4.0
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.
- package/README.md +121 -18
- package/dist/cjs/chunks/{floating-ui.react-O3sXJ80G.cjs → floating-ui.react-ChfuPAKc.cjs} +1 -1
- package/dist/cjs/chunks/{floating-ui.react-O3sXJ80G.cjs.map → floating-ui.react-ChfuPAKc.cjs.map} +1 -1
- package/dist/cjs/chunks/passkey-C8Dw6sNL.cjs +2 -0
- package/dist/cjs/chunks/passkey-C8Dw6sNL.cjs.map +1 -0
- package/dist/cjs/index.cjs +14 -14
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/plugins/export-key.cjs +2 -2
- package/dist/cjs/plugins/export-key.cjs.map +1 -1
- package/dist/cjs/plugins/passkey.cjs +2 -0
- package/dist/cjs/plugins/passkey.cjs.map +1 -0
- package/dist/esm/chunks/{floating-ui.react-Co7v2aHO.js → floating-ui.react-CxJSDrxv.js} +1 -1
- package/dist/esm/chunks/{floating-ui.react-Co7v2aHO.js.map → floating-ui.react-CxJSDrxv.js.map} +1 -1
- package/dist/esm/chunks/passkey-BbgvIGki.js +44 -0
- package/dist/esm/chunks/passkey-BbgvIGki.js.map +1 -0
- package/dist/esm/index.js +2888 -2601
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/plugins/export-key.js +13 -12
- package/dist/esm/plugins/export-key.js.map +1 -1
- package/dist/esm/plugins/passkey.js +578 -0
- package/dist/esm/plugins/passkey.js.map +1 -0
- package/dist/style.css +152 -0
- package/dist/types/components/ConnectWalletMenu.d.ts +7 -1
- package/dist/types/components/ConnectWalletMenu.d.ts.map +1 -1
- package/dist/types/components/ConnectedWalletMenu.d.ts.map +1 -1
- package/dist/types/components/PasskeyConnect.d.ts +29 -0
- package/dist/types/components/PasskeyConnect.d.ts.map +1 -0
- package/dist/types/components/WalletButton.d.ts +7 -1
- package/dist/types/components/WalletButton.d.ts.map +1 -1
- package/dist/types/components/WalletGroupLabel.d.ts +6 -0
- package/dist/types/components/WalletGroupLabel.d.ts.map +1 -0
- package/dist/types/components/WalletIcon.d.ts +6 -0
- package/dist/types/components/WalletIcon.d.ts.map +1 -0
- package/dist/types/components/WalletList.d.ts.map +1 -1
- package/dist/types/index.d.cts +5 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/plugins/passkey/PasskeyDisclosure.d.ts +11 -0
- package/dist/types/plugins/passkey/PasskeyDisclosure.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryDialog.d.ts +10 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryDialog.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryMenuButton.d.ts +5 -0
- package/dist/types/plugins/passkey/PasskeyRecoveryMenuButton.d.ts.map +1 -0
- package/dist/types/plugins/passkey/PasskeySessionControl.d.ts +6 -0
- package/dist/types/plugins/passkey/PasskeySessionControl.d.ts.map +1 -0
- package/dist/types/plugins/passkey/constants.d.ts +3 -0
- package/dist/types/plugins/passkey/constants.d.ts.map +1 -0
- package/dist/types/plugins/passkey/index.d.cts +36 -0
- package/dist/types/plugins/passkey/index.d.ts +36 -0
- package/dist/types/plugins/passkey/index.d.ts.map +1 -0
- package/dist/types/plugins/passkey/index.test.d.ts +2 -0
- package/dist/types/plugins/passkey/index.test.d.ts.map +1 -0
- package/dist/types/plugins/passkey/storage.d.ts +5 -0
- package/dist/types/plugins/passkey/storage.d.ts.map +1 -0
- package/dist/types/plugins/passkey/storage.test.d.ts +2 -0
- package/dist/types/plugins/passkey/storage.test.d.ts.map +1 -0
- package/dist/types/plugins/passkey/usePasskeyAdapter.d.ts +10 -0
- package/dist/types/plugins/passkey/usePasskeyAdapter.d.ts.map +1 -0
- package/dist/types/providers/WalletUIProvider.d.ts +15 -1
- package/dist/types/providers/WalletUIProvider.d.ts.map +1 -1
- package/dist/types/utils/passkey.d.ts +59 -0
- package/dist/types/utils/passkey.d.ts.map +1 -0
- package/dist/types/utils/passkey.test.d.ts +2 -0
- package/dist/types/utils/passkey.test.d.ts.map +1 -0
- package/package.json +16 -4
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),f=require("../chunks/passkey-C8Dw6sNL.cjs"),a=require("react"),g=require("../chunks/floating-ui.react-ChfuPAKc.cjs"),q=require("@txnlab/use-wallet-react"),N="passkey-recovery-dialog",I="This account is created by and for {domain}. Keep only what you need here, and move larger amounts to a wallet you control.";function z(r){const t=new Set;return{has(s){if(t.has(s))return!0;try{return localStorage.getItem(r+s)==="1"}catch{return!1}},set(s){t.add(s);try{localStorage.setItem(r+s,"1")}catch{}}}}const L=z("wui:passkey-disclosure-dismissed:"),K=r=>L.has(r),V=r=>L.set(r);function H({ctx:r,text:t}){var c,l;const s=r.activeAddress,[,u]=a.useState(0);if(!s||K(s))return null;const o=f.getPasskeyAccountDomain((l=(c=r.activeWallet)==null?void 0:c.activeAccount)==null?void 0:l.name),i=()=>{V(s),u(d=>d+1)};return e.jsxs("div",{role:"note","data-passkey-disclosure":!0,className:"mb-2 flex flex-col gap-2 rounded-[10px] border border-[var(--wui-color-border)] bg-[var(--wui-color-bg-secondary)] px-3 py-2.5",children:[e.jsx("p",{className:"text-xs leading-[1.55] text-[var(--wui-color-text-secondary)]",children:t.replaceAll("{domain}",o)}),e.jsx("button",{type:"button",onClick:i,className:"self-end rounded-md bg-[var(--wui-color-primary)] px-2.5 py-1 text-xs font-medium text-[var(--wui-color-primary-text)] hover:bg-[var(--wui-color-primary-hover)]",children:"Got it"})]})}function C(r){const t=q.useWalletManager();return!r||!f.isPasskeyWallet(r)?null:t.getWallet(r.walletKey)??null}const $=60;function G({ctx:r,onClose:t,displayTimeout:s=$}){const u=C(r.activeWallet),[o,i]=a.useState("warning"),[c,l]=a.useState(null),[d,p]=a.useState(s),[v,h]=a.useState(!1),[F,b]=a.useState(null),[S,R]=a.useState("starting"),y=a.useRef(!1),w=a.useRef(!0),j=a.useRef(!1),{refs:T,context:k}=g.useFloating({open:!0,onOpenChange:n=>{n||m()}}),U=g.useDismiss(k,{outsidePressEvent:"mousedown"}),_=g.useRole(k,{role:"dialog"}),{getFloatingProps:W}=g.useInteractions([U,_]);a.useEffect(()=>{requestAnimationFrame(()=>R("entered"))},[]);const P=a.useCallback(()=>{var n;l(null),y.current&&(y.current=!1,(n=navigator.clipboard)==null||n.writeText("").catch(()=>{}))},[]),m=a.useCallback(()=>{j.current||(j.current=!0,P(),R("exiting"),setTimeout(t,150))},[P,t]);a.useEffect(()=>{if(o!=="display")return;const n=setInterval(()=>{p(x=>Math.max(0,x-1))},1e3);return()=>clearInterval(n)},[o]),a.useEffect(()=>{o==="display"&&d===0&&m()},[o,d,m]),a.useEffect(()=>(w.current=!0,()=>{var n;w.current=!1,y.current&&(y.current=!1,(n=navigator.clipboard)==null||n.writeText("").catch(()=>{}))}),[]);const O=()=>{if(!u){b("No passkey account is connected."),i("error");return}let n;try{n=u.exportRecoveryPhrase()}catch(x){E(x);return}i("loading"),n.then(({phrase:x})=>{!w.current||j.current||(l(x.split(" ")),p(s),i("display"))},x=>{w.current&&E(x)})},E=n=>{b(f.getPasskeyErrorMessage(n)??(n instanceof Error?n.message:"Failed to export phrase")),i("error")},B=()=>{!c||!navigator.clipboard||navigator.clipboard.writeText(c.join(" ")).then(()=>{y.current=!0,h(!0),setTimeout(()=>h(!1),2e3)}).catch(()=>{})},Y=()=>{b(null),i("warning")};return e.jsx(g.FloatingOverlay,{className:"grid place-items-center px-4 z-50 transition-opacity duration-150 ease-in-out bg-[var(--wui-color-overlay)] data-[state=starting]:opacity-0 data-[state=exiting]:opacity-0 data-[state=entered]:opacity-100","data-state":S,lockScroll:!0,children:e.jsx(g.FloatingFocusManager,{context:k,modal:!0,children:e.jsxs("div",{ref:T.setFloating,...W(),role:"dialog","aria-label":o==="display"?"Recovery Phrase":"Export Recovery Phrase","data-passkey-recovery-dialog":!0,"data-state":S,className:"w-full max-w-sm max-h-[calc(100dvh-2rem)] overflow-y-auto rounded-3xl bg-[var(--wui-color-bg)] shadow-xl transform transition-all duration-150 ease-in-out data-[state=starting]:opacity-0 data-[state=starting]:scale-90 data-[state=exiting]:opacity-0 data-[state=exiting]:scale-90 data-[state=entered]:opacity-100 data-[state=entered]:scale-100",style:{marginTop:"-0.5rem"},children:[o==="warning"&&e.jsxs(e.Fragment,{children:[e.jsx(D,{title:"Export Recovery Phrase",onClose:m}),e.jsxs("div",{className:"px-6 pb-4 space-y-3",children:[e.jsxs("div",{className:"bg-[var(--wui-color-danger-bg)] rounded-xl p-4",children:[e.jsx("p",{className:"text-sm font-medium text-[var(--wui-color-danger-text)] mb-2",children:"Your recovery phrase gives full access to this account and its funds."}),e.jsxs("ul",{className:"text-sm text-[var(--wui-color-danger-text)] list-disc pl-5 space-y-1",children:[e.jsx("li",{children:"Never share it with anyone"}),e.jsx("li",{children:"Never enter it on unverified websites"}),e.jsx("li",{children:"Write it down and store it securely"})]})]}),e.jsx(A,{})]}),e.jsxs("div",{className:"px-6 pb-5 flex gap-2",children:[e.jsx("button",{onClick:m,className:"flex-1 py-2.5 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm",children:"Cancel"}),e.jsx("button",{onClick:O,className:"flex-1 py-2.5 px-4 bg-[var(--wui-color-danger-bg)] text-[var(--wui-color-danger-text)] font-medium rounded-xl hover:bg-[var(--wui-color-danger-bg-hover)] transition-colors text-sm",children:"Reveal Recovery Phrase"})]})]}),o==="loading"&&e.jsxs("div",{className:"px-6 py-12 flex flex-col items-center gap-3",children:[e.jsx(Z,{}),e.jsx("p",{role:"status",className:"text-sm text-[var(--wui-color-text-secondary)]",children:"Confirm with your passkey…"})]}),o==="display"&&c&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"relative flex items-center justify-between px-6 pt-5 pb-3",children:[e.jsx("h2",{className:"text-xl font-bold text-[var(--wui-color-text)] wallet-custom-font",children:"Recovery Phrase"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium tabular-nums text-[var(--wui-color-text-secondary)]","aria-label":`${d} seconds remaining`,children:J(d)}),e.jsx(M,{onClick:m})]})]}),e.jsx("div",{className:"px-6 pb-3",children:e.jsx("ol",{className:"grid grid-cols-3 gap-1 bg-[var(--wui-color-bg-secondary)] rounded-xl p-2",style:{userSelect:"none"},"data-passkey-phrase":!0,children:c.map((n,x)=>e.jsxs("li",{className:"flex items-baseline gap-1 py-1 px-1.5 rounded-md bg-[var(--wui-color-bg)] border border-[var(--wui-color-border)]",children:[e.jsx("span",{className:"w-4 shrink-0 text-right text-[10px] tabular-nums text-[var(--wui-color-text-tertiary)]",children:x+1}),e.jsx("span",{className:"text-xs font-medium text-[var(--wui-color-text)]",children:n})]},x))})}),e.jsx("div",{className:"px-6 pb-3",children:e.jsx(A,{compact:!0})}),e.jsxs("div",{className:"px-6 pb-2 flex gap-2",children:[e.jsx("button",{onClick:B,className:"flex-1 py-2 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm",children:v?"Copied":"Copy"}),e.jsx("button",{onClick:m,className:"flex-1 py-2 px-4 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-xl hover:bg-[var(--wui-color-primary-hover)] transition-colors text-sm",children:"Done"})]}),e.jsx("p",{className:"px-6 pb-5 text-xs text-[var(--wui-color-text-tertiary)] text-center",children:"Clear your clipboard after you paste it"})]}),o==="error"&&e.jsxs(e.Fragment,{children:[e.jsx(D,{title:"Export Recovery Phrase",onClose:m}),e.jsx("div",{className:"px-6 pb-4",children:e.jsx("p",{role:"alert",className:"bg-[var(--wui-color-danger-bg)] rounded-xl p-4 text-sm text-[var(--wui-color-danger-text)]",children:F||"An unexpected error occurred."})}),e.jsxs("div",{className:"px-6 pb-5 flex gap-2",children:[e.jsx("button",{onClick:m,className:"flex-1 py-2.5 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm",children:"Cancel"}),e.jsx("button",{onClick:Y,className:"flex-1 py-2.5 px-4 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-xl hover:bg-[var(--wui-color-primary-hover)] transition-colors text-sm",children:"Try Again"})]})]})]})})})}function A({compact:r=!1}){return e.jsxs("div",{"data-passkey-falcon-note":!0,className:"rounded-xl border border-[var(--wui-color-border)] bg-[var(--wui-color-bg-secondary)] p-3 text-sm text-[var(--wui-color-text)]",children:[e.jsx("p",{className:"font-medium",children:"Import it as a Falcon / quantum account"}),!r&&e.jsxs("ul",{className:"mt-1.5 list-disc pl-5 space-y-1 text-[var(--wui-color-text-secondary)]",children:[e.jsxs("li",{children:["Lute: Add account → ",e.jsx("strong",{children:"Falcon25 account"})," → Import"]}),e.jsx("li",{children:"Pera: use the quantum account import"})]}),e.jsx("p",{className:"mt-1.5 text-[var(--wui-color-text-secondary)]",children:"A regular 25-word import restores a different, empty account."})]})}function D({title:r,onClose:t}){return e.jsxs("div",{className:"relative flex items-center px-6 pt-5 pb-4",children:[e.jsx("h2",{className:"text-xl font-bold text-[var(--wui-color-text)] wallet-custom-font",children:r}),e.jsx(M,{onClick:t,className:"absolute right-4"})]})}function M({onClick:r,className:t=""}){return e.jsx("button",{onClick:r,className:`${t} rounded-full bg-[var(--wui-color-bg-tertiary)] p-2 text-[var(--wui-color-text-secondary)] hover:brightness-90 transition-all`,"aria-label":"Close dialog",children:e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",clipRule:"evenodd"})})})}function Z(){return e.jsxs("svg",{className:"h-8 w-8 text-[var(--wui-color-text-tertiary)] animate-spin",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]})}function J(r){const t=Math.floor(r/60),s=r%60;return`${t}:${s.toString().padStart(2,"0")}`}function Q({ctx:r}){const t=()=>{r.closeMenu(),r.openDialog(N)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"border-t border-[var(--wui-color-border)] mt-2 mb-2"}),e.jsxs("button",{onClick:t,className:"w-full flex items-center gap-2 px-2 py-2 rounded-lg text-sm text-[var(--wui-color-text-secondary)] hover:bg-[var(--wui-color-bg-hover)] transition-colors",children:[e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 shrink-0",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:e.jsx("path",{d:"M9.661 2.237a.531.531 0 0 1 .678 0 11.947 11.947 0 0 0 7.078 2.749.5.5 0 0 1 .479.425c.069.52.104 1.05.104 1.59 0 5.162-3.26 9.563-7.834 11.256a.48.48 0 0 1-.332 0C5.26 16.564 2 12.163 2 7c0-.538.035-1.069.104-1.589a.5.5 0 0 1 .48-.425 11.947 11.947 0 0 0 7.077-2.75Z"})}),e.jsx("span",{className:"flex-1 text-left",children:"Back up account"}),e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 shrink-0 opacity-50",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z",clipRule:"evenodd"})})]})]})}const X=1e3;function ee({ctx:r}){const t=C(r.activeWallet),[s,u]=a.useState(()=>!!(t!=null&&t.isUnlocked)),[o,i]=a.useState(!1),[c,l]=a.useState(null);if(a.useEffect(()=>{if(!t)return;u(t.isUnlocked);const v=setInterval(()=>u(t.isUnlocked),X);return()=>clearInterval(v)},[t]),!t)return null;const d=()=>{l(null);const v=t.unlock();i(!0),v.then(()=>u(t.isUnlocked)).catch(h=>{l(f.getPasskeyErrorMessage(h)??(h instanceof Error?h.message:"Unlock failed"))}).finally(()=>i(!1))},p=()=>{t.lock(),u(t.isUnlocked),l(null)};return e.jsxs("div",{"data-passkey-session":!0,className:"mb-2",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2 px-1 py-0.5",children:[e.jsxs("span",{className:"flex items-center gap-2 text-sm text-[var(--wui-color-text-secondary)]",children:[s?e.jsx(re,{}):e.jsx(te,{}),e.jsx("span",{children:s?"Unlocked":"Locked"})]}),s?e.jsx("button",{onClick:p,className:"py-1 px-2.5 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-md hover:brightness-90 transition-all text-xs",children:"Lock"}):e.jsx("button",{onClick:d,disabled:o,className:"py-1 px-2.5 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-md hover:bg-[var(--wui-color-primary-hover)] transition-colors text-xs disabled:opacity-50 disabled:cursor-not-allowed",children:o?"Waiting…":"Unlock"})]}),!s&&!c&&e.jsx("p",{className:"px-1 text-xs text-[var(--wui-color-text-tertiary)]",children:"The next signature asks for your passkey."}),c&&e.jsx("p",{role:"alert",className:"mt-1 rounded-lg bg-[var(--wui-color-danger-bg)] px-3 py-2 text-xs text-[var(--wui-color-danger-text)]",children:c})]})}function te(){return e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 shrink-0",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:e.jsx("path",{fillRule:"evenodd",d:"M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z",clipRule:"evenodd"})})}function re(){return e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 shrink-0",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:e.jsx("path",{d:"M10 2a5 5 0 00-5 5v2a2 2 0 00-2 2v5a2 2 0 002 2h10a2 2 0 002-2v-5a2 2 0 00-2-2H7V7a3 3 0 015.905-.75 1 1 0 001.937-.5A5.002 5.002 0 0010 2z"})})}function se(r={}){const{recoveryPhrase:t=!0,session:s=!1,disclosure:u=!1}=r,o=l=>f.isPasskeyWallet(l.activeWallet),i=[],c=[];if(u){const l=typeof u=="string"?u:I;i.push({key:"passkey-disclosure",slot:"after-wallet-info",order:5,enabled:o,render:d=>e.jsx(H,{ctx:d,text:l})})}if(s&&i.push({key:"passkey-session",slot:"after-wallet-info",order:10,enabled:o,render:l=>e.jsx(ee,{ctx:l})}),t){const l=typeof t=="object"?t.displayTimeout:void 0;i.push({key:"passkey-recovery-trigger",slot:"after-wallet-info",order:20,enabled:o,render:d=>e.jsx(Q,{ctx:d})}),c.push({key:N,render:({onClose:d,ctx:p})=>e.jsx(G,{ctx:p,onClose:d,displayTimeout:l})})}return{id:"passkey",name:"Passkey",menuItems:i,dialogs:c}}exports.DEFAULT_PASSKEY_DISCLOSURE=I;exports.PASSKEY_RECOVERY_DIALOG=N;exports.passkeyPlugin=se;exports.usePasskeyAdapter=C;
|
|
2
|
+
//# sourceMappingURL=passkey.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey.cjs","sources":["../../../src/plugins/passkey/constants.ts","../../../src/plugins/passkey/storage.ts","../../../src/plugins/passkey/PasskeyDisclosure.tsx","../../../src/plugins/passkey/usePasskeyAdapter.ts","../../../src/plugins/passkey/PasskeyRecoveryDialog.tsx","../../../src/plugins/passkey/PasskeyRecoveryMenuButton.tsx","../../../src/plugins/passkey/PasskeySessionControl.tsx","../../../src/plugins/passkey/index.tsx"],"sourcesContent":["export const PASSKEY_RECOVERY_DIALOG = 'passkey-recovery-dialog'\n\nexport const DEFAULT_PASSKEY_DISCLOSURE =\n 'This account is created by and for {domain}. Keep only what you need here, and move larger amounts to a wallet you control.'\n","/**\n * A per-account flag in localStorage. Falls back to memory when storage is\n * unavailable (private mode, blocked site data), so it lasts for the page\n * session.\n */\ninterface AddressFlag {\n has: (address: string) => boolean\n set: (address: string) => void\n}\n\nfunction createAddressFlag(keyPrefix: string): AddressFlag {\n const inMemory = new Set<string>()\n return {\n has(address: string): boolean {\n if (inMemory.has(address)) return true\n try {\n return localStorage.getItem(keyPrefix + address) === '1'\n } catch {\n return false\n }\n },\n set(address: string): void {\n inMemory.add(address)\n try {\n localStorage.setItem(keyPrefix + address, '1')\n } catch {\n // Kept in memory above\n }\n },\n }\n}\n\nconst disclosureDismissed = createAddressFlag(\n 'wui:passkey-disclosure-dismissed:',\n)\n\n/** Whether the user dismissed the passkey disclosure for this account */\nexport const isDisclosureDismissed = (address: string): boolean =>\n disclosureDismissed.has(address)\n\n/** Remember that the user dismissed the passkey disclosure for this account */\nexport const dismissDisclosure = (address: string): void =>\n disclosureDismissed.set(address)\n","import { useState } from 'react'\n\nimport { getPasskeyAccountDomain } from '../../utils/passkey'\n\nimport { dismissDisclosure, isDisclosureDismissed } from './storage'\n\nimport type { MenuRenderContext } from '../types'\n\n/**\n * Tells users the passkey account belongs to the site that created it. Shows\n * until the user chooses \"Got it\", once per account; the domain tag in the\n * menu stays after that.\n */\nexport function PasskeyDisclosure({\n ctx,\n text,\n}: {\n ctx: MenuRenderContext\n text: string\n}) {\n const address = ctx.activeAddress\n // Re-render after dismissing; the dismissal itself lives in storage\n const [, setDismissedCount] = useState(0)\n\n if (!address || isDisclosureDismissed(address)) return null\n\n const domain = getPasskeyAccountDomain(ctx.activeWallet?.activeAccount?.name)\n\n const handleDismiss = () => {\n dismissDisclosure(address)\n setDismissedCount((count) => count + 1)\n }\n\n return (\n <div\n role=\"note\"\n data-passkey-disclosure\n className=\"mb-2 flex flex-col gap-2 rounded-[10px] border border-[var(--wui-color-border)] bg-[var(--wui-color-bg-secondary)] px-3 py-2.5\"\n >\n <p className=\"text-xs leading-[1.55] text-[var(--wui-color-text-secondary)]\">\n {text.replaceAll('{domain}', domain)}\n </p>\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"self-end rounded-md bg-[var(--wui-color-primary)] px-2.5 py-1 text-xs font-medium text-[var(--wui-color-primary-text)] hover:bg-[var(--wui-color-primary-hover)]\"\n >\n Got it\n </button>\n </div>\n )\n}\n","import { useWalletManager } from '@txnlab/use-wallet-react'\n\nimport { isPasskeyWallet, type PasskeyWalletAdapter } from '../../utils/passkey'\n\nimport type { Wallet } from '@txnlab/use-wallet-react'\n\n/**\n * Returns the passkey adapter behind a `useWallet()` wallet object, or null\n * for any other wallet. Adapter-specific methods (`unlock`, `lock`,\n * `exportRecoveryPhrase`) aren't on the hook's wallet objects, so reach the\n * adapter through the manager. Requires @txnlab/use-wallet-react 5.2+.\n */\nexport function usePasskeyAdapter(\n wallet: Wallet | null,\n): PasskeyWalletAdapter | null {\n const manager = useWalletManager()\n if (!wallet || !isPasskeyWallet(wallet)) return null\n const adapter = manager.getWallet(wallet.walletKey)\n return (adapter as unknown as PasskeyWalletAdapter | undefined) ?? null\n}\n","import {\n FloatingFocusManager,\n FloatingOverlay,\n useDismiss,\n useFloating,\n useInteractions,\n useRole,\n} from '@floating-ui/react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { getPasskeyErrorMessage } from '../../utils/passkey'\n\nimport { usePasskeyAdapter } from './usePasskeyAdapter'\n\nimport type { PluginRenderContext } from '../types'\n\ntype DialogStep = 'warning' | 'loading' | 'display' | 'error'\n\nexport const DEFAULT_PASSKEY_DISPLAY_TIMEOUT = 60\n\nexport interface PasskeyRecoveryDialogProps {\n ctx: PluginRenderContext\n onClose: () => void\n /** Seconds to show the phrase before the dialog closes. Default: 60 */\n displayTimeout?: number\n}\n\nexport function PasskeyRecoveryDialog({\n ctx,\n onClose,\n displayTimeout = DEFAULT_PASSKEY_DISPLAY_TIMEOUT,\n}: PasskeyRecoveryDialogProps) {\n const adapter = usePasskeyAdapter(ctx.activeWallet)\n\n const [step, setStep] = useState<DialogStep>('warning')\n // The phrase only ever lives in this component's state\n const [words, setWords] = useState<string[] | null>(null)\n const [timeRemaining, setTimeRemaining] = useState(displayTimeout)\n const [showCopied, setShowCopied] = useState(false)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const [animationState, setAnimationState] = useState<\n 'starting' | 'entered' | 'exiting' | null\n >('starting')\n\n const hasCopiedRef = useRef(false)\n const isMountedRef = useRef(true)\n const isClosingRef = useRef(false)\n\n const { refs, context } = useFloating({\n open: true,\n onOpenChange: (open) => {\n if (!open) handleClose()\n },\n })\n\n const dismiss = useDismiss(context, { outsidePressEvent: 'mousedown' })\n const role = useRole(context, { role: 'dialog' })\n const { getFloatingProps } = useInteractions([dismiss, role])\n\n // Entry animation\n useEffect(() => {\n requestAnimationFrame(() => setAnimationState('entered'))\n }, [])\n\n const clearSensitiveData = useCallback(() => {\n setWords(null)\n // Best effort: clearing can fail without focus or permission\n if (hasCopiedRef.current) {\n hasCopiedRef.current = false\n navigator.clipboard?.writeText('').catch(() => {})\n }\n }, [])\n\n const handleClose = useCallback(() => {\n if (isClosingRef.current) return\n isClosingRef.current = true\n clearSensitiveData()\n setAnimationState('exiting')\n setTimeout(onClose, 150)\n }, [clearSensitiveData, onClose])\n\n // Hide the phrase (and close) when the countdown ends\n useEffect(() => {\n if (step !== 'display') return\n const timer = setInterval(() => {\n setTimeRemaining((prev) => Math.max(0, prev - 1))\n }, 1000)\n return () => clearInterval(timer)\n }, [step])\n\n useEffect(() => {\n if (step === 'display' && timeRemaining === 0) handleClose()\n }, [step, timeRemaining, handleClose])\n\n // Clear everything on unmount, e.g. when the wallet disconnects\n useEffect(() => {\n isMountedRef.current = true\n return () => {\n isMountedRef.current = false\n if (hasCopiedRef.current) {\n hasCopiedRef.current = false\n navigator.clipboard?.writeText('').catch(() => {})\n }\n }\n }, [])\n\n const handleReveal = () => {\n if (!adapter) {\n setErrorMessage('No passkey account is connected.')\n setStep('error')\n return\n }\n\n let exporting: ReturnType<typeof adapter.exportRecoveryPhrase>\n try {\n // Call exportRecoveryPhrase before any await: iOS drops the user's tap\n // across one, and the passkey prompt needs it\n exporting = adapter.exportRecoveryPhrase()\n } catch (error) {\n showError(error)\n return\n }\n setStep('loading')\n\n exporting.then(\n ({ phrase }) => {\n // Drop the phrase if the dialog closed while the prompt was open\n if (!isMountedRef.current || isClosingRef.current) return\n setWords(phrase.split(' '))\n setTimeRemaining(displayTimeout)\n setStep('display')\n },\n (error: unknown) => {\n if (isMountedRef.current) showError(error)\n },\n )\n }\n\n const showError = (error: unknown) => {\n setErrorMessage(\n getPasskeyErrorMessage(error) ??\n (error instanceof Error ? error.message : 'Failed to export phrase'),\n )\n setStep('error')\n }\n\n const handleCopy = () => {\n if (!words || !navigator.clipboard) return\n navigator.clipboard\n .writeText(words.join(' '))\n .then(() => {\n hasCopiedRef.current = true\n setShowCopied(true)\n setTimeout(() => setShowCopied(false), 2000)\n })\n .catch(() => {})\n }\n\n const handleRetry = () => {\n setErrorMessage(null)\n setStep('warning')\n }\n\n // Rendered inside PluginDialogRenderer's FloatingPortal,\n // so no FloatingPortal wrapper here\n return (\n <FloatingOverlay\n className=\"grid place-items-center px-4 z-50 transition-opacity duration-150 ease-in-out bg-[var(--wui-color-overlay)] data-[state=starting]:opacity-0 data-[state=exiting]:opacity-0 data-[state=entered]:opacity-100\"\n data-state={animationState}\n lockScroll\n >\n <FloatingFocusManager context={context} modal={true}>\n <div\n ref={refs.setFloating}\n {...getFloatingProps()}\n role=\"dialog\"\n aria-label={\n step === 'display' ? 'Recovery Phrase' : 'Export Recovery Phrase'\n }\n data-passkey-recovery-dialog\n data-state={animationState}\n className=\"w-full max-w-sm max-h-[calc(100dvh-2rem)] overflow-y-auto rounded-3xl bg-[var(--wui-color-bg)] shadow-xl transform transition-all duration-150 ease-in-out data-[state=starting]:opacity-0 data-[state=starting]:scale-90 data-[state=exiting]:opacity-0 data-[state=exiting]:scale-90 data-[state=entered]:opacity-100 data-[state=entered]:scale-100\"\n style={{ marginTop: '-0.5rem' }}\n >\n {step === 'warning' && (\n <>\n <DialogHeader\n title=\"Export Recovery Phrase\"\n onClose={handleClose}\n />\n <div className=\"px-6 pb-4 space-y-3\">\n <div className=\"bg-[var(--wui-color-danger-bg)] rounded-xl p-4\">\n <p className=\"text-sm font-medium text-[var(--wui-color-danger-text)] mb-2\">\n Your recovery phrase gives full access to this account and\n its funds.\n </p>\n <ul className=\"text-sm text-[var(--wui-color-danger-text)] list-disc pl-5 space-y-1\">\n <li>Never share it with anyone</li>\n <li>Never enter it on unverified websites</li>\n <li>Write it down and store it securely</li>\n </ul>\n </div>\n <FalconImportNote />\n </div>\n <div className=\"px-6 pb-5 flex gap-2\">\n <button\n onClick={handleClose}\n className=\"flex-1 py-2.5 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm\"\n >\n Cancel\n </button>\n <button\n onClick={handleReveal}\n className=\"flex-1 py-2.5 px-4 bg-[var(--wui-color-danger-bg)] text-[var(--wui-color-danger-text)] font-medium rounded-xl hover:bg-[var(--wui-color-danger-bg-hover)] transition-colors text-sm\"\n >\n Reveal Recovery Phrase\n </button>\n </div>\n </>\n )}\n\n {step === 'loading' && (\n <div className=\"px-6 py-12 flex flex-col items-center gap-3\">\n <Spinner />\n <p\n role=\"status\"\n className=\"text-sm text-[var(--wui-color-text-secondary)]\"\n >\n Confirm with your passkey…\n </p>\n </div>\n )}\n\n {step === 'display' && words && (\n <>\n <div className=\"relative flex items-center justify-between px-6 pt-5 pb-3\">\n <h2 className=\"text-xl font-bold text-[var(--wui-color-text)] wallet-custom-font\">\n Recovery Phrase\n </h2>\n <div className=\"flex items-center gap-2\">\n <span\n className=\"text-sm font-medium tabular-nums text-[var(--wui-color-text-secondary)]\"\n aria-label={`${timeRemaining} seconds remaining`}\n >\n {formatTime(timeRemaining)}\n </span>\n <CloseButton onClick={handleClose} />\n </div>\n </div>\n\n <div className=\"px-6 pb-3\">\n <ol\n className=\"grid grid-cols-3 gap-1 bg-[var(--wui-color-bg-secondary)] rounded-xl p-2\"\n style={{ userSelect: 'none' }}\n data-passkey-phrase\n >\n {words.map((word, i) => (\n <li\n key={i}\n className=\"flex items-baseline gap-1 py-1 px-1.5 rounded-md bg-[var(--wui-color-bg)] border border-[var(--wui-color-border)]\"\n >\n <span className=\"w-4 shrink-0 text-right text-[10px] tabular-nums text-[var(--wui-color-text-tertiary)]\">\n {i + 1}\n </span>\n <span className=\"text-xs font-medium text-[var(--wui-color-text)]\">\n {word}\n </span>\n </li>\n ))}\n </ol>\n </div>\n\n <div className=\"px-6 pb-3\">\n <FalconImportNote compact />\n </div>\n\n <div className=\"px-6 pb-2 flex gap-2\">\n <button\n onClick={handleCopy}\n className=\"flex-1 py-2 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm\"\n >\n {showCopied ? 'Copied' : 'Copy'}\n </button>\n <button\n onClick={handleClose}\n className=\"flex-1 py-2 px-4 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-xl hover:bg-[var(--wui-color-primary-hover)] transition-colors text-sm\"\n >\n Done\n </button>\n </div>\n <p className=\"px-6 pb-5 text-xs text-[var(--wui-color-text-tertiary)] text-center\">\n Clear your clipboard after you paste it\n </p>\n </>\n )}\n\n {step === 'error' && (\n <>\n <DialogHeader\n title=\"Export Recovery Phrase\"\n onClose={handleClose}\n />\n <div className=\"px-6 pb-4\">\n <p\n role=\"alert\"\n className=\"bg-[var(--wui-color-danger-bg)] rounded-xl p-4 text-sm text-[var(--wui-color-danger-text)]\"\n >\n {errorMessage || 'An unexpected error occurred.'}\n </p>\n </div>\n <div className=\"px-6 pb-5 flex gap-2\">\n <button\n onClick={handleClose}\n className=\"flex-1 py-2.5 px-4 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-xl hover:brightness-90 transition-all text-sm\"\n >\n Cancel\n </button>\n <button\n onClick={handleRetry}\n className=\"flex-1 py-2.5 px-4 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-xl hover:bg-[var(--wui-color-primary-hover)] transition-colors text-sm\"\n >\n Try Again\n </button>\n </div>\n </>\n )}\n </div>\n </FloatingFocusManager>\n </FloatingOverlay>\n )\n}\n\n/**\n * The phrase restores the account only as a Falcon-1024 account. The same\n * words in a regular import restore a different, empty account.\n */\nfunction FalconImportNote({ compact = false }: { compact?: boolean }) {\n return (\n <div\n data-passkey-falcon-note\n className=\"rounded-xl border border-[var(--wui-color-border)] bg-[var(--wui-color-bg-secondary)] p-3 text-sm text-[var(--wui-color-text)]\"\n >\n <p className=\"font-medium\">Import it as a Falcon / quantum account</p>\n {!compact && (\n <ul className=\"mt-1.5 list-disc pl-5 space-y-1 text-[var(--wui-color-text-secondary)]\">\n <li>\n Lute: Add account → <strong>Falcon25 account</strong> → Import\n </li>\n <li>Pera: use the quantum account import</li>\n </ul>\n )}\n <p className=\"mt-1.5 text-[var(--wui-color-text-secondary)]\">\n A regular 25-word import restores a different, empty account.\n </p>\n </div>\n )\n}\n\nfunction DialogHeader({\n title,\n onClose,\n}: {\n title: string\n onClose: () => void\n}) {\n return (\n <div className=\"relative flex items-center px-6 pt-5 pb-4\">\n <h2 className=\"text-xl font-bold text-[var(--wui-color-text)] wallet-custom-font\">\n {title}\n </h2>\n <CloseButton onClick={onClose} className=\"absolute right-4\" />\n </div>\n )\n}\n\nfunction CloseButton({\n onClick,\n className = '',\n}: {\n onClick: () => void\n className?: string\n}) {\n return (\n <button\n onClick={onClick}\n className={`${className} rounded-full bg-[var(--wui-color-bg-tertiary)] p-2 text-[var(--wui-color-text-secondary)] hover:brightness-90 transition-all`}\n aria-label=\"Close dialog\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-5 w-5\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n )\n}\n\nfunction Spinner() {\n return (\n <svg\n className=\"h-8 w-8 text-[var(--wui-color-text-tertiary)] animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )\n}\n\nfunction formatTime(seconds: number): string {\n const mins = Math.floor(seconds / 60)\n const secs = seconds % 60\n return `${mins}:${secs.toString().padStart(2, '0')}`\n}\n","import { PASSKEY_RECOVERY_DIALOG } from './constants'\n\nimport type { MenuRenderContext } from '../types'\n\nexport function PasskeyRecoveryMenuButton({ ctx }: { ctx: MenuRenderContext }) {\n // Only opens the dialog: the passkey prompt starts from its Reveal button\n const handleClick = () => {\n ctx.closeMenu()\n ctx.openDialog(PASSKEY_RECOVERY_DIALOG)\n }\n\n return (\n <>\n <div className=\"border-t border-[var(--wui-color-border)] mt-2 mb-2\" />\n <button\n onClick={handleClick}\n className=\"w-full flex items-center gap-2 px-2 py-2 rounded-lg text-sm text-[var(--wui-color-text-secondary)] hover:bg-[var(--wui-color-bg-hover)] transition-colors\"\n >\n {/* A plain shield: backing up is a protective step. No checkmark, so\n it doesn't read as already done, and no key, which means passkey\n sign-in. Heroicons solid shield-check without the check, MIT\n License */}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M9.661 2.237a.531.531 0 0 1 .678 0 11.947 11.947 0 0 0 7.078 2.749.5.5 0 0 1 .479.425c.069.52.104 1.05.104 1.59 0 5.162-3.26 9.563-7.834 11.256a.48.48 0 0 1-.332 0C5.26 16.564 2 12.163 2 7c0-.538.035-1.069.104-1.589a.5.5 0 0 1 .48-.425 11.947 11.947 0 0 0 7.077-2.75Z\" />\n </svg>\n <span className=\"flex-1 text-left\">Back up account</span>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 shrink-0 opacity-50\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n </>\n )\n}\n","import { useEffect, useState } from 'react'\n\nimport { getPasskeyErrorMessage } from '../../utils/passkey'\n\nimport { usePasskeyAdapter } from './usePasskeyAdapter'\n\nimport type { MenuRenderContext } from '../types'\n\n// The adapter's onLock/onUnlock callbacks belong to the app, so re-read\n// isUnlocked while the menu is open to catch locks from timeouts\nconst POLL_INTERVAL_MS = 1000\n\n/** Shows whether the passkey session is unlocked, with Unlock and Lock */\nexport function PasskeySessionControl({ ctx }: { ctx: MenuRenderContext }) {\n const adapter = usePasskeyAdapter(ctx.activeWallet)\n const [isUnlocked, setIsUnlocked] = useState(() => !!adapter?.isUnlocked)\n const [pending, setPending] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!adapter) return\n setIsUnlocked(adapter.isUnlocked)\n const timer = setInterval(\n () => setIsUnlocked(adapter.isUnlocked),\n POLL_INTERVAL_MS,\n )\n return () => clearInterval(timer)\n }, [adapter])\n\n if (!adapter) return null\n\n const handleUnlock = () => {\n setError(null)\n // Call unlock before any await: iOS drops the user's tap across one\n const unlocking = adapter.unlock()\n setPending(true)\n unlocking\n .then(() => setIsUnlocked(adapter.isUnlocked))\n .catch((err: unknown) => {\n setError(\n getPasskeyErrorMessage(err) ??\n (err instanceof Error ? err.message : 'Unlock failed'),\n )\n })\n .finally(() => setPending(false))\n }\n\n const handleLock = () => {\n adapter.lock()\n setIsUnlocked(adapter.isUnlocked)\n setError(null)\n }\n\n return (\n <div data-passkey-session className=\"mb-2\">\n <div className=\"flex items-center justify-between gap-2 px-1 py-0.5\">\n <span className=\"flex items-center gap-2 text-sm text-[var(--wui-color-text-secondary)]\">\n {isUnlocked ? <UnlockedIcon /> : <LockedIcon />}\n <span>{isUnlocked ? 'Unlocked' : 'Locked'}</span>\n </span>\n {isUnlocked ? (\n <button\n onClick={handleLock}\n className=\"py-1 px-2.5 bg-[var(--wui-color-bg-tertiary)] text-[var(--wui-color-text-secondary)] font-medium rounded-md hover:brightness-90 transition-all text-xs\"\n >\n Lock\n </button>\n ) : (\n <button\n onClick={handleUnlock}\n disabled={pending}\n className=\"py-1 px-2.5 bg-[var(--wui-color-primary)] text-[var(--wui-color-primary-text)] font-medium rounded-md hover:bg-[var(--wui-color-primary-hover)] transition-colors text-xs disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {pending ? 'Waiting…' : 'Unlock'}\n </button>\n )}\n </div>\n {!isUnlocked && !error && (\n <p className=\"px-1 text-xs text-[var(--wui-color-text-tertiary)]\">\n The next signature asks for your passkey.\n </p>\n )}\n {error && (\n <p\n role=\"alert\"\n className=\"mt-1 rounded-lg bg-[var(--wui-color-danger-bg)] px-3 py-2 text-xs text-[var(--wui-color-danger-text)]\"\n >\n {error}\n </p>\n )}\n </div>\n )\n}\n\nfunction LockedIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )\n}\n\nfunction UnlockedIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M10 2a5 5 0 00-5 5v2a2 2 0 00-2 2v5a2 2 0 002 2h10a2 2 0 002-2v-5a2 2 0 00-2-2H7V7a3 3 0 015.905-.75 1 1 0 001.937-.5A5.002 5.002 0 0010 2z\" />\n </svg>\n )\n}\n","import { isPasskeyWallet } from '../../utils/passkey'\n\nimport {\n DEFAULT_PASSKEY_DISCLOSURE,\n PASSKEY_RECOVERY_DIALOG,\n} from './constants'\nimport { PasskeyDisclosure } from './PasskeyDisclosure'\nimport { PasskeyRecoveryDialog } from './PasskeyRecoveryDialog'\nimport { PasskeyRecoveryMenuButton } from './PasskeyRecoveryMenuButton'\nimport { PasskeySessionControl } from './PasskeySessionControl'\n\nimport type { PluginDialog, PluginMenuItem, WalletUIPlugin } from '../types'\n\nexport {\n DEFAULT_PASSKEY_DISCLOSURE,\n PASSKEY_RECOVERY_DIALOG,\n} from './constants'\nexport { usePasskeyAdapter } from './usePasskeyAdapter'\nexport type { PasskeyWalletAdapter } from '../../utils/passkey'\n\nexport interface PasskeyPluginOptions {\n /**\n * Add \"Back up account\" to the menu, which reveals the recovery phrase.\n * Pass an object to set how long the phrase stays visible (seconds,\n * default 60). Default: true\n */\n recoveryPhrase?: boolean | { displayTimeout?: number }\n /**\n * Show the session's lock status with Unlock and Lock buttons. Turn it on\n * when the passkey wallet is configured with `passkey({ session })`.\n * Default: false\n */\n session?: boolean\n /**\n * Tell users the account belongs to this site, until they choose \"Got it\"\n * (remembered per account). Pass a string to replace the text; `{domain}`\n * is replaced with the account's domain. The menu always shows the domain\n * as a tag. Default: false\n */\n disclosure?: boolean | string\n}\n\n/**\n * Plugin that adds passkey account features to the ConnectedWalletMenu:\n * recovery phrase export, session lock status, and an optional note on whose\n * account it is. Only visible when the passkey wallet is active.\n *\n * Requires @txnlab/use-wallet-react 5.2 or later.\n */\nexport function passkeyPlugin(\n options: PasskeyPluginOptions = {},\n): WalletUIPlugin {\n const { recoveryPhrase = true, session = false, disclosure = false } = options\n\n const enabled = (ctx: { activeWallet: { id: string } | null }) =>\n isPasskeyWallet(ctx.activeWallet)\n\n const menuItems: PluginMenuItem[] = []\n const dialogs: PluginDialog[] = []\n\n if (disclosure) {\n const text =\n typeof disclosure === 'string' ? disclosure : DEFAULT_PASSKEY_DISCLOSURE\n menuItems.push({\n key: 'passkey-disclosure',\n slot: 'after-wallet-info',\n order: 5,\n enabled,\n render: (ctx) => <PasskeyDisclosure ctx={ctx} text={text} />,\n })\n }\n\n if (session) {\n menuItems.push({\n key: 'passkey-session',\n slot: 'after-wallet-info',\n order: 10,\n enabled,\n render: (ctx) => <PasskeySessionControl ctx={ctx} />,\n })\n }\n\n if (recoveryPhrase) {\n const displayTimeout =\n typeof recoveryPhrase === 'object'\n ? recoveryPhrase.displayTimeout\n : undefined\n menuItems.push({\n key: 'passkey-recovery-trigger',\n slot: 'after-wallet-info',\n order: 20,\n enabled,\n render: (ctx) => <PasskeyRecoveryMenuButton ctx={ctx} />,\n })\n dialogs.push({\n key: PASSKEY_RECOVERY_DIALOG,\n render: ({ onClose, ctx }) => (\n <PasskeyRecoveryDialog\n ctx={ctx}\n onClose={onClose}\n displayTimeout={displayTimeout}\n />\n ),\n })\n }\n\n return {\n id: 'passkey',\n name: 'Passkey',\n menuItems,\n dialogs,\n }\n}\n"],"names":["PASSKEY_RECOVERY_DIALOG","DEFAULT_PASSKEY_DISCLOSURE","createAddressFlag","keyPrefix","inMemory","address","disclosureDismissed","isDisclosureDismissed","dismissDisclosure","PasskeyDisclosure","ctx","text","setDismissedCount","useState","domain","getPasskeyAccountDomain","_b","_a","handleDismiss","count","jsxs","jsx","usePasskeyAdapter","wallet","manager","useWalletManager","isPasskeyWallet","DEFAULT_PASSKEY_DISPLAY_TIMEOUT","PasskeyRecoveryDialog","onClose","displayTimeout","adapter","step","setStep","words","setWords","timeRemaining","setTimeRemaining","showCopied","setShowCopied","errorMessage","setErrorMessage","animationState","setAnimationState","hasCopiedRef","useRef","isMountedRef","isClosingRef","refs","context","useFloating","open","handleClose","dismiss","useDismiss","role","useRole","getFloatingProps","useInteractions","useEffect","clearSensitiveData","useCallback","timer","prev","handleReveal","exporting","error","showError","phrase","getPasskeyErrorMessage","handleCopy","handleRetry","FloatingOverlay","FloatingFocusManager","Fragment","DialogHeader","FalconImportNote","Spinner","CloseButton","word","i","compact","title","onClick","className","formatTime","seconds","mins","secs","PasskeyRecoveryMenuButton","handleClick","POLL_INTERVAL_MS","PasskeySessionControl","isUnlocked","setIsUnlocked","pending","setPending","setError","handleUnlock","unlocking","err","handleLock","UnlockedIcon","LockedIcon","passkeyPlugin","options","recoveryPhrase","session","disclosure","enabled","menuItems","dialogs"],"mappings":"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"}
|