@lumen-dapps-kit/web3 0.1.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,32 @@
1
+ // src/utils.ts
2
+ var truncateAddress = (address, { head = 4, tail = 4, sep = "\u2026" } = {}) => {
3
+ if (!address) return "";
4
+ const hasPrefix = address.startsWith("0x");
5
+ const prefix = hasPrefix ? "0x" : "";
6
+ const body = hasPrefix ? address.slice(2) : address;
7
+ if (body.length <= head + tail) return address;
8
+ return `${prefix}${body.slice(0, head)}${sep}${body.slice(-tail)}`;
9
+ };
10
+ var formatGwei = (wei, decimals = 2) => {
11
+ const n = typeof wei === "bigint" ? Number(wei) : Number(wei);
12
+ const gwei = n / 1e9;
13
+ return gwei.toLocaleString("en-US", {
14
+ minimumFractionDigits: 0,
15
+ maximumFractionDigits: decimals
16
+ });
17
+ };
18
+ var formatUnits = (value, decimals, displayDecimals = 4) => {
19
+ const v = typeof value === "string" ? BigInt(value) : value;
20
+ const negative = v < 0n;
21
+ const abs = negative ? -v : v;
22
+ const base = 10n ** BigInt(decimals);
23
+ const whole = abs / base;
24
+ const frac = abs % base;
25
+ const fracStr = frac.toString().padStart(decimals, "0").slice(0, displayDecimals).replace(/0+$/, "");
26
+ const out = fracStr ? `${whole}.${fracStr}` : `${whole}`;
27
+ return negative ? `-${out}` : out;
28
+ };
29
+
30
+ export { formatGwei, formatUnits, truncateAddress };
31
+ //# sourceMappingURL=chunk-AMDZMZJO.js.map
32
+ //# sourceMappingURL=chunk-AMDZMZJO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"names":[],"mappings":";AAiBO,IAAM,eAAA,GAAkB,CAC7B,OAAA,EACA,EAAE,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,CAAA,EAAG,GAAA,GAAM,QAAA,EAAI,GAAyB,EAAC,KAC/C;AACX,EAAA,IAAI,CAAC,SAAS,OAAO,EAAA;AACrB,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA;AACzC,EAAA,MAAM,MAAA,GAAS,YAAY,IAAA,GAAO,EAAA;AAClC,EAAA,MAAM,IAAA,GAAO,SAAA,GAAY,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,OAAA;AAC5C,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,IAAA,GAAO,IAAA,EAAM,OAAO,OAAA;AACvC,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,EAAG,IAAI,CAAC,CAAA,EAAG,GAAG,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAC,IAAI,CAAC,CAAA,CAAA;AAClE;AAKO,IAAM,UAAA,GAAa,CACxB,GAAA,EACA,QAAA,GAAW,CAAA,KACA;AACX,EAAA,MAAM,CAAA,GAAI,OAAO,GAAA,KAAQ,QAAA,GAAW,OAAO,GAAG,CAAA,GAAI,OAAO,GAAG,CAAA;AAC5D,EAAA,MAAM,OAAO,CAAA,GAAI,GAAA;AACjB,EAAA,OAAO,IAAA,CAAK,eAAe,OAAA,EAAS;AAAA,IAClC,qBAAA,EAAuB,CAAA;AAAA,IACvB,qBAAA,EAAuB;AAAA,GACxB,CAAA;AACH;AAMO,IAAM,WAAA,GAAc,CACzB,KAAA,EACA,QAAA,EACA,kBAAkB,CAAA,KACP;AACX,EAAA,MAAM,IAAI,OAAO,KAAA,KAAU,QAAA,GAAW,MAAA,CAAO,KAAK,CAAA,GAAI,KAAA;AACtD,EAAA,MAAM,WAAW,CAAA,GAAI,EAAA;AACrB,EAAA,MAAM,GAAA,GAAM,QAAA,GAAW,CAAC,CAAA,GAAI,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,GAAA,IAAO,MAAA,CAAO,QAAQ,CAAA;AACnC,EAAA,MAAM,QAAQ,GAAA,GAAM,IAAA;AACpB,EAAA,MAAM,OAAO,GAAA,GAAM,IAAA;AACnB,EAAA,MAAM,OAAA,GAAU,IAAA,CACb,QAAA,EAAS,CACT,SAAS,QAAA,EAAU,GAAG,CAAA,CACtB,KAAA,CAAM,CAAA,EAAG,eAAe,CAAA,CACxB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACpB,EAAA,MAAM,GAAA,GAAM,UAAU,CAAA,EAAG,KAAK,IAAI,OAAO,CAAA,CAAA,GAAK,GAAG,KAAK,CAAA,CAAA;AACtD,EAAA,OAAO,QAAA,GAAW,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAChC","file":"chunk-AMDZMZJO.js","sourcesContent":["/**\n * Chain-agnostic formatting helpers. No wallet library required.\n */\n\nexport interface TruncateAddressOpts {\n /** Characters to show after the 0x prefix. */\n head?: number;\n /** Characters to show at the tail. */\n tail?: number;\n /** Separator. Defaults \"…\". */\n sep?: string;\n}\n\n/**\n * truncateAddress(\"0x7F3a2bC9...9C2e\") -> \"0x7F3a…9C2e\"\n * Works for EVM (0x-prefixed) and any other string-based addressing scheme.\n */\nexport const truncateAddress = (\n address: string,\n { head = 4, tail = 4, sep = '…' }: TruncateAddressOpts = {}\n): string => {\n if (!address) return '';\n const hasPrefix = address.startsWith('0x');\n const prefix = hasPrefix ? '0x' : '';\n const body = hasPrefix ? address.slice(2) : address;\n if (body.length <= head + tail) return address;\n return `${prefix}${body.slice(0, head)}${sep}${body.slice(-tail)}`;\n};\n\n/**\n * Format wei (bigint or string) as a gwei value with a fixed number of decimals.\n */\nexport const formatGwei = (\n wei: bigint | string | number,\n decimals = 2\n): string => {\n const n = typeof wei === 'bigint' ? Number(wei) : Number(wei);\n const gwei = n / 1e9;\n return gwei.toLocaleString('en-US', {\n minimumFractionDigits: 0,\n maximumFractionDigits: decimals,\n });\n};\n\n/**\n * Format a base-unit bigint as a human-readable token amount.\n * formatUnits(1500000000000000000n, 18) -> \"1.5\"\n */\nexport const formatUnits = (\n value: bigint | string,\n decimals: number,\n displayDecimals = 4\n): string => {\n const v = typeof value === 'string' ? BigInt(value) : value;\n const negative = v < 0n;\n const abs = negative ? -v : v;\n const base = 10n ** BigInt(decimals);\n const whole = abs / base;\n const frac = abs % base;\n const fracStr = frac\n .toString()\n .padStart(decimals, '0')\n .slice(0, displayDecimals)\n .replace(/0+$/, '');\n const out = fracStr ? `${whole}.${fracStr}` : `${whole}`;\n return negative ? `-${out}` : out;\n};\n\nexport type TxState =\n | 'idle'\n | 'preparing'\n | 'awaiting-signature'\n | 'pending'\n | 'confirmed'\n | 'failed'\n | 'rejected';\n\nexport interface ChainBrief {\n id: number | string;\n /** Short label, e.g. \"ETH\", \"BASE\", \"SOL\". */\n symbol: string;\n /** Full name, e.g. \"Ethereum Mainnet\". */\n name: string;\n /** Optional accent color (hex). */\n color?: string;\n /** True if this chain is a testnet. */\n testnet?: boolean;\n}\n"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,413 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var ui = require('@lumen-dapps-kit/ui');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/utils.ts
8
+ var truncateAddress = (address, { head = 4, tail = 4, sep = "\u2026" } = {}) => {
9
+ if (!address) return "";
10
+ const hasPrefix = address.startsWith("0x");
11
+ const prefix = hasPrefix ? "0x" : "";
12
+ const body = hasPrefix ? address.slice(2) : address;
13
+ if (body.length <= head + tail) return address;
14
+ return `${prefix}${body.slice(0, head)}${sep}${body.slice(-tail)}`;
15
+ };
16
+ var formatGwei = (wei, decimals = 2) => {
17
+ const n = typeof wei === "bigint" ? Number(wei) : Number(wei);
18
+ const gwei = n / 1e9;
19
+ return gwei.toLocaleString("en-US", {
20
+ minimumFractionDigits: 0,
21
+ maximumFractionDigits: decimals
22
+ });
23
+ };
24
+ var formatUnits = (value, decimals, displayDecimals = 4) => {
25
+ const v = typeof value === "string" ? BigInt(value) : value;
26
+ const negative = v < 0n;
27
+ const abs = negative ? -v : v;
28
+ const base = 10n ** BigInt(decimals);
29
+ const whole = abs / base;
30
+ const frac = abs % base;
31
+ const fracStr = frac.toString().padStart(decimals, "0").slice(0, displayDecimals).replace(/0+$/, "");
32
+ const out = fracStr ? `${whole}.${fracStr}` : `${whole}`;
33
+ return negative ? `-${out}` : out;
34
+ };
35
+ var AddressDisplay = ({
36
+ address,
37
+ name,
38
+ chainSymbol,
39
+ copyable = true,
40
+ variant = "pill",
41
+ head = 4,
42
+ tail = 4,
43
+ className
44
+ }) => {
45
+ const [copied, setCopied] = react.useState(false);
46
+ const handleCopy = react.useCallback(async () => {
47
+ if (!copyable || !address) return;
48
+ try {
49
+ await navigator.clipboard.writeText(address);
50
+ setCopied(true);
51
+ setTimeout(() => setCopied(false), 1200);
52
+ } catch {
53
+ }
54
+ }, [address, copyable]);
55
+ const label = name || truncateAddress(address, { head, tail });
56
+ if (variant === "inline") {
57
+ return /* @__PURE__ */ jsxRuntime.jsx(
58
+ "button",
59
+ {
60
+ type: "button",
61
+ onClick: handleCopy,
62
+ disabled: !copyable,
63
+ className: ui.cn(
64
+ "mono text-[11px] text-ink-900 hover:text-white transition-colors",
65
+ className
66
+ ),
67
+ title: address,
68
+ children: copied ? "COPIED" : label
69
+ }
70
+ );
71
+ }
72
+ return /* @__PURE__ */ jsxRuntime.jsxs(
73
+ "button",
74
+ {
75
+ type: "button",
76
+ onClick: handleCopy,
77
+ disabled: !copyable,
78
+ title: address,
79
+ className: ui.cn(
80
+ "flex items-center gap-2 px-3 h-8 hairline mono text-[11px] transition-colors",
81
+ copyable && "hover:bg-white/5",
82
+ className
83
+ ),
84
+ children: [
85
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 bg-white", "aria-hidden": "true" }),
86
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-900", children: copied ? "COPIED" : label }),
87
+ chainSymbol && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700", children: "\xB7" }),
89
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700", children: chainSymbol })
90
+ ] })
91
+ ]
92
+ }
93
+ );
94
+ };
95
+ var WalletPill = ({
96
+ address,
97
+ name,
98
+ chainSymbol,
99
+ onConnect,
100
+ onClick,
101
+ pending,
102
+ className
103
+ }) => {
104
+ const [copied, setCopied] = react.useState(false);
105
+ const handleCopy = react.useCallback(async () => {
106
+ if (!address) return;
107
+ try {
108
+ await navigator.clipboard.writeText(address);
109
+ setCopied(true);
110
+ setTimeout(() => setCopied(false), 1200);
111
+ } catch {
112
+ }
113
+ }, [address]);
114
+ if (!address) {
115
+ return /* @__PURE__ */ jsxRuntime.jsx(
116
+ ui.Button,
117
+ {
118
+ variant: "primary",
119
+ size: "sm",
120
+ onClick: onConnect,
121
+ disabled: pending,
122
+ className: ui.cn(className),
123
+ children: pending ? "CONNECTING\u2026" : "CONNECT WALLET"
124
+ }
125
+ );
126
+ }
127
+ const handleClick = onClick ?? handleCopy;
128
+ const label = copied ? "COPIED" : name || truncateAddress(address);
129
+ return /* @__PURE__ */ jsxRuntime.jsxs(
130
+ "button",
131
+ {
132
+ type: "button",
133
+ onClick: handleClick,
134
+ title: address,
135
+ className: ui.cn(
136
+ "flex items-center gap-2 px-3 h-8 hairline mono text-[11px] hover:bg-white/5 transition-colors",
137
+ className
138
+ ),
139
+ children: [
140
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 bg-white", "aria-hidden": "true" }),
141
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-900", children: label }),
142
+ chainSymbol && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
143
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700", children: "\xB7" }),
144
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700", children: chainSymbol })
145
+ ] })
146
+ ]
147
+ }
148
+ );
149
+ };
150
+ var TONE = {
151
+ online: { dot: "ok", txt: "NET ONLINE" },
152
+ degraded: { dot: "warn", txt: "NET DEGRADED" },
153
+ offline: { dot: "err", txt: "NET OFFLINE" }
154
+ };
155
+ var NetworkStatus = ({
156
+ state = "online",
157
+ latencyMs,
158
+ label,
159
+ className
160
+ }) => {
161
+ const tone = TONE[state];
162
+ return /* @__PURE__ */ jsxRuntime.jsxs(
163
+ "div",
164
+ {
165
+ className: ui.cn(
166
+ "flex items-center gap-2 px-3 h-8 hairline mono text-[11px] text-ink-800",
167
+ className
168
+ ),
169
+ children: [
170
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PulseDot, { tone: tone.dot }),
171
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label ?? tone.txt }),
172
+ typeof latencyMs === "number" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
173
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-600", children: "\xB7" }),
174
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ink-700", children: [
175
+ Math.round(latencyMs),
176
+ "ms"
177
+ ] })
178
+ ] })
179
+ ]
180
+ }
181
+ );
182
+ };
183
+ var ChainSelector = ({
184
+ chains,
185
+ value,
186
+ onChange,
187
+ className
188
+ }) => {
189
+ const [open, setOpen] = react.useState(false);
190
+ const active = chains.find((c) => c.id === value) ?? chains[0];
191
+ if (!active) return null;
192
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("relative", className), children: [
193
+ /* @__PURE__ */ jsxRuntime.jsxs(
194
+ "button",
195
+ {
196
+ type: "button",
197
+ onClick: () => setOpen((o) => !o),
198
+ "aria-haspopup": "listbox",
199
+ "aria-expanded": open,
200
+ className: "flex items-center gap-2 px-3 h-8 hairline mono text-[11px] hover:bg-white/5",
201
+ children: [
202
+ /* @__PURE__ */ jsxRuntime.jsx(
203
+ "span",
204
+ {
205
+ className: "w-1.5 h-1.5",
206
+ style: { backgroundColor: active.color ?? "#ffffff" },
207
+ "aria-hidden": "true"
208
+ }
209
+ ),
210
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-900", children: active.symbol }),
211
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700", children: "\xB7" }),
212
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700 text-[10.5px]", children: active.name }),
213
+ active.testnet && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-signal-warn ml-1", children: "TESTNET" })
214
+ ]
215
+ }
216
+ ),
217
+ open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
218
+ /* @__PURE__ */ jsxRuntime.jsx(
219
+ "div",
220
+ {
221
+ className: "fixed inset-0 z-40",
222
+ onClick: () => setOpen(false),
223
+ "aria-hidden": "true"
224
+ }
225
+ ),
226
+ /* @__PURE__ */ jsxRuntime.jsx(
227
+ "div",
228
+ {
229
+ role: "listbox",
230
+ className: "absolute right-0 mt-1 min-w-[240px] glass z-50 p-1",
231
+ children: chains.map((c) => {
232
+ const selected = c.id === value;
233
+ return /* @__PURE__ */ jsxRuntime.jsxs(
234
+ "button",
235
+ {
236
+ role: "option",
237
+ "aria-selected": selected,
238
+ type: "button",
239
+ onClick: () => {
240
+ onChange?.(c.id);
241
+ setOpen(false);
242
+ },
243
+ className: ui.cn(
244
+ "w-full flex items-center gap-2 px-3 h-8 mono text-[11px] text-left transition-colors",
245
+ selected ? "bg-white text-black" : "text-ink-800 hover:bg-white/5"
246
+ ),
247
+ children: [
248
+ /* @__PURE__ */ jsxRuntime.jsx(
249
+ "span",
250
+ {
251
+ className: "w-1.5 h-1.5",
252
+ style: { backgroundColor: c.color ?? "#ffffff" },
253
+ "aria-hidden": "true"
254
+ }
255
+ ),
256
+ /* @__PURE__ */ jsxRuntime.jsx(
257
+ "span",
258
+ {
259
+ className: ui.cn(
260
+ "font-medium",
261
+ selected ? "text-black" : "text-ink-900"
262
+ ),
263
+ children: c.symbol
264
+ }
265
+ ),
266
+ /* @__PURE__ */ jsxRuntime.jsxs(
267
+ "span",
268
+ {
269
+ className: ui.cn(
270
+ selected ? "text-black/60" : "text-ink-700"
271
+ ),
272
+ children: [
273
+ "\xB7 ",
274
+ c.name
275
+ ]
276
+ }
277
+ ),
278
+ c.testnet && /* @__PURE__ */ jsxRuntime.jsx(
279
+ "span",
280
+ {
281
+ className: ui.cn(
282
+ "ml-auto",
283
+ selected ? "text-black" : "text-signal-warn"
284
+ ),
285
+ children: "TESTNET"
286
+ }
287
+ )
288
+ ]
289
+ },
290
+ c.id
291
+ );
292
+ })
293
+ }
294
+ )
295
+ ] })
296
+ ] });
297
+ };
298
+ var GasIndicator = ({
299
+ value,
300
+ unit = "wei",
301
+ thresholds = { warn: 40, err: 100 },
302
+ label = "GAS",
303
+ className
304
+ }) => {
305
+ const gwei = unit === "gwei" ? Number(value) : Number(typeof value === "bigint" ? value : BigInt(value)) / 1e9;
306
+ const tone = gwei >= thresholds.err ? "text-signal-err" : gwei >= thresholds.warn ? "text-signal-warn" : "text-signal-ok";
307
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ui.cn("mono text-[10.5px] tracking-wider", className), children: [
308
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-800", children: label }),
309
+ " ",
310
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ui.cn("tabular-nums", tone), children: [
311
+ formatGwei(value),
312
+ " gwei"
313
+ ] })
314
+ ] });
315
+ };
316
+ var COPY = {
317
+ idle: { title: "IDLE", tone: "muted", live: false },
318
+ preparing: { title: "PREPARING", tone: "data", live: true },
319
+ "awaiting-signature": { title: "AWAITING SIGNATURE", tone: "warn", live: true },
320
+ pending: { title: "PENDING", tone: "data", live: true },
321
+ confirmed: { title: "CONFIRMED", tone: "ok", live: false },
322
+ failed: { title: "FAILED", tone: "err", live: false },
323
+ rejected: { title: "REJECTED", tone: "err", live: false }
324
+ };
325
+ var TxStatus = ({
326
+ state,
327
+ hash,
328
+ explorerUrl,
329
+ title,
330
+ confirmations,
331
+ requiredConfirmations,
332
+ className
333
+ }) => {
334
+ const copy = COPY[state];
335
+ const label = title ?? copy.title;
336
+ const link = hash && explorerUrl ? `${explorerUrl.replace(/\/$/, "")}/tx/${hash}` : void 0;
337
+ return /* @__PURE__ */ jsxRuntime.jsxs(
338
+ "div",
339
+ {
340
+ className: ui.cn(
341
+ "flex items-center justify-between hairline px-3 py-2.5",
342
+ className
343
+ ),
344
+ children: [
345
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
346
+ copy.live ? /* @__PURE__ */ jsxRuntime.jsx(ui.PulseDot, { tone: copy.tone === "muted" ? "data" : copy.tone }) : /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { tone: copy.tone, dot: true, children: "" }),
347
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mono text-[11px] text-ink-900", children: label })
348
+ ] }),
349
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mono text-[10.5px] text-ink-700", children: [
350
+ typeof confirmations === "number" && typeof requiredConfirmations === "number" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
351
+ confirmations,
352
+ "/",
353
+ requiredConfirmations,
354
+ " CONF"
355
+ ] }),
356
+ hash && (link ? /* @__PURE__ */ jsxRuntime.jsx(
357
+ "a",
358
+ {
359
+ href: link,
360
+ target: "_blank",
361
+ rel: "noreferrer",
362
+ className: "text-ink-800 hover:text-white underline-offset-2 hover:underline",
363
+ children: truncateAddress(hash, { head: 6, tail: 4 })
364
+ }
365
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-800", children: truncateAddress(hash, { head: 6, tail: 4 }) }))
366
+ ] })
367
+ ]
368
+ }
369
+ );
370
+ };
371
+ var SIZE = {
372
+ sm: "text-[14px]",
373
+ md: "text-[18px]",
374
+ lg: "text-[24px]",
375
+ xl: "text-[40px]"
376
+ };
377
+ var AmountDisplay = ({
378
+ value,
379
+ decimals,
380
+ symbol,
381
+ displayDecimals = 4,
382
+ size = "md",
383
+ usd,
384
+ className
385
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("leading-none", className), children: [
386
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1", children: [
387
+ /* @__PURE__ */ jsxRuntime.jsx(
388
+ "span",
389
+ {
390
+ className: ui.cn("font-semibold tabular-nums tracking-tight", SIZE[size]),
391
+ children: formatUnits(value, decimals, displayDecimals)
392
+ }
393
+ ),
394
+ symbol && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-700 text-[11px]", children: symbol })
395
+ ] }),
396
+ typeof usd === "number" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mono text-[10.5px] text-ink-700 mt-1 tabular-nums", children: [
397
+ "$",
398
+ usd.toLocaleString("en-US", { maximumFractionDigits: 2 })
399
+ ] })
400
+ ] });
401
+
402
+ exports.AddressDisplay = AddressDisplay;
403
+ exports.AmountDisplay = AmountDisplay;
404
+ exports.ChainSelector = ChainSelector;
405
+ exports.GasIndicator = GasIndicator;
406
+ exports.NetworkStatus = NetworkStatus;
407
+ exports.TxStatus = TxStatus;
408
+ exports.WalletPill = WalletPill;
409
+ exports.formatGwei = formatGwei;
410
+ exports.formatUnits = formatUnits;
411
+ exports.truncateAddress = truncateAddress;
412
+ //# sourceMappingURL=index.cjs.map
413
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts","../src/components/AddressDisplay.tsx","../src/components/WalletPill.tsx","../src/components/NetworkStatus.tsx","../src/components/ChainSelector.tsx","../src/components/GasIndicator.tsx","../src/components/TxStatus.tsx","../src/components/AmountDisplay.tsx"],"names":["useState","useCallback","jsx","cn","jsxs","Fragment","Button","PulseDot","StatusBadge"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Chain-agnostic formatting helpers. No wallet library required.\n */\n\nexport interface TruncateAddressOpts {\n /** Characters to show after the 0x prefix. */\n head?: number;\n /** Characters to show at the tail. */\n tail?: number;\n /** Separator. Defaults \"…\". */\n sep?: string;\n}\n\n/**\n * truncateAddress(\"0x7F3a2bC9...9C2e\") -> \"0x7F3a…9C2e\"\n * Works for EVM (0x-prefixed) and any other string-based addressing scheme.\n */\nexport const truncateAddress = (\n address: string,\n { head = 4, tail = 4, sep = '…' }: TruncateAddressOpts = {}\n): string => {\n if (!address) return '';\n const hasPrefix = address.startsWith('0x');\n const prefix = hasPrefix ? '0x' : '';\n const body = hasPrefix ? address.slice(2) : address;\n if (body.length <= head + tail) return address;\n return `${prefix}${body.slice(0, head)}${sep}${body.slice(-tail)}`;\n};\n\n/**\n * Format wei (bigint or string) as a gwei value with a fixed number of decimals.\n */\nexport const formatGwei = (\n wei: bigint | string | number,\n decimals = 2\n): string => {\n const n = typeof wei === 'bigint' ? Number(wei) : Number(wei);\n const gwei = n / 1e9;\n return gwei.toLocaleString('en-US', {\n minimumFractionDigits: 0,\n maximumFractionDigits: decimals,\n });\n};\n\n/**\n * Format a base-unit bigint as a human-readable token amount.\n * formatUnits(1500000000000000000n, 18) -> \"1.5\"\n */\nexport const formatUnits = (\n value: bigint | string,\n decimals: number,\n displayDecimals = 4\n): string => {\n const v = typeof value === 'string' ? BigInt(value) : value;\n const negative = v < 0n;\n const abs = negative ? -v : v;\n const base = 10n ** BigInt(decimals);\n const whole = abs / base;\n const frac = abs % base;\n const fracStr = frac\n .toString()\n .padStart(decimals, '0')\n .slice(0, displayDecimals)\n .replace(/0+$/, '');\n const out = fracStr ? `${whole}.${fracStr}` : `${whole}`;\n return negative ? `-${out}` : out;\n};\n\nexport type TxState =\n | 'idle'\n | 'preparing'\n | 'awaiting-signature'\n | 'pending'\n | 'confirmed'\n | 'failed'\n | 'rejected';\n\nexport interface ChainBrief {\n id: number | string;\n /** Short label, e.g. \"ETH\", \"BASE\", \"SOL\". */\n symbol: string;\n /** Full name, e.g. \"Ethereum Mainnet\". */\n name: string;\n /** Optional accent color (hex). */\n color?: string;\n /** True if this chain is a testnet. */\n testnet?: boolean;\n}\n","'use client';\n\nimport { useCallback, useState } from 'react';\nimport { cn } from '@lumen-dapps-kit/ui';\nimport { truncateAddress } from '../utils';\n\nexport interface AddressDisplayProps {\n /** Raw address. */\n address: string;\n /** Optional ENS / display name override. */\n name?: string;\n /** Show a small chain symbol after the address. */\n chainSymbol?: string;\n /** Enable click-to-copy. Defaults true. */\n copyable?: boolean;\n /** Surface treatment. */\n variant?: 'pill' | 'inline';\n /** Truncation params. */\n head?: number;\n tail?: number;\n className?: string;\n}\n\n/**\n * AddressDisplay — wallet address with optional name resolution, chain\n * label, and click-to-copy. Chain-agnostic — you resolve ENS/name yourself\n * (e.g. via wagmi's useEnsName) and pass it as `name`.\n */\nexport const AddressDisplay = ({\n address,\n name,\n chainSymbol,\n copyable = true,\n variant = 'pill',\n head = 4,\n tail = 4,\n className,\n}: AddressDisplayProps) => {\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n if (!copyable || !address) return;\n try {\n await navigator.clipboard.writeText(address);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n } catch {\n /* noop */\n }\n }, [address, copyable]);\n\n const label = name || truncateAddress(address, { head, tail });\n\n if (variant === 'inline') {\n return (\n <button\n type=\"button\"\n onClick={handleCopy}\n disabled={!copyable}\n className={cn(\n 'mono text-[11px] text-ink-900 hover:text-white transition-colors',\n className\n )}\n title={address}\n >\n {copied ? 'COPIED' : label}\n </button>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleCopy}\n disabled={!copyable}\n title={address}\n className={cn(\n 'flex items-center gap-2 px-3 h-8 hairline mono text-[11px] transition-colors',\n copyable && 'hover:bg-white/5',\n className\n )}\n >\n <span className=\"w-1.5 h-1.5 bg-white\" aria-hidden=\"true\" />\n <span className=\"text-ink-900\">{copied ? 'COPIED' : label}</span>\n {chainSymbol && (\n <>\n <span className=\"text-ink-700\">·</span>\n <span className=\"text-ink-700\">{chainSymbol}</span>\n </>\n )}\n </button>\n );\n};\n","'use client';\n\nimport { useCallback, useState } from 'react';\nimport { cn, Button } from '@lumen-dapps-kit/ui';\nimport { truncateAddress } from '../utils';\n\nexport interface WalletPillProps {\n /** Address — undefined renders the connect CTA. */\n address?: string;\n /** Display name (ENS, etc). */\n name?: string;\n /** Active chain symbol shown after the address. */\n chainSymbol?: string;\n onConnect?: () => void;\n /** When provided, the pill becomes a click target (opens an account drawer, etc).\n * When omitted, the pill defaults to click-to-copy. */\n onClick?: () => void;\n /** Loading state during connect/reconnect handshake. */\n pending?: boolean;\n className?: string;\n}\n\n/**\n * WalletPill — top-right wallet affordance. Renders a CONNECT button when\n * disconnected; a pill with truncated address (+ optional ENS, chain symbol)\n * when connected. Wallet-library agnostic — pass state in via props.\n */\nexport const WalletPill = ({\n address,\n name,\n chainSymbol,\n onConnect,\n onClick,\n pending,\n className,\n}: WalletPillProps) => {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n if (!address) return;\n try {\n await navigator.clipboard.writeText(address);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n } catch {\n /* noop */\n }\n }, [address]);\n\n if (!address) {\n return (\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={onConnect}\n disabled={pending}\n className={cn(className)}\n >\n {pending ? 'CONNECTING…' : 'CONNECT WALLET'}\n </Button>\n );\n }\n\n const handleClick = onClick ?? handleCopy;\n const label = copied ? 'COPIED' : name || truncateAddress(address);\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n title={address}\n className={cn(\n 'flex items-center gap-2 px-3 h-8 hairline mono text-[11px] hover:bg-white/5 transition-colors',\n className\n )}\n >\n <span className=\"w-1.5 h-1.5 bg-white\" aria-hidden=\"true\" />\n <span className=\"text-ink-900\">{label}</span>\n {chainSymbol && (\n <>\n <span className=\"text-ink-700\">·</span>\n <span className=\"text-ink-700\">{chainSymbol}</span>\n </>\n )}\n </button>\n );\n};\n","'use client';\n\nimport { cn, PulseDot } from '@lumen-dapps-kit/ui';\n\nexport interface NetworkStatusProps {\n /** \"online\" | \"degraded\" | \"offline\" */\n state?: 'online' | 'degraded' | 'offline';\n /** Latency in ms, rendered as \"42ms\". */\n latencyMs?: number;\n /** Optional override label (\"NET ONLINE\", \"RPC DOWN\", etc). */\n label?: string;\n className?: string;\n}\n\nconst TONE = {\n online: { dot: 'ok' as const, txt: 'NET ONLINE' },\n degraded: { dot: 'warn' as const, txt: 'NET DEGRADED' },\n offline: { dot: 'err' as const, txt: 'NET OFFLINE' },\n};\n\n/**\n * NetworkStatus — the pulsing network-state pill from the header. Pairs\n * with RPC health checks or a wagmi `useBlockNumber` watcher.\n */\nexport const NetworkStatus = ({\n state = 'online',\n latencyMs,\n label,\n className,\n}: NetworkStatusProps) => {\n const tone = TONE[state];\n return (\n <div\n className={cn(\n 'flex items-center gap-2 px-3 h-8 hairline mono text-[11px] text-ink-800',\n className\n )}\n >\n <PulseDot tone={tone.dot} />\n <span>{label ?? tone.txt}</span>\n {typeof latencyMs === 'number' && (\n <>\n <span className=\"text-ink-600\">·</span>\n <span className=\"text-ink-700\">{Math.round(latencyMs)}ms</span>\n </>\n )}\n </div>\n );\n};\n","'use client';\n\nimport { useState } from 'react';\nimport { cn } from '@lumen-dapps-kit/ui';\nimport type { ChainBrief } from '../utils';\n\nexport interface ChainSelectorProps {\n chains: ChainBrief[];\n /** Selected chain id. */\n value: ChainBrief['id'];\n onChange?: (id: ChainBrief['id']) => void;\n className?: string;\n}\n\n/**\n * ChainSelector — a minimal dropdown for switching active networks. Pure\n * controlled component — pair with wagmi's `useSwitchChain` for execution.\n *\n * For dApps that need testnet/mainnet groupings, sort the `chains` prop\n * upstream (testnets last) — this component renders them in input order.\n */\nexport const ChainSelector = ({\n chains,\n value,\n onChange,\n className,\n}: ChainSelectorProps) => {\n const [open, setOpen] = useState(false);\n const active = chains.find((c) => c.id === value) ?? chains[0];\n\n if (!active) return null;\n\n return (\n <div className={cn('relative', className)}>\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n className=\"flex items-center gap-2 px-3 h-8 hairline mono text-[11px] hover:bg-white/5\"\n >\n <span\n className=\"w-1.5 h-1.5\"\n style={{ backgroundColor: active.color ?? '#ffffff' }}\n aria-hidden=\"true\"\n />\n <span className=\"text-ink-900\">{active.symbol}</span>\n <span className=\"text-ink-700\">·</span>\n <span className=\"text-ink-700 text-[10.5px]\">{active.name}</span>\n {active.testnet && (\n <span className=\"text-signal-warn ml-1\">TESTNET</span>\n )}\n </button>\n\n {open && (\n <>\n <div\n className=\"fixed inset-0 z-40\"\n onClick={() => setOpen(false)}\n aria-hidden=\"true\"\n />\n <div\n role=\"listbox\"\n className=\"absolute right-0 mt-1 min-w-[240px] glass z-50 p-1\"\n >\n {chains.map((c) => {\n const selected = c.id === value;\n return (\n <button\n key={c.id}\n role=\"option\"\n aria-selected={selected}\n type=\"button\"\n onClick={() => {\n onChange?.(c.id);\n setOpen(false);\n }}\n className={cn(\n 'w-full flex items-center gap-2 px-3 h-8 mono text-[11px] text-left transition-colors',\n selected\n ? 'bg-white text-black'\n : 'text-ink-800 hover:bg-white/5'\n )}\n >\n <span\n className=\"w-1.5 h-1.5\"\n style={{ backgroundColor: c.color ?? '#ffffff' }}\n aria-hidden=\"true\"\n />\n <span\n className={cn(\n 'font-medium',\n selected ? 'text-black' : 'text-ink-900'\n )}\n >\n {c.symbol}\n </span>\n <span\n className={cn(\n selected ? 'text-black/60' : 'text-ink-700'\n )}\n >\n · {c.name}\n </span>\n {c.testnet && (\n <span\n className={cn(\n 'ml-auto',\n selected ? 'text-black' : 'text-signal-warn'\n )}\n >\n TESTNET\n </span>\n )}\n </button>\n );\n })}\n </div>\n </>\n )}\n </div>\n );\n};\n","'use client';\n\nimport { cn } from '@lumen-dapps-kit/ui';\nimport { formatGwei } from '../utils';\n\nexport interface GasIndicatorProps {\n /** Current gas price in wei (bigint) or gwei (pass `unit=\"gwei\"`). */\n value: bigint | string | number;\n /** Unit of the `value` prop. Defaults wei. */\n unit?: 'wei' | 'gwei';\n /** Optional threshold gwei values that flip tone (warn/err). */\n thresholds?: { warn: number; err: number };\n /** Label prefix. Defaults \"GAS\". */\n label?: string;\n className?: string;\n}\n\n/**\n * GasIndicator — chip showing current gas price with tone shifts at warn/err\n * thresholds. Drop into the footer status bar or near tx CTAs.\n */\nexport const GasIndicator = ({\n value,\n unit = 'wei',\n thresholds = { warn: 40, err: 100 },\n label = 'GAS',\n className,\n}: GasIndicatorProps) => {\n const gwei =\n unit === 'gwei'\n ? Number(value)\n : Number(typeof value === 'bigint' ? value : BigInt(value)) / 1e9;\n\n const tone =\n gwei >= thresholds.err\n ? 'text-signal-err'\n : gwei >= thresholds.warn\n ? 'text-signal-warn'\n : 'text-signal-ok';\n\n return (\n <span className={cn('mono text-[10.5px] tracking-wider', className)}>\n <span className=\"text-ink-800\">{label}</span>{' '}\n <span className={cn('tabular-nums', tone)}>{formatGwei(value)} gwei</span>\n </span>\n );\n};\n","'use client';\n\nimport { cn, StatusBadge, PulseDot } from '@lumen-dapps-kit/ui';\nimport type { TxState } from '../utils';\nimport { truncateAddress } from '../utils';\n\nexport interface TxStatusProps {\n state: TxState;\n /** Tx hash, when available. */\n hash?: string;\n /** Optional block explorer URL to link to. */\n explorerUrl?: string;\n /** Optional title (defaults from state). */\n title?: string;\n /** Confirmations seen so far. */\n confirmations?: number;\n /** Required confirmations target. */\n requiredConfirmations?: number;\n className?: string;\n}\n\nconst COPY: Record<TxState, { title: string; tone: 'ok' | 'warn' | 'err' | 'data' | 'muted'; live: boolean }> = {\n idle: { title: 'IDLE', tone: 'muted', live: false },\n preparing: { title: 'PREPARING', tone: 'data', live: true },\n 'awaiting-signature': { title: 'AWAITING SIGNATURE', tone: 'warn', live: true },\n pending: { title: 'PENDING', tone: 'data', live: true },\n confirmed: { title: 'CONFIRMED', tone: 'ok', live: false },\n failed: { title: 'FAILED', tone: 'err', live: false },\n rejected: { title: 'REJECTED', tone: 'err', live: false },\n};\n\n/**\n * TxStatus — transaction lifecycle indicator. Six canonical states, each\n * with its own tone + dot/badge. Pair with wagmi's `useWaitForTransactionReceipt`\n * to drive state, or any custom signer flow.\n */\nexport const TxStatus = ({\n state,\n hash,\n explorerUrl,\n title,\n confirmations,\n requiredConfirmations,\n className,\n}: TxStatusProps) => {\n const copy = COPY[state];\n const label = title ?? copy.title;\n const link =\n hash && explorerUrl\n ? `${explorerUrl.replace(/\\/$/, '')}/tx/${hash}`\n : undefined;\n\n return (\n <div\n className={cn(\n 'flex items-center justify-between hairline px-3 py-2.5',\n className\n )}\n >\n <div className=\"flex items-center gap-2.5\">\n {copy.live ? (\n <PulseDot tone={copy.tone === 'muted' ? 'data' : copy.tone} />\n ) : (\n <StatusBadge tone={copy.tone} dot>\n {''}\n </StatusBadge>\n )}\n <span className=\"mono text-[11px] text-ink-900\">{label}</span>\n </div>\n <div className=\"flex items-center gap-3 mono text-[10.5px] text-ink-700\">\n {typeof confirmations === 'number' &&\n typeof requiredConfirmations === 'number' && (\n <span className=\"tabular-nums\">\n {confirmations}/{requiredConfirmations} CONF\n </span>\n )}\n {hash && (\n link ? (\n <a\n href={link}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-ink-800 hover:text-white underline-offset-2 hover:underline\"\n >\n {truncateAddress(hash, { head: 6, tail: 4 })}\n </a>\n ) : (\n <span className=\"text-ink-800\">\n {truncateAddress(hash, { head: 6, tail: 4 })}\n </span>\n )\n )}\n </div>\n </div>\n );\n};\n","'use client';\n\nimport { cn } from '@lumen-dapps-kit/ui';\nimport { formatUnits } from '../utils';\n\nexport interface AmountDisplayProps {\n /** Raw value in base units (e.g. wei for ETH). */\n value: bigint | string;\n /** Decimal places of the token. */\n decimals: number;\n /** Symbol to render after the amount. */\n symbol?: string;\n /** Decimals to display. Defaults 4. */\n displayDecimals?: number;\n /** Size scale of the rendered amount. */\n size?: 'sm' | 'md' | 'lg' | 'xl';\n /** USD value (numeric). Renders as a caption beneath. */\n usd?: number;\n className?: string;\n}\n\nconst SIZE = {\n sm: 'text-[14px]',\n md: 'text-[18px]',\n lg: 'text-[24px]',\n xl: 'text-[40px]',\n} as const;\n\n/**\n * AmountDisplay — formats a base-unit bigint as a tabular-nums token amount\n * with optional USD caption. Use for balances, deposits, claim amounts.\n */\nexport const AmountDisplay = ({\n value,\n decimals,\n symbol,\n displayDecimals = 4,\n size = 'md',\n usd,\n className,\n}: AmountDisplayProps) => (\n <div className={cn('leading-none', className)}>\n <div className=\"flex items-baseline gap-1\">\n <span\n className={cn('font-semibold tabular-nums tracking-tight', SIZE[size])}\n >\n {formatUnits(value, decimals, displayDecimals)}\n </span>\n {symbol && (\n <span className=\"text-ink-700 text-[11px]\">{symbol}</span>\n )}\n </div>\n {typeof usd === 'number' && (\n <div className=\"mono text-[10.5px] text-ink-700 mt-1 tabular-nums\">\n ${usd.toLocaleString('en-US', { maximumFractionDigits: 2 })}\n </div>\n )}\n </div>\n);\n"]}