@fairmint/ui 0.2.2 → 0.2.4

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.
@@ -23733,6 +23733,46 @@ function EmailField({ error: error2, ...rest }) {
23733
23733
  }
23734
23734
  );
23735
23735
  }
23736
+ function truncateAddress(address, chars = 4) {
23737
+ if (address.length <= chars * 2 + 2) return address;
23738
+ return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
23739
+ }
23740
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
23741
+ const ETH_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
23742
+ function isEthereumAddress(value) {
23743
+ return ETH_ADDRESS_RE.test(value) && value.toLowerCase() !== ZERO_ADDRESS;
23744
+ }
23745
+ function validateEthereumAddress(value) {
23746
+ if (!ETH_ADDRESS_RE.test(value))
23747
+ return "Must be a valid Ethereum address (0x + 40 hex characters)";
23748
+ if (value.toLowerCase() === ZERO_ADDRESS) return "Cannot use the zero address";
23749
+ return null;
23750
+ }
23751
+ const ETHEREUM_ADDRESS_REGEX = ETH_ADDRESS_RE;
23752
+ const ZERO_ETHEREUM_ADDRESS = ZERO_ADDRESS;
23753
+ const ethereumAddressSchema = stringType().trim().regex(
23754
+ ETHEREUM_ADDRESS_REGEX,
23755
+ "Must be a valid Ethereum address (0x followed by 40 hex characters)"
23756
+ ).refine(
23757
+ (v) => v.toLowerCase() !== ZERO_ETHEREUM_ADDRESS.toLowerCase(),
23758
+ "Cannot use the zero address"
23759
+ );
23760
+ function EthereumAddressField({ error: error2, ...rest }) {
23761
+ return /* @__PURE__ */ jsx(
23762
+ TextInput,
23763
+ {
23764
+ type: "text",
23765
+ label: rest.label ?? "Wallet Address",
23766
+ placeholder: rest.placeholder ?? "0x...",
23767
+ autoComplete: "off",
23768
+ inputMode: "text",
23769
+ spellCheck: false,
23770
+ styles: { input: { fontFamily: "monospace" } },
23771
+ error: error2,
23772
+ ...rest
23773
+ }
23774
+ );
23775
+ }
23736
23776
  function validateFormName(name) {
23737
23777
  if (!/^[0-9a-zA-Z-]+$/.test(name)) {
23738
23778
  throw new Error(
@@ -24822,6 +24862,29 @@ function PhoneField({ error: error2, ...rest }) {
24822
24862
  }
24823
24863
  );
24824
24864
  }
24865
+ const US_ZIP_REGEX = /^\d{5}(-\d{4})?$/;
24866
+ const INTL_POSTAL_REGEX = /^[A-Z0-9]+(?:[ -][A-Z0-9]+)*$/i;
24867
+ function createZipSchema(options) {
24868
+ if (options?.international) {
24869
+ return stringType().trim().min(3, "Please enter a valid postal code").max(10, "Please enter a valid postal code").regex(INTL_POSTAL_REGEX, "Please enter a valid postal code");
24870
+ }
24871
+ return stringType().trim().regex(US_ZIP_REGEX, "Please enter a valid ZIP code (e.g. 94105 or 94105-1234)");
24872
+ }
24873
+ const zipSchema = createZipSchema();
24874
+ function ZipField({ error: error2, international = false, ...rest }) {
24875
+ return /* @__PURE__ */ jsx(
24876
+ TextInput,
24877
+ {
24878
+ type: "text",
24879
+ label: rest.label ?? "ZIP / Postal Code",
24880
+ placeholder: rest.placeholder ?? (international ? "SW1A 2AA" : "94105"),
24881
+ autoComplete: "postal-code",
24882
+ inputMode: "text",
24883
+ error: error2,
24884
+ ...rest
24885
+ }
24886
+ );
24887
+ }
24825
24888
  const ANIMATION_MAP = {
24826
24889
  up: "fadeUp",
24827
24890
  down: "fadeDown",
@@ -25054,6 +25117,75 @@ function DetailDrawer({
25054
25117
  }
25055
25118
  );
25056
25119
  }
25120
+ function EditableSection({
25121
+ title,
25122
+ readView,
25123
+ onSave,
25124
+ onCancel,
25125
+ disabled = false,
25126
+ onSaveError,
25127
+ editIcon,
25128
+ saveLabel = "Save",
25129
+ cancelLabel = "Cancel",
25130
+ children
25131
+ }) {
25132
+ const [isEditing, setIsEditing] = useState(false);
25133
+ const [isSaving, setIsSaving] = useState(false);
25134
+ useEffect(() => {
25135
+ if (disabled && isEditing) {
25136
+ onCancel?.();
25137
+ setIsEditing(false);
25138
+ }
25139
+ }, [disabled, isEditing, onCancel]);
25140
+ const handleEdit = () => setIsEditing(true);
25141
+ const handleSave = async () => {
25142
+ setIsSaving(true);
25143
+ try {
25144
+ await onSave();
25145
+ setIsEditing(false);
25146
+ } catch (err) {
25147
+ onSaveError?.(err);
25148
+ } finally {
25149
+ setIsSaving(false);
25150
+ }
25151
+ };
25152
+ const handleCancel = () => {
25153
+ onCancel?.();
25154
+ setIsEditing(false);
25155
+ };
25156
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
25157
+ (title || !disabled && !isEditing) && /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
25158
+ title && /* @__PURE__ */ jsx(Text, { fw: 500, size: "sm", children: title }),
25159
+ !disabled && !isEditing && (editIcon ? /* @__PURE__ */ jsx(
25160
+ ActionIcon,
25161
+ {
25162
+ variant: "subtle",
25163
+ size: "sm",
25164
+ onClick: handleEdit,
25165
+ "aria-label": `Edit ${typeof title === "string" ? title : "section"}`,
25166
+ children: editIcon
25167
+ }
25168
+ ) : /* @__PURE__ */ jsx(Button, { variant: "subtle", size: "xs", onClick: handleEdit, children: "Edit" }))
25169
+ ] }),
25170
+ isEditing ? /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
25171
+ children,
25172
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "flex-end", children: [
25173
+ /* @__PURE__ */ jsx(
25174
+ Button,
25175
+ {
25176
+ variant: "subtle",
25177
+ size: "xs",
25178
+ color: colors.neutral,
25179
+ onClick: handleCancel,
25180
+ disabled: isSaving,
25181
+ children: cancelLabel
25182
+ }
25183
+ ),
25184
+ /* @__PURE__ */ jsx(Button, { size: "xs", onClick: handleSave, loading: isSaving, children: saveLabel })
25185
+ ] })
25186
+ ] }) : readView
25187
+ ] });
25188
+ }
25057
25189
  const DefaultChevronIcon = () => /* @__PURE__ */ jsx(
25058
25190
  "svg",
25059
25191
  {
@@ -25515,23 +25647,6 @@ function InvestorProfileCard({
25515
25647
  children
25516
25648
  ] });
25517
25649
  }
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
25650
  const DEFAULT_TYPE_LABELS = {
25536
25651
  fairmint: "Fairmint Wallet",
25537
25652
  privy: "Fairmint Wallet",
@@ -25776,10 +25891,12 @@ export {
25776
25891
  DocumentRow,
25777
25892
  Drawer,
25778
25893
  ETHEREUM_ADDRESS_REGEX,
25894
+ EditableSection,
25779
25895
  EmailField,
25780
25896
  EmptyState,
25781
25897
  EquityGrantCard,
25782
25898
  ErrorFallback,
25899
+ EthereumAddressField,
25783
25900
  FairmintLogo,
25784
25901
  FairmintProvider,
25785
25902
  Flex,
@@ -25821,9 +25938,12 @@ export {
25821
25938
  UserMenu,
25822
25939
  WalletList,
25823
25940
  ZERO_ETHEREUM_ADDRESS,
25941
+ ZipField,
25824
25942
  brandColors,
25825
25943
  colors,
25944
+ createZipSchema,
25826
25945
  emailSchema,
25946
+ ethereumAddressSchema,
25827
25947
  formatCurrency,
25828
25948
  formatCurrencyPrecise,
25829
25949
  formatDate,
@@ -25853,6 +25973,7 @@ export {
25853
25973
  useScrollIntoView,
25854
25974
  useViewportSize,
25855
25975
  validateEthereumAddress,
25856
- z
25976
+ z,
25977
+ zipSchema
25857
25978
  };
25858
25979
  //# sourceMappingURL=fairmint-ui.js.map