@dexterai/connect 0.16.0 → 0.17.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.
@@ -0,0 +1,107 @@
1
+ // src/DexterButton.tsx
2
+ import { useEffect } from "react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ var STYLE_ID = "dexter-connect-button-styles";
5
+ var BUTTON_CSS = `
6
+ @keyframes dx-spin { to { transform: rotate(360deg); } }
7
+ @keyframes dx-pulse { 0%,100% { opacity: 1; } 50% { opacity: .6; } }
8
+ .dx-btn{
9
+ --dx-ember:#f26c18; --dx-ember-2:#ba3a00; --dx-fg:#fff4ea; --dx-radius:0px;
10
+ position:relative; display:inline-flex; align-items:center; justify-content:center; gap:10px;
11
+ padding:11px 22px; border:1px solid color-mix(in srgb,var(--dx-ember) 55%,transparent);
12
+ border-radius:var(--dx-radius);
13
+ background:linear-gradient(135deg,var(--dx-ember),var(--dx-ember-2));
14
+ color:var(--dx-fg); font:inherit; font-weight:600; font-size:.78rem; letter-spacing:.12em;
15
+ text-transform:uppercase; cursor:pointer; -webkit-tap-highlight-color:transparent;
16
+ box-shadow:0 14px 26px color-mix(in srgb,var(--dx-ember) 24%,transparent);
17
+ transition:transform .16s ease, box-shadow .16s ease, filter .16s ease, background .16s ease;
18
+ }
19
+ .dx-btn:hover{ transform:translateY(-1px); filter:brightness(1.07); box-shadow:0 20px 34px color-mix(in srgb,var(--dx-ember) 32%,transparent); }
20
+ .dx-btn:active{ transform:translateY(0); filter:brightness(.97); box-shadow:0 8px 16px color-mix(in srgb,var(--dx-ember) 22%,transparent); }
21
+ .dx-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--dx-ember) 38%,transparent); }
22
+ .dx-btn:disabled{ cursor:default; filter:saturate(.85) brightness(.98); }
23
+ .dx-btn--secondary{ background:transparent; color:var(--dx-ember); box-shadow:none; border-color:color-mix(in srgb,var(--dx-ember) 45%,transparent); }
24
+ .dx-btn--secondary:hover{ background:color-mix(in srgb,var(--dx-ember) 9%,transparent); filter:none; box-shadow:none; }
25
+ .dx-btn--block{ width:100%; }
26
+ .dx-btn__mark{ flex-shrink:0; }
27
+ .dx-btn__spin{ width:15px; height:15px; flex-shrink:0; border-radius:50%;
28
+ border:2px solid color-mix(in srgb,currentColor 30%,transparent); border-top-color:currentColor;
29
+ animation:dx-spin .7s linear infinite; }
30
+ .dx-btn__doing{ animation:dx-pulse 1.4s ease-in-out infinite; }
31
+ .dx-chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; font:inherit;
32
+ font-variant-numeric:tabular-nums; border-radius:var(--dx-radius,0);
33
+ border:1px solid color-mix(in srgb,var(--dx-ember,#f26c18) 35%,transparent); }
34
+ .dx-chip__dot{ width:7px; height:7px; border-radius:50%; background:var(--dx-ember,#f26c18); }
35
+ .dx-chip__bal{ font-weight:600; opacity:.85; }
36
+ .dx-chip__x{ margin-left:2px; border:none; background:transparent; color:inherit; cursor:pointer; font-size:16px; line-height:1; opacity:.6; }
37
+ .dx-chip__x:hover{ opacity:1; }
38
+ `;
39
+ function ensureDexterButtonStyles() {
40
+ if (typeof document === "undefined") return;
41
+ if (document.getElementById(STYLE_ID)) return;
42
+ const el = document.createElement("style");
43
+ el.id = STYLE_ID;
44
+ el.textContent = BUTTON_CSS;
45
+ document.head.appendChild(el);
46
+ }
47
+ ensureDexterButtonStyles();
48
+ function cx(...parts) {
49
+ return parts.filter(Boolean).join(" ");
50
+ }
51
+ function DexterMark() {
52
+ return /* @__PURE__ */ jsxs(
53
+ "svg",
54
+ {
55
+ className: "dx-btn__mark",
56
+ width: "18",
57
+ height: "18",
58
+ viewBox: "0 0 300 300",
59
+ fill: "currentColor",
60
+ "aria-hidden": "true",
61
+ children: [
62
+ /* @__PURE__ */ jsx("path", { d: "M143.18,22.65c35.41,7.66,68.19,23.6,94.89,48.28,5.22,4.86,11.17,10.45,15.18,16.1,1.38,1.93,1.94,3.6.99,5.23-1.08,1.92-4.22,3.41-6.56,4.17-28.39,9.43-61.55,8.26-88.62-4.69-13.81-7.66-17.02-5.76-31.67-3.48-21.89,2.38-46.67.37-65.06-12.31-6.07-4.99-9.33-12.71-8.8-20.52-.16-9.4,4.25-18.12,11.47-24.06,21.29-17.85,52.64-14.45,78-8.77l.18.04h0Z" }),
63
+ /* @__PURE__ */ jsx("path", { d: "M46.08,129.98c1.06-1.03,3.52-1.07,5.29-1.04,48.98-.05,98.1-.06,146.83-.1,17.53.14,35.01-.31,52.49.18,2.13.18,3.89.74,4.73,2.05,1.46,2.38.35,6.09-1.98,7.6-3.66,2.05-8.62,1.33-12.86,1.74-2.85.12-5.45.13-7.02,2.02-.91,1.07-1.28,2.56-1.56,3.95-.57,3.23-1.16,6.52-1.89,9.62-2.81,12.43-8.68,24.65-19.76,31.56-9.49,5.59-20.42,6.86-31.2,5.75-11.88-1.69-22.15-8.81-29.11-18.28-3.51-4.81-4.92-10.5-5.8-16.29-.47-2.56-.51-5.87-1.35-8-1.16-3.38-6.14-2.59-9.25-1.92-4.21.95-4.39,5.7-5.14,9.19-2.25,11.18-6.84,20.68-16.15,27.65-1.31,1.05-2.91,2.03-2.12,3.66,2.5,3.21,6.65,4.49,10.44,5.97,3.26,1.17,6.86,2.41,7.18,6.06.05,8.18-11.97,3.46-16.32,1.85-3.95-1.55-7.4-4.27-10.42-7.26-3.92-4.28-9.66-4.5-15.16-4.45-3.45-.07-6.99-.19-10.45-.82-21.29-4-31.08-21.3-30.9-42.01-.08-4.63.03-9.32.09-13.91.04-1.69.07-3.46,1.28-4.67l.1-.09h0Z" }),
64
+ /* @__PURE__ */ jsx("path", { d: "M173.06,203.11c9.24-.06,21.6,4.49,22.85,14.84.3,2.12-.67,4.34-2.92,4.73-1.38.29-2.88-.05-4.09-.75-1.64-.9-2.97-2.86-4.19-3.05-1.33-.2-1.99.81-2.93,1.94-10.27,13.34-28.04,20.92-44.83,20.42-15.41-.33-31.89-5.95-43.53-17.34-3.15-3.39-1.55-9.88,3.61-9.19,1.83.32,3.29,1.45,4.76,2.65,10.49,10.12,24.85,14.04,39.12,13.03,10.55-1.23,20.38-5.47,28.74-11.92,1.11-1.06,4.45-3.63,3.5-5.12-.76-.85-4.31-.47-5.92-2.01-2.25-1.92-1.39-6.22,1.16-7.36,1.36-.65,2.96-.81,4.47-.86h.2,0Z" })
65
+ ]
66
+ }
67
+ );
68
+ }
69
+ function DexterButton(props) {
70
+ const {
71
+ children,
72
+ loading = false,
73
+ loadingLabel = "Connecting\u2026",
74
+ variant = "primary",
75
+ block = false,
76
+ withMark = true,
77
+ onClick,
78
+ disabled = false,
79
+ className,
80
+ type = "button"
81
+ } = props;
82
+ useEffect(ensureDexterButtonStyles, []);
83
+ return /* @__PURE__ */ jsx(
84
+ "button",
85
+ {
86
+ type,
87
+ className: cx("dx-btn", variant === "secondary" && "dx-btn--secondary", block && "dx-btn--block", className),
88
+ onClick,
89
+ disabled: disabled || loading,
90
+ "aria-busy": loading,
91
+ children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
92
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__spin", "aria-hidden": true }),
93
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__doing", children: loadingLabel })
94
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
95
+ withMark && /* @__PURE__ */ jsx(DexterMark, {}),
96
+ children
97
+ ] })
98
+ }
99
+ );
100
+ }
101
+
102
+ export {
103
+ ensureDexterButtonStyles,
104
+ cx,
105
+ DexterMark,
106
+ DexterButton
107
+ };
package/dist/react.js CHANGED
@@ -15,6 +15,12 @@ import {
15
15
  subscribe,
16
16
  switchWallet
17
17
  } from "./chunk-Y22JFT53.js";
18
+ import {
19
+ DexterButton,
20
+ DexterMark,
21
+ cx,
22
+ ensureDexterButtonStyles
23
+ } from "./chunk-S7G2ZZOO.js";
18
24
 
19
25
  // src/useSignInWithDexter.ts
20
26
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -123,111 +129,8 @@ function useSignInWithDexter(config = {}) {
123
129
  }
124
130
 
125
131
  // src/SignInWithDexter.tsx
126
- import { useEffect as useEffect3 } from "react";
127
-
128
- // src/DexterButton.tsx
129
132
  import { useEffect as useEffect2 } from "react";
130
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
131
- var STYLE_ID = "dexter-connect-button-styles";
132
- var BUTTON_CSS = `
133
- @keyframes dx-spin { to { transform: rotate(360deg); } }
134
- @keyframes dx-pulse { 0%,100% { opacity: 1; } 50% { opacity: .6; } }
135
- .dx-btn{
136
- --dx-ember:#f26c18; --dx-ember-2:#ba3a00; --dx-fg:#fff4ea; --dx-radius:0px;
137
- position:relative; display:inline-flex; align-items:center; justify-content:center; gap:10px;
138
- padding:11px 22px; border:1px solid color-mix(in srgb,var(--dx-ember) 55%,transparent);
139
- border-radius:var(--dx-radius);
140
- background:linear-gradient(135deg,var(--dx-ember),var(--dx-ember-2));
141
- color:var(--dx-fg); font:inherit; font-weight:600; font-size:.78rem; letter-spacing:.12em;
142
- text-transform:uppercase; cursor:pointer; -webkit-tap-highlight-color:transparent;
143
- box-shadow:0 14px 26px color-mix(in srgb,var(--dx-ember) 24%,transparent);
144
- transition:transform .16s ease, box-shadow .16s ease, filter .16s ease, background .16s ease;
145
- }
146
- .dx-btn:hover{ transform:translateY(-1px); filter:brightness(1.07); box-shadow:0 20px 34px color-mix(in srgb,var(--dx-ember) 32%,transparent); }
147
- .dx-btn:active{ transform:translateY(0); filter:brightness(.97); box-shadow:0 8px 16px color-mix(in srgb,var(--dx-ember) 22%,transparent); }
148
- .dx-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--dx-ember) 38%,transparent); }
149
- .dx-btn:disabled{ cursor:default; filter:saturate(.85) brightness(.98); }
150
- .dx-btn--secondary{ background:transparent; color:var(--dx-ember); box-shadow:none; border-color:color-mix(in srgb,var(--dx-ember) 45%,transparent); }
151
- .dx-btn--secondary:hover{ background:color-mix(in srgb,var(--dx-ember) 9%,transparent); filter:none; box-shadow:none; }
152
- .dx-btn--block{ width:100%; }
153
- .dx-btn__mark{ flex-shrink:0; }
154
- .dx-btn__spin{ width:15px; height:15px; flex-shrink:0; border-radius:50%;
155
- border:2px solid color-mix(in srgb,currentColor 30%,transparent); border-top-color:currentColor;
156
- animation:dx-spin .7s linear infinite; }
157
- .dx-btn__doing{ animation:dx-pulse 1.4s ease-in-out infinite; }
158
- .dx-chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; font:inherit;
159
- font-variant-numeric:tabular-nums; border-radius:var(--dx-radius,0);
160
- border:1px solid color-mix(in srgb,var(--dx-ember,#f26c18) 35%,transparent); }
161
- .dx-chip__dot{ width:7px; height:7px; border-radius:50%; background:var(--dx-ember,#f26c18); }
162
- .dx-chip__bal{ font-weight:600; opacity:.85; }
163
- .dx-chip__x{ margin-left:2px; border:none; background:transparent; color:inherit; cursor:pointer; font-size:16px; line-height:1; opacity:.6; }
164
- .dx-chip__x:hover{ opacity:1; }
165
- `;
166
- function ensureDexterButtonStyles() {
167
- if (typeof document === "undefined") return;
168
- if (document.getElementById(STYLE_ID)) return;
169
- const el = document.createElement("style");
170
- el.id = STYLE_ID;
171
- el.textContent = BUTTON_CSS;
172
- document.head.appendChild(el);
173
- }
174
- ensureDexterButtonStyles();
175
- function cx(...parts) {
176
- return parts.filter(Boolean).join(" ");
177
- }
178
- function DexterMark() {
179
- return /* @__PURE__ */ jsxs(
180
- "svg",
181
- {
182
- className: "dx-btn__mark",
183
- width: "18",
184
- height: "18",
185
- viewBox: "0 0 300 300",
186
- fill: "currentColor",
187
- "aria-hidden": "true",
188
- children: [
189
- /* @__PURE__ */ jsx("path", { d: "M143.18,22.65c35.41,7.66,68.19,23.6,94.89,48.28,5.22,4.86,11.17,10.45,15.18,16.1,1.38,1.93,1.94,3.6.99,5.23-1.08,1.92-4.22,3.41-6.56,4.17-28.39,9.43-61.55,8.26-88.62-4.69-13.81-7.66-17.02-5.76-31.67-3.48-21.89,2.38-46.67.37-65.06-12.31-6.07-4.99-9.33-12.71-8.8-20.52-.16-9.4,4.25-18.12,11.47-24.06,21.29-17.85,52.64-14.45,78-8.77l.18.04h0Z" }),
190
- /* @__PURE__ */ jsx("path", { d: "M46.08,129.98c1.06-1.03,3.52-1.07,5.29-1.04,48.98-.05,98.1-.06,146.83-.1,17.53.14,35.01-.31,52.49.18,2.13.18,3.89.74,4.73,2.05,1.46,2.38.35,6.09-1.98,7.6-3.66,2.05-8.62,1.33-12.86,1.74-2.85.12-5.45.13-7.02,2.02-.91,1.07-1.28,2.56-1.56,3.95-.57,3.23-1.16,6.52-1.89,9.62-2.81,12.43-8.68,24.65-19.76,31.56-9.49,5.59-20.42,6.86-31.2,5.75-11.88-1.69-22.15-8.81-29.11-18.28-3.51-4.81-4.92-10.5-5.8-16.29-.47-2.56-.51-5.87-1.35-8-1.16-3.38-6.14-2.59-9.25-1.92-4.21.95-4.39,5.7-5.14,9.19-2.25,11.18-6.84,20.68-16.15,27.65-1.31,1.05-2.91,2.03-2.12,3.66,2.5,3.21,6.65,4.49,10.44,5.97,3.26,1.17,6.86,2.41,7.18,6.06.05,8.18-11.97,3.46-16.32,1.85-3.95-1.55-7.4-4.27-10.42-7.26-3.92-4.28-9.66-4.5-15.16-4.45-3.45-.07-6.99-.19-10.45-.82-21.29-4-31.08-21.3-30.9-42.01-.08-4.63.03-9.32.09-13.91.04-1.69.07-3.46,1.28-4.67l.1-.09h0Z" }),
191
- /* @__PURE__ */ jsx("path", { d: "M173.06,203.11c9.24-.06,21.6,4.49,22.85,14.84.3,2.12-.67,4.34-2.92,4.73-1.38.29-2.88-.05-4.09-.75-1.64-.9-2.97-2.86-4.19-3.05-1.33-.2-1.99.81-2.93,1.94-10.27,13.34-28.04,20.92-44.83,20.42-15.41-.33-31.89-5.95-43.53-17.34-3.15-3.39-1.55-9.88,3.61-9.19,1.83.32,3.29,1.45,4.76,2.65,10.49,10.12,24.85,14.04,39.12,13.03,10.55-1.23,20.38-5.47,28.74-11.92,1.11-1.06,4.45-3.63,3.5-5.12-.76-.85-4.31-.47-5.92-2.01-2.25-1.92-1.39-6.22,1.16-7.36,1.36-.65,2.96-.81,4.47-.86h.2,0Z" })
192
- ]
193
- }
194
- );
195
- }
196
- function DexterButton(props) {
197
- const {
198
- children,
199
- loading = false,
200
- loadingLabel = "Connecting\u2026",
201
- variant = "primary",
202
- block = false,
203
- withMark = true,
204
- onClick,
205
- disabled = false,
206
- className,
207
- type = "button"
208
- } = props;
209
- useEffect2(ensureDexterButtonStyles, []);
210
- return /* @__PURE__ */ jsx(
211
- "button",
212
- {
213
- type,
214
- className: cx("dx-btn", variant === "secondary" && "dx-btn--secondary", block && "dx-btn--block", className),
215
- onClick,
216
- disabled: disabled || loading,
217
- "aria-busy": loading,
218
- children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
219
- /* @__PURE__ */ jsx("span", { className: "dx-btn__spin", "aria-hidden": true }),
220
- /* @__PURE__ */ jsx("span", { className: "dx-btn__doing", children: loadingLabel })
221
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
222
- withMark && /* @__PURE__ */ jsx(DexterMark, {}),
223
- children
224
- ] })
225
- }
226
- );
227
- }
228
-
229
- // src/SignInWithDexter.tsx
230
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
133
+ import { jsx, jsxs } from "react/jsx-runtime";
231
134
  function shortAddress(addr) {
232
135
  return addr.length > 10 ? `${addr.slice(0, 4)}\u2026${addr.slice(-4)}` : addr;
233
136
  }
@@ -245,7 +148,7 @@ function SignInWithDexter(props) {
245
148
  showConnectedChip = true,
246
149
  ...config
247
150
  } = props;
248
- useEffect3(ensureDexterButtonStyles, []);
151
+ useEffect2(ensureDexterButtonStyles, []);
249
152
  const c = useSignInWithDexter(config);
250
153
  const handleClick = async () => {
251
154
  try {
@@ -256,17 +159,17 @@ function SignInWithDexter(props) {
256
159
  };
257
160
  if (c.isVaultConnected) {
258
161
  if (!showConnectedChip) return null;
259
- return /* @__PURE__ */ jsxs2("span", { className: cx("dx-chip", className), children: [
260
- /* @__PURE__ */ jsx2("span", { className: "dx-chip__dot", "aria-hidden": true }),
261
- /* @__PURE__ */ jsx2("span", { children: c.vaultAddress ? shortAddress(c.vaultAddress) : "Connected" }),
262
- c.usdcBalance !== null && /* @__PURE__ */ jsxs2("span", { className: "dx-chip__bal", children: [
162
+ return /* @__PURE__ */ jsxs("span", { className: cx("dx-chip", className), children: [
163
+ /* @__PURE__ */ jsx("span", { className: "dx-chip__dot", "aria-hidden": true }),
164
+ /* @__PURE__ */ jsx("span", { children: c.vaultAddress ? shortAddress(c.vaultAddress) : "Connected" }),
165
+ c.usdcBalance !== null && /* @__PURE__ */ jsxs("span", { className: "dx-chip__bal", children: [
263
166
  formatUsd(c.usdcBalance),
264
167
  " available"
265
168
  ] }),
266
- /* @__PURE__ */ jsx2("button", { type: "button", className: "dx-chip__x", onClick: c.disconnect, "aria-label": "Disconnect", children: "\xD7" })
169
+ /* @__PURE__ */ jsx("button", { type: "button", className: "dx-chip__x", onClick: c.disconnect, "aria-label": "Disconnect", children: "\xD7" })
267
170
  ] });
268
171
  }
269
- return /* @__PURE__ */ jsx2(
172
+ return /* @__PURE__ */ jsx(
270
173
  DexterButton,
271
174
  {
272
175
  loading: c.status === "pending",
@@ -281,13 +184,13 @@ function SignInWithDexter(props) {
281
184
  }
282
185
 
283
186
  // src/useDexterWallet.ts
284
- import { useCallback as useCallback2, useEffect as useEffect4, useState as useState2 } from "react";
187
+ import { useCallback as useCallback2, useEffect as useEffect3, useState as useState2 } from "react";
285
188
  var NO_SUPPORT = { rename: false, prune: false, syncAccepted: false };
286
189
  function useDexterWallet() {
287
190
  const [activeHandle, setHandle] = useState2(() => getActiveHandle());
288
191
  const [wallets, setWallets] = useState2(() => listWallets());
289
192
  const [support, setSupport] = useState2(NO_SUPPORT);
290
- useEffect4(() => {
193
+ useEffect3(() => {
291
194
  const sync = () => {
292
195
  setHandle(getActiveHandle());
293
196
  setWallets(listWallets());
@@ -324,10 +227,10 @@ function useDexterWallet() {
324
227
  }
325
228
 
326
229
  // src/DexterWalletChip.tsx
327
- import { useEffect as useEffect5 } from "react";
230
+ import { useEffect as useEffect4 } from "react";
328
231
 
329
232
  // src/walletKitStyles.ts
330
- var STYLE_ID2 = "dexter-connect-wallet-kit-styles";
233
+ var STYLE_ID = "dexter-connect-wallet-kit-styles";
331
234
  var WALLET_KIT_CSS = `
332
235
  .dx-wchip{
333
236
  --dx-ember:#f26c18; --dx-ember-2:#ba3a00; --dx-fg:#fff4ea; --dx-radius:0px;
@@ -366,21 +269,21 @@ var WALLET_KIT_CSS = `
366
269
  `;
367
270
  function ensureWalletKitStyles() {
368
271
  if (typeof document === "undefined") return;
369
- if (document.getElementById(STYLE_ID2)) return;
272
+ if (document.getElementById(STYLE_ID)) return;
370
273
  const el = document.createElement("style");
371
- el.id = STYLE_ID2;
274
+ el.id = STYLE_ID;
372
275
  el.textContent = WALLET_KIT_CSS;
373
276
  document.head.appendChild(el);
374
277
  }
375
278
  ensureWalletKitStyles();
376
279
 
377
280
  // src/DexterWalletChip.tsx
378
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
281
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
379
282
  function DexterWalletChip(props) {
380
283
  const { connected, label, avatarUrl, avatarInitial, onClick, className, ariaExpanded } = props;
381
- useEffect5(ensureWalletKitStyles, []);
284
+ useEffect4(ensureWalletKitStyles, []);
382
285
  const initial = (avatarInitial ?? label.trim().charAt(0) ?? "D").toUpperCase();
383
- return /* @__PURE__ */ jsxs3(
286
+ return /* @__PURE__ */ jsxs2(
384
287
  "button",
385
288
  {
386
289
  type: "button",
@@ -388,64 +291,64 @@ function DexterWalletChip(props) {
388
291
  onClick,
389
292
  "aria-expanded": ariaExpanded,
390
293
  children: [
391
- connected ? /* @__PURE__ */ jsx3("span", { className: "dx-wchip__avatar", "aria-hidden": "true", children: avatarUrl ? /* @__PURE__ */ jsx3("img", { src: avatarUrl, alt: "" }) : initial }) : null,
392
- /* @__PURE__ */ jsx3("span", { className: "dx-wchip__label", children: label })
294
+ connected ? /* @__PURE__ */ jsx2("span", { className: "dx-wchip__avatar", "aria-hidden": "true", children: avatarUrl ? /* @__PURE__ */ jsx2("img", { src: avatarUrl, alt: "" }) : initial }) : null,
295
+ /* @__PURE__ */ jsx2("span", { className: "dx-wchip__label", children: label })
393
296
  ]
394
297
  }
395
298
  );
396
299
  }
397
300
 
398
301
  // src/DexterWalletMenu.tsx
399
- import { useEffect as useEffect6, useState as useState3 } from "react";
400
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
302
+ import { useEffect as useEffect5, useState as useState3 } from "react";
303
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
401
304
  function DexterWalletMenu(props) {
402
305
  const { walletLabel, avatarInitial, onManageWallet, onStartFresh, saveSlot, saveHint, className } = props;
403
- useEffect6(ensureWalletKitStyles, []);
306
+ useEffect5(ensureWalletKitStyles, []);
404
307
  const [showSave, setShowSave] = useState3(false);
405
308
  const initial = (avatarInitial ?? walletLabel.trim().charAt(0) ?? "D").toUpperCase();
406
309
  if (showSave && saveSlot) {
407
- return /* @__PURE__ */ jsxs4("div", { className: cx("dx-wmenu", className), children: [
408
- /* @__PURE__ */ jsx4(
310
+ return /* @__PURE__ */ jsxs3("div", { className: cx("dx-wmenu", className), children: [
311
+ /* @__PURE__ */ jsx3(
409
312
  "button",
410
313
  {
411
314
  type: "button",
412
315
  className: "dx-wmenu__item dx-wmenu__back",
413
316
  onClick: () => setShowSave(false),
414
- children: /* @__PURE__ */ jsx4("span", { children: "\u2190 Back to wallet" })
317
+ children: /* @__PURE__ */ jsx3("span", { children: "\u2190 Back to wallet" })
415
318
  }
416
319
  ),
417
- /* @__PURE__ */ jsxs4("div", { className: "dx-wmenu__save", children: [
418
- saveHint ? /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__savehint", children: saveHint }) : null,
320
+ /* @__PURE__ */ jsxs3("div", { className: "dx-wmenu__save", children: [
321
+ saveHint ? /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__savehint", children: saveHint }) : null,
419
322
  saveSlot
420
323
  ] })
421
324
  ] });
422
325
  }
423
- return /* @__PURE__ */ jsxs4("div", { className: cx("dx-wmenu", className), children: [
424
- /* @__PURE__ */ jsxs4("div", { className: "dx-wmenu__id", children: [
425
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__avatar", "aria-hidden": "true", children: initial }),
426
- /* @__PURE__ */ jsxs4("span", { className: "dx-wmenu__meta", children: [
427
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__name", children: walletLabel }),
428
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__sub", children: "Your Dexter Wallet" })
326
+ return /* @__PURE__ */ jsxs3("div", { className: cx("dx-wmenu", className), children: [
327
+ /* @__PURE__ */ jsxs3("div", { className: "dx-wmenu__id", children: [
328
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__avatar", "aria-hidden": "true", children: initial }),
329
+ /* @__PURE__ */ jsxs3("span", { className: "dx-wmenu__meta", children: [
330
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__name", children: walletLabel }),
331
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__sub", children: "Your Dexter Wallet" })
429
332
  ] })
430
333
  ] }),
431
- /* @__PURE__ */ jsxs4("div", { className: "dx-wmenu__list", children: [
432
- onManageWallet ? /* @__PURE__ */ jsxs4("button", { type: "button", className: "dx-wmenu__item", onClick: onManageWallet, children: [
433
- /* @__PURE__ */ jsx4("span", { children: "Manage wallet" }),
434
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u2197" })
334
+ /* @__PURE__ */ jsxs3("div", { className: "dx-wmenu__list", children: [
335
+ onManageWallet ? /* @__PURE__ */ jsxs3("button", { type: "button", className: "dx-wmenu__item", onClick: onManageWallet, children: [
336
+ /* @__PURE__ */ jsx3("span", { children: "Manage wallet" }),
337
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u2197" })
435
338
  ] }) : null,
436
- saveSlot ? /* @__PURE__ */ jsxs4("button", { type: "button", className: "dx-wmenu__item", onClick: () => setShowSave(true), children: [
437
- /* @__PURE__ */ jsx4("span", { children: "Save your wallet" }),
438
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u2197" })
339
+ saveSlot ? /* @__PURE__ */ jsxs3("button", { type: "button", className: "dx-wmenu__item", onClick: () => setShowSave(true), children: [
340
+ /* @__PURE__ */ jsx3("span", { children: "Save your wallet" }),
341
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u2197" })
439
342
  ] }) : null,
440
- onStartFresh ? /* @__PURE__ */ jsxs4(
343
+ onStartFresh ? /* @__PURE__ */ jsxs3(
441
344
  "button",
442
345
  {
443
346
  type: "button",
444
347
  className: "dx-wmenu__item dx-wmenu__item--danger",
445
348
  onClick: onStartFresh,
446
349
  children: [
447
- /* @__PURE__ */ jsx4("span", { children: "Start fresh" }),
448
- /* @__PURE__ */ jsx4("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u27F5" })
350
+ /* @__PURE__ */ jsx3("span", { children: "Start fresh" }),
351
+ /* @__PURE__ */ jsx3("span", { className: "dx-wmenu__icon", "aria-hidden": "true", children: "\u27F5" })
449
352
  ]
450
353
  }
451
354
  ) : null
@@ -0,0 +1,61 @@
1
+ import { ReactElement } from 'react';
2
+ import { IDKitResult } from '@worldcoin/idkit';
3
+
4
+ type VerifyPersonhoodPhase = 'loading' | 'ready' | 'rp_error' | 'verified';
5
+ interface VerifyPersonhoodConfig {
6
+ /** World ID app id (`app_…`), from the developer portal. */
7
+ appId: `app_${string}`;
8
+ /** The registered action (e.g. `dexter-credit-root-v2`) — pins the nullifier namespace. */
9
+ action: string;
10
+ /** `production` | `staging`. Default `production`. */
11
+ environment?: 'production' | 'staging';
12
+ /**
13
+ * URL that returns the SERVER-SIGNED RP context as `{ rp_context: RpContext }`.
14
+ * The RP signing key is server-side only (never the browser), so the consumer
15
+ * exposes an endpoint that signs the request and returns just the signed
16
+ * context. Mirrors the capture rig's `/api/rp-context`.
17
+ */
18
+ rpContextUrl: string;
19
+ /** Optional `fetch` init for the RP-context request (auth headers, etc.). */
20
+ rpContextInit?: RequestInit;
21
+ }
22
+ interface UseVerifyPersonhood {
23
+ phase: VerifyPersonhoodPhase;
24
+ error: string | null;
25
+ result: IDKitResult | null;
26
+ /** Open the World App verification sheet. No-op until phase is 'ready'/'verified'. */
27
+ open: () => void;
28
+ /** The IDKitRequestWidget element to render (null until the RP context loads). */
29
+ widget: ReactElement | null;
30
+ }
31
+ /**
32
+ * Headless hook: manages the RP-context fetch + IDKit lifecycle and hands back
33
+ * the raw proof. Render `widget` and call `open()` from your own UI, or use the
34
+ * turnkey <VerifyPersonhood> below.
35
+ */
36
+ declare function useVerifyPersonhood(config: VerifyPersonhoodConfig, onProof?: (result: IDKitResult) => void, onError?: (error: Error) => void): UseVerifyPersonhood;
37
+ interface VerifyPersonhoodProps extends VerifyPersonhoodConfig {
38
+ /** Fired with the raw World ID v4 proof the moment verification completes. */
39
+ onProof?: (result: IDKitResult) => void;
40
+ /** Fired with the typed error if RP signing or verification fails. */
41
+ onError?: (error: Error) => void;
42
+ /** Button label when armed. Default "Verify your personhood". */
43
+ label?: string;
44
+ /** Label after a proof is captured. Default "Verify again". */
45
+ verifiedLabel?: string;
46
+ /** 'primary' = filled ember (default), 'secondary' = outline. */
47
+ variant?: 'primary' | 'secondary';
48
+ /** Full-width button. */
49
+ block?: boolean;
50
+ /** Extra className composed after the brand classes. */
51
+ className?: string;
52
+ }
53
+ /**
54
+ * Turnkey "Verify your personhood" element — the personhood sibling of
55
+ * <SignInWithDexter>. Renders the branded DexterButton (loading while the RP
56
+ * context signs server-side) that opens World App; on success hands the raw
57
+ * IDKitResult to `onProof`. Brand voice: no emojis. Themeable via --dx-* vars.
58
+ */
59
+ declare function VerifyPersonhood(props: VerifyPersonhoodProps): ReactElement;
60
+
61
+ export { type UseVerifyPersonhood, VerifyPersonhood, type VerifyPersonhoodConfig, type VerifyPersonhoodPhase, type VerifyPersonhoodProps, useVerifyPersonhood };
@@ -0,0 +1,108 @@
1
+ import {
2
+ DexterButton,
3
+ ensureDexterButtonStyles
4
+ } from "./chunk-S7G2ZZOO.js";
5
+
6
+ // src/worldid.tsx
7
+ import { useEffect, useState } from "react";
8
+ import {
9
+ IDKitRequestWidget,
10
+ proofOfHuman
11
+ } from "@worldcoin/idkit";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ function useVerifyPersonhood(config, onProof, onError) {
14
+ const { appId, action, environment = "production", rpContextUrl, rpContextInit } = config;
15
+ const [phase, setPhase] = useState("loading");
16
+ const [error, setError] = useState(null);
17
+ const [rpContext, setRpContext] = useState(null);
18
+ const [isOpen, setIsOpen] = useState(false);
19
+ const [result, setResult] = useState(null);
20
+ useEffect(() => {
21
+ let cancelled = false;
22
+ void (async () => {
23
+ try {
24
+ const res = await fetch(rpContextUrl, { cache: "no-store", ...rpContextInit });
25
+ const data = await res.json();
26
+ if (!res.ok) throw new Error(data?.message ?? `RP context fetch failed (HTTP ${res.status})`);
27
+ if (cancelled) return;
28
+ setRpContext(data.rp_context);
29
+ setPhase("ready");
30
+ } catch (e) {
31
+ if (cancelled) return;
32
+ const err = e instanceof Error ? e : new Error(String(e));
33
+ setError(err.message);
34
+ setPhase("rp_error");
35
+ onError?.(err);
36
+ }
37
+ })();
38
+ return () => {
39
+ cancelled = true;
40
+ };
41
+ }, [rpContextUrl]);
42
+ const widget = rpContext ? /* @__PURE__ */ jsx(
43
+ IDKitRequestWidget,
44
+ {
45
+ app_id: appId,
46
+ action,
47
+ rp_context: rpContext,
48
+ preset: proofOfHuman(),
49
+ allow_legacy_proofs: false,
50
+ environment,
51
+ open: isOpen,
52
+ onOpenChange: setIsOpen,
53
+ onSuccess: (res) => {
54
+ setResult(res);
55
+ setPhase("verified");
56
+ onProof?.(res);
57
+ },
58
+ onError: (code) => {
59
+ const err = new Error(`World App error: ${code}`);
60
+ setError(err.message);
61
+ onError?.(err);
62
+ }
63
+ }
64
+ ) : null;
65
+ return {
66
+ phase,
67
+ error,
68
+ result,
69
+ open: () => {
70
+ if (phase === "ready" || phase === "verified") setIsOpen(true);
71
+ },
72
+ widget
73
+ };
74
+ }
75
+ function VerifyPersonhood(props) {
76
+ const {
77
+ onProof,
78
+ onError,
79
+ label = "Verify your personhood",
80
+ verifiedLabel = "Verify again",
81
+ variant = "primary",
82
+ block = false,
83
+ className,
84
+ ...config
85
+ } = props;
86
+ useEffect(ensureDexterButtonStyles, []);
87
+ const v = useVerifyPersonhood(config, onProof, onError);
88
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
89
+ /* @__PURE__ */ jsx(
90
+ DexterButton,
91
+ {
92
+ onClick: v.open,
93
+ loading: v.phase === "loading",
94
+ loadingLabel: "Preparing\u2026",
95
+ variant,
96
+ block,
97
+ className,
98
+ disabled: v.phase === "rp_error",
99
+ children: v.phase === "verified" ? verifiedLabel : label
100
+ }
101
+ ),
102
+ v.widget
103
+ ] });
104
+ }
105
+ export {
106
+ VerifyPersonhood,
107
+ useVerifyPersonhood
108
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/connect",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Sign in with Dexter — passkey connector. Composes @dexterai/vault.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,6 +11,10 @@
11
11
  "./react": {
12
12
  "types": "./dist/react.d.ts",
13
13
  "import": "./dist/react.js"
14
+ },
15
+ "./worldid": {
16
+ "types": "./dist/worldid.d.ts",
17
+ "import": "./dist/worldid.js"
14
18
  }
15
19
  },
16
20
  "files": [
@@ -24,17 +28,22 @@
24
28
  "peerDependencies": {
25
29
  "@dexterai/vault": ">=0.22",
26
30
  "@solana/web3.js": "^1.98.0",
31
+ "@worldcoin/idkit": "^4.1.8",
27
32
  "react": ">=18"
28
33
  },
29
34
  "peerDependenciesMeta": {
30
35
  "@solana/web3.js": {
31
36
  "optional": true
37
+ },
38
+ "@worldcoin/idkit": {
39
+ "optional": true
32
40
  }
33
41
  },
34
42
  "devDependencies": {
35
43
  "@dexterai/vault": "^0.24.0",
36
44
  "@solana/web3.js": "^1.98.4",
37
45
  "@types/react": "^19.1.12",
46
+ "@worldcoin/idkit": "^4.1.8",
38
47
  "react": "^19.2.5",
39
48
  "tsup": "^8.5.0",
40
49
  "typescript": "^5.6.2",