@orangecheck/auth-client 0.3.0 → 0.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/dist/index.d.mts CHANGED
@@ -33,6 +33,15 @@ declare function OcSessionProvider({ children, config, defaultReturnTo, }: OcSes
33
33
  declare function useOcSession(): OcSessionState;
34
34
  declare function useOptionalOcSession(): OcSessionState | null;
35
35
 
36
+ interface OcAccountChipProps {
37
+ dashboardUrl?: string;
38
+ signInLabel?: string;
39
+ className?: string;
40
+ triggerClassName?: string;
41
+ popoverClassName?: string;
42
+ menuItemClassName?: string;
43
+ }
44
+ declare function OcAccountChip({ dashboardUrl, signInLabel, className, triggerClassName, popoverClassName, menuItemClassName, }: OcAccountChipProps): React.ReactElement | null;
36
45
  interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
37
46
  label?: string;
38
47
  eager?: boolean;
@@ -79,4 +88,4 @@ interface UseOcAddressSuggestionReturn {
79
88
  declare function useOcAddressSuggestion(options: UseOcAddressSuggestionOptions): UseOcAddressSuggestionReturn;
80
89
  declare const OcAddressInput: React.ForwardRefExoticComponent<OcAddressInputProps & React.RefAttributes<HTMLInputElement>>;
81
90
 
82
- export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
91
+ export { DEFAULT_CONFIG, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
package/dist/index.d.ts CHANGED
@@ -33,6 +33,15 @@ declare function OcSessionProvider({ children, config, defaultReturnTo, }: OcSes
33
33
  declare function useOcSession(): OcSessionState;
34
34
  declare function useOptionalOcSession(): OcSessionState | null;
35
35
 
36
+ interface OcAccountChipProps {
37
+ dashboardUrl?: string;
38
+ signInLabel?: string;
39
+ className?: string;
40
+ triggerClassName?: string;
41
+ popoverClassName?: string;
42
+ menuItemClassName?: string;
43
+ }
44
+ declare function OcAccountChip({ dashboardUrl, signInLabel, className, triggerClassName, popoverClassName, menuItemClassName, }: OcAccountChipProps): React.ReactElement | null;
36
45
  interface OcSignInButtonProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
37
46
  label?: string;
38
47
  eager?: boolean;
@@ -79,4 +88,4 @@ interface UseOcAddressSuggestionReturn {
79
88
  declare function useOcAddressSuggestion(options: UseOcAddressSuggestionOptions): UseOcAddressSuggestionReturn;
80
89
  declare const OcAddressInput: React.ForwardRefExoticComponent<OcAddressInputProps & React.RefAttributes<HTMLInputElement>>;
81
90
 
82
- export { DEFAULT_CONFIG, type OcAccount, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
91
+ export { DEFAULT_CONFIG, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignInButton, type OcSignInButtonProps, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React = require('react');
3
+ var React2 = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
6
  function _interopNamespace(e) {
@@ -21,7 +21,7 @@ function _interopNamespace(e) {
21
21
  return Object.freeze(n);
22
22
  }
23
23
 
24
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
24
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
25
25
 
26
26
  // src/provider.tsx
27
27
 
@@ -42,7 +42,7 @@ function buildSignInUrl(cfg, returnTo) {
42
42
  u.searchParams.set("return_to", returnTo);
43
43
  return u.toString();
44
44
  }
45
- var SessionContext = React__namespace.createContext(null);
45
+ var SessionContext = React2__namespace.createContext(null);
46
46
  function normalizeAccount(raw) {
47
47
  if (!raw) return null;
48
48
  const address = raw.btc_address ?? raw.address;
@@ -60,11 +60,11 @@ function OcSessionProvider({
60
60
  config,
61
61
  defaultReturnTo
62
62
  }) {
63
- const cfg = React__namespace.useMemo(() => resolveConfig(config), [config]);
64
- const [account, setAccount] = React__namespace.useState(null);
65
- const [status, setStatus] = React__namespace.useState("loading");
66
- const [error, setError] = React__namespace.useState(null);
67
- const refresh = React__namespace.useCallback(async () => {
63
+ const cfg = React2__namespace.useMemo(() => resolveConfig(config), [config]);
64
+ const [account, setAccount] = React2__namespace.useState(null);
65
+ const [status, setStatus] = React2__namespace.useState("loading");
66
+ const [error, setError] = React2__namespace.useState(null);
67
+ const refresh = React2__namespace.useCallback(async () => {
68
68
  if (typeof window === "undefined") return;
69
69
  try {
70
70
  const res = await fetch(cfg.mePath, {
@@ -93,10 +93,10 @@ function OcSessionProvider({
93
93
  setError(err instanceof Error ? err : new Error(String(err)));
94
94
  }
95
95
  }, [cfg.mePath]);
96
- React__namespace.useEffect(() => {
96
+ React2__namespace.useEffect(() => {
97
97
  void refresh();
98
98
  }, [refresh]);
99
- const signOut = React__namespace.useCallback(async () => {
99
+ const signOut = React2__namespace.useCallback(async () => {
100
100
  try {
101
101
  await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {
102
102
  method: "POST",
@@ -107,7 +107,7 @@ function OcSessionProvider({
107
107
  setAccount(null);
108
108
  setStatus("anonymous");
109
109
  }, [cfg.authOrigin, cfg.logoutPath]);
110
- const value = React__namespace.useMemo(() => {
110
+ const value = React2__namespace.useMemo(() => {
111
111
  const returnTo = defaultReturnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
112
112
  return {
113
113
  status,
@@ -121,7 +121,7 @@ function OcSessionProvider({
121
121
  return /* @__PURE__ */ jsxRuntime.jsx(SessionContext.Provider, { value, children });
122
122
  }
123
123
  function useOcSession() {
124
- const ctx = React__namespace.useContext(SessionContext);
124
+ const ctx = React2__namespace.useContext(SessionContext);
125
125
  if (!ctx) {
126
126
  throw new Error(
127
127
  "[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>"
@@ -130,7 +130,7 @@ function useOcSession() {
130
130
  return ctx;
131
131
  }
132
132
  function useOptionalOcSession() {
133
- return React__namespace.useContext(SessionContext);
133
+ return React2__namespace.useContext(SessionContext);
134
134
  }
135
135
  function shortenAddress(addr) {
136
136
  if (addr.length <= 12) return addr;
@@ -145,9 +145,243 @@ function isPrefixOf(value, target) {
145
145
  }
146
146
  var listboxIdCounter = 0;
147
147
  function useUniqueId(prefix) {
148
- const [id] = React__namespace.useState(() => `${prefix}-${++listboxIdCounter}`);
148
+ const [id] = React2__namespace.useState(() => `${prefix}-${++listboxIdCounter}`);
149
149
  return id;
150
150
  }
151
+ function OcAccountChip({
152
+ dashboardUrl = "https://ochk.io/dashboard",
153
+ signInLabel = "sign in",
154
+ className,
155
+ triggerClassName,
156
+ popoverClassName,
157
+ menuItemClassName
158
+ }) {
159
+ const { status, account, signInUrl, signOut } = useOcSession();
160
+ const [open, setOpen] = React2__namespace.useState(false);
161
+ const wrapRef = React2__namespace.useRef(null);
162
+ React2__namespace.useEffect(() => {
163
+ if (!open) return;
164
+ function handleClickOutside(e) {
165
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) {
166
+ setOpen(false);
167
+ }
168
+ }
169
+ function handleEscape(e) {
170
+ if (e.key === "Escape") setOpen(false);
171
+ }
172
+ document.addEventListener("mousedown", handleClickOutside);
173
+ document.addEventListener("keydown", handleEscape);
174
+ return () => {
175
+ document.removeEventListener("mousedown", handleClickOutside);
176
+ document.removeEventListener("keydown", handleEscape);
177
+ };
178
+ }, [open]);
179
+ if (status === "loading") return null;
180
+ if (status !== "authenticated" || !account) {
181
+ return /* @__PURE__ */ jsxRuntime.jsx(
182
+ "a",
183
+ {
184
+ href: signInUrl,
185
+ className: triggerClassName ?? className,
186
+ "data-oc-account-chip-signin": "",
187
+ children: signInLabel
188
+ }
189
+ );
190
+ }
191
+ return /* @__PURE__ */ jsxRuntime.jsxs(
192
+ "div",
193
+ {
194
+ ref: wrapRef,
195
+ className,
196
+ "data-oc-account-chip": "",
197
+ style: { position: "relative", display: "inline-block" },
198
+ children: [
199
+ /* @__PURE__ */ jsxRuntime.jsxs(
200
+ "button",
201
+ {
202
+ type: "button",
203
+ onClick: () => setOpen((v) => !v),
204
+ "aria-haspopup": "menu",
205
+ "aria-expanded": open,
206
+ "aria-label": `Signed in as ${account.address}. Open account menu.`,
207
+ className: triggerClassName,
208
+ "data-oc-account-chip-trigger": "",
209
+ style: triggerClassName ? void 0 : {
210
+ display: "inline-flex",
211
+ alignItems: "center",
212
+ gap: "0.4rem",
213
+ padding: "0.25rem 0.625rem",
214
+ borderRadius: "9999px",
215
+ border: "1px solid #27272a",
216
+ background: "rgba(39, 39, 42, 0.4)",
217
+ color: "#fafafa",
218
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
219
+ fontSize: 12,
220
+ cursor: "pointer"
221
+ },
222
+ children: [
223
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: "#22c55e", fontSize: 8 }, children: "\u25CF" }),
224
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: shortenAddress(account.address) }),
225
+ /* @__PURE__ */ jsxRuntime.jsx(
226
+ "svg",
227
+ {
228
+ width: "9",
229
+ height: "9",
230
+ viewBox: "0 0 10 10",
231
+ "aria-hidden": "true",
232
+ style: {
233
+ transition: "transform 120ms",
234
+ transform: open ? "rotate(180deg)" : "rotate(0)",
235
+ opacity: 0.6
236
+ },
237
+ children: /* @__PURE__ */ jsxRuntime.jsx(
238
+ "path",
239
+ {
240
+ d: "M2 4 L5 7 L8 4",
241
+ stroke: "currentColor",
242
+ strokeWidth: "1.5",
243
+ fill: "none",
244
+ strokeLinecap: "round"
245
+ }
246
+ )
247
+ }
248
+ )
249
+ ]
250
+ }
251
+ ),
252
+ open && /* @__PURE__ */ jsxRuntime.jsxs(
253
+ "div",
254
+ {
255
+ role: "menu",
256
+ "aria-label": "Account menu",
257
+ className: popoverClassName,
258
+ "data-oc-account-chip-popover": "",
259
+ style: popoverClassName ? { position: "absolute", zIndex: 50, top: "calc(100% + 6px)", right: 0 } : {
260
+ position: "absolute",
261
+ zIndex: 50,
262
+ top: "calc(100% + 6px)",
263
+ right: 0,
264
+ minWidth: 240,
265
+ background: "#0a0a0a",
266
+ border: "1px solid #27272a",
267
+ boxShadow: "0 10px 32px -4px rgba(0,0,0,0.6)",
268
+ fontFamily: "ui-monospace, SFMono-Regular, monospace"
269
+ },
270
+ children: [
271
+ /* @__PURE__ */ jsxRuntime.jsxs(
272
+ "div",
273
+ {
274
+ "data-oc-account-chip-header": "",
275
+ style: { padding: "0.75rem 0.75rem 0.625rem", borderBottom: "1px solid #27272a" },
276
+ children: [
277
+ /* @__PURE__ */ jsxRuntime.jsx(
278
+ "div",
279
+ {
280
+ "data-oc-account-chip-label": "",
281
+ style: {
282
+ color: "#f97316",
283
+ fontSize: 10,
284
+ letterSpacing: "0.18em",
285
+ textTransform: "uppercase",
286
+ marginBottom: 4
287
+ },
288
+ children: "\xA7 signed in"
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsxRuntime.jsx(
292
+ "div",
293
+ {
294
+ "data-oc-account-chip-address": "",
295
+ style: {
296
+ color: "#fafafa",
297
+ fontSize: 11,
298
+ wordBreak: "break-all",
299
+ lineHeight: 1.35
300
+ },
301
+ children: account.address
302
+ }
303
+ ),
304
+ account.displayName ? /* @__PURE__ */ jsxRuntime.jsx(
305
+ "div",
306
+ {
307
+ style: {
308
+ color: "#a1a1aa",
309
+ fontSize: 10,
310
+ marginTop: 4,
311
+ letterSpacing: "0.06em"
312
+ },
313
+ children: account.displayName
314
+ }
315
+ ) : null
316
+ ]
317
+ }
318
+ ),
319
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", style: { padding: "0.25rem" }, children: [
320
+ dashboardUrl ? /* @__PURE__ */ jsxRuntime.jsxs(
321
+ "a",
322
+ {
323
+ role: "menuitem",
324
+ href: dashboardUrl,
325
+ onClick: () => setOpen(false),
326
+ className: menuItemClassName,
327
+ "data-oc-account-chip-item": "",
328
+ style: menuItemClassName ? void 0 : {
329
+ display: "flex",
330
+ alignItems: "center",
331
+ gap: "0.5rem",
332
+ padding: "0.5rem 0.625rem",
333
+ fontSize: 12,
334
+ color: "#fafafa",
335
+ textDecoration: "none",
336
+ cursor: "pointer"
337
+ },
338
+ children: [
339
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: "#a1a1aa" }, children: "\u2192" }),
340
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: "dashboard" }),
341
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#a1a1aa", fontSize: 10 }, children: "\u2197" })
342
+ ]
343
+ }
344
+ ) : null,
345
+ /* @__PURE__ */ jsxRuntime.jsxs(
346
+ "button",
347
+ {
348
+ type: "button",
349
+ role: "menuitem",
350
+ onClick: () => {
351
+ setOpen(false);
352
+ void signOut();
353
+ },
354
+ className: menuItemClassName,
355
+ "data-oc-account-chip-item": "",
356
+ "data-oc-account-chip-signout": "",
357
+ style: menuItemClassName ? void 0 : {
358
+ display: "flex",
359
+ alignItems: "center",
360
+ gap: "0.5rem",
361
+ width: "100%",
362
+ padding: "0.5rem 0.625rem",
363
+ fontSize: 12,
364
+ color: "#fafafa",
365
+ background: "transparent",
366
+ border: 0,
367
+ fontFamily: "inherit",
368
+ textAlign: "left",
369
+ cursor: "pointer"
370
+ },
371
+ children: [
372
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { color: "#a1a1aa" }, children: "\u2192" }),
373
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: "sign out" })
374
+ ]
375
+ }
376
+ )
377
+ ] })
378
+ ]
379
+ }
380
+ )
381
+ ]
382
+ }
383
+ );
384
+ }
151
385
  function OcSignInButton({
152
386
  label = "sign in with bitcoin",
153
387
  eager = false,
@@ -219,9 +453,9 @@ function useOcAddressSuggestion(options) {
219
453
  } = options;
220
454
  const { status, account } = useOcSession();
221
455
  const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
222
- const [open, setOpen] = React__namespace.useState(false);
223
- const [highlighted, setHighlighted] = React__namespace.useState(false);
224
- const blurTimer = React__namespace.useRef(null);
456
+ const [open, setOpen] = React2__namespace.useState(false);
457
+ const [highlighted, setHighlighted] = React2__namespace.useState(false);
458
+ const blurTimer = React2__namespace.useRef(null);
225
459
  const listboxId = useUniqueId("oc-addr-listbox");
226
460
  const optionId = `${listboxId}-opt`;
227
461
  const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
@@ -233,7 +467,7 @@ function useOcAddressSuggestion(options) {
233
467
  setOpen(false);
234
468
  setHighlighted(false);
235
469
  }
236
- React__namespace.useEffect(() => {
470
+ React2__namespace.useEffect(() => {
237
471
  return () => {
238
472
  if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
239
473
  };
@@ -336,7 +570,7 @@ function useOcAddressSuggestion(options) {
336
570
  ) : null;
337
571
  return { inputProps, popover };
338
572
  }
339
- var OcAddressInput = React__namespace.forwardRef(
573
+ var OcAddressInput = React2__namespace.forwardRef(
340
574
  function OcAddressInput2({
341
575
  value,
342
576
  onValueChange,
@@ -351,15 +585,15 @@ var OcAddressInput = React__namespace.forwardRef(
351
585
  }, forwardedRef) {
352
586
  const { status, account } = useOcSession();
353
587
  const sessionAddress = status === "authenticated" ? account?.address ?? null : null;
354
- const [open, setOpen] = React__namespace.useState(false);
355
- const [highlighted, setHighlighted] = React__namespace.useState(false);
356
- const innerRef = React__namespace.useRef(null);
588
+ const [open, setOpen] = React2__namespace.useState(false);
589
+ const [highlighted, setHighlighted] = React2__namespace.useState(false);
590
+ const innerRef = React2__namespace.useRef(null);
357
591
  const setRef = (node) => {
358
592
  innerRef.current = node;
359
593
  if (typeof forwardedRef === "function") forwardedRef(node);
360
594
  else if (forwardedRef) forwardedRef.current = node;
361
595
  };
362
- const blurTimer = React__namespace.useRef(null);
596
+ const blurTimer = React2__namespace.useRef(null);
363
597
  const listboxId = useUniqueId("oc-addr-listbox");
364
598
  const optionId = `${listboxId}-opt`;
365
599
  const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
@@ -406,7 +640,7 @@ var OcAddressInput = React__namespace.forwardRef(
406
640
  }
407
641
  onKeyDown?.(e);
408
642
  }
409
- React__namespace.useEffect(() => {
643
+ React2__namespace.useEffect(() => {
410
644
  return () => {
411
645
  if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
412
646
  };
@@ -501,6 +735,7 @@ var OcAddressInput = React__namespace.forwardRef(
501
735
  );
502
736
 
503
737
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
738
+ exports.OcAccountChip = OcAccountChip;
504
739
  exports.OcAccountPill = OcAccountPill;
505
740
  exports.OcAddressInput = OcAddressInput;
506
741
  exports.OcSessionProvider = OcSessionProvider;