@unicitylabs/sphere-ui 0.1.7 → 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 +80 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -474,7 +474,8 @@ function EmptyState({ title, description, action }) {
|
|
|
474
474
|
}
|
|
475
475
|
|
|
476
476
|
// src/components/CustomSelect.tsx
|
|
477
|
-
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";
|
|
478
479
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
479
480
|
function CustomSelect({
|
|
480
481
|
options,
|
|
@@ -485,13 +486,23 @@ function CustomSelect({
|
|
|
485
486
|
size = "md"
|
|
486
487
|
}) {
|
|
487
488
|
const [open, setOpen] = useState2(false);
|
|
488
|
-
const
|
|
489
|
+
const btnRef = useRef(null);
|
|
490
|
+
const dropRef = useRef(null);
|
|
491
|
+
const [pos, setPos] = useState2({ top: 0, left: 0, width: 0 });
|
|
489
492
|
const selected = options.find((o) => o.value === value);
|
|
490
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
|
+
}, []);
|
|
491
499
|
useEffect3(() => {
|
|
492
500
|
if (!open) return;
|
|
493
501
|
const handler = (e) => {
|
|
494
|
-
|
|
502
|
+
const target = e.target;
|
|
503
|
+
if (btnRef.current?.contains(target)) return;
|
|
504
|
+
if (dropRef.current?.contains(target)) return;
|
|
505
|
+
setOpen(false);
|
|
495
506
|
};
|
|
496
507
|
document.addEventListener("mousedown", handler);
|
|
497
508
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -504,13 +515,27 @@ function CustomSelect({
|
|
|
504
515
|
document.addEventListener("keydown", handler);
|
|
505
516
|
return () => document.removeEventListener("keydown", handler);
|
|
506
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]);
|
|
507
528
|
const textSize = size === "sm" ? "text-xs" : "text-sm";
|
|
508
|
-
return /* @__PURE__ */ jsxs10("div", {
|
|
529
|
+
return /* @__PURE__ */ jsxs10("div", { className, children: [
|
|
509
530
|
/* @__PURE__ */ jsxs10(
|
|
510
531
|
"button",
|
|
511
532
|
{
|
|
533
|
+
ref: btnRef,
|
|
512
534
|
type: "button",
|
|
513
|
-
onClick: () =>
|
|
535
|
+
onClick: () => {
|
|
536
|
+
updatePos();
|
|
537
|
+
setOpen((o) => !o);
|
|
538
|
+
},
|
|
514
539
|
className: `admin-input w-full flex items-center justify-between gap-2 ${textSize} text-left`,
|
|
515
540
|
style: { color: selected ? "var(--text-primary)" : "var(--text-muted)" },
|
|
516
541
|
children: [
|
|
@@ -537,40 +562,50 @@ function CustomSelect({
|
|
|
537
562
|
]
|
|
538
563
|
}
|
|
539
564
|
),
|
|
540
|
-
open &&
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
},
|
|
558
|
-
className: `block w-full text-left px-3 py-1.5 ${textSize} transition-colors`,
|
|
559
|
-
style: {
|
|
560
|
-
color: opt.value === value ? "var(--accent-text)" : "var(--text-primary)",
|
|
561
|
-
background: opt.value === value ? "var(--accent-glow)" : "transparent"
|
|
562
|
-
},
|
|
563
|
-
onMouseEnter: (e) => {
|
|
564
|
-
if (opt.value !== value) e.currentTarget.style.background = "var(--bg-hover)";
|
|
565
|
-
},
|
|
566
|
-
onMouseLeave: (e) => {
|
|
567
|
-
e.currentTarget.style.background = opt.value === value ? "var(--accent-glow)" : "transparent";
|
|
568
|
-
},
|
|
569
|
-
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)"
|
|
570
582
|
},
|
|
571
|
-
opt
|
|
572
|
-
|
|
573
|
-
|
|
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
|
|
574
609
|
)
|
|
575
610
|
] });
|
|
576
611
|
}
|
|
@@ -703,7 +738,7 @@ function AlertBanner({ type, title, children }) {
|
|
|
703
738
|
}
|
|
704
739
|
|
|
705
740
|
// src/components/AddressDisplay.tsx
|
|
706
|
-
import { useState as useState4, useCallback } from "react";
|
|
741
|
+
import { useState as useState4, useCallback as useCallback2 } from "react";
|
|
707
742
|
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
708
743
|
function truncateAddress(address) {
|
|
709
744
|
const prefix = "DIRECT://";
|
|
@@ -720,7 +755,7 @@ function truncateAddress(address) {
|
|
|
720
755
|
}
|
|
721
756
|
function AddressDisplay({ address, nametag, truncate = true }) {
|
|
722
757
|
const [copied, setCopied] = useState4(false);
|
|
723
|
-
const handleCopy =
|
|
758
|
+
const handleCopy = useCallback2(() => {
|
|
724
759
|
navigator.clipboard.writeText(address).then(() => {
|
|
725
760
|
setCopied(true);
|
|
726
761
|
setTimeout(() => setCopied(false), 1500);
|
|
@@ -774,7 +809,7 @@ function AddressDisplay({ address, nametag, truncate = true }) {
|
|
|
774
809
|
}
|
|
775
810
|
|
|
776
811
|
// src/components/JsonPanel.tsx
|
|
777
|
-
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";
|
|
778
813
|
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
779
814
|
function JsonPanel({
|
|
780
815
|
value,
|
|
@@ -796,7 +831,7 @@ function JsonPanel({
|
|
|
796
831
|
setText(JSON.stringify(clean, null, 2));
|
|
797
832
|
setParseError(null);
|
|
798
833
|
}, [value, isEditing, excludeKeys]);
|
|
799
|
-
const handleChange =
|
|
834
|
+
const handleChange = useCallback3((newText) => {
|
|
800
835
|
setText(newText);
|
|
801
836
|
try {
|
|
802
837
|
const parsed = JSON.parse(newText);
|
|
@@ -806,10 +841,10 @@ function JsonPanel({
|
|
|
806
841
|
setParseError(e instanceof Error ? e.message : "Invalid JSON");
|
|
807
842
|
}
|
|
808
843
|
}, [onChange]);
|
|
809
|
-
const handleFocus =
|
|
810
|
-
const handleBlur =
|
|
844
|
+
const handleFocus = useCallback3(() => setIsEditing(true), []);
|
|
845
|
+
const handleBlur = useCallback3(() => setIsEditing(false), []);
|
|
811
846
|
const [copied, setCopied] = useState5(false);
|
|
812
|
-
const handleCopy =
|
|
847
|
+
const handleCopy = useCallback3(async () => {
|
|
813
848
|
await navigator.clipboard.writeText(text);
|
|
814
849
|
setCopied(true);
|
|
815
850
|
setTimeout(() => setCopied(false), 1500);
|