@unicitylabs/sphere-ui 0.1.6 → 0.1.8
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.js +87 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,6 +20,11 @@ function DashboardLayout({ logo, nav, footer, children }) {
|
|
|
20
20
|
background: "var(--bg-root)",
|
|
21
21
|
borderRight: "1px solid var(--border)"
|
|
22
22
|
},
|
|
23
|
+
onClick: (e) => {
|
|
24
|
+
if (e.target.closest("button, a")) {
|
|
25
|
+
setMobileOpen(false);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
23
28
|
children: [
|
|
24
29
|
/* @__PURE__ */ jsx(
|
|
25
30
|
"div",
|
|
@@ -49,9 +54,8 @@ function DashboardLayout({ logo, nav, footer, children }) {
|
|
|
49
54
|
),
|
|
50
55
|
logo
|
|
51
56
|
] }),
|
|
52
|
-
/* @__PURE__ */ jsx("nav", { className: "flex-1 px-3 py-3 flex flex-col overflow-y-auto",
|
|
53
|
-
footer && /*
|
|
54
|
-
/* @__PURE__ */ jsx("div", { className: "px-3 py-4", style: { borderTop: "1px solid var(--border)" }, onClick: () => setMobileOpen(false), children: footer })
|
|
57
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 px-3 py-3 flex flex-col overflow-y-auto", children: nav }),
|
|
58
|
+
footer && /* @__PURE__ */ jsx("div", { className: "px-3 py-4", style: { borderTop: "1px solid var(--border)" }, children: footer })
|
|
55
59
|
]
|
|
56
60
|
}
|
|
57
61
|
),
|
|
@@ -470,7 +474,8 @@ function EmptyState({ title, description, action }) {
|
|
|
470
474
|
}
|
|
471
475
|
|
|
472
476
|
// src/components/CustomSelect.tsx
|
|
473
|
-
import { useState as useState2, useRef, useEffect as useEffect3 } from "react";
|
|
477
|
+
import { useState as useState2, useRef, useEffect as useEffect3, useCallback } from "react";
|
|
478
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
474
479
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
475
480
|
function CustomSelect({
|
|
476
481
|
options,
|
|
@@ -481,13 +486,23 @@ function CustomSelect({
|
|
|
481
486
|
size = "md"
|
|
482
487
|
}) {
|
|
483
488
|
const [open, setOpen] = useState2(false);
|
|
484
|
-
const
|
|
489
|
+
const btnRef = useRef(null);
|
|
490
|
+
const dropRef = useRef(null);
|
|
491
|
+
const [pos, setPos] = useState2({ top: 0, left: 0, width: 0 });
|
|
485
492
|
const selected = options.find((o) => o.value === value);
|
|
486
493
|
const label = selected?.label ?? placeholder ?? "Select...";
|
|
494
|
+
const updatePos = useCallback(() => {
|
|
495
|
+
if (!btnRef.current) return;
|
|
496
|
+
const rect = btnRef.current.getBoundingClientRect();
|
|
497
|
+
setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width });
|
|
498
|
+
}, []);
|
|
487
499
|
useEffect3(() => {
|
|
488
500
|
if (!open) return;
|
|
489
501
|
const handler = (e) => {
|
|
490
|
-
|
|
502
|
+
const target = e.target;
|
|
503
|
+
if (btnRef.current?.contains(target)) return;
|
|
504
|
+
if (dropRef.current?.contains(target)) return;
|
|
505
|
+
setOpen(false);
|
|
491
506
|
};
|
|
492
507
|
document.addEventListener("mousedown", handler);
|
|
493
508
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -500,13 +515,27 @@ function CustomSelect({
|
|
|
500
515
|
document.addEventListener("keydown", handler);
|
|
501
516
|
return () => document.removeEventListener("keydown", handler);
|
|
502
517
|
}, [open]);
|
|
518
|
+
useEffect3(() => {
|
|
519
|
+
if (!open) return;
|
|
520
|
+
updatePos();
|
|
521
|
+
window.addEventListener("scroll", updatePos, true);
|
|
522
|
+
window.addEventListener("resize", updatePos);
|
|
523
|
+
return () => {
|
|
524
|
+
window.removeEventListener("scroll", updatePos, true);
|
|
525
|
+
window.removeEventListener("resize", updatePos);
|
|
526
|
+
};
|
|
527
|
+
}, [open, updatePos]);
|
|
503
528
|
const textSize = size === "sm" ? "text-xs" : "text-sm";
|
|
504
|
-
return /* @__PURE__ */ jsxs10("div", {
|
|
529
|
+
return /* @__PURE__ */ jsxs10("div", { className, children: [
|
|
505
530
|
/* @__PURE__ */ jsxs10(
|
|
506
531
|
"button",
|
|
507
532
|
{
|
|
533
|
+
ref: btnRef,
|
|
508
534
|
type: "button",
|
|
509
|
-
onClick: () =>
|
|
535
|
+
onClick: () => {
|
|
536
|
+
updatePos();
|
|
537
|
+
setOpen((o) => !o);
|
|
538
|
+
},
|
|
510
539
|
className: `admin-input w-full flex items-center justify-between gap-2 ${textSize} text-left`,
|
|
511
540
|
style: { color: selected ? "var(--text-primary)" : "var(--text-muted)" },
|
|
512
541
|
children: [
|
|
@@ -533,40 +562,50 @@ function CustomSelect({
|
|
|
533
562
|
]
|
|
534
563
|
}
|
|
535
564
|
),
|
|
536
|
-
open &&
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
},
|
|
554
|
-
className: `block w-full text-left px-3 py-1.5 ${textSize} transition-colors`,
|
|
555
|
-
style: {
|
|
556
|
-
color: opt.value === value ? "var(--accent-text)" : "var(--text-primary)",
|
|
557
|
-
background: opt.value === value ? "var(--accent-glow)" : "transparent"
|
|
558
|
-
},
|
|
559
|
-
onMouseEnter: (e) => {
|
|
560
|
-
if (opt.value !== value) e.currentTarget.style.background = "var(--bg-hover)";
|
|
561
|
-
},
|
|
562
|
-
onMouseLeave: (e) => {
|
|
563
|
-
e.currentTarget.style.background = opt.value === value ? "var(--accent-glow)" : "transparent";
|
|
564
|
-
},
|
|
565
|
-
children: opt.label
|
|
565
|
+
open && createPortal3(
|
|
566
|
+
/* @__PURE__ */ jsx11(
|
|
567
|
+
"div",
|
|
568
|
+
{
|
|
569
|
+
ref: dropRef,
|
|
570
|
+
className: "py-1 max-h-48 overflow-y-auto",
|
|
571
|
+
style: {
|
|
572
|
+
position: "fixed",
|
|
573
|
+
top: pos.top,
|
|
574
|
+
left: pos.left,
|
|
575
|
+
width: pos.width,
|
|
576
|
+
minWidth: 120,
|
|
577
|
+
zIndex: 9999,
|
|
578
|
+
background: "var(--bg-elevated)",
|
|
579
|
+
border: "1px solid var(--border)",
|
|
580
|
+
borderRadius: "var(--radius-md)",
|
|
581
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.4)"
|
|
566
582
|
},
|
|
567
|
-
opt
|
|
568
|
-
|
|
569
|
-
|
|
583
|
+
children: options.map((opt) => /* @__PURE__ */ jsx11(
|
|
584
|
+
"button",
|
|
585
|
+
{
|
|
586
|
+
type: "button",
|
|
587
|
+
onClick: () => {
|
|
588
|
+
onChange(opt.value);
|
|
589
|
+
setOpen(false);
|
|
590
|
+
},
|
|
591
|
+
className: `block w-full text-left px-3 py-1.5 ${textSize} transition-colors`,
|
|
592
|
+
style: {
|
|
593
|
+
color: opt.value === value ? "var(--accent-text)" : "var(--text-primary)",
|
|
594
|
+
background: opt.value === value ? "var(--accent-glow)" : "transparent"
|
|
595
|
+
},
|
|
596
|
+
onMouseEnter: (e) => {
|
|
597
|
+
if (opt.value !== value) e.currentTarget.style.background = "var(--bg-hover)";
|
|
598
|
+
},
|
|
599
|
+
onMouseLeave: (e) => {
|
|
600
|
+
e.currentTarget.style.background = opt.value === value ? "var(--accent-glow)" : "transparent";
|
|
601
|
+
},
|
|
602
|
+
children: opt.label
|
|
603
|
+
},
|
|
604
|
+
opt.value
|
|
605
|
+
))
|
|
606
|
+
}
|
|
607
|
+
),
|
|
608
|
+
document.body
|
|
570
609
|
)
|
|
571
610
|
] });
|
|
572
611
|
}
|
|
@@ -699,7 +738,7 @@ function AlertBanner({ type, title, children }) {
|
|
|
699
738
|
}
|
|
700
739
|
|
|
701
740
|
// src/components/AddressDisplay.tsx
|
|
702
|
-
import { useState as useState4, useCallback } from "react";
|
|
741
|
+
import { useState as useState4, useCallback as useCallback2 } from "react";
|
|
703
742
|
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
704
743
|
function truncateAddress(address) {
|
|
705
744
|
const prefix = "DIRECT://";
|
|
@@ -716,7 +755,7 @@ function truncateAddress(address) {
|
|
|
716
755
|
}
|
|
717
756
|
function AddressDisplay({ address, nametag, truncate = true }) {
|
|
718
757
|
const [copied, setCopied] = useState4(false);
|
|
719
|
-
const handleCopy =
|
|
758
|
+
const handleCopy = useCallback2(() => {
|
|
720
759
|
navigator.clipboard.writeText(address).then(() => {
|
|
721
760
|
setCopied(true);
|
|
722
761
|
setTimeout(() => setCopied(false), 1500);
|
|
@@ -770,7 +809,7 @@ function AddressDisplay({ address, nametag, truncate = true }) {
|
|
|
770
809
|
}
|
|
771
810
|
|
|
772
811
|
// src/components/JsonPanel.tsx
|
|
773
|
-
import { useState as useState5, useEffect as useEffect4, useRef as useRef2, useCallback as
|
|
812
|
+
import { useState as useState5, useEffect as useEffect4, useRef as useRef2, useCallback as useCallback3 } from "react";
|
|
774
813
|
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
775
814
|
function JsonPanel({
|
|
776
815
|
value,
|
|
@@ -792,7 +831,7 @@ function JsonPanel({
|
|
|
792
831
|
setText(JSON.stringify(clean, null, 2));
|
|
793
832
|
setParseError(null);
|
|
794
833
|
}, [value, isEditing, excludeKeys]);
|
|
795
|
-
const handleChange =
|
|
834
|
+
const handleChange = useCallback3((newText) => {
|
|
796
835
|
setText(newText);
|
|
797
836
|
try {
|
|
798
837
|
const parsed = JSON.parse(newText);
|
|
@@ -802,10 +841,10 @@ function JsonPanel({
|
|
|
802
841
|
setParseError(e instanceof Error ? e.message : "Invalid JSON");
|
|
803
842
|
}
|
|
804
843
|
}, [onChange]);
|
|
805
|
-
const handleFocus =
|
|
806
|
-
const handleBlur =
|
|
844
|
+
const handleFocus = useCallback3(() => setIsEditing(true), []);
|
|
845
|
+
const handleBlur = useCallback3(() => setIsEditing(false), []);
|
|
807
846
|
const [copied, setCopied] = useState5(false);
|
|
808
|
-
const handleCopy =
|
|
847
|
+
const handleCopy = useCallback3(async () => {
|
|
809
848
|
await navigator.clipboard.writeText(text);
|
|
810
849
|
setCopied(true);
|
|
811
850
|
setTimeout(() => setCopied(false), 1500);
|