@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.
- package/dist/components/specific/WalletList/WalletList.d.ts +45 -0
- package/dist/components/specific/WalletList/WalletList.d.ts.map +1 -0
- package/dist/fairmint-ui.cjs +210 -4
- package/dist/fairmint-ui.cjs.map +1 -1
- package/dist/fairmint-ui.js +210 -4
- package/dist/fairmint-ui.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/address.d.ts +13 -0
- package/dist/utils/address.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface Wallet {
|
|
3
|
+
/** Ethereum wallet address. */
|
|
4
|
+
address: string;
|
|
5
|
+
/** Wallet type identifier (e.g. "fairmint", "privy", "manual"). */
|
|
6
|
+
type: string;
|
|
7
|
+
/** Optional display label. */
|
|
8
|
+
label?: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface WalletListProps {
|
|
11
|
+
/** Wallets to display. */
|
|
12
|
+
wallets: Wallet[];
|
|
13
|
+
/** Called when user adds a new wallet address. */
|
|
14
|
+
onAdd?: (address: string) => void | Promise<void>;
|
|
15
|
+
/** Called when user confirms removal of a wallet address. */
|
|
16
|
+
onRemove?: (address: string) => void | Promise<void>;
|
|
17
|
+
/** Whether add/remove actions are disabled (e.g. admin viewing another user). */
|
|
18
|
+
readOnly?: boolean;
|
|
19
|
+
/** Whether an add operation is in progress. */
|
|
20
|
+
addLoading?: boolean;
|
|
21
|
+
/** Whether a remove operation is in progress. */
|
|
22
|
+
removeLoading?: boolean;
|
|
23
|
+
/** Icon for the empty state. Passed as ReactNode. */
|
|
24
|
+
emptyIcon?: ReactNode;
|
|
25
|
+
/** Icon for the copy button. Passed as ReactNode. */
|
|
26
|
+
copyIcon?: ReactNode;
|
|
27
|
+
/** Icon for the "copied" state. Passed as ReactNode. */
|
|
28
|
+
copiedIcon?: ReactNode;
|
|
29
|
+
/** Icon for the remove button. Passed as ReactNode. */
|
|
30
|
+
removeIcon?: ReactNode;
|
|
31
|
+
/** Icon for the add button. Passed as ReactNode. */
|
|
32
|
+
addIcon?: ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* Map a wallet type string to a display label.
|
|
35
|
+
* @default Built-in: "fairmint"|"privy" → "Fairmint Wallet", "manual" → "Manual", else as-is
|
|
36
|
+
*/
|
|
37
|
+
typeLabels?: Record<string, string>;
|
|
38
|
+
/**
|
|
39
|
+
* Which wallet types can be removed.
|
|
40
|
+
* @default ["manual"]
|
|
41
|
+
*/
|
|
42
|
+
removableTypes?: string[];
|
|
43
|
+
}
|
|
44
|
+
export declare function WalletList({ wallets, onAdd, onRemove, readOnly, addLoading, removeLoading, emptyIcon, copyIcon, copiedIcon, removeIcon, addIcon, typeLabels, removableTypes, }: WalletListProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
//# sourceMappingURL=WalletList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WalletList.d.ts","sourceRoot":"","sources":["../../../../src/components/specific/WalletList/WalletList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAYpE,MAAM,WAAW,MAAM;IACrB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qDAAqD;IACrD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,wDAAwD;IACxD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,uDAAuD;IACvD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAaD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,UAAkB,EAClB,aAAqB,EACrB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,OAAO,EACP,UAAU,EACV,cAA2B,GAC5B,EAAE,eAAe,2CAmMjB"}
|
package/dist/fairmint-ui.cjs
CHANGED
|
@@ -25533,6 +25533,211 @@ function InvestorProfileCard({
|
|
|
25533
25533
|
children
|
|
25534
25534
|
] });
|
|
25535
25535
|
}
|
|
25536
|
+
function truncateAddress(address, chars = 4) {
|
|
25537
|
+
if (address.length <= chars * 2 + 2) return address;
|
|
25538
|
+
return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
|
|
25539
|
+
}
|
|
25540
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
25541
|
+
const ETH_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
25542
|
+
function isEthereumAddress(value) {
|
|
25543
|
+
return ETH_ADDRESS_RE.test(value) && value.toLowerCase() !== ZERO_ADDRESS;
|
|
25544
|
+
}
|
|
25545
|
+
function validateEthereumAddress(value) {
|
|
25546
|
+
if (!ETH_ADDRESS_RE.test(value))
|
|
25547
|
+
return "Must be a valid Ethereum address (0x + 40 hex characters)";
|
|
25548
|
+
if (value.toLowerCase() === ZERO_ADDRESS) return "Cannot use the zero address";
|
|
25549
|
+
return null;
|
|
25550
|
+
}
|
|
25551
|
+
const ETHEREUM_ADDRESS_REGEX = ETH_ADDRESS_RE;
|
|
25552
|
+
const ZERO_ETHEREUM_ADDRESS = ZERO_ADDRESS;
|
|
25553
|
+
const DEFAULT_TYPE_LABELS = {
|
|
25554
|
+
fairmint: "Fairmint Wallet",
|
|
25555
|
+
privy: "Fairmint Wallet",
|
|
25556
|
+
manual: "Manual"
|
|
25557
|
+
};
|
|
25558
|
+
function getTypeLabel(type, custom2) {
|
|
25559
|
+
if (custom2?.[type]) return custom2[type];
|
|
25560
|
+
return DEFAULT_TYPE_LABELS[type] ?? type;
|
|
25561
|
+
}
|
|
25562
|
+
function WalletList({
|
|
25563
|
+
wallets,
|
|
25564
|
+
onAdd,
|
|
25565
|
+
onRemove,
|
|
25566
|
+
readOnly = false,
|
|
25567
|
+
addLoading = false,
|
|
25568
|
+
removeLoading = false,
|
|
25569
|
+
emptyIcon,
|
|
25570
|
+
copyIcon,
|
|
25571
|
+
copiedIcon,
|
|
25572
|
+
removeIcon,
|
|
25573
|
+
addIcon,
|
|
25574
|
+
typeLabels,
|
|
25575
|
+
removableTypes = ["manual"]
|
|
25576
|
+
}) {
|
|
25577
|
+
const [newAddress, setNewAddress] = React.useState("");
|
|
25578
|
+
const [addressError, setAddressError] = React.useState(null);
|
|
25579
|
+
const [showAddForm, setShowAddForm] = React.useState(false);
|
|
25580
|
+
const [walletToRemove, setWalletToRemove] = React.useState(null);
|
|
25581
|
+
const [copiedAddress, setCopiedAddress] = React.useState(null);
|
|
25582
|
+
const copyTimeoutRef = React.useRef(void 0);
|
|
25583
|
+
React.useEffect(() => () => clearTimeout(copyTimeoutRef.current), []);
|
|
25584
|
+
const copyAddress = async (address) => {
|
|
25585
|
+
try {
|
|
25586
|
+
await navigator.clipboard.writeText(address);
|
|
25587
|
+
clearTimeout(copyTimeoutRef.current);
|
|
25588
|
+
setCopiedAddress(address);
|
|
25589
|
+
copyTimeoutRef.current = setTimeout(() => setCopiedAddress(null), 2e3);
|
|
25590
|
+
} catch {
|
|
25591
|
+
}
|
|
25592
|
+
};
|
|
25593
|
+
const canAdd = !readOnly && !!onAdd;
|
|
25594
|
+
const canRemove = !readOnly && !!onRemove;
|
|
25595
|
+
const handleAdd = async () => {
|
|
25596
|
+
const trimmed = newAddress.trim();
|
|
25597
|
+
const error2 = validateEthereumAddress(trimmed);
|
|
25598
|
+
if (error2) {
|
|
25599
|
+
setAddressError(error2);
|
|
25600
|
+
return;
|
|
25601
|
+
}
|
|
25602
|
+
setAddressError(null);
|
|
25603
|
+
try {
|
|
25604
|
+
await onAdd?.(trimmed);
|
|
25605
|
+
setNewAddress("");
|
|
25606
|
+
setShowAddForm(false);
|
|
25607
|
+
} catch {
|
|
25608
|
+
setAddressError("Failed to add wallet");
|
|
25609
|
+
}
|
|
25610
|
+
};
|
|
25611
|
+
const [removeError, setRemoveError] = React.useState(null);
|
|
25612
|
+
const handleRemove = async () => {
|
|
25613
|
+
if (!walletToRemove) return;
|
|
25614
|
+
setRemoveError(null);
|
|
25615
|
+
try {
|
|
25616
|
+
await onRemove?.(walletToRemove);
|
|
25617
|
+
setWalletToRemove(null);
|
|
25618
|
+
} catch {
|
|
25619
|
+
setRemoveError("Failed to remove wallet. Please try again.");
|
|
25620
|
+
}
|
|
25621
|
+
};
|
|
25622
|
+
if (wallets.length === 0 && !showAddForm) {
|
|
25623
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
25624
|
+
EmptyState,
|
|
25625
|
+
{
|
|
25626
|
+
icon: emptyIcon,
|
|
25627
|
+
title: "No wallets connected",
|
|
25628
|
+
description: "Add a wallet address to receive equity on-chain.",
|
|
25629
|
+
actionLabel: canAdd ? "Add Wallet" : void 0,
|
|
25630
|
+
onAction: canAdd ? () => setShowAddForm(true) : void 0
|
|
25631
|
+
}
|
|
25632
|
+
);
|
|
25633
|
+
}
|
|
25634
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Stack, { gap: "sm", children: [
|
|
25635
|
+
wallets.map((w) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25636
|
+
Group,
|
|
25637
|
+
{
|
|
25638
|
+
justify: "space-between",
|
|
25639
|
+
p: "xs",
|
|
25640
|
+
style: {
|
|
25641
|
+
borderRadius: "var(--mantine-radius-sm)",
|
|
25642
|
+
border: "1px solid var(--mantine-color-default-border)"
|
|
25643
|
+
},
|
|
25644
|
+
children: [
|
|
25645
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Group, { gap: "xs", children: [
|
|
25646
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "xs", variant: "light", children: getTypeLabel(w.type, typeLabels) }),
|
|
25647
|
+
w.label && /* @__PURE__ */ jsxRuntime.jsx(Text, { size: "xs", c: `${colors.neutral}.5`, children: w.label }),
|
|
25648
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: "sm", ff: "monospace", children: truncateAddress(w.address) })
|
|
25649
|
+
] }),
|
|
25650
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Group, { gap: 4, children: [
|
|
25651
|
+
copyIcon && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: copiedAddress === w.address ? "Copied!" : "Copy address", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
25652
|
+
ActionIcon,
|
|
25653
|
+
{
|
|
25654
|
+
variant: "subtle",
|
|
25655
|
+
size: "sm",
|
|
25656
|
+
onClick: () => copyAddress(w.address),
|
|
25657
|
+
"aria-label": "Copy wallet address",
|
|
25658
|
+
children: copiedAddress === w.address ? copiedIcon ?? copyIcon : copyIcon
|
|
25659
|
+
}
|
|
25660
|
+
) }),
|
|
25661
|
+
canRemove && removeIcon && removableTypes.includes(w.type) && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: "Remove wallet", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
25662
|
+
ActionIcon,
|
|
25663
|
+
{
|
|
25664
|
+
variant: "subtle",
|
|
25665
|
+
size: "sm",
|
|
25666
|
+
color: colors.error,
|
|
25667
|
+
onClick: () => setWalletToRemove(w.address),
|
|
25668
|
+
disabled: removeLoading,
|
|
25669
|
+
"aria-label": "Remove wallet",
|
|
25670
|
+
children: removeIcon
|
|
25671
|
+
}
|
|
25672
|
+
) })
|
|
25673
|
+
] })
|
|
25674
|
+
]
|
|
25675
|
+
},
|
|
25676
|
+
w.address
|
|
25677
|
+
)),
|
|
25678
|
+
canAdd && (showAddForm ? /* @__PURE__ */ jsxRuntime.jsxs(Group, { gap: "xs", mt: "xs", children: [
|
|
25679
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25680
|
+
TextInput,
|
|
25681
|
+
{
|
|
25682
|
+
placeholder: "0x...",
|
|
25683
|
+
"aria-label": "Wallet address",
|
|
25684
|
+
value: newAddress,
|
|
25685
|
+
onChange: (e) => {
|
|
25686
|
+
setNewAddress(e.currentTarget.value);
|
|
25687
|
+
setAddressError(null);
|
|
25688
|
+
},
|
|
25689
|
+
error: addressError,
|
|
25690
|
+
style: { flex: 1 }
|
|
25691
|
+
}
|
|
25692
|
+
),
|
|
25693
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", onClick: handleAdd, loading: addLoading, children: "Add" }),
|
|
25694
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25695
|
+
Button,
|
|
25696
|
+
{
|
|
25697
|
+
size: "sm",
|
|
25698
|
+
variant: "subtle",
|
|
25699
|
+
color: colors.neutral,
|
|
25700
|
+
onClick: () => {
|
|
25701
|
+
setShowAddForm(false);
|
|
25702
|
+
setNewAddress("");
|
|
25703
|
+
setAddressError(null);
|
|
25704
|
+
},
|
|
25705
|
+
children: "Cancel"
|
|
25706
|
+
}
|
|
25707
|
+
)
|
|
25708
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
25709
|
+
Button,
|
|
25710
|
+
{
|
|
25711
|
+
variant: "light",
|
|
25712
|
+
size: "xs",
|
|
25713
|
+
leftSection: addIcon,
|
|
25714
|
+
onClick: () => setShowAddForm(true),
|
|
25715
|
+
mt: "xs",
|
|
25716
|
+
children: "Add Wallet"
|
|
25717
|
+
}
|
|
25718
|
+
)),
|
|
25719
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25720
|
+
ConfirmDialog,
|
|
25721
|
+
{
|
|
25722
|
+
title: "Remove Wallet",
|
|
25723
|
+
message: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { gap: "sm", children: [
|
|
25724
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: "sm", children: "Are you sure you want to remove this wallet address? This action cannot be undone." }),
|
|
25725
|
+
walletToRemove && /* @__PURE__ */ jsxRuntime.jsx(Text, { size: "sm", ff: "monospace", c: `${colors.neutral}.5`, children: walletToRemove }),
|
|
25726
|
+
removeError && /* @__PURE__ */ jsxRuntime.jsx(Text, { size: "sm", c: colors.error, children: removeError })
|
|
25727
|
+
] }),
|
|
25728
|
+
opened: walletToRemove !== null,
|
|
25729
|
+
confirmLabel: "Remove",
|
|
25730
|
+
confirmColor: colors.error,
|
|
25731
|
+
onConfirm: handleRemove,
|
|
25732
|
+
onCancel: () => {
|
|
25733
|
+
setWalletToRemove(null);
|
|
25734
|
+
setRemoveError(null);
|
|
25735
|
+
},
|
|
25736
|
+
loading: removeLoading
|
|
25737
|
+
}
|
|
25738
|
+
)
|
|
25739
|
+
] });
|
|
25740
|
+
}
|
|
25536
25741
|
function useDebouncedCallback(fn, delay) {
|
|
25537
25742
|
const timer = React.useRef(null);
|
|
25538
25743
|
const fnRef = React.useRef(fn);
|
|
@@ -25564,10 +25769,6 @@ const notify = {
|
|
|
25564
25769
|
warning: ({ title, message, autoClose = 5e3 }) => notifications.show({ title, message, color: colors.warning, autoClose }),
|
|
25565
25770
|
info: ({ title, message, autoClose = 4e3 }) => notifications.show({ title, message, color: colors.info, autoClose })
|
|
25566
25771
|
};
|
|
25567
|
-
function truncateAddress(address, chars = 4) {
|
|
25568
|
-
if (address.length <= chars * 2 + 2) return address;
|
|
25569
|
-
return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
|
|
25570
|
-
}
|
|
25571
25772
|
exports.AVATAR_PALETTE = AVATAR_PALETTE;
|
|
25572
25773
|
exports.ActionIcon = ActionIcon;
|
|
25573
25774
|
exports.Alert = Alert;
|
|
@@ -25591,6 +25792,7 @@ exports.DetailDrawer = DetailDrawer;
|
|
|
25591
25792
|
exports.Divider = Divider;
|
|
25592
25793
|
exports.DocumentRow = DocumentRow;
|
|
25593
25794
|
exports.Drawer = Drawer;
|
|
25795
|
+
exports.ETHEREUM_ADDRESS_REGEX = ETHEREUM_ADDRESS_REGEX;
|
|
25594
25796
|
exports.EmailField = EmailField;
|
|
25595
25797
|
exports.EmptyState = EmptyState;
|
|
25596
25798
|
exports.EquityGrantCard = EquityGrantCard;
|
|
@@ -25634,6 +25836,8 @@ exports.TextInput = TextInput;
|
|
|
25634
25836
|
exports.Title = Title;
|
|
25635
25837
|
exports.Tooltip = Tooltip;
|
|
25636
25838
|
exports.UserMenu = UserMenu;
|
|
25839
|
+
exports.WalletList = WalletList;
|
|
25840
|
+
exports.ZERO_ETHEREUM_ADDRESS = ZERO_ETHEREUM_ADDRESS;
|
|
25637
25841
|
exports.brandColors = brandColors;
|
|
25638
25842
|
exports.colors = colors;
|
|
25639
25843
|
exports.emailSchema = emailSchema;
|
|
@@ -25644,6 +25848,7 @@ exports.formatNumber = formatNumber;
|
|
|
25644
25848
|
exports.formatPercent = formatPercent;
|
|
25645
25849
|
exports.formatPreciseWithCurrency = formatPreciseWithCurrency;
|
|
25646
25850
|
exports.getAvatarColor = getAvatarColor;
|
|
25851
|
+
exports.isEthereumAddress = isEthereumAddress;
|
|
25647
25852
|
exports.neutralColors = neutralColors;
|
|
25648
25853
|
exports.notify = notify;
|
|
25649
25854
|
exports.passwordSchema = passwordSchema;
|
|
@@ -25664,5 +25869,6 @@ exports.useIsMobile = useIsMobile;
|
|
|
25664
25869
|
exports.useMediaQuery = useMediaQuery;
|
|
25665
25870
|
exports.useScrollIntoView = useScrollIntoView;
|
|
25666
25871
|
exports.useViewportSize = useViewportSize;
|
|
25872
|
+
exports.validateEthereumAddress = validateEthereumAddress;
|
|
25667
25873
|
exports.z = z;
|
|
25668
25874
|
//# sourceMappingURL=fairmint-ui.cjs.map
|