@dexterai/connect 0.6.0 → 0.8.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/dist/react.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
2
2
  import { S as SignInResult, P as PasskeyLoginTokens, C as ConnectVault, a as ConnectError, c as StoredWallet, b as PasskeySignalSupport } from './signals-CkBFwCNw.js';
3
- import { ReactElement } from 'react';
3
+ import { ReactElement, ReactNode } from 'react';
4
4
 
5
5
  type ConnectStatus = 'idle' | 'pending' | 'done' | 'error';
6
6
  interface UseSignInWithDexterConfig {
@@ -48,22 +48,49 @@ interface SignInWithDexterProps extends UseSignInWithDexterConfig {
48
48
  onError?: (error: ConnectError) => void;
49
49
  /** Button label when signed out. Default "Sign in with Dexter". */
50
50
  label?: string;
51
- /** className on the root (button when signed out, chip when connected) — for
52
- * full restyling. Brand it from the consumer; the inline defaults are a base. */
51
+ /** 'primary' = filled ember (default), 'secondary' = outline. */
52
+ variant?: 'primary' | 'secondary';
53
+ /** Full-width button. */
54
+ block?: boolean;
55
+ /** Extra className composed after the brand classes. Prefer overriding the
56
+ * `--dx-*` CSS variables for theming. */
53
57
  className?: string;
54
- /** Render the built-in connected chip (wallet + balance). Default true.
55
- * Set false to render nothing once connected (consumer renders its own UI). */
58
+ /** Render the built-in connected chip (wallet + balance). Default true. */
56
59
  showConnectedChip?: boolean;
57
60
  }
58
61
  /**
59
- * Turnkey "Sign in with Dexter" element. Signed out → an ember button; signed
60
- * in a compact chip with the Dexter Wallet address + USD available. Wraps
61
- * useSignInWithDexter; consumers who need the raw vault/passkey data should use
62
- * that hook directly. Inline styles are a sensible default — restyle via
63
- * className (Dexter Ember, no emojis, "unlock" banned per brand voice).
62
+ * Turnkey "Sign in with Dexter" element. Signed out → the branded DexterButton
63
+ * (hover / focus / active / loading states, themeable via --dx-* CSS vars);
64
+ * signed in a compact chip with the Dexter Wallet address + USD available.
65
+ * Wraps useSignInWithDexter; for the wallet CREATE flow use <DexterButton>
66
+ * wired to your create action. Brand voice: no emojis, "unlock" banned.
64
67
  */
65
68
  declare function SignInWithDexter(props: SignInWithDexterProps): ReactElement | null;
66
69
 
70
+ /** The Dexter passkey mark — the brand glyph carried on the branded button. */
71
+ declare function DexterMark(): ReactElement;
72
+ interface DexterButtonProps {
73
+ /** Button content (e.g. "Sign in with Dexter", "Create your Dexter Wallet"). */
74
+ children?: ReactNode;
75
+ /** Loading state: shows the animated spinner + `loadingLabel`, disables click. */
76
+ loading?: boolean;
77
+ /** Label shown next to the spinner while loading. Default "Connecting…". */
78
+ loadingLabel?: string;
79
+ /** 'primary' = filled ember (default), 'secondary' = outline. */
80
+ variant?: 'primary' | 'secondary';
81
+ /** Full-width (fills its container). */
82
+ block?: boolean;
83
+ /** Render the Dexter mark before the children. Default true. */
84
+ withMark?: boolean;
85
+ onClick?: () => void;
86
+ disabled?: boolean;
87
+ /** Extra className composed after the brand classes. */
88
+ className?: string;
89
+ type?: 'button' | 'submit';
90
+ }
91
+ /** The branded Dexter button. Wire it to any action via `onClick`. */
92
+ declare function DexterButton(props: DexterButtonProps): ReactElement;
93
+
67
94
  interface UseDexterWallet {
68
95
  /** Active wallet handle, or null if this browser has no active wallet. */
69
96
  activeHandle: string | null;
@@ -94,4 +121,4 @@ interface UseDexterWallet {
94
121
  }
95
122
  declare function useDexterWallet(): UseDexterWallet;
96
123
 
97
- export { type ConnectStatus, SignInWithDexter, type SignInWithDexterProps, type UseDexterWallet, type UseSignInWithDexter, type UseSignInWithDexterConfig, useDexterWallet, useSignInWithDexter };
124
+ export { type ConnectStatus, DexterButton, type DexterButtonProps, DexterMark, SignInWithDexter, type SignInWithDexterProps, type UseDexterWallet, type UseSignInWithDexter, type UseSignInWithDexterConfig, useDexterWallet, useSignInWithDexter };
package/dist/react.js CHANGED
@@ -116,23 +116,68 @@ function useSignInWithDexter(config = {}) {
116
116
  }
117
117
 
118
118
  // src/SignInWithDexter.tsx
119
+ import { useEffect as useEffect3 } from "react";
120
+
121
+ // src/DexterButton.tsx
122
+ import { useEffect as useEffect2 } from "react";
119
123
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
120
- function shortAddress(addr) {
121
- return addr.length > 10 ? `${addr.slice(0, 4)}\u2026${addr.slice(-4)}` : addr;
124
+ var STYLE_ID = "dexter-connect-button-styles";
125
+ var BUTTON_CSS = `
126
+ @keyframes dx-spin { to { transform: rotate(360deg); } }
127
+ @keyframes dx-pulse { 0%,100% { opacity: 1; } 50% { opacity: .6; } }
128
+ .dx-btn{
129
+ --dx-ember:#f26c18; --dx-ember-2:#ba3a00; --dx-fg:#fff4ea; --dx-radius:0px;
130
+ position:relative; display:inline-flex; align-items:center; justify-content:center; gap:10px;
131
+ padding:11px 22px; border:1px solid color-mix(in srgb,var(--dx-ember) 55%,transparent);
132
+ border-radius:var(--dx-radius);
133
+ background:linear-gradient(135deg,var(--dx-ember),var(--dx-ember-2));
134
+ color:var(--dx-fg); font:inherit; font-weight:600; font-size:.78rem; letter-spacing:.12em;
135
+ text-transform:uppercase; cursor:pointer; -webkit-tap-highlight-color:transparent;
136
+ box-shadow:0 14px 26px color-mix(in srgb,var(--dx-ember) 24%,transparent);
137
+ transition:transform .16s ease, box-shadow .16s ease, filter .16s ease, background .16s ease;
122
138
  }
123
- function formatUsd(n) {
124
- return n.toLocaleString("en-US", { style: "currency", currency: "USD" });
139
+ .dx-btn:hover{ transform:translateY(-1px); filter:brightness(1.07); box-shadow:0 20px 34px color-mix(in srgb,var(--dx-ember) 32%,transparent); }
140
+ .dx-btn:active{ transform:translateY(0); filter:brightness(.97); box-shadow:0 8px 16px color-mix(in srgb,var(--dx-ember) 22%,transparent); }
141
+ .dx-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--dx-ember) 38%,transparent); }
142
+ .dx-btn:disabled{ cursor:default; filter:saturate(.85) brightness(.98); }
143
+ .dx-btn--secondary{ background:transparent; color:var(--dx-ember); box-shadow:none; border-color:color-mix(in srgb,var(--dx-ember) 45%,transparent); }
144
+ .dx-btn--secondary:hover{ background:color-mix(in srgb,var(--dx-ember) 9%,transparent); filter:none; box-shadow:none; }
145
+ .dx-btn--block{ width:100%; }
146
+ .dx-btn__mark{ flex-shrink:0; }
147
+ .dx-btn__spin{ width:15px; height:15px; flex-shrink:0; border-radius:50%;
148
+ border:2px solid color-mix(in srgb,currentColor 30%,transparent); border-top-color:currentColor;
149
+ animation:dx-spin .7s linear infinite; }
150
+ .dx-btn__doing{ animation:dx-pulse 1.4s ease-in-out infinite; }
151
+ .dx-chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; font:inherit;
152
+ font-variant-numeric:tabular-nums; border-radius:var(--dx-radius,0);
153
+ border:1px solid color-mix(in srgb,var(--dx-ember,#f26c18) 35%,transparent); }
154
+ .dx-chip__dot{ width:7px; height:7px; border-radius:50%; background:var(--dx-ember,#f26c18); }
155
+ .dx-chip__bal{ font-weight:600; opacity:.85; }
156
+ .dx-chip__x{ margin-left:2px; border:none; background:transparent; color:inherit; cursor:pointer; font-size:16px; line-height:1; opacity:.6; }
157
+ .dx-chip__x:hover{ opacity:1; }
158
+ `;
159
+ function ensureDexterButtonStyles() {
160
+ if (typeof document === "undefined") return;
161
+ if (document.getElementById(STYLE_ID)) return;
162
+ const el = document.createElement("style");
163
+ el.id = STYLE_ID;
164
+ el.textContent = BUTTON_CSS;
165
+ document.head.appendChild(el);
166
+ }
167
+ ensureDexterButtonStyles();
168
+ function cx(...parts) {
169
+ return parts.filter(Boolean).join(" ");
125
170
  }
126
171
  function DexterMark() {
127
172
  return /* @__PURE__ */ jsxs(
128
173
  "svg",
129
174
  {
175
+ className: "dx-btn__mark",
130
176
  width: "18",
131
177
  height: "18",
132
178
  viewBox: "0 0 300 300",
133
179
  fill: "currentColor",
134
180
  "aria-hidden": "true",
135
- style: { flexShrink: 0 },
136
181
  children: [
137
182
  /* @__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" }),
138
183
  /* @__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" }),
@@ -141,15 +186,59 @@ function DexterMark() {
141
186
  }
142
187
  );
143
188
  }
189
+ function DexterButton(props) {
190
+ const {
191
+ children,
192
+ loading = false,
193
+ loadingLabel = "Connecting\u2026",
194
+ variant = "primary",
195
+ block = false,
196
+ withMark = true,
197
+ onClick,
198
+ disabled = false,
199
+ className,
200
+ type = "button"
201
+ } = props;
202
+ useEffect2(ensureDexterButtonStyles, []);
203
+ return /* @__PURE__ */ jsx(
204
+ "button",
205
+ {
206
+ type,
207
+ className: cx("dx-btn", variant === "secondary" && "dx-btn--secondary", block && "dx-btn--block", className),
208
+ onClick,
209
+ disabled: disabled || loading,
210
+ "aria-busy": loading,
211
+ children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
212
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__spin", "aria-hidden": true }),
213
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__doing", children: loadingLabel })
214
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
215
+ withMark && /* @__PURE__ */ jsx(DexterMark, {}),
216
+ children
217
+ ] })
218
+ }
219
+ );
220
+ }
221
+
222
+ // src/SignInWithDexter.tsx
223
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
224
+ function shortAddress(addr) {
225
+ return addr.length > 10 ? `${addr.slice(0, 4)}\u2026${addr.slice(-4)}` : addr;
226
+ }
227
+ function formatUsd(n) {
228
+ return n.toLocaleString("en-US", { style: "currency", currency: "USD" });
229
+ }
144
230
  function SignInWithDexter(props) {
145
231
  const {
146
232
  onSuccess,
147
233
  onError,
148
234
  label = "Sign in with Dexter",
235
+ variant = "primary",
236
+ block = false,
149
237
  className,
150
238
  showConnectedChip = true,
151
239
  ...config
152
240
  } = props;
241
+ useEffect3(ensureDexterButtonStyles, []);
153
242
  const c = useSignInWithDexter(config);
154
243
  const handleClick = async () => {
155
244
  try {
@@ -160,91 +249,37 @@ function SignInWithDexter(props) {
160
249
  };
161
250
  if (c.isVaultConnected) {
162
251
  if (!showConnectedChip) return null;
163
- return /* @__PURE__ */ jsxs("span", { className, style: CHIP, children: [
164
- /* @__PURE__ */ jsx("span", { style: DOT, "aria-hidden": true }),
165
- /* @__PURE__ */ jsx("span", { children: c.vaultAddress ? shortAddress(c.vaultAddress) : "Connected" }),
166
- c.usdcBalance !== null && /* @__PURE__ */ jsxs("span", { style: BALANCE, children: [
252
+ return /* @__PURE__ */ jsxs2("span", { className: cx("dx-chip", className), children: [
253
+ /* @__PURE__ */ jsx2("span", { className: "dx-chip__dot", "aria-hidden": true }),
254
+ /* @__PURE__ */ jsx2("span", { children: c.vaultAddress ? shortAddress(c.vaultAddress) : "Connected" }),
255
+ c.usdcBalance !== null && /* @__PURE__ */ jsxs2("span", { className: "dx-chip__bal", children: [
167
256
  formatUsd(c.usdcBalance),
168
257
  " available"
169
258
  ] }),
170
- /* @__PURE__ */ jsx("button", { type: "button", onClick: c.disconnect, style: DISCONNECT, "aria-label": "Disconnect", children: "\xD7" })
259
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "dx-chip__x", onClick: c.disconnect, "aria-label": "Disconnect", children: "\xD7" })
171
260
  ] });
172
261
  }
173
- return /* @__PURE__ */ jsx(
174
- "button",
262
+ return /* @__PURE__ */ jsx2(
263
+ DexterButton,
175
264
  {
176
- type: "button",
265
+ loading: c.status === "pending",
266
+ variant,
267
+ block,
177
268
  className,
178
269
  onClick: handleClick,
179
- disabled: c.status === "pending",
180
- style: BUTTON,
181
- children: c.status === "pending" ? "Signing in\u2026" : /* @__PURE__ */ jsxs(Fragment, { children: [
182
- /* @__PURE__ */ jsx(DexterMark, {}),
183
- label
184
- ] })
270
+ children: label
185
271
  }
186
272
  );
187
273
  }
188
- var EMBER = "#ef6820";
189
- var BUTTON = {
190
- display: "inline-flex",
191
- alignItems: "center",
192
- justifyContent: "center",
193
- gap: 10,
194
- padding: "10px 22px",
195
- border: "1px solid rgba(242, 108, 24, 0.55)",
196
- borderRadius: 0,
197
- // sharp corners — Dexter brand drops radius on structural elements
198
- background: "linear-gradient(135deg, rgba(242, 108, 24, 0.95), rgba(186, 58, 0, 0.88))",
199
- color: "#fff4ea",
200
- font: "inherit",
201
- fontWeight: 600,
202
- fontSize: "0.78rem",
203
- letterSpacing: "0.12em",
204
- textTransform: "uppercase",
205
- boxShadow: "0 16px 28px rgba(242, 108, 24, 0.25)",
206
- cursor: "pointer"
207
- };
208
- var CHIP = {
209
- display: "inline-flex",
210
- alignItems: "center",
211
- gap: 8,
212
- padding: "6px 10px",
213
- borderRadius: 0,
214
- // sharp — match the brand
215
- border: "1px solid rgba(239,104,32,0.35)",
216
- font: "inherit",
217
- fontVariantNumeric: "tabular-nums"
218
- };
219
- var DOT = {
220
- width: 7,
221
- height: 7,
222
- borderRadius: "50%",
223
- background: EMBER
224
- };
225
- var BALANCE = {
226
- fontWeight: 600,
227
- opacity: 0.85
228
- };
229
- var DISCONNECT = {
230
- marginLeft: 2,
231
- border: "none",
232
- background: "transparent",
233
- color: "inherit",
234
- cursor: "pointer",
235
- fontSize: 16,
236
- lineHeight: 1,
237
- opacity: 0.6
238
- };
239
274
 
240
275
  // src/useDexterWallet.ts
241
- import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
276
+ import { useCallback as useCallback2, useEffect as useEffect4, useState as useState2 } from "react";
242
277
  var NO_SUPPORT = { rename: false, prune: false, syncAccepted: false };
243
278
  function useDexterWallet() {
244
279
  const [activeHandle, setHandle] = useState2(() => getActiveHandle());
245
280
  const [wallets, setWallets] = useState2(() => listWallets());
246
281
  const [support, setSupport] = useState2(NO_SUPPORT);
247
- useEffect2(() => {
282
+ useEffect4(() => {
248
283
  const sync = () => {
249
284
  setHandle(getActiveHandle());
250
285
  setWallets(listWallets());
@@ -280,6 +315,8 @@ function useDexterWallet() {
280
315
  };
281
316
  }
282
317
  export {
318
+ DexterButton,
319
+ DexterMark,
283
320
  SignInWithDexter,
284
321
  useDexterWallet,
285
322
  useSignInWithDexter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/connect",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Sign in with Dexter — passkey connector. Composes @dexterai/vault.",
5
5
  "type": "module",
6
6
  "exports": {