@fairmint/ui 0.2.1 → 0.2.2

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.
@@ -25515,6 +25515,211 @@ function InvestorProfileCard({
25515
25515
  children
25516
25516
  ] });
25517
25517
  }
25518
+ function truncateAddress(address, chars = 4) {
25519
+ if (address.length <= chars * 2 + 2) return address;
25520
+ return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
25521
+ }
25522
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
25523
+ const ETH_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
25524
+ function isEthereumAddress(value) {
25525
+ return ETH_ADDRESS_RE.test(value) && value.toLowerCase() !== ZERO_ADDRESS;
25526
+ }
25527
+ function validateEthereumAddress(value) {
25528
+ if (!ETH_ADDRESS_RE.test(value))
25529
+ return "Must be a valid Ethereum address (0x + 40 hex characters)";
25530
+ if (value.toLowerCase() === ZERO_ADDRESS) return "Cannot use the zero address";
25531
+ return null;
25532
+ }
25533
+ const ETHEREUM_ADDRESS_REGEX = ETH_ADDRESS_RE;
25534
+ const ZERO_ETHEREUM_ADDRESS = ZERO_ADDRESS;
25535
+ const DEFAULT_TYPE_LABELS = {
25536
+ fairmint: "Fairmint Wallet",
25537
+ privy: "Fairmint Wallet",
25538
+ manual: "Manual"
25539
+ };
25540
+ function getTypeLabel(type, custom2) {
25541
+ if (custom2?.[type]) return custom2[type];
25542
+ return DEFAULT_TYPE_LABELS[type] ?? type;
25543
+ }
25544
+ function WalletList({
25545
+ wallets,
25546
+ onAdd,
25547
+ onRemove,
25548
+ readOnly = false,
25549
+ addLoading = false,
25550
+ removeLoading = false,
25551
+ emptyIcon,
25552
+ copyIcon,
25553
+ copiedIcon,
25554
+ removeIcon,
25555
+ addIcon,
25556
+ typeLabels,
25557
+ removableTypes = ["manual"]
25558
+ }) {
25559
+ const [newAddress, setNewAddress] = useState("");
25560
+ const [addressError, setAddressError] = useState(null);
25561
+ const [showAddForm, setShowAddForm] = useState(false);
25562
+ const [walletToRemove, setWalletToRemove] = useState(null);
25563
+ const [copiedAddress, setCopiedAddress] = useState(null);
25564
+ const copyTimeoutRef = useRef(void 0);
25565
+ useEffect(() => () => clearTimeout(copyTimeoutRef.current), []);
25566
+ const copyAddress = async (address) => {
25567
+ try {
25568
+ await navigator.clipboard.writeText(address);
25569
+ clearTimeout(copyTimeoutRef.current);
25570
+ setCopiedAddress(address);
25571
+ copyTimeoutRef.current = setTimeout(() => setCopiedAddress(null), 2e3);
25572
+ } catch {
25573
+ }
25574
+ };
25575
+ const canAdd = !readOnly && !!onAdd;
25576
+ const canRemove = !readOnly && !!onRemove;
25577
+ const handleAdd = async () => {
25578
+ const trimmed = newAddress.trim();
25579
+ const error2 = validateEthereumAddress(trimmed);
25580
+ if (error2) {
25581
+ setAddressError(error2);
25582
+ return;
25583
+ }
25584
+ setAddressError(null);
25585
+ try {
25586
+ await onAdd?.(trimmed);
25587
+ setNewAddress("");
25588
+ setShowAddForm(false);
25589
+ } catch {
25590
+ setAddressError("Failed to add wallet");
25591
+ }
25592
+ };
25593
+ const [removeError, setRemoveError] = useState(null);
25594
+ const handleRemove = async () => {
25595
+ if (!walletToRemove) return;
25596
+ setRemoveError(null);
25597
+ try {
25598
+ await onRemove?.(walletToRemove);
25599
+ setWalletToRemove(null);
25600
+ } catch {
25601
+ setRemoveError("Failed to remove wallet. Please try again.");
25602
+ }
25603
+ };
25604
+ if (wallets.length === 0 && !showAddForm) {
25605
+ return /* @__PURE__ */ jsx(
25606
+ EmptyState,
25607
+ {
25608
+ icon: emptyIcon,
25609
+ title: "No wallets connected",
25610
+ description: "Add a wallet address to receive equity on-chain.",
25611
+ actionLabel: canAdd ? "Add Wallet" : void 0,
25612
+ onAction: canAdd ? () => setShowAddForm(true) : void 0
25613
+ }
25614
+ );
25615
+ }
25616
+ return /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
25617
+ wallets.map((w) => /* @__PURE__ */ jsxs(
25618
+ Group,
25619
+ {
25620
+ justify: "space-between",
25621
+ p: "xs",
25622
+ style: {
25623
+ borderRadius: "var(--mantine-radius-sm)",
25624
+ border: "1px solid var(--mantine-color-default-border)"
25625
+ },
25626
+ children: [
25627
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
25628
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: getTypeLabel(w.type, typeLabels) }),
25629
+ w.label && /* @__PURE__ */ jsx(Text, { size: "xs", c: `${colors.neutral}.5`, children: w.label }),
25630
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: truncateAddress(w.address) })
25631
+ ] }),
25632
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
25633
+ copyIcon && /* @__PURE__ */ jsx(Tooltip, { label: copiedAddress === w.address ? "Copied!" : "Copy address", children: /* @__PURE__ */ jsx(
25634
+ ActionIcon,
25635
+ {
25636
+ variant: "subtle",
25637
+ size: "sm",
25638
+ onClick: () => copyAddress(w.address),
25639
+ "aria-label": "Copy wallet address",
25640
+ children: copiedAddress === w.address ? copiedIcon ?? copyIcon : copyIcon
25641
+ }
25642
+ ) }),
25643
+ canRemove && removeIcon && removableTypes.includes(w.type) && /* @__PURE__ */ jsx(Tooltip, { label: "Remove wallet", children: /* @__PURE__ */ jsx(
25644
+ ActionIcon,
25645
+ {
25646
+ variant: "subtle",
25647
+ size: "sm",
25648
+ color: colors.error,
25649
+ onClick: () => setWalletToRemove(w.address),
25650
+ disabled: removeLoading,
25651
+ "aria-label": "Remove wallet",
25652
+ children: removeIcon
25653
+ }
25654
+ ) })
25655
+ ] })
25656
+ ]
25657
+ },
25658
+ w.address
25659
+ )),
25660
+ canAdd && (showAddForm ? /* @__PURE__ */ jsxs(Group, { gap: "xs", mt: "xs", children: [
25661
+ /* @__PURE__ */ jsx(
25662
+ TextInput,
25663
+ {
25664
+ placeholder: "0x...",
25665
+ "aria-label": "Wallet address",
25666
+ value: newAddress,
25667
+ onChange: (e) => {
25668
+ setNewAddress(e.currentTarget.value);
25669
+ setAddressError(null);
25670
+ },
25671
+ error: addressError,
25672
+ style: { flex: 1 }
25673
+ }
25674
+ ),
25675
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: handleAdd, loading: addLoading, children: "Add" }),
25676
+ /* @__PURE__ */ jsx(
25677
+ Button,
25678
+ {
25679
+ size: "sm",
25680
+ variant: "subtle",
25681
+ color: colors.neutral,
25682
+ onClick: () => {
25683
+ setShowAddForm(false);
25684
+ setNewAddress("");
25685
+ setAddressError(null);
25686
+ },
25687
+ children: "Cancel"
25688
+ }
25689
+ )
25690
+ ] }) : /* @__PURE__ */ jsx(
25691
+ Button,
25692
+ {
25693
+ variant: "light",
25694
+ size: "xs",
25695
+ leftSection: addIcon,
25696
+ onClick: () => setShowAddForm(true),
25697
+ mt: "xs",
25698
+ children: "Add Wallet"
25699
+ }
25700
+ )),
25701
+ /* @__PURE__ */ jsx(
25702
+ ConfirmDialog,
25703
+ {
25704
+ title: "Remove Wallet",
25705
+ message: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
25706
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: "Are you sure you want to remove this wallet address? This action cannot be undone." }),
25707
+ walletToRemove && /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: `${colors.neutral}.5`, children: walletToRemove }),
25708
+ removeError && /* @__PURE__ */ jsx(Text, { size: "sm", c: colors.error, children: removeError })
25709
+ ] }),
25710
+ opened: walletToRemove !== null,
25711
+ confirmLabel: "Remove",
25712
+ confirmColor: colors.error,
25713
+ onConfirm: handleRemove,
25714
+ onCancel: () => {
25715
+ setWalletToRemove(null);
25716
+ setRemoveError(null);
25717
+ },
25718
+ loading: removeLoading
25719
+ }
25720
+ )
25721
+ ] });
25722
+ }
25518
25723
  function useDebouncedCallback(fn, delay) {
25519
25724
  const timer = useRef(null);
25520
25725
  const fnRef = useRef(fn);
@@ -25546,10 +25751,6 @@ const notify = {
25546
25751
  warning: ({ title, message, autoClose = 5e3 }) => notifications.show({ title, message, color: colors.warning, autoClose }),
25547
25752
  info: ({ title, message, autoClose = 4e3 }) => notifications.show({ title, message, color: colors.info, autoClose })
25548
25753
  };
25549
- function truncateAddress(address, chars = 4) {
25550
- if (address.length <= chars * 2 + 2) return address;
25551
- return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
25552
- }
25553
25754
  export {
25554
25755
  AVATAR_PALETTE,
25555
25756
  ActionIcon,
@@ -25574,6 +25775,7 @@ export {
25574
25775
  Divider,
25575
25776
  DocumentRow,
25576
25777
  Drawer,
25778
+ ETHEREUM_ADDRESS_REGEX,
25577
25779
  EmailField,
25578
25780
  EmptyState,
25579
25781
  EquityGrantCard,
@@ -25617,6 +25819,8 @@ export {
25617
25819
  Title,
25618
25820
  Tooltip,
25619
25821
  UserMenu,
25822
+ WalletList,
25823
+ ZERO_ETHEREUM_ADDRESS,
25620
25824
  brandColors,
25621
25825
  colors,
25622
25826
  emailSchema,
@@ -25627,6 +25831,7 @@ export {
25627
25831
  formatPercent,
25628
25832
  formatPreciseWithCurrency,
25629
25833
  getAvatarColor,
25834
+ isEthereumAddress,
25630
25835
  neutralColors,
25631
25836
  notify,
25632
25837
  passwordSchema,
@@ -25647,6 +25852,7 @@ export {
25647
25852
  useMediaQuery,
25648
25853
  useScrollIntoView,
25649
25854
  useViewportSize,
25855
+ validateEthereumAddress,
25650
25856
  z
25651
25857
  };
25652
25858
  //# sourceMappingURL=fairmint-ui.js.map