@bufinance/web3-signin 0.1.4 → 0.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bufinance/web3-signin",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Headless cross-app Web3 wallet sign-in for BUFI: EIP-6963 wallet discovery + Supabase signInWithWeb3 (EIP-4361) + Turnstile captcha. Shared by desk-v1 and defi-web-app. Source of truth lives here; both apps consume it.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -0,0 +1,134 @@
1
+ import { type CSSProperties, useState } from "react";
2
+
3
+ /**
4
+ * AssetCircles — overlapping token/asset icon circles that arc up and reveal a
5
+ * ticker tooltip on hover, with a "+N" overflow chip. Ported from desk-v1's
6
+ * `WalletTokenIcons` (the "which assets does this wallet hold" affordance) into
7
+ * the shared package so BOTH apps render assets the same way. This is the
8
+ * asset/token stack (icon + ticker tooltip) — NOT a people/profile stack.
9
+ *
10
+ * Dependency-light: inline styles only (no Tailwind purge risk, no framer/radix),
11
+ * so it drops into any consumer unchanged. The host supplies `assets`.
12
+ */
13
+ export interface AssetCircleItem {
14
+ /** Token icon URL. */
15
+ iconUrl: string;
16
+ /** Ticker shown in the tooltip + used as alt text (e.g. "USDC"). */
17
+ label: string;
18
+ }
19
+
20
+ export interface AssetCirclesProps {
21
+ assets: AssetCircleItem[];
22
+ /** Max circles before collapsing the rest into a "+N" chip (default 4). */
23
+ max?: number;
24
+ /** Circle diameter in px (default 18, tuned for a header pill). */
25
+ size?: number;
26
+ className?: string;
27
+ }
28
+
29
+ export function AssetCircles({
30
+ assets,
31
+ max = 4,
32
+ size = 18,
33
+ className,
34
+ }: AssetCirclesProps) {
35
+ const [hover, setHover] = useState<number | null>(null);
36
+ if (assets.length === 0) return null;
37
+
38
+ const shown = assets.slice(0, max);
39
+ const overflow = assets.length - shown.length;
40
+ const overlap = Math.round(size / 3);
41
+ const lift = Math.max(5, Math.round(size * 0.4));
42
+
43
+ return (
44
+ <div
45
+ className={className}
46
+ style={{ display: "inline-flex", alignItems: "center" }}
47
+ data-bufi-asset-circles
48
+ >
49
+ {shown.map((a, i) => {
50
+ const h = hover === i;
51
+ return (
52
+ <span
53
+ key={`${a.label}:${i}`}
54
+ onMouseEnter={() => setHover(i)}
55
+ onMouseLeave={() => setHover((p) => (p === i ? null : p))}
56
+ style={{
57
+ position: "relative",
58
+ marginLeft: i === 0 ? 0 : -overlap,
59
+ zIndex: h ? 50 : shown.length - i,
60
+ transform: h ? `translateY(-${lift}px) scale(1.2)` : "none",
61
+ transition: "transform 160ms cubic-bezier(0.23, 1, 0.32, 1)",
62
+ display: "inline-flex",
63
+ }}
64
+ >
65
+ {/* Ticker tooltip — sits just above the circle. */}
66
+ {h && <span style={tooltipStyle}>{a.label}</span>}
67
+ <span
68
+ style={{
69
+ width: size,
70
+ height: size,
71
+ borderRadius: "9999px",
72
+ overflow: "hidden",
73
+ display: "inline-flex",
74
+ alignItems: "center",
75
+ justifyContent: "center",
76
+ background: "#fff",
77
+ boxShadow: "0 0 0 2px #fff",
78
+ }}
79
+ >
80
+ {/* eslint-disable-next-line @next/next/no-img-element */}
81
+ <img
82
+ src={a.iconUrl}
83
+ alt={a.label}
84
+ width={size}
85
+ height={size}
86
+ style={{ width: size, height: size, objectFit: "cover", display: "block" }}
87
+ />
88
+ </span>
89
+ </span>
90
+ );
91
+ })}
92
+
93
+ {overflow > 0 && (
94
+ <span
95
+ style={{
96
+ width: size,
97
+ height: size,
98
+ marginLeft: -overlap,
99
+ borderRadius: "9999px",
100
+ display: "grid",
101
+ placeItems: "center",
102
+ background: "#F4F4F4",
103
+ boxShadow: "0 0 0 2px #fff",
104
+ fontSize: Math.max(9, Math.round(size * 0.5)),
105
+ fontWeight: 600,
106
+ color: "#6a55cf",
107
+ }}
108
+ >
109
+ +{overflow}
110
+ </span>
111
+ )}
112
+ </div>
113
+ );
114
+ }
115
+
116
+ const tooltipStyle: CSSProperties = {
117
+ position: "absolute",
118
+ bottom: "100%",
119
+ left: "50%",
120
+ transform: "translateX(-50%)",
121
+ marginBottom: 6,
122
+ whiteSpace: "nowrap",
123
+ padding: "2px 6px",
124
+ borderRadius: 6,
125
+ fontSize: 9,
126
+ fontWeight: 700,
127
+ background: "#6a55cf",
128
+ color: "#fff",
129
+ pointerEvents: "none",
130
+ zIndex: 60,
131
+ boxShadow: "0 2px 6px -2px rgba(0,0,0,0.3)",
132
+ };
133
+
134
+ export default AssetCircles;
@@ -11,3 +11,8 @@ export {
11
11
  type WalletDropdownProps,
12
12
  type WalletDropdownClassNames,
13
13
  } from "./wallet-dropdown";
14
+ export {
15
+ AssetCircles,
16
+ type AssetCircleItem,
17
+ type AssetCirclesProps,
18
+ } from "./avatar-circles";