@dexterai/connect 0.6.0 → 0.7.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
@@ -48,19 +48,21 @@ 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
+ /** Visual variant: 'primary' = filled ember (default), 'secondary' = outline. */
52
+ variant?: 'primary' | 'secondary';
53
+ /** Extra className composed after the brand classes. Prefer overriding the
54
+ * `--dx-*` CSS variables for theming over restyling from scratch. */
53
55
  className?: string;
54
56
  /** Render the built-in connected chip (wallet + balance). Default true.
55
57
  * Set false to render nothing once connected (consumer renders its own UI). */
56
58
  showConnectedChip?: boolean;
57
59
  }
58
60
  /**
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).
61
+ * Turnkey "Sign in with Dexter" element. Signed out → the branded ember button
62
+ * (hover / focus / active / loading states, themeable via --dx-* CSS vars);
63
+ * signed in a compact chip with the Dexter Wallet address + USD available.
64
+ * Wraps useSignInWithDexter; consumers who need the raw vault/passkey data
65
+ * should use that hook directly. Brand voice: no emojis, "unlock" banned.
64
66
  */
65
67
  declare function SignInWithDexter(props: SignInWithDexterProps): ReactElement | null;
66
68
 
package/dist/react.js CHANGED
@@ -116,7 +116,54 @@ function useSignInWithDexter(config = {}) {
116
116
  }
117
117
 
118
118
  // src/SignInWithDexter.tsx
119
+ import { useEffect as useEffect2 } from "react";
119
120
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
121
+ var STYLE_ID = "dexter-connect-button-styles";
122
+ var BUTTON_CSS = `
123
+ @keyframes dx-spin { to { transform: rotate(360deg); } }
124
+ @keyframes dx-pulse { 0%,100% { opacity: 1; } 50% { opacity: .6; } }
125
+ .dx-btn{
126
+ --dx-ember:#f26c18; --dx-ember-2:#ba3a00; --dx-fg:#fff4ea; --dx-radius:0px;
127
+ position:relative; display:inline-flex; align-items:center; justify-content:center; gap:10px;
128
+ padding:11px 22px; border:1px solid color-mix(in srgb,var(--dx-ember) 55%,transparent);
129
+ border-radius:var(--dx-radius);
130
+ background:linear-gradient(135deg,var(--dx-ember),var(--dx-ember-2));
131
+ color:var(--dx-fg); font:inherit; font-weight:600; font-size:.78rem; letter-spacing:.12em;
132
+ text-transform:uppercase; cursor:pointer; -webkit-tap-highlight-color:transparent;
133
+ box-shadow:0 14px 26px color-mix(in srgb,var(--dx-ember) 24%,transparent);
134
+ transition:transform .16s ease, box-shadow .16s ease, filter .16s ease, background .16s ease;
135
+ }
136
+ .dx-btn:hover{ transform:translateY(-1px); filter:brightness(1.07); box-shadow:0 20px 34px color-mix(in srgb,var(--dx-ember) 32%,transparent); }
137
+ .dx-btn:active{ transform:translateY(0); filter:brightness(.97); box-shadow:0 8px 16px color-mix(in srgb,var(--dx-ember) 22%,transparent); }
138
+ .dx-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--dx-ember) 38%,transparent); }
139
+ .dx-btn:disabled{ cursor:default; filter:saturate(.85) brightness(.98); }
140
+ .dx-btn--secondary{ background:transparent; color:var(--dx-ember); box-shadow:none; border-color:color-mix(in srgb,var(--dx-ember) 45%,transparent); }
141
+ .dx-btn--secondary:hover{ background:color-mix(in srgb,var(--dx-ember) 9%,transparent); filter:none; box-shadow:none; }
142
+ .dx-btn__mark{ flex-shrink:0; }
143
+ .dx-btn__spin{ width:15px; height:15px; flex-shrink:0; border-radius:50%;
144
+ border:2px solid color-mix(in srgb,currentColor 30%,transparent); border-top-color:currentColor;
145
+ animation:dx-spin .7s linear infinite; }
146
+ .dx-btn__doing{ animation:dx-pulse 1.4s ease-in-out infinite; }
147
+ .dx-chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; font:inherit;
148
+ font-variant-numeric:tabular-nums; border-radius:var(--dx-radius,0);
149
+ border:1px solid color-mix(in srgb,var(--dx-ember,#f26c18) 35%,transparent); }
150
+ .dx-chip__dot{ width:7px; height:7px; border-radius:50%; background:var(--dx-ember,#f26c18); }
151
+ .dx-chip__bal{ font-weight:600; opacity:.85; }
152
+ .dx-chip__x{ margin-left:2px; border:none; background:transparent; color:inherit; cursor:pointer; font-size:16px; line-height:1; opacity:.6; }
153
+ .dx-chip__x:hover{ opacity:1; }
154
+ `;
155
+ function ensureStyles() {
156
+ if (typeof document === "undefined") return;
157
+ if (document.getElementById(STYLE_ID)) return;
158
+ const el = document.createElement("style");
159
+ el.id = STYLE_ID;
160
+ el.textContent = BUTTON_CSS;
161
+ document.head.appendChild(el);
162
+ }
163
+ ensureStyles();
164
+ function cx(...parts) {
165
+ return parts.filter(Boolean).join(" ");
166
+ }
120
167
  function shortAddress(addr) {
121
168
  return addr.length > 10 ? `${addr.slice(0, 4)}\u2026${addr.slice(-4)}` : addr;
122
169
  }
@@ -127,12 +174,12 @@ function DexterMark() {
127
174
  return /* @__PURE__ */ jsxs(
128
175
  "svg",
129
176
  {
177
+ className: "dx-btn__mark",
130
178
  width: "18",
131
179
  height: "18",
132
180
  viewBox: "0 0 300 300",
133
181
  fill: "currentColor",
134
182
  "aria-hidden": "true",
135
- style: { flexShrink: 0 },
136
183
  children: [
137
184
  /* @__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
185
  /* @__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" }),
@@ -146,10 +193,12 @@ function SignInWithDexter(props) {
146
193
  onSuccess,
147
194
  onError,
148
195
  label = "Sign in with Dexter",
196
+ variant = "primary",
149
197
  className,
150
198
  showConnectedChip = true,
151
199
  ...config
152
200
  } = props;
201
+ useEffect2(ensureStyles, []);
153
202
  const c = useSignInWithDexter(config);
154
203
  const handleClick = async () => {
155
204
  try {
@@ -160,91 +209,44 @@ function SignInWithDexter(props) {
160
209
  };
161
210
  if (c.isVaultConnected) {
162
211
  if (!showConnectedChip) return null;
163
- return /* @__PURE__ */ jsxs("span", { className, style: CHIP, children: [
164
- /* @__PURE__ */ jsx("span", { style: DOT, "aria-hidden": true }),
212
+ return /* @__PURE__ */ jsxs("span", { className: cx("dx-chip", className), children: [
213
+ /* @__PURE__ */ jsx("span", { className: "dx-chip__dot", "aria-hidden": true }),
165
214
  /* @__PURE__ */ jsx("span", { children: c.vaultAddress ? shortAddress(c.vaultAddress) : "Connected" }),
166
- c.usdcBalance !== null && /* @__PURE__ */ jsxs("span", { style: BALANCE, children: [
215
+ c.usdcBalance !== null && /* @__PURE__ */ jsxs("span", { className: "dx-chip__bal", children: [
167
216
  formatUsd(c.usdcBalance),
168
217
  " available"
169
218
  ] }),
170
- /* @__PURE__ */ jsx("button", { type: "button", onClick: c.disconnect, style: DISCONNECT, "aria-label": "Disconnect", children: "\xD7" })
219
+ /* @__PURE__ */ jsx("button", { type: "button", className: "dx-chip__x", onClick: c.disconnect, "aria-label": "Disconnect", children: "\xD7" })
171
220
  ] });
172
221
  }
222
+ const pending = c.status === "pending";
173
223
  return /* @__PURE__ */ jsx(
174
224
  "button",
175
225
  {
176
226
  type: "button",
177
- className,
227
+ className: cx("dx-btn", variant === "secondary" && "dx-btn--secondary", className),
178
228
  onClick: handleClick,
179
- disabled: c.status === "pending",
180
- style: BUTTON,
181
- children: c.status === "pending" ? "Signing in\u2026" : /* @__PURE__ */ jsxs(Fragment, { children: [
229
+ disabled: pending,
230
+ "aria-busy": pending,
231
+ children: pending ? /* @__PURE__ */ jsxs(Fragment, { children: [
232
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__spin", "aria-hidden": true }),
233
+ /* @__PURE__ */ jsx("span", { className: "dx-btn__doing", children: "Connecting\u2026" })
234
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
182
235
  /* @__PURE__ */ jsx(DexterMark, {}),
183
236
  label
184
237
  ] })
185
238
  }
186
239
  );
187
240
  }
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
241
 
240
242
  // src/useDexterWallet.ts
241
- import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
243
+ import { useCallback as useCallback2, useEffect as useEffect3, useState as useState2 } from "react";
242
244
  var NO_SUPPORT = { rename: false, prune: false, syncAccepted: false };
243
245
  function useDexterWallet() {
244
246
  const [activeHandle, setHandle] = useState2(() => getActiveHandle());
245
247
  const [wallets, setWallets] = useState2(() => listWallets());
246
248
  const [support, setSupport] = useState2(NO_SUPPORT);
247
- useEffect2(() => {
249
+ useEffect3(() => {
248
250
  const sync = () => {
249
251
  setHandle(getActiveHandle());
250
252
  setWallets(listWallets());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/connect",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Sign in with Dexter — passkey connector. Composes @dexterai/vault.",
5
5
  "type": "module",
6
6
  "exports": {