decane-connect-kit 2.2.3 → 2.2.5

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/dist/index.cjs CHANGED
@@ -3861,11 +3861,25 @@ var CSS_VARS = {
3861
3861
 
3862
3862
  // src/ui/icons.tsx
3863
3863
  var import_react = __toESM(require("react"), 1);
3864
- var DECAGON_OUTER = "12,2 17.88,3.91 21.51,8.91 21.51,15.09 17.88,20.09 12,22 6.12,20.09 2.49,15.09 2.49,8.91 6.12,3.91";
3865
- var DECAGON_INNER = "12,7.4 14.7,8.28 16.37,10.58 16.37,13.42 14.7,15.72 12,16.6 9.3,15.72 7.63,13.42 7.63,10.58 9.3,8.28";
3866
- function DecaneMark({ size = 24, muted = false }) {
3867
- const color = muted ? "var(--dc-text-muted)" : "var(--dc-accent)";
3868
- return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, style: { flexShrink: 0, display: "block" } }, /* @__PURE__ */ import_react.default.createElement("polygon", { points: DECAGON_OUTER, fill: color, fillOpacity: muted ? 0.08 : 0.1, stroke: color, strokeWidth: "1.4", strokeLinejoin: "round" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: DECAGON_INNER, fill: color, fillOpacity: muted ? 0.55 : 0.95 }));
3864
+ function DecaneMark({ size = 28, muted = false }) {
3865
+ const uid = import_react.default.useId().replace(/:/g, "");
3866
+ const fid = `dl_logo_f_${uid}`;
3867
+ const w = size;
3868
+ const h = Math.round(size * 64 / 68);
3869
+ return /* @__PURE__ */ import_react.default.createElement(
3870
+ "svg",
3871
+ {
3872
+ width: w,
3873
+ height: h,
3874
+ viewBox: "0 0 68 64",
3875
+ fill: "none",
3876
+ xmlns: "http://www.w3.org/2000/svg",
3877
+ "aria-hidden": true,
3878
+ style: { display: "block", flexShrink: 0, opacity: muted ? 0.55 : 1 }
3879
+ },
3880
+ /* @__PURE__ */ import_react.default.createElement("g", { filter: `url(#${fid})` }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M32.8031 10.2986C33.1971 9.68929 34.0886 9.68929 34.4826 10.2986L35.7297 12.2273C36.1599 12.8926 35.6823 13.7703 34.89 13.7703H32.3957C31.6034 13.7703 31.1257 12.8926 31.556 12.2273L32.8031 10.2986Z", fill: "#FFD700" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M16.6095 20.8798C25.5139 8.28662 47.0755 12.2298 51.4641 20.5617C54.9502 24.0479 55.2167 30.8018 55.2167 30.8018C55.2167 30.8018 58.8421 37.862 57.4428 41.3601C55.7891 56.7522 13.9381 57.0066 11.3304 41.3601C9.93111 37.0351 13.4293 31.3744 13.4293 31.3744C13.4293 31.3744 12.9841 27.2404 16.6095 20.8798Z", fill: "#FFD700" }), /* @__PURE__ */ import_react.default.createElement("ellipse", { cx: "48.9999", cy: "39.2669", rx: "2.38155", ry: "1.89957", transform: "rotate(-22.395 48.9999 39.2669)", fill: "#FFE55F", fillOpacity: "0.45" }), /* @__PURE__ */ import_react.default.createElement("ellipse", { cx: "18.9785", cy: "39.2671", rx: "2.38155", ry: "1.89958", transform: "rotate(15.8893 18.9785 39.2671)", fill: "#FFE55F", fillOpacity: "0.26" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M43.5977 30.7344C43.1619 30.7344 42.6943 30.9653 42.3027 31.4824C41.9107 32.0001 41.6388 32.7597 41.6387 33.6406C41.6387 34.5217 41.9107 35.2821 42.3027 35.7998C42.6943 36.3168 43.1619 36.5479 43.5977 36.5479C44.0332 36.5477 44.5002 36.3166 44.8916 35.7998C45.2837 35.2821 45.5557 34.5217 45.5557 33.6406C45.5556 32.7597 45.2836 32.0001 44.8916 31.4824C44.5002 30.9656 44.0333 30.7345 43.5977 30.7344Z", fill: "#1A1A1A", stroke: "#F4EBBC", strokeWidth: "2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M25.1514 30.7344C25.5871 30.7344 26.0547 30.9653 26.4463 31.4824C26.8383 32.0001 27.1103 32.7597 27.1104 33.6406C27.1104 34.5217 26.8384 35.2821 26.4463 35.7998C26.0547 36.3168 25.5871 36.5479 25.1514 36.5479C24.7158 36.5477 24.2489 36.3166 23.8574 35.7998C23.4654 35.2821 23.1934 34.5217 23.1934 33.6406C23.1934 32.7597 23.4654 32.0001 23.8574 31.4824C24.2489 30.9656 24.7157 30.7345 25.1514 30.7344Z", fill: "#1A1A1A", stroke: "#F4EBBC", strokeWidth: "2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M26.0107 41.6924C26.0107 41.6924 28.0937 46.399 34.759 46.399C41.008 46.399 43.3109 41.6924 43.3109 41.6924", stroke: "#1A1A1A", strokeLinecap: "round" })),
3881
+ /* @__PURE__ */ import_react.default.createElement("defs", null, /* @__PURE__ */ import_react.default.createElement("filter", { id: fid, x: "0.589964", y: "0.334365", width: "66.5809", height: "62.9754", filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB" }, /* @__PURE__ */ import_react.default.createElement("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }), /* @__PURE__ */ import_react.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }), /* @__PURE__ */ import_react.default.createElement("feOffset", { dx: "-0.501447", dy: "0.401157" }), /* @__PURE__ */ import_react.default.createElement("feGaussianBlur", { stdDeviation: "4.95429" }), /* @__PURE__ */ import_react.default.createElement("feComposite", { in2: "hardAlpha", operator: "out" }), /* @__PURE__ */ import_react.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0.996078 0 0 0 0 0.996078 0 0 0 0 0.996078 0 0 0 0.12 0" }), /* @__PURE__ */ import_react.default.createElement("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1_dropShadow" }), /* @__PURE__ */ import_react.default.createElement("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect1_dropShadow", result: "shape" })))
3882
+ );
3869
3883
  }
3870
3884
  function DecaneWordmark({ size = 15, muted = false }) {
3871
3885
  return /* @__PURE__ */ import_react.default.createElement(
@@ -4874,7 +4888,10 @@ function SignInView({
4874
4888
  authMethods,
4875
4889
  resumeHint,
4876
4890
  customAuthLabel,
4877
- onCustomAuthSignIn
4891
+ onCustomAuthSignIn,
4892
+ canUsePasskey,
4893
+ passkeyAddress,
4894
+ onPasskeySignIn
4878
4895
  }) {
4879
4896
  const [googleLoading, setGoogleLoading] = (0, import_react3.useState)(false);
4880
4897
  const [email, setEmail] = (0, import_react3.useState)("");
@@ -4882,7 +4899,25 @@ function SignInView({
4882
4899
  const [emailSent, setEmailSent] = (0, import_react3.useState)(false);
4883
4900
  const [emailLoading, setEmailLoading] = (0, import_react3.useState)(false);
4884
4901
  const [customLoading, setCustomLoading] = (0, import_react3.useState)(false);
4902
+ const [passkeyLoading, setPasskeyLoading] = (0, import_react3.useState)(false);
4903
+ const [showOtherMethods, setShowOtherMethods] = (0, import_react3.useState)(false);
4885
4904
  const [error, setError] = (0, import_react3.useState)("");
4905
+ const passkeyFirst = !!canUsePasskey && !!onPasskeySignIn && !showOtherMethods;
4906
+ async function handlePasskey() {
4907
+ if (!onPasskeySignIn) return;
4908
+ setError("");
4909
+ setPasskeyLoading(true);
4910
+ try {
4911
+ await onPasskeySignIn();
4912
+ } catch (e) {
4913
+ const err = e;
4914
+ if (err?.name !== "UserCancelledError") {
4915
+ setError(err?.message ?? "Passkey sign-in failed");
4916
+ setShowOtherMethods(true);
4917
+ }
4918
+ setPasskeyLoading(false);
4919
+ }
4920
+ }
4886
4921
  async function handleGoogle() {
4887
4922
  setError("");
4888
4923
  setGoogleLoading(true);
@@ -4942,7 +4977,47 @@ function SignInView({
4942
4977
  fontFamily: "inherit",
4943
4978
  boxSizing: "border-box"
4944
4979
  };
4945
- return /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "0 16px 16px" } }, resumeHint && /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 12, color: "var(--dc-text-muted)", marginBottom: 12, textAlign: "center" } }, "Welcome back \u2014 sign in again to resume ", resumeHint), authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement(
4980
+ return /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "0 16px 16px" } }, resumeHint && !passkeyFirst && /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 12, color: "var(--dc-text-muted)", marginBottom: 12, textAlign: "center" } }, "Welcome back \u2014 sign in again to resume ", resumeHint), passkeyFirst && /* @__PURE__ */ import_react3.default.createElement("div", null, /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 12, color: "var(--dc-text-muted)", marginBottom: 12, textAlign: "center" } }, "Welcome back \u2014 unlock to resume", passkeyAddress ? ` ${passkeyAddress.slice(0, 6)}\u2026${passkeyAddress.slice(-4)}` : ""), /* @__PURE__ */ import_react3.default.createElement(
4981
+ "button",
4982
+ {
4983
+ onClick: handlePasskey,
4984
+ disabled: passkeyLoading,
4985
+ style: {
4986
+ width: "100%",
4987
+ padding: "11px 0",
4988
+ background: "var(--dc-accent)",
4989
+ color: "var(--dc-accent-text)",
4990
+ border: "none",
4991
+ borderRadius: 10,
4992
+ fontSize: 13,
4993
+ fontWeight: 700,
4994
+ cursor: passkeyLoading ? "not-allowed" : "pointer",
4995
+ opacity: passkeyLoading ? 0.7 : 1,
4996
+ fontFamily: "inherit",
4997
+ display: "flex",
4998
+ alignItems: "center",
4999
+ justifyContent: "center",
5000
+ gap: 7
5001
+ }
5002
+ },
5003
+ passkeyLoading ? "Verifying\u2026" : "\u{1F513} Continue with passkey"
5004
+ ), /* @__PURE__ */ import_react3.default.createElement(
5005
+ "button",
5006
+ {
5007
+ onClick: () => setShowOtherMethods(true),
5008
+ style: {
5009
+ width: "100%",
5010
+ marginTop: 10,
5011
+ background: "none",
5012
+ border: "none",
5013
+ color: "var(--dc-text-muted)",
5014
+ fontSize: 12,
5015
+ cursor: "pointer",
5016
+ fontFamily: "inherit"
5017
+ }
5018
+ },
5019
+ "Use email or Google instead"
5020
+ ), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { marginTop: 10, fontSize: 12, color: "var(--dc-danger, #ff5533)" } }, error)), !passkeyFirst && authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement(
4946
5021
  "button",
4947
5022
  {
4948
5023
  onClick: handleGoogle,
@@ -4963,7 +5038,7 @@ function SignInView({
4963
5038
  }
4964
5039
  },
4965
5040
  googleLoading ? "Redirecting\u2026" : "Continue with Google"
4966
- ), authMethods.includes("email") && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !emailSent ? /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
5041
+ ), !passkeyFirst && authMethods.includes("email") && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !emailSent ? /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
4967
5042
  "input",
4968
5043
  {
4969
5044
  type: "email",
@@ -5002,7 +5077,7 @@ function SignInView({
5002
5077
  fontWeight: 700,
5003
5078
  cursor: "pointer",
5004
5079
  fontFamily: "inherit"
5005
- } }, emailLoading ? "\u2026" : "Verify"))), customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), /* @__PURE__ */ import_react3.default.createElement(
5080
+ } }, emailLoading ? "\u2026" : "Verify"))), !passkeyFirst && customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), /* @__PURE__ */ import_react3.default.createElement(
5006
5081
  "button",
5007
5082
  {
5008
5083
  onClick: handleCustomAuth,
@@ -5141,6 +5216,9 @@ function SocialWalletModal({
5141
5216
  authMethods = ["google", "email"],
5142
5217
  customAuthLabel,
5143
5218
  onCustomAuthSignIn,
5219
+ canUsePasskey,
5220
+ passkeyAddress,
5221
+ onPasskeySignIn,
5144
5222
  onRotateShares,
5145
5223
  onExportPortableBackup,
5146
5224
  rpcUrls,
@@ -5242,17 +5320,7 @@ function SocialWalletModal({
5242
5320
  top: 0,
5243
5321
  zIndex: 1,
5244
5322
  background: "linear-gradient(90deg, transparent, var(--dc-accent) 30%, var(--dc-accent) 70%, transparent)"
5245
- } }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap: 11 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
5246
- width: 38,
5247
- height: 38,
5248
- borderRadius: 11,
5249
- background: "var(--dc-surface)",
5250
- border: "1px solid var(--dc-border)",
5251
- display: "flex",
5252
- alignItems: "center",
5253
- justifyContent: "center",
5254
- flexShrink: 0
5255
- } }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 22 })), /* @__PURE__ */ import_react3.default.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 15 }), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "-0.01em" } }, "wallet")), /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Non-custodial \xB7 key split three ways")), /* @__PURE__ */ import_react3.default.createElement(
5323
+ } }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap: 11 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 38 }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 15 }), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "-0.01em" } }, "wallet")), /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Non-custodial \xB7 key split three ways")), /* @__PURE__ */ import_react3.default.createElement(
5256
5324
  "button",
5257
5325
  {
5258
5326
  onClick: onClose,
@@ -5281,7 +5349,10 @@ function SocialWalletModal({
5281
5349
  authMethods,
5282
5350
  resumeHint: socialAuth.needsReconnect ? "your wallet" : void 0,
5283
5351
  customAuthLabel,
5284
- onCustomAuthSignIn
5352
+ onCustomAuthSignIn,
5353
+ canUsePasskey,
5354
+ passkeyAddress,
5355
+ onPasskeySignIn
5285
5356
  }
5286
5357
  ) : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
5287
5358
  margin: "0 16px 14px",
@@ -5669,6 +5740,9 @@ function DecaneKit({ config, children }) {
5669
5740
  onEmailStart: connectWithEmail,
5670
5741
  onEmailVerify: verifyEmailCode2,
5671
5742
  authMethods: config?.social?.authMethods ?? ["google", "email"],
5743
+ canUsePasskey: socialAuth.canUsePasskey,
5744
+ passkeyAddress: socialAuth.addresses?.evm ?? socialAuth.addresses?.solana ?? null,
5745
+ onPasskeySignIn: signInWithPasskey,
5672
5746
  onRotateShares: socialRotateShares,
5673
5747
  onExportPortableBackup: socialExportPortableBackup,
5674
5748
  rpcUrls: config?.social?.rpcUrls,
@@ -5698,6 +5772,7 @@ function useSocialAuth() {
5698
5772
  connectWithToken,
5699
5773
  customAuthLabel,
5700
5774
  connectWithCustomAuth,
5775
+ signInWithPasskey: ctxSignInWithPasskey,
5701
5776
  socialUnlock,
5702
5777
  socialDisconnect
5703
5778
  } = useDecaneContext();
@@ -5766,6 +5841,15 @@ function useSocialAuth() {
5766
5841
  setCustomLoading(false);
5767
5842
  }
5768
5843
  }, [connectWithCustomAuth]);
5844
+ const signInWithPasskey = (0, import_react5.useCallback)(async () => {
5845
+ setError(null);
5846
+ try {
5847
+ await ctxSignInWithPasskey();
5848
+ } catch (e) {
5849
+ setError(e.message);
5850
+ throw e;
5851
+ }
5852
+ }, [ctxSignInWithPasskey]);
5769
5853
  const unlock = (0, import_react5.useCallback)(async () => {
5770
5854
  setError(null);
5771
5855
  try {
@@ -5790,6 +5874,8 @@ function useSocialAuth() {
5790
5874
  isNewUser: socialAuth.isNewUser,
5791
5875
  addresses: socialAuth.addresses,
5792
5876
  sessionExpiresAt: socialAuth.sessionExpiresAt,
5877
+ // True when this device can skip the full sign-in and resume with a passkey.
5878
+ canUsePasskey: socialAuth.canUsePasskey,
5793
5879
  // True when addresses are known (from a previous visit) but there's no
5794
5880
  // live session — unlock() will always throw in this state (every
5795
5881
  // unlock requires a fresh JWT, and JWTs are never persisted). Route
@@ -5807,6 +5893,7 @@ function useSocialAuth() {
5807
5893
  confirmEmailCode,
5808
5894
  signInWithToken,
5809
5895
  signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
5896
+ signInWithPasskey,
5810
5897
  unlock,
5811
5898
  disconnect
5812
5899
  };